llvfs.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:57k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llvfs.cpp
  3.  * @brief Implementation of virtual file system
  4.  *
  5.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2002-2010, 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 <sys/stat.h>
  34. #include <set>
  35. #include <map>
  36. #if LL_WINDOWS
  37. #include <share.h>
  38. #elif LL_SOLARIS
  39. #include <sys/types.h>
  40. #include <unistd.h>
  41. #include <fcntl.h>
  42. #else
  43. #include <sys/file.h>
  44. #endif
  45.     
  46. #include "llvfs.h"
  47. #include "llstl.h"
  48. #include "lltimer.h"
  49.     
  50. const S32 FILE_BLOCK_MASK = 0x000003FF;  // 1024-byte blocks
  51. const S32 VFS_CLEANUP_SIZE = 5242880;  // how much space we free up in a single stroke
  52. const S32 BLOCK_LENGTH_INVALID = -1; // mLength for invalid LLVFSFileBlocks
  53. LLVFS *gVFS = NULL;
  54. // internal class definitions
  55. class LLVFSBlock
  56. {
  57. public:
  58. LLVFSBlock() 
  59. {
  60. mLocation = 0;
  61. mLength = 0;
  62. }
  63.     
  64. LLVFSBlock(U32 loc, S32 size)
  65. {
  66. mLocation = loc;
  67. mLength = size;
  68. }
  69.     
  70. static bool locationSortPredicate(
  71. const LLVFSBlock* lhs,
  72. const LLVFSBlock* rhs)
  73. {
  74. return lhs->mLocation < rhs->mLocation;
  75. }
  76. public:
  77. U32 mLocation;
  78. S32 mLength; // allocated block size
  79. };
  80.     
  81. LLVFSFileSpecifier::LLVFSFileSpecifier()
  82. : mFileID(),
  83. mFileType( LLAssetType::AT_NONE )
  84. {
  85. }
  86.     
  87. LLVFSFileSpecifier::LLVFSFileSpecifier(const LLUUID &file_id, const LLAssetType::EType file_type)
  88. {
  89. mFileID = file_id;
  90. mFileType = file_type;
  91. }
  92.     
  93. bool LLVFSFileSpecifier::operator<(const LLVFSFileSpecifier &rhs) const
  94. {
  95. return (mFileID == rhs.mFileID)
  96. ? mFileType < rhs.mFileType
  97. : mFileID < rhs.mFileID;
  98. }
  99.     
  100. bool LLVFSFileSpecifier::operator==(const LLVFSFileSpecifier &rhs) const
  101. {
  102. return (mFileID == rhs.mFileID && 
  103. mFileType == rhs.mFileType);
  104. }
  105.     
  106.     
  107. class LLVFSFileBlock : public LLVFSBlock, public LLVFSFileSpecifier
  108. {
  109. public:
  110. LLVFSFileBlock() : LLVFSBlock(), LLVFSFileSpecifier()
  111. {
  112. init();
  113. }
  114.     
  115. LLVFSFileBlock(const LLUUID &file_id, LLAssetType::EType file_type, U32 loc = 0, S32 size = 0)
  116. : LLVFSBlock(loc, size), LLVFSFileSpecifier( file_id, file_type )
  117. {
  118. init();
  119. }
  120. void init()
  121. {
  122. mSize = 0;
  123. mIndexLocation = -1;
  124. mAccessTime = (U32)time(NULL);
  125. for (S32 i = 0; i < (S32)VFSLOCK_COUNT; i++)
  126. {
  127. mLocks[(EVFSLock)i] = 0;
  128. }
  129. }
  130. #ifdef LL_LITTLE_ENDIAN
  131. inline void swizzleCopy(void *dst, void *src, int size) { memcpy(dst, src, size); /* Flawfinder: ignore */}
  132. #else
  133. inline U32 swizzle32(U32 x)
  134. {
  135. return(((x >> 24) & 0x000000FF) | ((x >> 8)  & 0x0000FF00) | ((x << 8)  & 0x00FF0000) |((x << 24) & 0xFF000000));
  136. }
  137. inline U16 swizzle16(U16 x)
  138. {
  139. return( ((x >> 8)  & 0x000000FF) | ((x << 8)  & 0x0000FF00) );
  140. }
  141. inline void swizzleCopy(void *dst, void *src, int size) 
  142. {
  143. if(size == 4)
  144. {
  145. ((U32*)dst)[0] = swizzle32(((U32*)src)[0]); 
  146. }
  147. else if(size == 2)
  148. {
  149. ((U16*)dst)[0] = swizzle16(((U16*)src)[0]); 
  150. }
  151. else
  152. {
  153. // Perhaps this should assert...
  154. memcpy(dst, src, size); /* Flawfinder: ignore */
  155. }
  156. }
  157. #endif
  158. void serialize(U8 *buffer)
  159. {
  160. swizzleCopy(buffer, &mLocation, 4);
  161. buffer += 4;
  162. swizzleCopy(buffer, &mLength, 4);
  163. buffer +=4;
  164. swizzleCopy(buffer, &mAccessTime, 4);
  165. buffer +=4;
  166. memcpy(buffer, &mFileID.mData, 16); /* Flawfinder: ignore */
  167. buffer += 16;
  168. S16 temp_type = mFileType;
  169. swizzleCopy(buffer, &temp_type, 2);
  170. buffer += 2;
  171. swizzleCopy(buffer, &mSize, 4);
  172. }
  173.     
  174. void deserialize(U8 *buffer, const S32 index_loc)
  175. {
  176. mIndexLocation = index_loc;
  177.     
  178. swizzleCopy(&mLocation, buffer, 4);
  179. buffer += 4;
  180. swizzleCopy(&mLength, buffer, 4);
  181. buffer += 4;
  182. swizzleCopy(&mAccessTime, buffer, 4);
  183. buffer += 4;
  184. memcpy(&mFileID.mData, buffer, 16);
  185. buffer += 16;
  186. S16 temp_type;
  187. swizzleCopy(&temp_type, buffer, 2);
  188. mFileType = (LLAssetType::EType)temp_type;
  189. buffer += 2;
  190. swizzleCopy(&mSize, buffer, 4);
  191. }
  192.     
  193. static BOOL insertLRU(LLVFSFileBlock* const& first,
  194.   LLVFSFileBlock* const& second)
  195. {
  196. return (first->mAccessTime == second->mAccessTime)
  197. ? *first < *second
  198. : first->mAccessTime < second->mAccessTime;
  199. }
  200.     
  201. public:
  202. S32  mSize;
  203. S32  mIndexLocation; // location of index entry
  204. U32  mAccessTime;
  205. BOOL mLocks[VFSLOCK_COUNT]; // number of outstanding locks of each type
  206.     
  207. static const S32 SERIAL_SIZE;
  208. };
  209. // Helper structure for doing lru w/ stl... is there a simpler way?
  210. struct LLVFSFileBlock_less
  211. {
  212. bool operator()(LLVFSFileBlock* const& lhs, LLVFSFileBlock* const& rhs) const
  213. {
  214. return (LLVFSFileBlock::insertLRU(lhs, rhs)) ? true : false;
  215. }
  216. };
  217. const S32 LLVFSFileBlock::SERIAL_SIZE = 34;
  218.      
  219. LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash)
  220. : mRemoveAfterCrash(remove_after_crash),
  221. mDataFP(NULL),
  222. mIndexFP(NULL)
  223. {
  224. mDataMutex = new LLMutex(0);
  225. S32 i;
  226. for (i = 0; i < VFSLOCK_COUNT; i++)
  227. {
  228. mLockCounts[i] = 0;
  229. }
  230. mValid = VFSVALID_OK;
  231. mReadOnly = read_only;
  232. mIndexFilename = index_filename;
  233. mDataFilename = data_filename;
  234.     
  235. const char *file_mode = mReadOnly ? "rb" : "r+b";
  236.     
  237. LL_INFOS("VFS") << "Attempting to open VFS index file " << mIndexFilename << LL_ENDL;
  238. LL_INFOS("VFS") << "Attempting to open VFS data file " << mDataFilename << LL_ENDL;
  239. mDataFP = openAndLock(mDataFilename, file_mode, mReadOnly);
  240. if (!mDataFP)
  241. {
  242. if (mReadOnly)
  243. {
  244. LL_WARNS("VFS") << "Can't find " << mDataFilename << " to open read-only VFS" << LL_ENDL;
  245. mValid = VFSVALID_BAD_CANNOT_OPEN_READONLY;
  246. return;
  247. }
  248. mDataFP = openAndLock(mDataFilename, "w+b", FALSE);
  249. if (mDataFP)
  250. {
  251. // Since we're creating this data file, assume any index file is bogus
  252. // remove the index, since this vfs is now blank
  253. LLFile::remove(mIndexFilename);
  254. }
  255. else
  256. {
  257. LL_WARNS("VFS") << "Couldn't open vfs data file " 
  258. << mDataFilename << LL_ENDL;
  259. mValid = VFSVALID_BAD_CANNOT_CREATE;
  260. return;
  261. }
  262. if (presize)
  263. {
  264. presizeDataFile(presize);
  265. }
  266. }
  267. // Did we leave this file open for writing last time?
  268. // If so, close it and start over.
  269. if (!mReadOnly && mRemoveAfterCrash)
  270. {
  271. llstat marker_info;
  272. std::string marker = mDataFilename + ".open";
  273. if (!LLFile::stat(marker, &marker_info))
  274. {
  275. // marker exists, kill the lock and the VFS files
  276. unlockAndClose(mDataFP);
  277. mDataFP = NULL;
  278. LL_WARNS("VFS") << "VFS: File left open on last run, removing old VFS file " << mDataFilename << LL_ENDL;
  279. LLFile::remove(mIndexFilename);
  280. LLFile::remove(mDataFilename);
  281. LLFile::remove(marker);
  282. mDataFP = openAndLock(mDataFilename, "w+b", FALSE);
  283. if (!mDataFP)
  284. {
  285. LL_WARNS("VFS") << "Can't open VFS data file in crash recovery" << LL_ENDL;
  286. mValid = VFSVALID_BAD_CANNOT_CREATE;
  287. return;
  288. }
  289. if (presize)
  290. {
  291. presizeDataFile(presize);
  292. }
  293. }
  294. }
  295. // determine the real file size
  296. fseek(mDataFP, 0, SEEK_END);
  297. U32 data_size = ftell(mDataFP);
  298. // read the index file
  299. // make sure there's at least one file in it too
  300. // if not, we'll treat this as a new vfs
  301. llstat fbuf;
  302. if (! LLFile::stat(mIndexFilename, &fbuf) &&
  303. fbuf.st_size >= LLVFSFileBlock::SERIAL_SIZE &&
  304. (mIndexFP = openAndLock(mIndexFilename, file_mode, mReadOnly)) // Yes, this is an assignment and not '=='
  305. )
  306. {
  307. std::vector<U8> buffer(fbuf.st_size);
  308.      size_t buf_offset = 0;
  309. size_t nread = fread(&buffer[0], 1, fbuf.st_size, mIndexFP);
  310.  
  311. std::vector<LLVFSFileBlock*> files_by_loc;
  312. while (buf_offset < nread)
  313. {
  314. LLVFSFileBlock *block = new LLVFSFileBlock();
  315.     
  316. block->deserialize(&buffer[buf_offset], (S32)buf_offset);
  317.     
  318. // Do sanity check on this block.
  319. // Note that this skips zero size blocks, which helps VFS
  320. // to heal after some errors. JC
  321. if (block->mLength > 0 &&
  322. (U32)block->mLength <= data_size &&
  323. block->mLocation < data_size &&
  324. block->mSize > 0 &&
  325. block->mSize <= block->mLength &&
  326. block->mFileType >= LLAssetType::AT_NONE &&
  327. block->mFileType < LLAssetType::AT_COUNT)
  328. {
  329. mFileBlocks.insert(fileblock_map::value_type(*block, block));
  330. files_by_loc.push_back(block);
  331. }
  332. else
  333. if (block->mLength && block->mSize > 0)
  334. {
  335. // this is corrupt, not empty
  336. LL_WARNS("VFS") << "VFS corruption: " << block->mFileID << " (" << block->mFileType << ") at index " << block->mIndexLocation << " DS: " << data_size << LL_ENDL;
  337. LL_WARNS("VFS") << "Length: " << block->mLength << "tLocation: " << block->mLocation << "tSize: " << block->mSize << LL_ENDL;
  338. LL_WARNS("VFS") << "File has bad data - VFS removed" << LL_ENDL;
  339. delete block;
  340. unlockAndClose( mIndexFP );
  341. mIndexFP = NULL;
  342. LLFile::remove( mIndexFilename );
  343. unlockAndClose( mDataFP );
  344. mDataFP = NULL;
  345. LLFile::remove( mDataFilename );
  346. LL_WARNS("VFS") << "Deleted corrupt VFS files " 
  347. << mDataFilename 
  348. << " and "
  349. << mIndexFilename
  350. << LL_ENDL;
  351. mValid = VFSVALID_BAD_CORRUPT;
  352. return;
  353. }
  354. else
  355. {
  356. // this is a null or bad entry, skip it
  357. mIndexHoles.push_back(buf_offset);
  358.     
  359. delete block;
  360. }
  361.     
  362. buf_offset += LLVFSFileBlock::SERIAL_SIZE;
  363. }
  364. std::sort(
  365. files_by_loc.begin(),
  366. files_by_loc.end(),
  367. LLVFSFileBlock::locationSortPredicate);
  368. // There are 3 cases that have to be considered.
  369. // 1. No blocks
  370. // 2. One block.
  371. // 3. Two or more blocks.
  372. if (!files_by_loc.empty())
  373. {
  374. // cur walks through the list.
  375. std::vector<LLVFSFileBlock*>::iterator cur = files_by_loc.begin();
  376. std::vector<LLVFSFileBlock*>::iterator end = files_by_loc.end();
  377. LLVFSFileBlock* last_file_block = *cur;
  378. // Check to see if there is an empty space before the first file.
  379. if (last_file_block->mLocation > 0)
  380. {
  381. // If so, create a free block.
  382. addFreeBlock(new LLVFSBlock(0, last_file_block->mLocation));
  383. }
  384. // Walk through the 2nd+ block.  If there is a free space
  385. // between cur_file_block and last_file_block, add it to
  386. // the free space collection.  This block will not need to
  387. // run in the case there is only one entry in the VFS.
  388. ++cur;
  389. while( cur != end )
  390. {
  391. LLVFSFileBlock* cur_file_block = *cur;
  392. // Dupe check on the block
  393. if (cur_file_block->mLocation == last_file_block->mLocation
  394. && cur_file_block->mLength == last_file_block->mLength)
  395. {
  396. LL_WARNS("VFS") << "VFS: removing duplicate entry"
  397. << " at " << cur_file_block->mLocation 
  398. << " length " << cur_file_block->mLength 
  399. << " size " << cur_file_block->mSize
  400. << " ID " << cur_file_block->mFileID 
  401. << " type " << cur_file_block->mFileType 
  402. << LL_ENDL;
  403. // Duplicate entries.  Nuke them both for safety.
  404. mFileBlocks.erase(*cur_file_block); // remove ID/type entry
  405. if (cur_file_block->mLength > 0)
  406. {
  407. // convert to hole
  408. addFreeBlock(
  409. new LLVFSBlock(
  410. cur_file_block->mLocation,
  411. cur_file_block->mLength));
  412. }
  413. lockData(); // needed for sync()
  414. sync(cur_file_block, TRUE); // remove first on disk
  415. sync(last_file_block, TRUE); // remove last on disk
  416. unlockData(); // needed for sync()
  417. last_file_block = cur_file_block;
  418. ++cur;
  419. continue;
  420. }
  421. // Figure out where the last block ended.
  422. S32 loc = last_file_block->mLocation+last_file_block->mLength;
  423. // Figure out how much space there is between where
  424. // the last block ended and this block begins.
  425. S32 length = cur_file_block->mLocation - loc;
  426.     
  427. // Check for more errors...  Seeing if the current
  428. // entry and the last entry make sense together.
  429. if (length < 0 || loc < 0 || (U32)loc > data_size)
  430. {
  431. // Invalid VFS
  432. unlockAndClose( mIndexFP );
  433. mIndexFP = NULL;
  434. LLFile::remove( mIndexFilename );
  435. unlockAndClose( mDataFP );
  436. mDataFP = NULL;
  437. LLFile::remove( mDataFilename );
  438. LL_WARNS("VFS") << "VFS: overlapping entries"
  439. << " at " << cur_file_block->mLocation 
  440. << " length " << cur_file_block->mLength 
  441. << " ID " << cur_file_block->mFileID 
  442. << " type " << cur_file_block->mFileType 
  443. << LL_ENDL;
  444. LL_WARNS("VFS") << "Deleted corrupt VFS files " 
  445. << mDataFilename 
  446. << " and "
  447. << mIndexFilename
  448. << LL_ENDL;
  449. mValid = VFSVALID_BAD_CORRUPT;
  450. return;
  451. }
  452. // we don't want to add empty blocks to the list...
  453. if (length > 0)
  454. {
  455. addFreeBlock(new LLVFSBlock(loc, length));
  456. }
  457. last_file_block = cur_file_block;
  458. ++cur;
  459. }
  460.     
  461. // also note any empty space at the end
  462. U32 loc = last_file_block->mLocation + last_file_block->mLength;
  463. if (loc < data_size)
  464. {
  465. addFreeBlock(new LLVFSBlock(loc, data_size - loc));
  466. }
  467. }
  468. else // There where no blocks in the file.
  469. {
  470. addFreeBlock(new LLVFSBlock(0, data_size));
  471. }
  472. }
  473. else // Pre-existing index file wasn't opened
  474. {
  475. if (mReadOnly)
  476. {
  477. LL_WARNS("VFS") << "Can't find " << mIndexFilename << " to open read-only VFS" << LL_ENDL;
  478. mValid = VFSVALID_BAD_CANNOT_OPEN_READONLY;
  479. return;
  480. }
  481.     
  482. mIndexFP = openAndLock(mIndexFilename, "w+b", FALSE);
  483. if (!mIndexFP)
  484. {
  485. LL_WARNS("VFS") << "Couldn't open an index file for the VFS, probably a sharing violation!" << LL_ENDL;
  486. unlockAndClose( mDataFP );
  487. mDataFP = NULL;
  488. LLFile::remove( mDataFilename );
  489. mValid = VFSVALID_BAD_CANNOT_CREATE;
  490. return;
  491. }
  492. // no index file, start from scratch w/ 1GB allocation
  493. LLVFSBlock *first_block = new LLVFSBlock(0, data_size ? data_size : 0x40000000);
  494. addFreeBlock(first_block);
  495. }
  496. // Open marker file to look for bad shutdowns
  497. if (!mReadOnly && mRemoveAfterCrash)
  498. {
  499. std::string marker = mDataFilename + ".open";
  500. LLFILE* marker_fp = LLFile::fopen(marker, "w"); /* Flawfinder: ignore */
  501. if (marker_fp)
  502. {
  503. fclose(marker_fp);
  504. marker_fp = NULL;
  505. }
  506. }
  507. LL_INFOS("VFS") << "Using VFS index file " << mIndexFilename << LL_ENDL;
  508. LL_INFOS("VFS") << "Using VFS data file " << mDataFilename << LL_ENDL;
  509. mValid = VFSVALID_OK;
  510. }
  511.     
  512. LLVFS::~LLVFS()
  513. {
  514. if (mDataMutex->isLocked())
  515. {
  516. LL_ERRS("VFS") << "LLVFS destroyed with mutex locked" << LL_ENDL;
  517. }
  518. unlockAndClose(mIndexFP);
  519. mIndexFP = NULL;
  520. fileblock_map::const_iterator it;
  521. for (it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it)
  522. {
  523. delete (*it).second;
  524. }
  525. mFileBlocks.clear();
  526. mFreeBlocksByLength.clear();
  527. for_each(mFreeBlocksByLocation.begin(), mFreeBlocksByLocation.end(), DeletePairedPointer());
  528.     
  529. unlockAndClose(mDataFP);
  530. mDataFP = NULL;
  531.     
  532. // Remove marker file
  533. if (!mReadOnly && mRemoveAfterCrash)
  534. {
  535. std::string marker = mDataFilename + ".open";
  536. LLFile::remove(marker);
  537. }
  538. delete mDataMutex;
  539. }
  540. // Use this function normally to create LLVFS files.  
  541. // Will append digits to the end of the filename with multiple re-trys
  542. // static 
  543. LLVFS * LLVFS::createLLVFS(const std::string& index_filename, 
  544. const std::string& data_filename, 
  545. const BOOL read_only, 
  546. const U32 presize, 
  547. const BOOL remove_after_crash)
  548. {
  549. LLVFS * new_vfs = new LLVFS(index_filename, data_filename, read_only, presize, remove_after_crash);
  550. if( !new_vfs->isValid() )
  551. { // First name failed, retry with new names
  552. std::string retry_vfs_index_name;
  553. std::string retry_vfs_data_name;
  554. S32 count = 0;
  555. while (!new_vfs->isValid() &&
  556. count < 256)
  557. { // Append '.<number>' to end of filenames
  558. retry_vfs_index_name = index_filename + llformat(".%u",count);
  559. retry_vfs_data_name = data_filename + llformat(".%u", count);
  560. delete new_vfs; // Delete bad VFS and try again
  561. new_vfs = new LLVFS(retry_vfs_index_name, retry_vfs_data_name, read_only, presize, remove_after_crash);
  562. count++;
  563. }
  564. }
  565. if( !new_vfs->isValid() )
  566. {
  567. delete new_vfs; // Delete bad VFS
  568. new_vfs = NULL; // Total failure
  569. }
  570. return new_vfs;
  571. }
  572. void LLVFS::presizeDataFile(const U32 size)
  573. {
  574. if (!mDataFP)
  575. {
  576. llerrs << "LLVFS::presizeDataFile() with no data file open" << llendl;
  577. return;
  578. }
  579. // we're creating this file for the first time, size it
  580. fseek(mDataFP, size-1, SEEK_SET);
  581. S32 tmp = 0;
  582. tmp = (S32)fwrite(&tmp, 1, 1, mDataFP);
  583. // fflush(mDataFP);
  584. // also remove any index, since this vfs is now blank
  585. LLFile::remove(mIndexFilename);
  586. if (tmp)
  587. {
  588. llinfos << "Pre-sized VFS data file to " << ftell(mDataFP) << " bytes" << llendl;
  589. }
  590. else
  591. {
  592. llwarns << "Failed to pre-size VFS data file" << llendl;
  593. }
  594. }
  595. BOOL LLVFS::getExists(const LLUUID &file_id, const LLAssetType::EType file_type)
  596. {
  597. LLVFSFileBlock *block = NULL;
  598. if (!isValid())
  599. {
  600. llerrs << "Attempting to use invalid VFS!" << llendl;
  601. }
  602. lockData();
  603. LLVFSFileSpecifier spec(file_id, file_type);
  604. fileblock_map::iterator it = mFileBlocks.find(spec);
  605. if (it != mFileBlocks.end())
  606. {
  607. block = (*it).second;
  608. block->mAccessTime = (U32)time(NULL);
  609. }
  610. BOOL res = (block && block->mLength > 0) ? TRUE : FALSE;
  611. unlockData();
  612. return res;
  613. }
  614.     
  615. S32  LLVFS::getSize(const LLUUID &file_id, const LLAssetType::EType file_type)
  616. {
  617. S32 size = 0;
  618. if (!isValid())
  619. {
  620. llerrs << "Attempting to use invalid VFS!" << llendl;
  621. }
  622. lockData();
  623. LLVFSFileSpecifier spec(file_id, file_type);
  624. fileblock_map::iterator it = mFileBlocks.find(spec);
  625. if (it != mFileBlocks.end())
  626. {
  627. LLVFSFileBlock *block = (*it).second;
  628. block->mAccessTime = (U32)time(NULL);
  629. size = block->mSize;
  630. }
  631. unlockData();
  632. return size;
  633. }
  634.     
  635. S32  LLVFS::getMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type)
  636. {
  637. S32 size = 0;
  638. if (!isValid())
  639. {
  640. llerrs << "Attempting to use invalid VFS!" << llendl;
  641. }
  642. lockData();
  643. LLVFSFileSpecifier spec(file_id, file_type);
  644. fileblock_map::iterator it = mFileBlocks.find(spec);
  645. if (it != mFileBlocks.end())
  646. {
  647. LLVFSFileBlock *block = (*it).second;
  648. block->mAccessTime = (U32)time(NULL);
  649. size = block->mLength;
  650. }
  651. unlockData();
  652. return size;
  653. }
  654. BOOL LLVFS::checkAvailable(S32 max_size)
  655. {
  656. lockData();
  657. blocks_length_map_t::iterator iter = mFreeBlocksByLength.lower_bound(max_size); // first entry >= size
  658. const BOOL res(iter == mFreeBlocksByLength.end() ? FALSE : TRUE);
  659. unlockData();
  660. return res;
  661. }
  662. BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type, S32 max_size)
  663. {
  664. if (!isValid())
  665. {
  666. llerrs << "Attempting to use invalid VFS!" << llendl;
  667. }
  668. if (mReadOnly)
  669. {
  670. llerrs << "Attempt to write to read-only VFS" << llendl;
  671. }
  672. if (max_size <= 0)
  673. {
  674. llwarns << "VFS: Attempt to assign size " << max_size << " to vfile " << file_id << llendl;
  675. return FALSE;
  676. }
  677. lockData();
  678. LLVFSFileSpecifier spec(file_id, file_type);
  679. LLVFSFileBlock *block = NULL;
  680. fileblock_map::iterator it = mFileBlocks.find(spec);
  681. if (it != mFileBlocks.end())
  682. {
  683. block = (*it).second;
  684. }
  685.     
  686. // round all sizes upward to KB increments
  687. // SJB: Need to not round for the new texture-pipeline code so we know the correct
  688. //      max file size. Need to investigate the potential problems with this...
  689. if (file_type != LLAssetType::AT_TEXTURE)
  690. {
  691. if (max_size & FILE_BLOCK_MASK)
  692. {
  693. max_size += FILE_BLOCK_MASK;
  694. max_size &= ~FILE_BLOCK_MASK;
  695. }
  696.     }
  697. if (block && block->mLength > 0)
  698. {    
  699. block->mAccessTime = (U32)time(NULL);
  700.     
  701. if (max_size == block->mLength)
  702. {
  703. unlockData();
  704. return TRUE;
  705. }
  706. else if (max_size < block->mLength)
  707. {
  708. // this file is shrinking
  709. LLVFSBlock *free_block = new LLVFSBlock(block->mLocation + max_size, block->mLength - max_size);
  710. addFreeBlock(free_block);
  711.     
  712. block->mLength = max_size;
  713.     
  714. if (block->mLength < block->mSize)
  715. {
  716. // JC: Was a warning, but Ian says it's bad.
  717. llerrs << "Truncating virtual file " << file_id << " to " << block->mLength << " bytes" << llendl;
  718. block->mSize = block->mLength;
  719. }
  720.     
  721. sync(block);
  722. //mergeFreeBlocks();
  723. unlockData();
  724. return TRUE;
  725. }
  726. else if (max_size > block->mLength)
  727. {
  728. // this file is growing
  729. // first check for an adjacent free block to grow into
  730. S32 size_increase = max_size - block->mLength;
  731. // Find the first free block with and addres > block->mLocation
  732. LLVFSBlock *free_block;
  733. blocks_location_map_t::iterator iter = mFreeBlocksByLocation.upper_bound(block->mLocation);
  734. if (iter != mFreeBlocksByLocation.end())
  735. {
  736. free_block = iter->second;
  737. if (free_block->mLocation == block->mLocation + block->mLength &&
  738. free_block->mLength >= size_increase)
  739. {
  740. // this free block is at the end of the file and is large enough
  741. // Must call useFreeSpace before sync(), as sync()
  742. // unlocks data structures.
  743. useFreeSpace(free_block, size_increase);
  744. block->mLength += size_increase;
  745. sync(block);
  746. unlockData();
  747. return TRUE;
  748. }
  749. }
  750. // no adjecent free block, find one in the list
  751. free_block = findFreeBlock(max_size, block);
  752.     
  753. if (free_block)
  754. {
  755. // Save location where data is going, useFreeSpace will move free_block->mLocation;
  756. U32 new_data_location = free_block->mLocation;
  757. //mark the free block as used so it does not
  758. //interfere with other operations such as addFreeBlock
  759. useFreeSpace(free_block, max_size); // useFreeSpace takes ownership (and may delete) free_block
  760. if (block->mLength > 0)
  761. {
  762. // create a new free block where this file used to be
  763. LLVFSBlock *new_free_block = new LLVFSBlock(block->mLocation, block->mLength);
  764. addFreeBlock(new_free_block);
  765. if (block->mSize > 0)
  766. {
  767. // move the file into the new block
  768. std::vector<U8> buffer(block->mSize);
  769. fseek(mDataFP, block->mLocation, SEEK_SET);
  770. if (fread(&buffer[0], block->mSize, 1, mDataFP) == 1)
  771. {
  772. fseek(mDataFP, new_data_location, SEEK_SET);
  773. if (fwrite(&buffer[0], block->mSize, 1, mDataFP) != 1)
  774. {
  775. llwarns << "Short write" << llendl;
  776. }
  777. } else {
  778. llwarns << "Short read" << llendl;
  779. }
  780. }
  781. }
  782.     
  783. block->mLocation = new_data_location;
  784.     
  785. block->mLength = max_size;
  786. sync(block);
  787. unlockData();
  788. return TRUE;
  789. }
  790. else
  791. {
  792. llwarns << "VFS: No space (" << max_size << ") to resize existing vfile " << file_id << llendl;
  793. //dumpMap();
  794. unlockData();
  795. dumpStatistics();
  796. return FALSE;
  797. }
  798. }
  799. }
  800. else
  801. {
  802. // find a free block in the list
  803. LLVFSBlock *free_block = findFreeBlock(max_size);
  804.     
  805. if (free_block)
  806. {        
  807. if (block)
  808. {
  809. block->mLocation = free_block->mLocation;
  810. block->mLength = max_size;
  811. }
  812. else
  813. {
  814. // this file doesn't exist, create it
  815. block = new LLVFSFileBlock(file_id, file_type, free_block->mLocation, max_size);
  816. mFileBlocks.insert(fileblock_map::value_type(spec, block));
  817. }
  818. // Must call useFreeSpace before sync(), as sync()
  819. // unlocks data structures.
  820. useFreeSpace(free_block, max_size);
  821. block->mAccessTime = (U32)time(NULL);
  822. sync(block);
  823. }
  824. else
  825. {
  826. llwarns << "VFS: No space (" << max_size << ") for new virtual file " << file_id << llendl;
  827. //dumpMap();
  828. unlockData();
  829. dumpStatistics();
  830. return FALSE;
  831. }
  832. }
  833. unlockData();
  834. return TRUE;
  835. }
  836. // WARNING: HERE BE DRAGONS!
  837. // rename is the weirdest VFS op, because the file moves but the locks don't!
  838. void LLVFS::renameFile(const LLUUID &file_id, const LLAssetType::EType file_type,
  839.    const LLUUID &new_id, const LLAssetType::EType &new_type)
  840. {
  841. if (!isValid())
  842. {
  843. llerrs << "Attempting to use invalid VFS!" << llendl;
  844. }
  845. if (mReadOnly)
  846. {
  847. llerrs << "Attempt to write to read-only VFS" << llendl;
  848. }
  849. lockData();
  850. LLVFSFileSpecifier new_spec(new_id, new_type);
  851. LLVFSFileSpecifier old_spec(file_id, file_type);
  852. fileblock_map::iterator it = mFileBlocks.find(old_spec);
  853. if (it != mFileBlocks.end())
  854. {
  855. LLVFSFileBlock *src_block = (*it).second;
  856. // this will purge the data but leave the file block in place, w/ locks, if any
  857. // WAS: removeFile(new_id, new_type); NOW uses removeFileBlock() to avoid mutex lock recursion
  858. fileblock_map::iterator new_it = mFileBlocks.find(new_spec);
  859. if (new_it != mFileBlocks.end())
  860. {
  861. LLVFSFileBlock *new_block = (*new_it).second;
  862. removeFileBlock(new_block);
  863. }
  864. // if there's something in the target location, remove it but inherit its locks
  865. it = mFileBlocks.find(new_spec);
  866. if (it != mFileBlocks.end())
  867. {
  868. LLVFSFileBlock *dest_block = (*it).second;
  869. for (S32 i = 0; i < (S32)VFSLOCK_COUNT; i++)
  870. {
  871. if(dest_block->mLocks[i])
  872. {
  873. llerrs << "Renaming VFS block to a locked file." << llendl;
  874. }
  875. dest_block->mLocks[i] = src_block->mLocks[i];
  876. }
  877. mFileBlocks.erase(new_spec);
  878. delete dest_block;
  879. }
  880. src_block->mFileID = new_id;
  881. src_block->mFileType = new_type;
  882. src_block->mAccessTime = (U32)time(NULL);
  883.    
  884. mFileBlocks.erase(old_spec);
  885. mFileBlocks.insert(fileblock_map::value_type(new_spec, src_block));
  886. sync(src_block);
  887. }
  888. else
  889. {
  890. llwarns << "VFS: Attempt to rename nonexistent vfile " << file_id << ":" << file_type << llendl;
  891. }
  892. unlockData();
  893. }
  894. // mDataMutex must be LOCKED before calling this
  895. void LLVFS::removeFileBlock(LLVFSFileBlock *fileblock)
  896. {
  897. // convert this into an unsaved, dummy fileblock to preserve locks
  898. // a more rubust solution would store the locks in a seperate data structure
  899. sync(fileblock, TRUE);
  900. if (fileblock->mLength > 0)
  901. {
  902. // turn this file into an empty block
  903. LLVFSBlock *free_block = new LLVFSBlock(fileblock->mLocation, fileblock->mLength);
  904. addFreeBlock(free_block);
  905. }
  906. fileblock->mLocation = 0;
  907. fileblock->mSize = 0;
  908. fileblock->mLength = BLOCK_LENGTH_INVALID;
  909. fileblock->mIndexLocation = -1;
  910. //mergeFreeBlocks();
  911. }
  912. void LLVFS::removeFile(const LLUUID &file_id, const LLAssetType::EType file_type)
  913. {
  914. if (!isValid())
  915. {
  916. llerrs << "Attempting to use invalid VFS!" << llendl;
  917. }
  918. if (mReadOnly)
  919. {
  920. llerrs << "Attempt to write to read-only VFS" << llendl;
  921. }
  922.     lockData();
  923. LLVFSFileSpecifier spec(file_id, file_type);
  924. fileblock_map::iterator it = mFileBlocks.find(spec);
  925. if (it != mFileBlocks.end())
  926. {
  927. LLVFSFileBlock *block = (*it).second;
  928. removeFileBlock(block);
  929. }
  930. else
  931. {
  932. llwarns << "VFS: attempting to remove nonexistent file " << file_id << " type " << file_type << llendl;
  933. }
  934. unlockData();
  935. }
  936.     
  937.     
  938. S32 LLVFS::getData(const LLUUID &file_id, const LLAssetType::EType file_type, U8 *buffer, S32 location, S32 length)
  939. {
  940. S32 bytesread = 0;
  941. if (!isValid())
  942. {
  943. llerrs << "Attempting to use invalid VFS!" << llendl;
  944. }
  945. llassert(location >= 0);
  946. llassert(length >= 0);
  947. BOOL do_read = FALSE;
  948.     lockData();
  949. LLVFSFileSpecifier spec(file_id, file_type);
  950. fileblock_map::iterator it = mFileBlocks.find(spec);
  951. if (it != mFileBlocks.end())
  952. {
  953. LLVFSFileBlock *block = (*it).second;
  954. block->mAccessTime = (U32)time(NULL);
  955.     
  956. if (location > block->mSize)
  957. {
  958. llwarns << "VFS: Attempt to read location " << location << " in file " << file_id << " of length " << block->mSize << llendl;
  959. }
  960. else
  961. {
  962. if (length > block->mSize - location)
  963. {
  964. length = block->mSize - location;
  965. }
  966. location += block->mLocation;
  967. do_read = TRUE;
  968. }
  969. }
  970. if (do_read)
  971. {
  972. fseek(mDataFP, location, SEEK_SET);
  973. bytesread = (S32)fread(buffer, 1, length, mDataFP);
  974. }
  975. unlockData();
  976. return bytesread;
  977. }
  978.     
  979. S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type, const U8 *buffer, S32 location, S32 length)
  980. {
  981. if (!isValid())
  982. {
  983. llerrs << "Attempting to use invalid VFS!" << llendl;
  984. }
  985. if (mReadOnly)
  986. {
  987. llerrs << "Attempt to write to read-only VFS" << llendl;
  988. }
  989.     
  990. llassert(length > 0);
  991.     lockData();
  992.     
  993. LLVFSFileSpecifier spec(file_id, file_type);
  994. fileblock_map::iterator it = mFileBlocks.find(spec);
  995. if (it != mFileBlocks.end())
  996. {
  997. LLVFSFileBlock *block = (*it).second;
  998. S32 in_loc = location;
  999. if (location == -1)
  1000. {
  1001. location = block->mSize;
  1002. }
  1003. llassert(location >= 0);
  1004. block->mAccessTime = (U32)time(NULL);
  1005.     
  1006. if (block->mLength == BLOCK_LENGTH_INVALID)
  1007. {
  1008. // Block was removed, ignore write
  1009. llwarns << "VFS: Attempt to write to invalid block"
  1010. << " in file " << file_id 
  1011. << " location: " << in_loc
  1012. << " bytes: " << length
  1013. << llendl;
  1014. unlockData();
  1015. return length;
  1016. }
  1017. else if (location > block->mLength)
  1018. {
  1019. llwarns << "VFS: Attempt to write to location " << location 
  1020. << " in file " << file_id 
  1021. << " type " << S32(file_type)
  1022. << " of size " << block->mSize
  1023. << " block length " << block->mLength
  1024. << llendl;
  1025. unlockData();
  1026. return length;
  1027. }
  1028. else
  1029. {
  1030. if (length > block->mLength - location )
  1031. {
  1032. llwarns << "VFS: Truncating write to virtual file " << file_id << " type " << S32(file_type) << llendl;
  1033. length = block->mLength - location;
  1034. }
  1035. U32 file_location = location + block->mLocation;
  1036. fseek(mDataFP, file_location, SEEK_SET);
  1037. S32 write_len = (S32)fwrite(buffer, 1, length, mDataFP);
  1038. if (write_len != length)
  1039. {
  1040. llwarns << llformat("VFS Write Error: %d != %d",write_len,length) << llendl;
  1041. }
  1042. // fflush(mDataFP);
  1043. if (location + length > block->mSize)
  1044. {
  1045. block->mSize = location + write_len;
  1046. sync(block);
  1047. }
  1048. unlockData();
  1049. return write_len;
  1050. }
  1051. }
  1052. else
  1053. {
  1054. unlockData();
  1055. return 0;
  1056. }
  1057. }
  1058.  
  1059. void LLVFS::incLock(const LLUUID &file_id, const LLAssetType::EType file_type, EVFSLock lock)
  1060. {
  1061. lockData();
  1062. LLVFSFileSpecifier spec(file_id, file_type);
  1063. LLVFSFileBlock *block;
  1064.   fileblock_map::iterator it = mFileBlocks.find(spec);
  1065. if (it != mFileBlocks.end())
  1066. {
  1067. block = (*it).second;
  1068. }
  1069. else
  1070. {
  1071. // Create a dummy block which isn't saved
  1072. block = new LLVFSFileBlock(file_id, file_type, 0, BLOCK_LENGTH_INVALID);
  1073.      block->mAccessTime = (U32)time(NULL);
  1074. mFileBlocks.insert(fileblock_map::value_type(spec, block));
  1075. }
  1076. block->mLocks[lock]++;
  1077. mLockCounts[lock]++;
  1078. unlockData();
  1079. }
  1080. void LLVFS::decLock(const LLUUID &file_id, const LLAssetType::EType file_type, EVFSLock lock)
  1081. {
  1082. lockData();
  1083. LLVFSFileSpecifier spec(file_id, file_type);
  1084.   fileblock_map::iterator it = mFileBlocks.find(spec);
  1085. if (it != mFileBlocks.end())
  1086. {
  1087. LLVFSFileBlock *block = (*it).second;
  1088. if (block->mLocks[lock] > 0)
  1089. {
  1090. block->mLocks[lock]--;
  1091. }
  1092. else
  1093. {
  1094. llwarns << "VFS: Decrementing zero-value lock " << lock << llendl;
  1095. }
  1096. mLockCounts[lock]--;
  1097. }
  1098. unlockData();
  1099. }
  1100. BOOL LLVFS::isLocked(const LLUUID &file_id, const LLAssetType::EType file_type, EVFSLock lock)
  1101. {
  1102. lockData();
  1103. BOOL res = FALSE;
  1104. LLVFSFileSpecifier spec(file_id, file_type);
  1105.   fileblock_map::iterator it = mFileBlocks.find(spec);
  1106. if (it != mFileBlocks.end())
  1107. {
  1108. LLVFSFileBlock *block = (*it).second;
  1109. res = (block->mLocks[lock] > 0);
  1110. }
  1111. unlockData();
  1112. return res;
  1113. }
  1114. //============================================================================
  1115. // protected
  1116. //============================================================================
  1117. void LLVFS::eraseBlockLength(LLVFSBlock *block)
  1118. {
  1119. // find the corresponding map entry in the length map and erase it
  1120. S32 length = block->mLength;
  1121. blocks_length_map_t::iterator iter = mFreeBlocksByLength.lower_bound(length);
  1122. blocks_length_map_t::iterator end = mFreeBlocksByLength.end();
  1123. bool found_block = false;
  1124. while(iter != end)
  1125. {
  1126. LLVFSBlock *tblock = iter->second;
  1127. llassert(tblock->mLength == length); // there had -better- be an entry with our length!
  1128. if (tblock == block)
  1129. {
  1130. mFreeBlocksByLength.erase(iter);
  1131. found_block = true;
  1132. break;
  1133. }
  1134. ++iter;
  1135. }
  1136. if(!found_block)
  1137. {
  1138. llerrs << "eraseBlock could not find block" << llendl;
  1139. }
  1140. }
  1141. // Remove block from both free lists (by location and by length).
  1142. void LLVFS::eraseBlock(LLVFSBlock *block)
  1143. {
  1144. eraseBlockLength(block);
  1145. // find the corresponding map entry in the location map and erase it
  1146. U32 location = block->mLocation;
  1147. llverify(mFreeBlocksByLocation.erase(location) == 1); // we should only have one entry per location.
  1148. }
  1149. // Add the region specified by block location and length to the free lists.
  1150. // Also incrementally defragment by merging with previous and next free blocks.
  1151. void LLVFS::addFreeBlock(LLVFSBlock *block)
  1152. {
  1153. #if LL_DEBUG
  1154. size_t dbgcount = mFreeBlocksByLocation.count(block->mLocation);
  1155. if(dbgcount > 0)
  1156. {
  1157. llerrs << "addFreeBlock called with block already in list" << llendl;
  1158. }
  1159. #endif
  1160. // Get a pointer to the next free block (by location).
  1161. blocks_location_map_t::iterator next_free_it = mFreeBlocksByLocation.lower_bound(block->mLocation);
  1162. // We can merge with previous if it ends at our requested location.
  1163. LLVFSBlock* prev_block = NULL;
  1164. bool merge_prev = false;
  1165. if (next_free_it != mFreeBlocksByLocation.begin())
  1166. {
  1167. blocks_location_map_t::iterator prev_free_it = next_free_it;
  1168. --prev_free_it;
  1169. prev_block = prev_free_it->second;
  1170. merge_prev = (prev_block->mLocation + prev_block->mLength == block->mLocation);
  1171. }
  1172. // We can merge with next if our block ends at the next block's location.
  1173. LLVFSBlock* next_block = NULL;
  1174. bool merge_next = false;
  1175. if (next_free_it != mFreeBlocksByLocation.end())
  1176. {
  1177. next_block = next_free_it->second;
  1178. merge_next = (block->mLocation + block->mLength == next_block->mLocation);
  1179. }
  1180. if (merge_prev && merge_next)
  1181. {
  1182. // llinfos << "VFS merge BOTH" << llendl;
  1183. // Previous block is changing length (a lot), so only need to update length map.
  1184. // Next block is going away completely. JC
  1185. eraseBlockLength(prev_block);
  1186. eraseBlock(next_block);
  1187. prev_block->mLength += block->mLength + next_block->mLength;
  1188. mFreeBlocksByLength.insert(blocks_length_map_t::value_type(prev_block->mLength, prev_block));
  1189. delete block;
  1190. block = NULL;
  1191. delete next_block;
  1192. next_block = NULL;
  1193. }
  1194. else if (merge_prev)
  1195. {
  1196. // llinfos << "VFS merge previous" << llendl;
  1197. // Previous block is maintaining location, only changing length,
  1198. // therefore only need to update the length map. JC
  1199. eraseBlockLength(prev_block);
  1200. prev_block->mLength += block->mLength;
  1201. mFreeBlocksByLength.insert(blocks_length_map_t::value_type(prev_block->mLength, prev_block)); // multimap insert
  1202. delete block;
  1203. block = NULL;
  1204. }
  1205. else if (merge_next)
  1206. {
  1207. // llinfos << "VFS merge next" << llendl;
  1208. // Next block is changing both location and length,
  1209. // so both free lists must update. JC
  1210. eraseBlock(next_block);
  1211. next_block->mLocation = block->mLocation;
  1212. next_block->mLength += block->mLength;
  1213. // Don't hint here, next_free_it iterator may be invalid.
  1214. mFreeBlocksByLocation.insert(blocks_location_map_t::value_type(next_block->mLocation, next_block)); // multimap insert
  1215. mFreeBlocksByLength.insert(blocks_length_map_t::value_type(next_block->mLength, next_block)); // multimap insert
  1216. delete block;
  1217. block = NULL;
  1218. }
  1219. else
  1220. {
  1221. // Can't merge with other free blocks.
  1222. // Hint that insert should go near next_free_it.
  1223.   mFreeBlocksByLocation.insert(next_free_it, blocks_location_map_t::value_type(block->mLocation, block)); // multimap insert
  1224.   mFreeBlocksByLength.insert(blocks_length_map_t::value_type(block->mLength, block)); // multimap insert
  1225. }
  1226. }
  1227. // Superceeded by new addFreeBlock which does incremental free space merging.
  1228. // Incremental is faster overall.
  1229. //void LLVFS::mergeFreeBlocks()
  1230. //{
  1231. //  if (!isValid())
  1232. //  {
  1233. //  llerrs << "Attempting to use invalid VFS!" << llendl;
  1234. //  }
  1235. //  // TODO: could we optimize this with hints from the calling code?
  1236. //  blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin();
  1237. //  blocks_location_map_t::iterator end = mFreeBlocksByLocation.end();
  1238. //  LLVFSBlock *first_block = iter->second;
  1239. //  while(iter != end)
  1240. //  {
  1241. //  blocks_location_map_t::iterator first_iter = iter; // save for if we do a merge
  1242. //  if (++iter == end)
  1243. //  break;
  1244. //  LLVFSBlock *second_block = iter->second;
  1245. //  if (first_block->mLocation + first_block->mLength == second_block->mLocation)
  1246. //  {
  1247. //  // remove the first block from the length map
  1248. //  eraseBlockLength(first_block);
  1249. //  // merge first_block with second_block, since they're adjacent
  1250. //  first_block->mLength += second_block->mLength;
  1251. //  // add the first block to the length map (with the new size)
  1252. //  mFreeBlocksByLength.insert(blocks_length_map_t::value_type(first_block->mLength, first_block)); // multimap insert
  1253. //
  1254. //  // erase and delete the second block
  1255. //  eraseBlock(second_block);
  1256. //  delete second_block;
  1257. //
  1258. //  // reset iterator
  1259. //  iter = first_iter; // haven't changed first_block, so corresponding iterator is still valid
  1260. //  end = mFreeBlocksByLocation.end();
  1261. //  }
  1262. //  first_block = second_block;
  1263. //  }
  1264. //}
  1265. // length bytes from free_block are going to be used (so they are no longer free)
  1266. void LLVFS::useFreeSpace(LLVFSBlock *free_block, S32 length)
  1267. {
  1268. if (free_block->mLength == length)
  1269. {
  1270. eraseBlock(free_block);
  1271. delete free_block;
  1272. }
  1273. else
  1274. {
  1275. eraseBlock(free_block);
  1276.   
  1277. free_block->mLocation += length;
  1278. free_block->mLength -= length;
  1279. addFreeBlock(free_block);
  1280. }
  1281. }
  1282. // NOTE! mDataMutex must be LOCKED before calling this
  1283. // sync this index entry out to the index file
  1284. // we need to do this constantly to avoid corruption on viewer crash
  1285. void LLVFS::sync(LLVFSFileBlock *block, BOOL remove)
  1286. {
  1287. if (!isValid())
  1288. {
  1289. llerrs << "Attempting to use invalid VFS!" << llendl;
  1290. }
  1291. if (mReadOnly)
  1292. {
  1293. llwarns << "Attempt to sync read-only VFS" << llendl;
  1294. return;
  1295. }
  1296. if (block->mLength == BLOCK_LENGTH_INVALID)
  1297. {
  1298. // This is a dummy file, don't save
  1299. return;
  1300. }
  1301. if (block->mLength == 0)
  1302. {
  1303. llerrs << "VFS syncing zero-length block" << llendl;
  1304. }
  1305.     BOOL set_index_to_end = FALSE;
  1306. long seek_pos = block->mIndexLocation;
  1307. if (-1 == seek_pos)
  1308. {
  1309. if (!mIndexHoles.empty())
  1310. {
  1311. seek_pos = mIndexHoles.front();
  1312. mIndexHoles.pop_front();
  1313. }
  1314. else
  1315. {
  1316. set_index_to_end = TRUE;
  1317. }
  1318. }
  1319.     if (set_index_to_end)
  1320. {
  1321. // Need fseek/ftell to update the seek_pos and hence data
  1322. // structures, so can't unlockData() before this.
  1323. fseek(mIndexFP, 0, SEEK_END);
  1324. seek_pos = ftell(mIndexFP);
  1325. }
  1326.     
  1327. block->mIndexLocation = seek_pos;
  1328. if (remove)
  1329. {
  1330. mIndexHoles.push_back(seek_pos);
  1331. }
  1332. U8 buffer[LLVFSFileBlock::SERIAL_SIZE];
  1333. if (remove)
  1334. {
  1335. memset(buffer, 0, LLVFSFileBlock::SERIAL_SIZE);
  1336. }
  1337. else
  1338. {
  1339. block->serialize(buffer);
  1340. }
  1341. // If set_index_to_end, file pointer is already at seek_pos
  1342. // and we don't need to do anything.  Only seek if not at end.
  1343. if (!set_index_to_end)
  1344. {
  1345. fseek(mIndexFP, seek_pos, SEEK_SET);
  1346. }
  1347. if (fwrite(buffer, LLVFSFileBlock::SERIAL_SIZE, 1, mIndexFP) != 1)
  1348. {
  1349. llwarns << "Short write" << llendl;
  1350. }
  1351. // *NOTE:  Why was this commented out?
  1352. // fflush(mIndexFP);
  1353. return;
  1354. }
  1355. // mDataMutex must be LOCKED before calling this
  1356. // Can initiate LRU-based file removal to make space.
  1357. // The immune file block will not be removed.
  1358. LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune)
  1359. {
  1360. if (!isValid())
  1361. {
  1362. llerrs << "Attempting to use invalid VFS!" << llendl;
  1363. }
  1364. LLVFSBlock *block = NULL;
  1365. BOOL have_lru_list = FALSE;
  1366. typedef std::set<LLVFSFileBlock*, LLVFSFileBlock_less> lru_set;
  1367. lru_set lru_list;
  1368.     
  1369. LLTimer timer;
  1370. while (! block)
  1371. {
  1372. // look for a suitable free block
  1373. blocks_length_map_t::iterator iter = mFreeBlocksByLength.lower_bound(size); // first entry >= size
  1374. if (iter != mFreeBlocksByLength.end())
  1375. block = iter->second;
  1376.     
  1377. // no large enough free blocks, time to clean out some junk
  1378. if (! block)
  1379. {
  1380. // create a list of files sorted by usage time
  1381. // this is far faster than sorting a linked list
  1382. if (! have_lru_list)
  1383. {
  1384. for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it)
  1385. {
  1386. LLVFSFileBlock *tmp = (*it).second;
  1387. if (tmp != immune &&
  1388. tmp->mLength > 0 &&
  1389. ! tmp->mLocks[VFSLOCK_READ] &&
  1390. ! tmp->mLocks[VFSLOCK_APPEND] &&
  1391. ! tmp->mLocks[VFSLOCK_OPEN])
  1392. {
  1393. lru_list.insert(tmp);
  1394. }
  1395. }
  1396. have_lru_list = TRUE;
  1397. }
  1398. if (lru_list.size() == 0)
  1399. {
  1400. // No more files to delete, and still not enough room!
  1401. llwarns << "VFS: Can't make " << size << " bytes of free space in VFS, giving up" << llendl;
  1402. break;
  1403. }
  1404. // is the oldest file big enough?  (Should be about half the time)
  1405. lru_set::iterator it = lru_list.begin();
  1406. LLVFSFileBlock *file_block = *it;
  1407. if (file_block->mLength >= size && file_block != immune)
  1408. {
  1409. // ditch this file and look again for a free block - should find it
  1410. // TODO: it'll be faster just to assign the free block and break
  1411. llinfos << "LRU: Removing " << file_block->mFileID << ":" << file_block->mFileType << llendl;
  1412. lru_list.erase(it);
  1413. removeFileBlock(file_block);
  1414. file_block = NULL;
  1415. continue;
  1416. }
  1417. llinfos << "VFS: LRU: Aggressive: " << (S32)lru_list.size() << " files remain" << llendl;
  1418. dumpLockCounts();
  1419. // Now it's time to aggressively make more space
  1420. // Delete the oldest 5MB of the vfs or enough to hold the file, which ever is larger
  1421. // This may yield too much free space, but we'll use it up soon enough
  1422. U32 cleanup_target = (size > VFS_CLEANUP_SIZE) ? size : VFS_CLEANUP_SIZE;
  1423. U32 cleaned_up = 0;
  1424.     for (it = lru_list.begin();
  1425.  it != lru_list.end() && cleaned_up < cleanup_target;
  1426.  )
  1427. {
  1428. file_block = *it;
  1429. // TODO: it would be great to be able to batch all these sync() calls
  1430. // llinfos << "LRU2: Removing " << file_block->mFileID << ":" << file_block->mFileType << " last accessed" << file_block->mAccessTime << llendl;
  1431. cleaned_up += file_block->mLength;
  1432. lru_list.erase(it++);
  1433. removeFileBlock(file_block);
  1434. file_block = NULL;
  1435. }
  1436. //mergeFreeBlocks();
  1437. }
  1438. }
  1439.     
  1440. F32 time = timer.getElapsedTimeF32();
  1441. if (time > 0.5f)
  1442. {
  1443. llwarns << "VFS: Spent " << time << " seconds in findFreeBlock!" << llendl;
  1444. }
  1445. return block;
  1446. }
  1447. //============================================================================
  1448. // public
  1449. //============================================================================
  1450. void LLVFS::pokeFiles()
  1451. {
  1452. if (!isValid())
  1453. {
  1454. llerrs << "Attempting to use invalid VFS!" << llendl;
  1455. }
  1456. U32 word;
  1457. // only write data if we actually read 4 bytes
  1458. // otherwise we're writing garbage and screwing up the file
  1459. fseek(mDataFP, 0, SEEK_SET);
  1460. if (fread(&word, sizeof(word), 1, mDataFP) == 1)
  1461. {
  1462. fseek(mDataFP, 0, SEEK_SET);
  1463. if (fwrite(&word, sizeof(word), 1, mDataFP) != 1)
  1464. {
  1465. llwarns << "Could not write to data file" << llendl;
  1466. }
  1467. fflush(mDataFP);
  1468. }
  1469. fseek(mIndexFP, 0, SEEK_SET);
  1470. if (fread(&word, sizeof(word), 1, mIndexFP) == 1)
  1471. {
  1472. fseek(mIndexFP, 0, SEEK_SET);
  1473. if (fwrite(&word, sizeof(word), 1, mIndexFP) != 1)
  1474. {
  1475. llwarns << "Could not write to index file" << llendl;
  1476. }
  1477. fflush(mIndexFP);
  1478. }
  1479. }
  1480.     
  1481. void LLVFS::dumpMap()
  1482. {
  1483. llinfos << "Files:" << llendl;
  1484. for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it)
  1485. {
  1486. LLVFSFileBlock *file_block = (*it).second;
  1487. llinfos << "Location: " << file_block->mLocation << "tLength: " << file_block->mLength << "t" << file_block->mFileID << "t" << file_block->mFileType << llendl;
  1488. }
  1489.     
  1490. llinfos << "Free Blocks:" << llendl;
  1491. for (blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin(),
  1492.  end = mFreeBlocksByLocation.end();
  1493.  iter != end; iter++)
  1494. {
  1495. LLVFSBlock *free_block = iter->second;
  1496. llinfos << "Location: " << free_block->mLocation << "tLength: " << free_block->mLength << llendl;
  1497. }
  1498. }
  1499.     
  1500. // verify that the index file contents match the in-memory file structure
  1501. // Very slow, do not call routinely. JC
  1502. void LLVFS::audit()
  1503. {
  1504. // Lock the mutex through this whole function.
  1505. LLMutexLock lock_data(mDataMutex);
  1506. fflush(mIndexFP);
  1507. fseek(mIndexFP, 0, SEEK_END);
  1508. size_t index_size = ftell(mIndexFP);
  1509. fseek(mIndexFP, 0, SEEK_SET);
  1510.     
  1511. BOOL vfs_corrupt = FALSE;
  1512. std::vector<U8> buffer(index_size);
  1513. if (fread(&buffer[0], 1, index_size, mIndexFP) != index_size)
  1514. {
  1515. llwarns << "Index truncated" << llendl;
  1516. vfs_corrupt = TRUE;
  1517. }
  1518.     
  1519. size_t buf_offset = 0;
  1520.     
  1521. std::map<LLVFSFileSpecifier, LLVFSFileBlock*> found_files;
  1522. U32 cur_time = (U32)time(NULL);
  1523. std::vector<LLVFSFileBlock*> audit_blocks;
  1524. while (!vfs_corrupt && buf_offset < index_size)
  1525. {
  1526. LLVFSFileBlock *block = new LLVFSFileBlock();
  1527. audit_blocks.push_back(block);
  1528. block->deserialize(&buffer[buf_offset], (S32)buf_offset);
  1529. buf_offset += block->SERIAL_SIZE;
  1530.     
  1531. // do sanity check on this block
  1532. if (block->mLength >= 0 &&
  1533. block->mSize >= 0 &&
  1534. block->mSize <= block->mLength &&
  1535. block->mFileType >= LLAssetType::AT_NONE &&
  1536. block->mFileType < LLAssetType::AT_COUNT &&
  1537. block->mAccessTime <= cur_time &&
  1538. block->mFileID != LLUUID::null)
  1539. {
  1540. if (mFileBlocks.find(*block) == mFileBlocks.end())
  1541. {
  1542. llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " on disk, not in memory, loc " << block->mIndexLocation << llendl;
  1543. }
  1544. else if (found_files.find(*block) != found_files.end())
  1545. {
  1546. std::map<LLVFSFileSpecifier, LLVFSFileBlock*>::iterator it;
  1547. it = found_files.find(*block);
  1548. LLVFSFileBlock* dupe = it->second;
  1549. // try to keep data from being lost
  1550. unlockAndClose(mIndexFP);
  1551. mIndexFP = NULL;
  1552. unlockAndClose(mDataFP);
  1553. mDataFP = NULL;
  1554. llwarns << "VFS: Original block index " << block->mIndexLocation
  1555. << " location " << block->mLocation 
  1556. << " length " << block->mLength 
  1557. << " size " << block->mSize 
  1558. << " id " << block->mFileID
  1559. << " type " << block->mFileType
  1560. << llendl;
  1561. llwarns << "VFS: Duplicate block index " << dupe->mIndexLocation
  1562. << " location " << dupe->mLocation 
  1563. << " length " << dupe->mLength 
  1564. << " size " << dupe->mSize 
  1565. << " id " << dupe->mFileID
  1566. << " type " << dupe->mFileType
  1567. << llendl;
  1568. llwarns << "VFS: Index size " << index_size << llendl;
  1569. llwarns << "VFS: INDEX CORRUPT" << llendl;
  1570. vfs_corrupt = TRUE;
  1571. break;
  1572. }
  1573. else
  1574. {
  1575. found_files[*block] = block;
  1576. }
  1577. }
  1578. else
  1579. {
  1580. if (block->mLength)
  1581. {
  1582. llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " corrupt on disk" << llendl;
  1583. }
  1584. // else this is just a hole
  1585. }
  1586. }
  1587.     
  1588. if (!vfs_corrupt)
  1589. {
  1590. for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it)
  1591. {
  1592. LLVFSFileBlock* block = (*it).second;
  1593. if (block->mSize > 0)
  1594. {
  1595. if (! found_files.count(*block))
  1596. {
  1597. llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " in memory, not on disk, loc " << block->mIndexLocation<< llendl;
  1598. fseek(mIndexFP, block->mIndexLocation, SEEK_SET);
  1599. U8 buf[LLVFSFileBlock::SERIAL_SIZE];
  1600. if (fread(buf, LLVFSFileBlock::SERIAL_SIZE, 1, mIndexFP) != 1)
  1601. {
  1602. llwarns << "VFile " << block->mFileID
  1603. << " gave short read" << llendl;
  1604. }
  1605.     
  1606. LLVFSFileBlock disk_block;
  1607. disk_block.deserialize(buf, block->mIndexLocation);
  1608. llwarns << "Instead found " << disk_block.mFileID << ":" << block->mFileType << llendl;
  1609. }
  1610. else
  1611. {
  1612. block = found_files.find(*block)->second;
  1613. found_files.erase(*block);
  1614. }
  1615. }
  1616. }
  1617.     
  1618. for (std::map<LLVFSFileSpecifier, LLVFSFileBlock*>::iterator iter = found_files.begin();
  1619.  iter != found_files.end(); iter++)
  1620. {
  1621. LLVFSFileBlock* block = iter->second;
  1622. llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " szie:" << block->mSize << " leftover" << llendl;
  1623. }
  1624.     
  1625. llinfos << "VFS: audit OK" << llendl;
  1626. // mutex released by LLMutexLock() destructor.
  1627. }
  1628. for_each(audit_blocks.begin(), audit_blocks.end(), DeletePointer());
  1629. }
  1630.     
  1631.     
  1632. // quick check for uninitialized blocks
  1633. // Slow, do not call in release.
  1634. void LLVFS::checkMem()
  1635. {
  1636. lockData();
  1637. for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it)
  1638. {
  1639. LLVFSFileBlock *block = (*it).second;
  1640. llassert(block->mFileType >= LLAssetType::AT_NONE &&
  1641.  block->mFileType < LLAssetType::AT_COUNT &&
  1642.  block->mFileID != LLUUID::null);
  1643.     
  1644. for (std::deque<S32>::iterator iter = mIndexHoles.begin();
  1645.  iter != mIndexHoles.end(); ++iter)
  1646. {
  1647. S32 index_loc = *iter;
  1648. if (index_loc == block->mIndexLocation)
  1649. {
  1650. llwarns << "VFile block " << block->mFileID << ":" << block->mFileType << " is marked as a hole" << llendl;
  1651. }
  1652. }
  1653. }
  1654.     
  1655. llinfos << "VFS: mem check OK" << llendl;
  1656. unlockData();
  1657. }
  1658. void LLVFS::dumpLockCounts()
  1659. {
  1660. S32 i;
  1661. for (i = 0; i < VFSLOCK_COUNT; i++)
  1662. {
  1663. llinfos << "LockType: " << i << ": " << mLockCounts[i] << llendl;
  1664. }
  1665. }
  1666. void LLVFS::dumpStatistics()
  1667. {
  1668. lockData();
  1669. // Investigate file blocks.
  1670. std::map<S32, S32> size_counts;
  1671. std::map<U32, S32> location_counts;
  1672. std::map<LLAssetType::EType, std::pair<S32,S32> > filetype_counts;
  1673. S32 max_file_size = 0;
  1674. S32 total_file_size = 0;
  1675. S32 invalid_file_count = 0;
  1676. for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it)
  1677. {
  1678. LLVFSFileBlock *file_block = (*it).second;
  1679. if (file_block->mLength == BLOCK_LENGTH_INVALID)
  1680. {
  1681. invalid_file_count++;
  1682. }
  1683. else if (file_block->mLength <= 0)
  1684. {
  1685. llinfos << "Bad file block at: " << file_block->mLocation << "tLength: " << file_block->mLength << "t" << file_block->mFileID << "t" << file_block->mFileType << llendl;
  1686. size_counts[file_block->mLength]++;
  1687. location_counts[file_block->mLocation]++;
  1688. }
  1689. else
  1690. {
  1691. total_file_size += file_block->mLength;
  1692. }
  1693. if (file_block->mLength > max_file_size)
  1694. {
  1695. max_file_size = file_block->mLength;
  1696. }
  1697. filetype_counts[file_block->mFileType].first++;
  1698. filetype_counts[file_block->mFileType].second += file_block->mLength;
  1699. }
  1700.     
  1701. for (std::map<S32,S32>::iterator it = size_counts.begin(); it != size_counts.end(); ++it)
  1702. {
  1703. S32 size = it->first;
  1704. S32 size_count = it->second;
  1705. llinfos << "Bad files size " << size << " count " << size_count << llendl;
  1706. }
  1707. for (std::map<U32,S32>::iterator it = location_counts.begin(); it != location_counts.end(); ++it)
  1708. {
  1709. U32 location = it->first;
  1710. S32 location_count = it->second;
  1711. llinfos << "Bad files location " << location << " count " << location_count << llendl;
  1712. }
  1713. // Investigate free list.
  1714. S32 max_free_size = 0;
  1715. S32 total_free_size = 0;
  1716. std::map<S32, S32> free_length_counts;
  1717. for (blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin(),
  1718.  end = mFreeBlocksByLocation.end();
  1719.  iter != end; iter++)
  1720. {
  1721. LLVFSBlock *free_block = iter->second;
  1722. if (free_block->mLength <= 0)
  1723. {
  1724. llinfos << "Bad free block at: " << free_block->mLocation << "tLength: " << free_block->mLength << llendl;
  1725. }
  1726. else
  1727. {
  1728. llinfos << "Block: " << free_block->mLocation
  1729. << "tLength: " << free_block->mLength
  1730. << "tEnd: " << free_block->mLocation + free_block->mLength
  1731. << llendl;
  1732. total_free_size += free_block->mLength;
  1733. }
  1734. if (free_block->mLength > max_free_size)
  1735. {
  1736. max_free_size = free_block->mLength;
  1737. }
  1738. free_length_counts[free_block->mLength]++;
  1739. }
  1740. // Dump histogram of free block sizes
  1741. for (std::map<S32,S32>::iterator it = free_length_counts.begin(); it != free_length_counts.end(); ++it)
  1742. {
  1743. llinfos << "Free length " << it->first << " count " << it->second << llendl;
  1744. }
  1745. llinfos << "Invalid blocks: " << invalid_file_count << llendl;
  1746. llinfos << "File blocks:    " << mFileBlocks.size() << llendl;
  1747. S32 length_list_count = (S32)mFreeBlocksByLength.size();
  1748. S32 location_list_count = (S32)mFreeBlocksByLocation.size();
  1749. if (length_list_count == location_list_count)
  1750. {
  1751. llinfos << "Free list lengths match, free blocks: " << location_list_count << llendl;
  1752. }
  1753. else
  1754. {
  1755. llwarns << "Free list lengths do not match!" << llendl;
  1756. llwarns << "By length: " << length_list_count << llendl;
  1757. llwarns << "By location: " << location_list_count << llendl;
  1758. }
  1759. llinfos << "Max file: " << max_file_size/1024 << "K" << llendl;
  1760. llinfos << "Max free: " << max_free_size/1024 << "K" << llendl;
  1761. llinfos << "Total file size: " << total_file_size/1024 << "K" << llendl;
  1762. llinfos << "Total free size: " << total_free_size/1024 << "K" << llendl;
  1763. llinfos << "Sum: " << (total_file_size + total_free_size) << " bytes" << llendl;
  1764. llinfos << llformat("%.0f%% full",((F32)(total_file_size)/(F32)(total_file_size+total_free_size))*100.f) << llendl;
  1765. llinfos << " " << llendl;
  1766. for (std::map<LLAssetType::EType, std::pair<S32,S32> >::iterator iter = filetype_counts.begin();
  1767.  iter != filetype_counts.end(); ++iter)
  1768. {
  1769. llinfos << "Type: " << LLAssetType::getDesc(iter->first)
  1770. << " Count: " << iter->second.first
  1771. << " Bytes: " << (iter->second.second>>20) << " MB" << llendl;
  1772. }
  1773. // Look for potential merges 
  1774. {
  1775.   blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin();
  1776.   blocks_location_map_t::iterator end = mFreeBlocksByLocation.end();
  1777.   LLVFSBlock *first_block = iter->second;
  1778.   while(iter != end)
  1779.   {
  1780.   if (++iter == end)
  1781.   break;
  1782.   LLVFSBlock *second_block = iter->second;
  1783.   if (first_block->mLocation + first_block->mLength == second_block->mLocation)
  1784.   {
  1785. llinfos << "Potential merge at " << first_block->mLocation << llendl;
  1786.   }
  1787.   first_block = second_block;
  1788.   }
  1789. }
  1790. unlockData();
  1791. }
  1792. // Debug Only!
  1793. std::string get_extension(LLAssetType::EType type)
  1794. {
  1795. std::string extension;
  1796. switch(type)
  1797. {
  1798. case LLAssetType::AT_TEXTURE:
  1799. extension = ".jp2"; // formerly ".j2c"
  1800. break;
  1801. case LLAssetType::AT_SOUND:
  1802. extension = ".ogg";
  1803. break;
  1804. case LLAssetType::AT_SOUND_WAV:
  1805. extension = ".wav";
  1806. break;
  1807. case LLAssetType::AT_TEXTURE_TGA:
  1808. extension = ".tga";
  1809. break;
  1810. case LLAssetType::AT_ANIMATION:
  1811. extension = ".lla";
  1812. break;
  1813. default:
  1814. // Just use the asset server filename extension in most cases
  1815. extension += ".";
  1816. extension += LLAssetType::lookup(type);
  1817. break;
  1818. }
  1819. return extension;
  1820. }
  1821. void LLVFS::listFiles()
  1822. {
  1823. lockData();
  1824. for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it)
  1825. {
  1826. LLVFSFileSpecifier file_spec = it->first;
  1827. LLVFSFileBlock *file_block = it->second;
  1828. S32 length = file_block->mLength;
  1829. S32 size = file_block->mSize;
  1830. if (length != BLOCK_LENGTH_INVALID && size > 0)
  1831. {
  1832. LLUUID id = file_spec.mFileID;
  1833. std::string extension = get_extension(file_spec.mFileType);
  1834. llinfos << " File: " << id
  1835. << " Type: " << LLAssetType::getDesc(file_spec.mFileType)
  1836. << " Size: " << size
  1837. << llendl;
  1838. }
  1839. }
  1840. unlockData();
  1841. }
  1842. #include "llapr.h"
  1843. void LLVFS::dumpFiles()
  1844. {
  1845. lockData();
  1846. S32 files_extracted = 0;
  1847. for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it)
  1848. {
  1849. LLVFSFileSpecifier file_spec = it->first;
  1850. LLVFSFileBlock *file_block = it->second;
  1851. S32 length = file_block->mLength;
  1852. S32 size = file_block->mSize;
  1853. if (length != BLOCK_LENGTH_INVALID && size > 0)
  1854. {
  1855. LLUUID id = file_spec.mFileID;
  1856. LLAssetType::EType type = file_spec.mFileType;
  1857. std::vector<U8> buffer(size);
  1858. unlockData();
  1859. getData(id, type, &buffer[0], 0, size);
  1860. lockData();
  1861. std::string extension = get_extension(type);
  1862. std::string filename = id.asString() + extension;
  1863. llinfos << " Writing " << filename << llendl;
  1864. LLAPRFile outfile;
  1865. outfile.open(filename, LL_APR_WB);
  1866. outfile.write(&buffer[0], size);
  1867. outfile.close();
  1868. files_extracted++;
  1869. }
  1870. }
  1871. unlockData();
  1872. llinfos << "Extracted " << files_extracted << " files out of " << mFileBlocks.size() << llendl;
  1873. }
  1874. //============================================================================
  1875. // protected
  1876. //============================================================================
  1877. // static
  1878. LLFILE *LLVFS::openAndLock(const std::string& filename, const char* mode, BOOL read_lock)
  1879. {
  1880. #if LL_WINDOWS
  1881.     
  1882. return LLFile::_fsopen(filename, mode, (read_lock ? _SH_DENYWR : _SH_DENYRW));
  1883.     
  1884. #else
  1885. LLFILE *fp;
  1886. int fd;
  1887. // first test the lock in a non-destructive way
  1888. #if LL_SOLARIS
  1889.         struct flock fl;
  1890.         fl.l_whence = SEEK_SET;
  1891.         fl.l_start = 0;
  1892.         fl.l_len = 1;
  1893. #else // !LL_SOLARIS
  1894. if (strchr(mode, 'w') != NULL)
  1895. {
  1896. fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */
  1897. if (fp)
  1898. {
  1899. fd = fileno(fp);
  1900. if (flock(fd, (read_lock ? LOCK_SH : LOCK_EX) | LOCK_NB) == -1)
  1901. {
  1902. fclose(fp);
  1903. return NULL;
  1904. }
  1905.   
  1906. fclose(fp);
  1907. }
  1908. }
  1909. #endif // !LL_SOLARIS
  1910. // now actually open the file for use
  1911. fp = LLFile::fopen(filename, mode); /* Flawfinder: ignore */
  1912. if (fp)
  1913. {
  1914. fd = fileno(fp);
  1915. #if LL_SOLARIS
  1916.                 fl.l_type = read_lock ? F_RDLCK : F_WRLCK;
  1917.                 if (fcntl(fd, F_SETLK, &fl) == -1)
  1918. #else
  1919. if (flock(fd, (read_lock ? LOCK_SH : LOCK_EX) | LOCK_NB) == -1)
  1920. #endif
  1921. {
  1922. fclose(fp);
  1923. fp = NULL;
  1924. }
  1925. }
  1926. return fp;
  1927.     
  1928. #endif
  1929. }
  1930.     
  1931. // static
  1932. void LLVFS::unlockAndClose(LLFILE *fp)
  1933. {
  1934. if (fp)
  1935. {
  1936. // IW: we don't actually want to unlock on linux
  1937. // this is because a forked process can kill the parent's lock
  1938. // with an explicit unlock
  1939. // however, fclose() will implicitly remove the lock
  1940. // but only once both parent and child have closed the file
  1941.     /*
  1942.   #if !LL_WINDOWS
  1943.   int fd = fileno(fp);
  1944.   flock(fd, LOCK_UN);
  1945.   #endif
  1946.     */
  1947. #if LL_SOLARIS
  1948.         struct flock fl;
  1949. fl.l_whence = SEEK_SET;
  1950. fl.l_start = 0;
  1951. fl.l_len = 1;
  1952. fl.l_type = F_UNLCK;
  1953. fcntl(fileno(fp), F_SETLK, &fl);
  1954. #endif
  1955. fclose(fp);
  1956. }
  1957. }