00001
00032 #include "linden_common.h"
00033
00034 #if !LL_WINDOWS
00035 #include <errno.h>
00036 #include <unistd.h>
00037 #endif
00038
00039 #include "llxfer_file.h"
00040 #include "lluuid.h"
00041 #include "llerror.h"
00042 #include "llmath.h"
00043 #include "llstring.h"
00044 #include "lldir.h"
00045
00046
00047 const U32 LL_MAX_XFER_FILE_BUFFER = 65536;
00048
00049
00050 S32 copy_file(const char* from, const char* to);
00051
00053
00054 LLXfer_File::LLXfer_File (S32 chunk_size)
00055 : LLXfer(chunk_size)
00056 {
00057 init(LLString::null, FALSE, chunk_size);
00058 }
00059
00060 LLXfer_File::LLXfer_File (const LLString& local_filename, BOOL delete_local_on_completion, S32 chunk_size)
00061 : LLXfer(chunk_size)
00062 {
00063 init(local_filename, delete_local_on_completion, chunk_size);
00064 }
00065
00067
00068 LLXfer_File::~LLXfer_File ()
00069 {
00070 free();
00071 }
00072
00074
00075 void LLXfer_File::init (const LLString& local_filename, BOOL delete_local_on_completion, S32 chunk_size)
00076 {
00077
00078 mFp = NULL;
00079 mLocalFilename[0] = 0;
00080 mRemoteFilename[0] = 0;
00081 mRemotePath = LL_PATH_NONE;
00082 mTempFilename[0] = 0;
00083 mDeleteLocalOnCompletion = FALSE;
00084 mDeleteRemoteOnCompletion = FALSE;
00085
00086 if (!local_filename.empty())
00087 {
00088 strncpy(mLocalFilename, local_filename.c_str(), LL_MAX_PATH-1);
00089 mLocalFilename[LL_MAX_PATH-1] = '\0';
00090
00091
00092 mDeleteLocalOnCompletion = (delete_local_on_completion && (strstr(mLocalFilename,".tmp") == &mLocalFilename[strlen(mLocalFilename)-4]));
00093 }
00094 }
00095
00097
00098 void LLXfer_File::free ()
00099 {
00100 if (mFp)
00101 {
00102 fclose(mFp);
00103 mFp = NULL;
00104 }
00105
00106 LLFile::remove(mTempFilename);
00107
00108 if (mDeleteLocalOnCompletion)
00109 {
00110 lldebugs << "Removing file: " << mLocalFilename << llendl;
00111 LLFile::remove(mLocalFilename);
00112 }
00113 else
00114 {
00115 lldebugs << "Keeping local file: " << mLocalFilename << llendl;
00116 }
00117
00118 LLXfer::free();
00119 }
00120
00122
00123 S32 LLXfer_File::initializeRequest(U64 xfer_id,
00124 const LLString& local_filename,
00125 const LLString& remote_filename,
00126 ELLPath remote_path,
00127 const LLHost& remote_host,
00128 BOOL delete_remote_on_completion,
00129 void (*callback)(void**,S32,LLExtStat),
00130 void** user_data)
00131 {
00132 S32 retval = 0;
00133
00134 mID = xfer_id;
00135 strncpy(mLocalFilename, local_filename.c_str(), LL_MAX_PATH-1);
00136 mLocalFilename[LL_MAX_PATH-1] = '\0';
00137 strncpy(mRemoteFilename,remote_filename.c_str(), LL_MAX_PATH-1);
00138 mRemoteFilename[LL_MAX_PATH-1] = '\0';
00139 mRemotePath = remote_path;
00140 mRemoteHost = remote_host;
00141 mDeleteRemoteOnCompletion = delete_remote_on_completion;
00142
00143 snprintf(mTempFilename, sizeof(mTempFilename), "%s",gDirUtilp->getTempFilename().c_str());
00144
00145 mCallback = callback;
00146 mCallbackDataHandle = user_data;
00147 mCallbackResult = LL_ERR_NOERR;
00148
00149 llinfos << "Requesting xfer from " << remote_host << " for file: " << mLocalFilename << llendl;
00150
00151 if (mBuffer)
00152 {
00153 delete(mBuffer);
00154 mBuffer = NULL;
00155 }
00156
00157 mBuffer = new char[LL_MAX_XFER_FILE_BUFFER];
00158 mBufferLength = 0;
00159
00160 mPacketNum = 0;
00161
00162 mStatus = e_LL_XFER_PENDING;
00163 return retval;
00164 }
00165
00167
00168 S32 LLXfer_File::startDownload()
00169 {
00170 S32 retval = 0;
00171 mFp = LLFile::fopen(mTempFilename,"w+b");
00172 if (mFp)
00173 {
00174 fclose(mFp);
00175 mFp = NULL;
00176
00177 gMessageSystem->newMessageFast(_PREHASH_RequestXfer);
00178 gMessageSystem->nextBlockFast(_PREHASH_XferID);
00179 gMessageSystem->addU64Fast(_PREHASH_ID, mID);
00180 gMessageSystem->addStringFast(_PREHASH_Filename, mRemoteFilename);
00181 gMessageSystem->addU8("FilePath", (U8) mRemotePath);
00182 gMessageSystem->addBOOL("DeleteOnCompletion", mDeleteRemoteOnCompletion);
00183 gMessageSystem->addBOOL("UseBigPackets", BOOL(mChunkSize == LL_XFER_LARGE_PAYLOAD));
00184 gMessageSystem->addUUIDFast(_PREHASH_VFileID, LLUUID::null);
00185 gMessageSystem->addS16Fast(_PREHASH_VFileType, -1);
00186
00187 gMessageSystem->sendReliable(mRemoteHost);
00188 mStatus = e_LL_XFER_IN_PROGRESS;
00189 }
00190 else
00191 {
00192 llwarns << "Couldn't create file to be received!" << llendl;
00193 retval = -1;
00194 }
00195
00196 return (retval);
00197 }
00198
00200
00201 S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host)
00202 {
00203 S32 retval = LL_ERR_NOERR;
00204
00205 mRemoteHost = remote_host;
00206 mID = xfer_id;
00207 mPacketNum = -1;
00208
00209
00210
00211 delete [] mBuffer;
00212 mBuffer = new char[LL_MAX_XFER_FILE_BUFFER];
00213
00214 mBufferLength = 0;
00215 mBufferStartOffset = 0;
00216
00217 mFp = LLFile::fopen(mLocalFilename,"rb");
00218 if (mFp)
00219 {
00220 fseek(mFp,0,SEEK_END);
00221
00222 S32 file_size = ftell(mFp);
00223 if (file_size <= 0)
00224 {
00225 return LL_ERR_FILE_EMPTY;
00226 }
00227 setXferSize(file_size);
00228
00229 fseek(mFp,0,SEEK_SET);
00230 }
00231 else
00232 {
00233 llinfos << "Warning: " << mLocalFilename << " not found." << llendl;
00234 return (LL_ERR_FILE_NOT_FOUND);
00235 }
00236
00237 mStatus = e_LL_XFER_PENDING;
00238
00239 return (retval);
00240 }
00241
00243
00244 S32 LLXfer_File::getMaxBufferSize ()
00245 {
00246 return(LL_MAX_XFER_FILE_BUFFER);
00247 }
00248
00250
00251 S32 LLXfer_File::suck(S32 start_position)
00252 {
00253 S32 retval = 0;
00254
00255 if (mFp)
00256 {
00257
00258 fseek (mFp,start_position,SEEK_SET);
00259
00260 mBufferLength = (U32)fread(mBuffer,1,LL_MAX_XFER_FILE_BUFFER,mFp);
00261 mBufferStartOffset = start_position;
00262
00263 if (feof(mFp))
00264 {
00265 mBufferContainsEOF = TRUE;
00266 }
00267 else
00268 {
00269 mBufferContainsEOF = FALSE;
00270 }
00271 }
00272 else
00273 {
00274 retval = -1;
00275 }
00276
00277 return (retval);
00278 }
00279
00281
00282 S32 LLXfer_File::flush()
00283 {
00284 S32 retval = 0;
00285 if (mBufferLength)
00286 {
00287 if (mFp)
00288 {
00289 llerrs << "Overwriting open file pointer!" << llendl;
00290 }
00291 mFp = LLFile::fopen(mTempFilename,"a+b");
00292
00293 if (mFp)
00294 {
00295 if (fwrite(mBuffer,1,mBufferLength,mFp) != mBufferLength)
00296 {
00297 llwarns << "Short write" << llendl;
00298 }
00299
00300
00301 fclose(mFp);
00302 mFp = NULL;
00303
00304 mBufferLength = 0;
00305 }
00306 else
00307 {
00308 llwarns << "LLXfer_File::flush() unable to open " << mTempFilename << " for writing!" << llendl;
00309 retval = LL_ERR_CANNOT_OPEN_FILE;
00310 }
00311 }
00312 return (retval);
00313 }
00314
00316
00317 S32 LLXfer_File::processEOF()
00318 {
00319 S32 retval = 0;
00320 mStatus = e_LL_XFER_COMPLETE;
00321
00322 S32 flushval = flush();
00323
00324
00325
00326 if (!mCallbackResult)
00327 {
00328 mCallbackResult = flushval;
00329 }
00330
00331 LLFile::remove(mLocalFilename);
00332
00333 if (!mCallbackResult)
00334 {
00335 if (LLFile::rename(mTempFilename,mLocalFilename))
00336 {
00337 #if !LL_WINDOWS
00338 S32 error_number = errno;
00339 llinfos << "Rename failure (" << error_number << ") - "
00340 << mTempFilename << " to " << mLocalFilename << llendl;
00341 if(EXDEV == error_number)
00342 {
00343 if(copy_file(mTempFilename, mLocalFilename) == 0)
00344 {
00345 llinfos << "Rename across mounts; copying+unlinking the file instead." << llendl;
00346 unlink(mTempFilename);
00347 }
00348 else
00349 {
00350 llwarns << "Copy failure - " << mTempFilename << " to "
00351 << mLocalFilename << llendl;
00352 }
00353 }
00354 else
00355 {
00356
00357
00358
00359
00360
00361
00362
00363
00364 llwarns << "Rename fatally failed, can only handle EXDEV ("
00365 << EXDEV << ")" << llendl;
00366 }
00367 #else
00368 llwarns << "Rename failure - " << mTempFilename << " to "
00369 << mLocalFilename << llendl;
00370 #endif
00371 }
00372 }
00373
00374 if (mFp)
00375 {
00376 fclose(mFp);
00377 mFp = NULL;
00378 }
00379
00380 retval = LLXfer::processEOF();
00381
00382 return(retval);
00383 }
00384
00386
00387 BOOL LLXfer_File::matchesLocalFilename(const LLString& filename)
00388 {
00389 return (filename == mLocalFilename);
00390 }
00391
00393
00394 BOOL LLXfer_File::matchesRemoteFilename(const LLString& filename, ELLPath remote_path)
00395 {
00396 return ((filename == mRemoteFilename) && (remote_path == mRemotePath));
00397 }
00398
00399
00401
00402 const char * LLXfer_File::getName()
00403 {
00404 return (mLocalFilename);
00405 }
00406
00408
00409
00410
00411 U32 LLXfer_File::getXferTypeTag()
00412 {
00413 return LLXfer::XFER_FILE;
00414 }
00415
00417
00418 #if !LL_WINDOWS
00419
00420
00421
00422
00423
00424 S32 copy_file(const char* from, const char* to)
00425 {
00426 S32 rv = 0;
00427 FILE* in = LLFile::fopen(from, "rb");
00428 FILE* out = LLFile::fopen(to, "wb");
00429 if(in && out)
00430 {
00431 S32 read = 0;
00432 const S32 COPY_BUFFER_SIZE = 16384;
00433 U8 buffer[COPY_BUFFER_SIZE];
00434 while(((read = fread(buffer, 1, sizeof(buffer), in)) > 0)
00435 && (fwrite(buffer, 1, read, out) == (U32)read));
00436 if(ferror(in) || ferror(out)) rv = -2;
00437 }
00438 else
00439 {
00440 rv = -1;
00441 }
00442 if(in) fclose(in);
00443 if(out) fclose(out);
00444 return rv;
00445 }
00446 #endif