llxfer_file.cpp

Go to the documentation of this file.
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 // size of chunks read from/written to disk
00047 const U32 LL_MAX_XFER_FILE_BUFFER = 65536;
00048 
00049 // local function to copy a file
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'; // stupid strncpy.
00090 
00091                 // You can only automatically delete .tmp file as a safeguard against nasty messages.
00092                 mDeleteLocalOnCompletion = (delete_local_on_completion && (strstr(mLocalFilename,".tmp") == &mLocalFilename[strlen(mLocalFilename)-4]));                /* Flawfinder : ignore */
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;  // presume success
00133         
00134         mID = xfer_id;
00135         strncpy(mLocalFilename, local_filename.c_str(), LL_MAX_PATH-1);
00136         mLocalFilename[LL_MAX_PATH-1] = '\0'; // stupid strncpy.
00137         strncpy(mRemoteFilename,remote_filename.c_str(), LL_MAX_PATH-1);
00138         mRemoteFilename[LL_MAX_PATH-1] = '\0'; // stupid strncpy.
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());      /* Flawfinder: ignore */
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;  // presume success
00171         mFp = LLFile::fopen(mTempFilename,"w+b");               /* Flawfinder : ignore */
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;  // presume success
00204         
00205     mRemoteHost = remote_host;
00206         mID = xfer_id;
00207         mPacketNum = -1;
00208 
00209 //      cout << "Sending file: " << mLocalFilename << endl;
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");               /* Flawfinder : ignore */
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                 // grab a buffer from the right place in the file
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");               /* Flawfinder : ignore */
00292 
00293                 if (mFp)
00294                 {
00295                         if (fwrite(mBuffer,1,mBufferLength,mFp) != mBufferLength)
00296                         {
00297                                 llwarns << "Short write" << llendl;
00298                         }
00299                         
00300 //                      llinfos << "******* wrote " << mBufferLength << " bytes of file xfer" << llendl;
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         // If we have no other errors, our error becomes the error generated by
00325         // flush.
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                                 //FILE* fp = LLFile::fopen(mTempFilename, "r");
00357                                 //llwarns << "File " << mTempFilename << " does "
00358                                 //              << (!fp ? "not" : "" ) << " exit." << llendl;
00359                                 //if(fp) fclose(fp);
00360                                 //fp = LLFile::fopen(mLocalFilename, "r");
00361                                 //llwarns << "File " << mLocalFilename << " does "
00362                                 //              << (!fp ? "not" : "" ) << " exit." << llendl;
00363                                 //if(fp) fclose(fp);
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 // hacky - doesn't matter what this is
00410 // as long as it's different from the other classes
00411 U32 LLXfer_File::getXferTypeTag()
00412 {
00413         return LLXfer::XFER_FILE;
00414 }
00415 
00417 
00418 #if !LL_WINDOWS
00419 
00420 // This is really close to, but not quite a general purpose copy
00421 // function. It does not really spam enough information, but is useful
00422 // for this cpp file, because this should never be called in a
00423 // production environment.
00424 S32 copy_file(const char* from, const char* to)
00425 {
00426         S32 rv = 0;
00427         FILE* in = LLFile::fopen(from, "rb");   /*Flawfinder: ignore*/
00428         FILE* out = LLFile::fopen(to, "wb");    /*Flawfinder: ignore*/
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));              /* Flawfinder : ignore */
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

Generated on Thu Jul 1 06:09:47 2010 for Second Life Viewer by  doxygen 1.4.7