llxfer_file.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /**
  2. * @file llxfer_file.cpp
  3. * @brief implementation of LLXfer_File class for a single xfer (file)
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include "llxfer_file.h"
  34. #include "lldir.h"
  35. #include "llmath.h"
  36. #include "llstring.h"
  37. // local function to copy a file
  38. LLXfer_File::LLXfer_File (S32 chunk_size)
  39. : LLXfer(chunk_size)
  40. {
  41. init(LLStringUtil::null, false, chunk_size);
  42. }
  43. LLXfer_File::LLXfer_File (const std::string& local_filename,
  44. bool delete_local_on_completion, S32 chunk_size)
  45. : LLXfer(chunk_size)
  46. {
  47. init(local_filename, delete_local_on_completion, chunk_size);
  48. }
  49. LLXfer_File::~LLXfer_File ()
  50. {
  51. cleanup();
  52. }
  53. void LLXfer_File::init(const std::string& local_filename,
  54. bool delete_local_on_completion, S32 chunk_size)
  55. {
  56. mFp = NULL;
  57. mLocalFilename.clear();
  58. mRemoteFilename.clear();
  59. mRemotePath = LL_PATH_NONE;
  60. mTempFilename.clear();
  61. mDeleteLocalOnCompletion = false;
  62. mDeleteRemoteOnCompletion = false;
  63. if (!local_filename.empty())
  64. {
  65. mLocalFilename = local_filename.substr(0, LL_MAX_PATH - 1);
  66. // You can only automatically delete .tmp file as a safeguard against
  67. // nasty messages.
  68. std::string exten;
  69. exten = mLocalFilename.substr(mLocalFilename.length() - 4, 4);
  70. mDeleteLocalOnCompletion = delete_local_on_completion &&
  71. exten == ".tmp";
  72. }
  73. }
  74. void LLXfer_File::cleanup ()
  75. {
  76. if (mFp)
  77. {
  78. LLFile::close(mFp);
  79. mFp = NULL;
  80. }
  81. LLFile::remove(mTempFilename);
  82. if (mDeleteLocalOnCompletion)
  83. {
  84. LL_DEBUGS("FileTransfer") << "Removing file: " << mLocalFilename
  85. << LL_ENDL;
  86. LLFile::remove(mLocalFilename);
  87. }
  88. else
  89. {
  90. LL_DEBUGS("FileTransfer") << "Keeping local file: " << mLocalFilename
  91. << LL_ENDL;
  92. }
  93. LLXfer::cleanup();
  94. }
  95. S32 LLXfer_File::initializeRequest(U64 xfer_id,
  96. const std::string& local_filename,
  97. const std::string& remote_filename,
  98. ELLPath remote_path,
  99. const LLHost& remote_host,
  100. bool delete_remote_on_completion,
  101. void (*callback)(void**, S32, LLExtStat),
  102. void** user_data)
  103. {
  104. S32 retval = 0; // presume success
  105. mID = xfer_id;
  106. mLocalFilename = local_filename;
  107. mRemoteFilename = remote_filename;
  108. mRemotePath = remote_path;
  109. mRemoteHost = remote_host;
  110. mDeleteRemoteOnCompletion = delete_remote_on_completion;
  111. mTempFilename = gDirUtil.getTempFilename();
  112. mCallback = callback;
  113. mCallbackDataHandle = user_data;
  114. mCallbackResult = LL_ERR_NOERR;
  115. llinfos << "Requesting xfer from " << remote_host << " for file: "
  116. << 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. S32 LLXfer_File::startDownload()
  129. {
  130. S32 retval = 0; // presume success
  131. mFp = LLFile::open(mTempFilename, "w+b");
  132. if (mFp)
  133. {
  134. LLFile::close(mFp);
  135. mFp = NULL;
  136. LLMessageSystem* msg = gMessageSystemp;
  137. msg->newMessageFast(_PREHASH_RequestXfer);
  138. msg->nextBlockFast(_PREHASH_XferID);
  139. msg->addU64Fast(_PREHASH_ID, mID);
  140. msg->addStringFast(_PREHASH_Filename, mRemoteFilename);
  141. msg->addU8("FilePath", (U8) mRemotePath);
  142. msg->addBool("DeleteOnCompletion", mDeleteRemoteOnCompletion);
  143. msg->addBool("UseBigPackets", mChunkSize == LL_XFER_LARGE_PAYLOAD);
  144. msg->addUUIDFast(_PREHASH_VFileID, LLUUID::null);
  145. msg->addS16Fast(_PREHASH_VFileType, -1);
  146. msg->sendReliable(mRemoteHost);
  147. mStatus = e_LL_XFER_IN_PROGRESS;
  148. }
  149. else
  150. {
  151. llwarns << "Could not create file '" << mTempFilename
  152. << "' to be received !" << llendl;
  153. retval = -1;
  154. }
  155. return retval;
  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. delete [] mBuffer;
  164. mBuffer = new char[LL_MAX_XFER_FILE_BUFFER];
  165. mBufferLength = 0;
  166. mBufferStartOffset = 0;
  167. // We leave the file open, assuming we will start reading and sending soon
  168. mFp = LLFile::open(mLocalFilename, "rb");
  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. llwarns << mLocalFilename << " not found." << llendl;
  183. return LL_ERR_FILE_NOT_FOUND;
  184. }
  185. mStatus = e_LL_XFER_PENDING;
  186. return retval;
  187. }
  188. void LLXfer_File::closeFileHandle()
  189. {
  190. if (mFp)
  191. {
  192. LLFile::close(mFp);
  193. mFp = NULL;
  194. }
  195. }
  196. S32 LLXfer_File::reopenFileHandle()
  197. {
  198. if (!mFp)
  199. {
  200. mFp = LLFile::open(mLocalFilename, "rb");
  201. if (!mFp)
  202. {
  203. llwarns << mLocalFilename << " not found for reopening." << llendl;
  204. return LL_ERR_FILE_NOT_FOUND;
  205. }
  206. }
  207. return LL_ERR_NOERR;
  208. }
  209. S32 LLXfer_File::suck(S32 start_position)
  210. {
  211. if (mFp)
  212. {
  213. // Grab a buffer from the right place in the file
  214. fseek (mFp, start_position, SEEK_SET);
  215. mBufferLength = (U32)fread(mBuffer, 1, LL_MAX_XFER_FILE_BUFFER, mFp);
  216. mBufferStartOffset = start_position;
  217. mBufferContainsEOF = feof(mFp) != 0;
  218. return 0;
  219. }
  220. return -1;
  221. }
  222. S32 LLXfer_File::flush()
  223. {
  224. if (mBufferLength)
  225. {
  226. if (mFp)
  227. {
  228. llerrs << "Overwriting open file pointer !" << llendl;
  229. }
  230. mFp = LLFile::open(mTempFilename, "a+b");
  231. if (mFp)
  232. {
  233. S32 bytes_written = fwrite(mBuffer, 1, mBufferLength, mFp);
  234. if (bytes_written != (S32)mBufferLength)
  235. {
  236. llwarns << "Bad write size: requested " << mBufferLength
  237. << " bytes but wrote " << bytes_written << " bytes."
  238. << llendl;
  239. }
  240. LLFile::close(mFp);
  241. mFp = NULL;
  242. mBufferLength = 0;
  243. }
  244. else
  245. {
  246. llwarns << "Unable to open " << mTempFilename << " for writing !"
  247. << llendl;
  248. return LL_ERR_CANNOT_OPEN_FILE;
  249. }
  250. }
  251. return LL_ERR_NOERR;
  252. }
  253. S32 LLXfer_File::processEOF()
  254. {
  255. S32 retval = 0;
  256. mStatus = e_LL_XFER_COMPLETE;
  257. S32 flushval = flush();
  258. // If we have no other errors, our error becomes the error generated by
  259. // flush.
  260. if (!mCallbackResult)
  261. {
  262. mCallbackResult = flushval;
  263. }
  264. LLFile::remove(mLocalFilename);
  265. if (!mCallbackResult)
  266. {
  267. // Note: this will properly emit a warning in case of failure, and
  268. // after attempting a file move for renames across mounts under Linux
  269. // or macOS.
  270. LLFile::rename(mTempFilename, mLocalFilename, true);
  271. }
  272. if (mFp)
  273. {
  274. LLFile::close(mFp);
  275. mFp = NULL;
  276. }
  277. retval = LLXfer::processEOF();
  278. return retval;
  279. }