llxfer_vfile.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /**
  2. * @file llxfer_vfile.cpp
  3. * @brief implementation of LLXfer_VFile class for a single xfer (vfile).
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-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_vfile.h"
  34. #include "lldir.h"
  35. #include "llfilesystem.h"
  36. #include "llmath.h"
  37. LLXfer_VFile::LLXfer_VFile()
  38. : LLXfer(-1),
  39. mDeleteTempFile(false)
  40. {
  41. init(LLUUID::null, LLAssetType::AT_NONE);
  42. }
  43. LLXfer_VFile::LLXfer_VFile(const LLUUID& local_id, LLAssetType::EType type)
  44. : LLXfer(-1),
  45. mDeleteTempFile(false)
  46. {
  47. init(local_id, type);
  48. }
  49. LLXfer_VFile::~LLXfer_VFile()
  50. {
  51. cleanup();
  52. }
  53. void LLXfer_VFile::init(const LLUUID& local_id, LLAssetType::EType type)
  54. {
  55. mLocalID = local_id;
  56. mType = type;
  57. mVFile = NULL;
  58. std::string id_string;
  59. mLocalID.toString(id_string);
  60. mName = llformat("VFile %s:%s", id_string.c_str(),
  61. LLAssetType::lookup(mType));
  62. }
  63. void LLXfer_VFile::cleanup()
  64. {
  65. if (mTempID.notNull() && mDeleteTempFile)
  66. {
  67. LLFileSystem file(mTempID);
  68. if (file.exists())
  69. {
  70. file.remove();
  71. }
  72. else
  73. {
  74. llwarns << "No matching cache file " << file.getName()
  75. << ". Nothing deleted." << llendl;
  76. }
  77. }
  78. if (mVFile)
  79. {
  80. delete mVFile;
  81. mVFile = NULL;
  82. }
  83. LLXfer::cleanup();
  84. }
  85. S32 LLXfer_VFile::initializeRequest(U64 xfer_id, const LLUUID& local_id,
  86. const LLUUID& remote_id,
  87. LLAssetType::EType type,
  88. const LLHost& remote_host,
  89. void (*callback)(void**, S32, LLExtStat),
  90. void** user_data)
  91. {
  92. mRemoteHost = remote_host;
  93. mLocalID = local_id;
  94. mRemoteID = remote_id;
  95. mType = type;
  96. mID = xfer_id;
  97. mCallback = callback;
  98. mCallbackDataHandle = user_data;
  99. mCallbackResult = LL_ERR_NOERR;
  100. std::string id_string;
  101. mLocalID.toString(id_string);
  102. mName = llformat("VFile %s:%s", id_string.c_str(),
  103. LLAssetType::lookup(mType));
  104. llinfos << "Requesting " << mName << llendl;
  105. if (mBuffer)
  106. {
  107. delete[] mBuffer;
  108. mBuffer = NULL;
  109. }
  110. mBuffer = new char[LL_MAX_XFER_FILE_BUFFER];
  111. mBufferLength = 0;
  112. mPacketNum = 0;
  113. mTempID.generate();
  114. mDeleteTempFile = true;
  115. mStatus = e_LL_XFER_PENDING;
  116. return LL_ERR_NOERR;
  117. }
  118. S32 LLXfer_VFile::startDownload()
  119. {
  120. LLMessageSystem* msg = gMessageSystemp;
  121. msg->newMessageFast(_PREHASH_RequestXfer);
  122. msg->nextBlockFast(_PREHASH_XferID);
  123. msg->addU64Fast(_PREHASH_ID, mID);
  124. msg->addStringFast(_PREHASH_Filename, "");
  125. msg->addU8("FilePath", (U8) LL_PATH_NONE);
  126. msg->addBool("DeleteOnCompletion", false);
  127. msg->addBool("UseBigPackets", mChunkSize == LL_XFER_LARGE_PAYLOAD);
  128. msg->addUUIDFast(_PREHASH_VFileID, mRemoteID);
  129. msg->addS16Fast(_PREHASH_VFileType, (S16)mType);
  130. msg->sendReliable(mRemoteHost);
  131. mStatus = e_LL_XFER_IN_PROGRESS;
  132. return LL_ERR_NOERR;
  133. }
  134. S32 LLXfer_VFile::startSend(U64 xfer_id, const LLHost& remote_host)
  135. {
  136. mRemoteHost = remote_host;
  137. mID = xfer_id;
  138. mPacketNum = -1;
  139. if (mBuffer)
  140. {
  141. delete[] mBuffer;
  142. }
  143. mBuffer = new char[LL_MAX_XFER_FILE_BUFFER];
  144. mBufferLength = 0;
  145. mBufferStartOffset = 0;
  146. if (mVFile)
  147. {
  148. delete mVFile;
  149. }
  150. mVFile = new LLFileSystem(mLocalID);
  151. if (!mVFile->exists())
  152. {
  153. llwarns << "Cannot read cache file " << mVFile->getName()
  154. << ". Aborted." << llendl;
  155. delete mVFile;
  156. mVFile = NULL;
  157. return LL_ERR_FILE_NOT_FOUND;
  158. }
  159. S32 size = mVFile->getSize();
  160. if (size <= 0)
  161. {
  162. llwarns << "Empty cache file " << mVFile->getName() << ". Aborted."
  163. << llendl;
  164. delete mVFile;
  165. mVFile = NULL;
  166. return LL_ERR_FILE_EMPTY;
  167. }
  168. setXferSize(size);
  169. mStatus = e_LL_XFER_PENDING;
  170. return LL_ERR_NOERR;
  171. }
  172. void LLXfer_VFile::closeFileHandle()
  173. {
  174. if (mVFile)
  175. {
  176. delete mVFile;
  177. mVFile = NULL;
  178. }
  179. }
  180. S32 LLXfer_VFile::reopenFileHandle()
  181. {
  182. if (!mVFile)
  183. {
  184. mVFile = new LLFileSystem(mLocalID);
  185. if (!mVFile->exists())
  186. {
  187. llwarns << "Cannot read cache file; " << mVFile->getName()
  188. << llendl;
  189. delete mVFile;
  190. mVFile = NULL;
  191. return LL_ERR_FILE_NOT_FOUND;
  192. }
  193. }
  194. return LL_ERR_NOERR;
  195. }
  196. void LLXfer_VFile::setXferSize(S32 xfer_size)
  197. {
  198. LLXfer::setXferSize(xfer_size);
  199. // Do not do this on the server side, where we have a persistent mVFile
  200. // It would be nice if LLXFers could tell which end of the pipe they were
  201. if (!mVFile)
  202. {
  203. LLFileSystem file(mTempID, LLFileSystem::APPEND);
  204. }
  205. }
  206. S32 LLXfer_VFile::suck(S32 start_position)
  207. {
  208. S32 retval = 0;
  209. if (mVFile)
  210. {
  211. // Grab a buffer from the right place in the file
  212. if (!mVFile->seek(start_position, 0))
  213. {
  214. llwarns << "VFile Xfer Can't seek to position: " << start_position
  215. << " - File length: " << mVFile->getSize()
  216. << " - While sending file " << mLocalID << llendl;
  217. return -1;
  218. }
  219. if (mVFile->read((U8*)mBuffer, LL_MAX_XFER_FILE_BUFFER))
  220. {
  221. mBufferLength = mVFile->getLastBytesRead();
  222. mBufferStartOffset = start_position;
  223. mBufferContainsEOF = mVFile->eof();
  224. }
  225. else
  226. {
  227. retval = -1;
  228. }
  229. }
  230. else
  231. {
  232. retval = -1;
  233. }
  234. return retval;
  235. }
  236. S32 LLXfer_VFile::flush()
  237. {
  238. if (mBufferLength)
  239. {
  240. LLFileSystem file(mTempID, LLFileSystem::APPEND);
  241. file.write((U8*)mBuffer, mBufferLength);
  242. mBufferLength = 0;
  243. }
  244. return LL_ERR_NOERR;
  245. }
  246. S32 LLXfer_VFile::processEOF()
  247. {
  248. mStatus = e_LL_XFER_COMPLETE;
  249. flush();
  250. if (!mCallbackResult)
  251. {
  252. LLFileSystem file(mTempID);
  253. if (file.exists())
  254. {
  255. if (file.rename(mLocalID))
  256. {
  257. // Rename worked and the original file is gone. Clear flag so
  258. // that we do not attempt to delete the gone file in cleanup().
  259. mDeleteTempFile = false;
  260. }
  261. else
  262. {
  263. llwarns << "Unable to rename cache file: " << file.getName()
  264. << llendl;
  265. }
  266. }
  267. else
  268. {
  269. llwarns << "Cannot open cache file: " << file.getName() << llendl;
  270. }
  271. }
  272. if (mVFile)
  273. {
  274. delete mVFile;
  275. mVFile = NULL;
  276. }
  277. return LLXfer::processEOF();
  278. }