PageRenderTime 29ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llmessage/llxfer_file.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 439 lines | 296 code | 80 blank | 63 comment | 37 complexity | d055321016fb8582061ecd6139916ade MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llxfer_file.cpp
  3. * @brief implementation of LLXfer_File class for a single xfer (file)
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #if !LL_WINDOWS
  28. #include <errno.h>
  29. #include <unistd.h>
  30. #endif
  31. #include "llxfer_file.h"
  32. #include "lluuid.h"
  33. #include "llerror.h"
  34. #include "llmath.h"
  35. #include "llstring.h"
  36. #include "lldir.h"
  37. // size of chunks read from/written to disk
  38. const U32 LL_MAX_XFER_FILE_BUFFER = 65536;
  39. // local function to copy a file
  40. S32 copy_file(const std::string& from, const std::string& to);
  41. ///////////////////////////////////////////////////////////
  42. LLXfer_File::LLXfer_File (S32 chunk_size)
  43. : LLXfer(chunk_size)
  44. {
  45. init(LLStringUtil::null, FALSE, chunk_size);
  46. }
  47. LLXfer_File::LLXfer_File (const std::string& local_filename, BOOL delete_local_on_completion, S32 chunk_size)
  48. : LLXfer(chunk_size)
  49. {
  50. init(local_filename, delete_local_on_completion, chunk_size);
  51. }
  52. ///////////////////////////////////////////////////////////
  53. LLXfer_File::~LLXfer_File ()
  54. {
  55. cleanup();
  56. }
  57. ///////////////////////////////////////////////////////////
  58. void LLXfer_File::init (const std::string& local_filename, BOOL delete_local_on_completion, S32 chunk_size)
  59. {
  60. mFp = NULL;
  61. mLocalFilename.clear();
  62. mRemoteFilename.clear();
  63. mRemotePath = LL_PATH_NONE;
  64. mTempFilename.clear();
  65. mDeleteLocalOnCompletion = FALSE;
  66. mDeleteRemoteOnCompletion = FALSE;
  67. if (!local_filename.empty())
  68. {
  69. mLocalFilename = local_filename.substr(0,LL_MAX_PATH-1);
  70. // You can only automatically delete .tmp file as a safeguard against nasty messages.
  71. std::string exten = mLocalFilename.substr(mLocalFilename.length()-4, 4);
  72. mDeleteLocalOnCompletion = (delete_local_on_completion && exten == ".tmp");
  73. }
  74. }
  75. ///////////////////////////////////////////////////////////
  76. void LLXfer_File::cleanup ()
  77. {
  78. if (mFp)
  79. {
  80. fclose(mFp);
  81. mFp = NULL;
  82. }
  83. LLFile::remove(mTempFilename);
  84. if (mDeleteLocalOnCompletion)
  85. {
  86. lldebugs << "Removing file: " << mLocalFilename << llendl;
  87. LLFile::remove(mLocalFilename);
  88. }
  89. else
  90. {
  91. lldebugs << "Keeping local file: " << mLocalFilename << llendl;
  92. }
  93. LLXfer::cleanup();
  94. }
  95. ///////////////////////////////////////////////////////////
  96. S32 LLXfer_File::initializeRequest(U64 xfer_id,
  97. const std::string& local_filename,
  98. const std::string& remote_filename,
  99. ELLPath remote_path,
  100. const LLHost& remote_host,
  101. BOOL delete_remote_on_completion,
  102. void (*callback)(void**,S32,LLExtStat),
  103. void** user_data)
  104. {
  105. S32 retval = 0; // presume success
  106. mID = xfer_id;
  107. mLocalFilename = local_filename;
  108. mRemoteFilename = remote_filename;
  109. mRemotePath = remote_path;
  110. mRemoteHost = remote_host;
  111. mDeleteRemoteOnCompletion = delete_remote_on_completion;
  112. mTempFilename = gDirUtilp->getTempFilename();
  113. mCallback = callback;
  114. mCallbackDataHandle = user_data;
  115. mCallbackResult = LL_ERR_NOERR;
  116. llinfos << "Requesting xfer from " << remote_host << " for file: " << mLocalFilename << llendl;
  117. if (mBuffer)
  118. {
  119. delete(mBuffer);
  120. mBuffer = NULL;
  121. }
  122. mBuffer = new char[LL_MAX_XFER_FILE_BUFFER];
  123. mBufferLength = 0;
  124. mPacketNum = 0;
  125. mStatus = e_LL_XFER_PENDING;
  126. return retval;
  127. }
  128. ///////////////////////////////////////////////////////////
  129. S32 LLXfer_File::startDownload()
  130. {
  131. S32 retval = 0; // presume success
  132. mFp = LLFile::fopen(mTempFilename,"w+b"); /* Flawfinder : ignore */
  133. if (mFp)
  134. {
  135. fclose(mFp);
  136. mFp = NULL;
  137. gMessageSystem->newMessageFast(_PREHASH_RequestXfer);
  138. gMessageSystem->nextBlockFast(_PREHASH_XferID);
  139. gMessageSystem->addU64Fast(_PREHASH_ID, mID);
  140. gMessageSystem->addStringFast(_PREHASH_Filename, mRemoteFilename);
  141. gMessageSystem->addU8("FilePath", (U8) mRemotePath);
  142. gMessageSystem->addBOOL("DeleteOnCompletion", mDeleteRemoteOnCompletion);
  143. gMessageSystem->addBOOL("UseBigPackets", BOOL(mChunkSize == LL_XFER_LARGE_PAYLOAD));
  144. gMessageSystem->addUUIDFast(_PREHASH_VFileID, LLUUID::null);
  145. gMessageSystem->addS16Fast(_PREHASH_VFileType, -1);
  146. gMessageSystem->sendReliable(mRemoteHost);
  147. mStatus = e_LL_XFER_IN_PROGRESS;
  148. }
  149. else
  150. {
  151. llwarns << "Couldn't create file to be received!" << llendl;
  152. retval = -1;
  153. }
  154. return (retval);
  155. }
  156. ///////////////////////////////////////////////////////////
  157. S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host)
  158. {
  159. S32 retval = LL_ERR_NOERR; // presume success
  160. mRemoteHost = remote_host;
  161. mID = xfer_id;
  162. mPacketNum = -1;
  163. // cout << "Sending file: " << mLocalFilename << endl;
  164. delete [] mBuffer;
  165. mBuffer = new char[LL_MAX_XFER_FILE_BUFFER];
  166. mBufferLength = 0;
  167. mBufferStartOffset = 0;
  168. mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */
  169. if (mFp)
  170. {
  171. fseek(mFp,0,SEEK_END);
  172. S32 file_size = ftell(mFp);
  173. if (file_size <= 0)
  174. {
  175. return LL_ERR_FILE_EMPTY;
  176. }
  177. setXferSize(file_size);
  178. fseek(mFp,0,SEEK_SET);
  179. }
  180. else
  181. {
  182. llinfos << "Warning: " << mLocalFilename << " not found." << llendl;
  183. return (LL_ERR_FILE_NOT_FOUND);
  184. }
  185. mStatus = e_LL_XFER_PENDING;
  186. return (retval);
  187. }
  188. ///////////////////////////////////////////////////////////
  189. S32 LLXfer_File::getMaxBufferSize ()
  190. {
  191. return(LL_MAX_XFER_FILE_BUFFER);
  192. }
  193. ///////////////////////////////////////////////////////////
  194. S32 LLXfer_File::suck(S32 start_position)
  195. {
  196. S32 retval = 0;
  197. if (mFp)
  198. {
  199. // grab a buffer from the right place in the file
  200. fseek (mFp,start_position,SEEK_SET);
  201. mBufferLength = (U32)fread(mBuffer,1,LL_MAX_XFER_FILE_BUFFER,mFp);
  202. mBufferStartOffset = start_position;
  203. if (feof(mFp))
  204. {
  205. mBufferContainsEOF = TRUE;
  206. }
  207. else
  208. {
  209. mBufferContainsEOF = FALSE;
  210. }
  211. }
  212. else
  213. {
  214. retval = -1;
  215. }
  216. return (retval);
  217. }
  218. ///////////////////////////////////////////////////////////
  219. S32 LLXfer_File::flush()
  220. {
  221. S32 retval = 0;
  222. if (mBufferLength)
  223. {
  224. if (mFp)
  225. {
  226. llerrs << "Overwriting open file pointer!" << llendl;
  227. }
  228. mFp = LLFile::fopen(mTempFilename,"a+b"); /* Flawfinder : ignore */
  229. if (mFp)
  230. {
  231. if (fwrite(mBuffer,1,mBufferLength,mFp) != mBufferLength)
  232. {
  233. llwarns << "Short write" << llendl;
  234. }
  235. // llinfos << "******* wrote " << mBufferLength << " bytes of file xfer" << llendl;
  236. fclose(mFp);
  237. mFp = NULL;
  238. mBufferLength = 0;
  239. }
  240. else
  241. {
  242. llwarns << "LLXfer_File::flush() unable to open " << mTempFilename << " for writing!" << llendl;
  243. retval = LL_ERR_CANNOT_OPEN_FILE;
  244. }
  245. }
  246. return (retval);
  247. }
  248. ///////////////////////////////////////////////////////////
  249. S32 LLXfer_File::processEOF()
  250. {
  251. S32 retval = 0;
  252. mStatus = e_LL_XFER_COMPLETE;
  253. S32 flushval = flush();
  254. // If we have no other errors, our error becomes the error generated by
  255. // flush.
  256. if (!mCallbackResult)
  257. {
  258. mCallbackResult = flushval;
  259. }
  260. LLFile::remove(mLocalFilename);
  261. if (!mCallbackResult)
  262. {
  263. if (LLFile::rename(mTempFilename,mLocalFilename))
  264. {
  265. #if !LL_WINDOWS
  266. S32 error_number = errno;
  267. llinfos << "Rename failure (" << error_number << ") - "
  268. << mTempFilename << " to " << mLocalFilename << llendl;
  269. if(EXDEV == error_number)
  270. {
  271. if(copy_file(mTempFilename, mLocalFilename) == 0)
  272. {
  273. llinfos << "Rename across mounts; copying+unlinking the file instead." << llendl;
  274. unlink(mTempFilename.c_str());
  275. }
  276. else
  277. {
  278. llwarns << "Copy failure - " << mTempFilename << " to "
  279. << mLocalFilename << llendl;
  280. }
  281. }
  282. else
  283. {
  284. //LLFILE* fp = LLFile::fopen(mTempFilename, "r");
  285. //llwarns << "File " << mTempFilename << " does "
  286. // << (!fp ? "not" : "" ) << " exit." << llendl;
  287. //if(fp) fclose(fp);
  288. //fp = LLFile::fopen(mLocalFilename, "r");
  289. //llwarns << "File " << mLocalFilename << " does "
  290. // << (!fp ? "not" : "" ) << " exit." << llendl;
  291. //if(fp) fclose(fp);
  292. llwarns << "Rename fatally failed, can only handle EXDEV ("
  293. << EXDEV << ")" << llendl;
  294. }
  295. #else
  296. llwarns << "Rename failure - " << mTempFilename << " to "
  297. << mLocalFilename << llendl;
  298. #endif
  299. }
  300. }
  301. if (mFp)
  302. {
  303. fclose(mFp);
  304. mFp = NULL;
  305. }
  306. retval = LLXfer::processEOF();
  307. return(retval);
  308. }
  309. ///////////////////////////////////////////////////////////
  310. BOOL LLXfer_File::matchesLocalFilename(const std::string& filename)
  311. {
  312. return (filename == mLocalFilename);
  313. }
  314. ///////////////////////////////////////////////////////////
  315. BOOL LLXfer_File::matchesRemoteFilename(const std::string& filename, ELLPath remote_path)
  316. {
  317. return ((filename == mRemoteFilename) && (remote_path == mRemotePath));
  318. }
  319. ///////////////////////////////////////////////////////////
  320. std::string LLXfer_File::getFileName()
  321. {
  322. return mLocalFilename;
  323. }
  324. ///////////////////////////////////////////////////////////
  325. // hacky - doesn't matter what this is
  326. // as long as it's different from the other classes
  327. U32 LLXfer_File::getXferTypeTag()
  328. {
  329. return LLXfer::XFER_FILE;
  330. }
  331. ///////////////////////////////////////////////////////////
  332. #if !LL_WINDOWS
  333. // This is really close to, but not quite a general purpose copy
  334. // function. It does not really spam enough information, but is useful
  335. // for this cpp file, because this should never be called in a
  336. // production environment.
  337. S32 copy_file(const std::string& from, const std::string& to)
  338. {
  339. S32 rv = 0;
  340. LLFILE* in = LLFile::fopen(from, "rb"); /*Flawfinder: ignore*/
  341. LLFILE* out = LLFile::fopen(to, "wb"); /*Flawfinder: ignore*/
  342. if(in && out)
  343. {
  344. S32 read = 0;
  345. const S32 COPY_BUFFER_SIZE = 16384;
  346. U8 buffer[COPY_BUFFER_SIZE];
  347. while(((read = fread(buffer, 1, sizeof(buffer), in)) > 0)
  348. && (fwrite(buffer, 1, read, out) == (U32)read)); /* Flawfinder : ignore */
  349. if(ferror(in) || ferror(out)) rv = -2;
  350. }
  351. else
  352. {
  353. rv = -1;
  354. }
  355. if(in) fclose(in);
  356. if(out) fclose(out);
  357. return rv;
  358. }
  359. #endif