Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2060 lines
74 KiB

  1. //========= Copyright � 2006, Electonic Arts(C) 2006 - All Rights Reserved ============//
  2. #include "tier0/platform.h"
  3. #ifdef _PS3
  4. #include "FileGroup.h"
  5. #include <unistd.h>
  6. #include <sys/timer.h>
  7. #include "memalloc.h"
  8. // #include "debug/inc/debug.h"
  9. // #include <tty.h>
  10. #include "generichash.h"
  11. #include <ctype.h>
  12. #include "ps3/ps3_console.h"
  13. #include <sys/stat.h>
  14. #include "tier1/strtools.h"
  15. #include "tier0/dbg.h"
  16. //#include <libsntuner.h>
  17. #ifdef _DEBUG
  18. int CFileGroupOpenedFile::refCount = 0;
  19. int CFileGroupSystem::refCount = 0;
  20. int CFileGroup::refCount = 0;
  21. #endif
  22. const int MAX_OPENED_FILES = 8;
  23. const int FILEGROUP_READ_CMD_PRIO = 1000;
  24. const int FILEGROUP_READ_CMD_STACKSIZE = 16*1024;
  25. #define DebugPrint(fmt, ...) Msg(fmt, ## __VA_ARGS__)
  26. static void TidyUpSynchObjects(FileGroupReadBuffer* pBuf)
  27. {
  28. int ret = sys_lwmutex_destroy(&pBuf->mBufferStartEndPosMutex);
  29. if (ret != CELL_OK) {
  30. printf("TidyUpSynchObjects sys_lwmutex_destroy failed: %d\n", ret);
  31. exit(ret);
  32. }
  33. ret = sys_cond_destroy(pBuf->mReadThreadSignal);
  34. if (ret != CELL_OK) {
  35. printf("TidyUpSynchObjects sys_cond_destroy failed: %d\n", ret);
  36. exit(ret);
  37. }
  38. ret = sys_mutex_destroy(pBuf->mReadThreadSignalMutex);
  39. if (ret != CELL_OK) {
  40. printf("TidyUpSynchObjects sys_mutex_destroy failed: %d\n", ret);
  41. exit(ret);
  42. }
  43. }
  44. void FileGroupReadBuffer::WaitOnDiskEjectRecovery()
  45. {
  46. //Grab mutex
  47. int ret = sys_lwmutex_trylock(&mEjectRecoveryMutex);
  48. if (ret == CELL_OK)
  49. {
  50. int fileGroupHandle = 0;
  51. CellFsErrno retFs;
  52. while(retFs != CELL_FS_SUCCEEDED)
  53. {
  54. if(fileGroupHandle)
  55. {
  56. cellFsClose(fileGroupHandle);
  57. }
  58. retFs = PS3_RetryOpenWhileDiskEjected(mFileName, CELL_FS_O_RDONLY, &fileGroupHandle);
  59. if (retFs == CELL_FS_SUCCEEDED)
  60. {
  61. mFile = fileGroupHandle;
  62. uint64_t pos = 0;
  63. retFs = cellFsLseek(mFile,(uint64_t)mCurrentPos,CELL_FS_SEEK_SET,&pos);
  64. if(retFs == CELL_FS_EIO)
  65. {
  66. PS3_DisplayDiskErrorDialog(); //Assume dirty disk, rather than disk eject if this point is reached
  67. }
  68. }
  69. else
  70. {
  71. Msg("FileGroupReadBuffer::WaitOnDiskEjectRecovery: Fatal disk error\n");
  72. exit(-1);
  73. }
  74. }
  75. PS3_ClearDiskErrorDialog();
  76. sys_lwmutex_unlock(&mEjectRecoveryMutex);
  77. }
  78. else //i.e. another thread is running
  79. {
  80. Msg("Disk eject waiting on retry\n");
  81. ret = sys_lwmutex_lock(&mEjectRecoveryMutex,0); //Wait for disk eject recovery to complete
  82. ret = sys_lwmutex_unlock(&mEjectRecoveryMutex);
  83. Msg("Disk eject waiting on retry complete\n");
  84. }
  85. }
  86. void FileGroupReadBuffer::CloseFile()
  87. {
  88. if (mFile)
  89. {
  90. cellFsClose(mFile);
  91. mFile = NULL;
  92. int ret = sys_lwmutex_destroy(&mEjectRecoveryMutex);
  93. if (ret != CELL_OK) {
  94. Msg("sys_lwmutex_destroy failed for mEjectRecoveryMutex: %d\n", ret);
  95. }
  96. ret = sys_lwmutex_destroy(&mBufferMutex);
  97. if (ret != CELL_OK) {
  98. printf("TidyUpSynchObjects sys_lwmutex_destroy failed: %d\n", ret);
  99. }
  100. ret = sys_lwmutex_destroy(&mNextConsumeByteMutex);
  101. if (ret != CELL_OK) {
  102. printf("TidyUpSynchObjects sys_lwmutex_destroy failed: %d\n", ret);
  103. }
  104. }
  105. }
  106. void FileGroupReadBuffer::AllocateBuffer(size_t readBufferSize)
  107. {
  108. MEM_ALLOC_CREDIT();
  109. if (mBuffer)
  110. {
  111. FreeBuffer();
  112. }
  113. mBuffer = new unsigned char[readBufferSize];
  114. mBufferSize = readBufferSize;
  115. mCurrentByte = mBuffer;
  116. }
  117. void FileGroupReadBuffer::FreeBuffer()
  118. {
  119. if (mBuffer)
  120. {
  121. delete[] mBuffer;
  122. mBuffer = NULL;
  123. mBufferSize = 0;
  124. mCurrentByte = NULL;
  125. mNextConsumePos = 0;
  126. mAwaitingConsumer = false;
  127. mBufferEndPos = 0;
  128. mBufferStartPos = 0;
  129. mCurrentPos = 0;
  130. }
  131. }
  132. static void thr_FileGroupRead(uint64_t arg)
  133. {
  134. FileGroupReadBuffer* pBuf = reinterpret_cast<FileGroupReadBuffer*>(arg);
  135. while (1) {
  136. int ret = sys_mutex_lock(pBuf->mReadThreadSignalMutex, 0);
  137. while (!pBuf->mAwaitingConsumer && !pBuf->mFileGroupDeleted) // Data ready for read and filegroup not flagged for deletion
  138. {
  139. ret = sys_lwmutex_lock(&pBuf->mBufferMutex,0);
  140. //Read next chunk of data
  141. if ((pBuf->mBufferEndPos > 0) && //i.e. we're overwriting existing data
  142. (pBuf->mNextConsumePos > 0) &&
  143. ((pBuf->mCurrentPos + FILEGROUP_READ_CHUNK_SIZE) - pBuf->mNextConsumePos) > (pBuf->mBufferSize - FILEGROUP_READ_STORE_SIZE))
  144. {
  145. pBuf->mAwaitingConsumer = true; //Need to wait for consumer to read more data
  146. }
  147. else
  148. {
  149. //Do the seek and read
  150. #ifdef TIME_FILE_OPERATIONS
  151. system_time_t time1 = sys_time_get_system_time();
  152. #endif
  153. uint64_t pos;
  154. uint64_t bytesRead;
  155. ret = cellFsLseek(pBuf->mFile,(int64_t)pBuf->mCurrentPos,CELL_FS_SEEK_SET,&pos);
  156. if (ret == CELL_FS_SUCCEEDED)
  157. {
  158. ret = cellFsRead(pBuf->mFile,pBuf->mCurrentByte,FILEGROUP_READ_CHUNK_SIZE,&bytesRead);
  159. }
  160. while (ret!= CELL_FS_SUCCEEDED)
  161. {
  162. cellFsClose(pBuf->mFile);
  163. sys_timer_usleep(250000); //Sleep for 0.25 seconds
  164. pBuf->WaitOnDiskEjectRecovery();
  165. ret = cellFsLseek(pBuf->mFile,(int64_t)pBuf->mCurrentPos,CELL_FS_SEEK_SET,&pos);
  166. if(ret == CELL_FS_SUCCEEDED)
  167. {
  168. ret = cellFsRead(pBuf->mFile,pBuf->mCurrentByte,FILEGROUP_READ_CHUNK_SIZE,&bytesRead);
  169. }
  170. if(ret == CELL_FS_EIO) //Assume dirty disk
  171. {
  172. PS3_DisplayDiskErrorDialog();
  173. }
  174. else if (ret == CELL_FS_SUCCEEDED)
  175. {
  176. PS3_ClearDiskErrorDialog();
  177. }
  178. }
  179. #ifdef TIME_FILE_OPERATIONS
  180. system_time_t time2 = sys_time_get_system_time();
  181. pBuf->m_fReadTime += (time2-time1);
  182. pBuf->m_fReadBytes += bytesRead;
  183. #endif
  184. if (pBuf->mCurrentByte == pBuf->mBuffer)
  185. {
  186. ret = sys_lwmutex_lock(&pBuf->mBufferStartEndPosMutex,0);
  187. pBuf->mBufferStartPos = pBuf->mCurrentPos;
  188. ret = sys_lwmutex_unlock(&pBuf->mBufferStartEndPosMutex);
  189. }
  190. pBuf->mCurrentPos += bytesRead;
  191. pBuf->mCurrentByte += bytesRead;
  192. if (bytesRead == FILEGROUP_READ_CHUNK_SIZE)
  193. {
  194. if ((pBuf->mCurrentByte - pBuf->mBuffer) >= pBuf->mBufferSize)
  195. {
  196. //We've reached the end of the buffer
  197. sys_lwmutex_lock(&pBuf->mBufferStartEndPosMutex,0); //Prevent any 'consumes' from calculating available data while buffer is reset
  198. pBuf->mBufferEndPos = pBuf->mCurrentPos;
  199. pBuf->mCurrentByte = pBuf->mBuffer;
  200. if (pBuf->mNextConsumePos == 0)
  201. {
  202. pBuf->mAwaitingConsumer = true;
  203. }
  204. sys_lwmutex_unlock(&pBuf->mBufferStartEndPosMutex);
  205. }
  206. }
  207. else
  208. {
  209. //Assume EOF - await signal from consumer that there is more data to read
  210. pBuf->mAwaitingConsumer = true;
  211. }
  212. }
  213. ret = sys_lwmutex_unlock(&pBuf->mBufferMutex);
  214. }
  215. if (pBuf->mFileGroupDeleted)
  216. {
  217. int ret = sys_mutex_unlock(pBuf->mReadThreadSignalMutex);
  218. TidyUpSynchObjects(pBuf);
  219. pBuf->CloseFile();
  220. pBuf->FreeBuffer();
  221. pBuf->mReadThread = NULL;
  222. pBuf->mFileGroupDeleted = false;
  223. sys_ppu_thread_exit(1);
  224. }
  225. ret = sys_cond_wait(pBuf->mReadThreadSignal, 0);
  226. if (ret == CELL_OK)
  227. {
  228. pBuf->mAwaitingConsumer = false;
  229. }
  230. }
  231. }
  232. CFileGroupSystem::CFileGroupSystem()
  233. {
  234. m_numFileGroups = 0;
  235. m_lastGroupPopulated = -1;
  236. m_currentFileGroup = 0;
  237. for(int i=0;i<MAX_FILE_GROUPS;i++)
  238. {
  239. m_fileGroups[i]=NULL;
  240. }
  241. //Create the filesystem mutex
  242. sys_lwmutex_attribute_t mutexAttr;
  243. sys_lwmutex_attribute_initialize(mutexAttr);
  244. mutexAttr.attr_recursive = SYS_SYNC_RECURSIVE;
  245. int ret = sys_lwmutex_create(&mFileGroupSystemMutex, &mutexAttr);
  246. if (ret != CELL_OK) {
  247. printf("CFileGroupSystem::CFileGroupSystem sys_lwmutex_create failed: %d\n", ret);
  248. exit(1);
  249. }
  250. m_openedFilePool = NULL;
  251. m_availableFileNodes = NULL;
  252. m_openedFileNodes = NULL;
  253. m_totalOpenedFiles = 0;
  254. m_initComplete = false;
  255. #ifdef _DEBUG
  256. refCount++;
  257. #endif
  258. }
  259. CFileGroupSystem::~CFileGroupSystem()
  260. {
  261. for(int i=0;i<MAX_FILE_GROUPS;i++)
  262. {
  263. if (m_fileGroups[i])
  264. {
  265. m_fileGroups[i]->Clear();
  266. delete m_fileGroups[i];
  267. }
  268. }
  269. int ret = sys_lwmutex_destroy(&mFileGroupSystemMutex);
  270. if (ret != CELL_OK) {
  271. printf("CFileGroupSystem::~CFileGroupSystem sys_lwmutex_destroy failed: %d\n", ret);
  272. }
  273. #ifdef _DEBUG
  274. refCount--;
  275. #endif
  276. }
  277. void CFileGroupSystem::Init()
  278. {
  279. MEM_ALLOC_CREDIT();
  280. //Initialise pool of CFileGroupOpenedFile objects:
  281. DebugPrint("Initialising pool of %d FileGroupFilePoolNodes for filegroupsystem\n", MAX_OPENED_FILES);
  282. m_openedFilePool = new FileGroupFilePoolNode[MAX_OPENED_FILES];
  283. m_availableFileNodes = m_openedFilePool;
  284. for(int i=0;i<(MAX_OPENED_FILES-1);i++)
  285. {
  286. m_openedFilePool[i].nextNode = &m_openedFilePool[i+1];
  287. }
  288. m_openedFilePool[MAX_OPENED_FILES-1].nextNode = NULL;
  289. //DebugPrint("Initialising filegroup objects for filegroupsystem\n");
  290. for (int i = 0; i<(MAX_FILE_GROUPS); i++)
  291. {
  292. m_fileGroups[i] = new CFileGroup(this);
  293. m_fileGroups[i]->Clear();
  294. }
  295. //int fileSystemMemAllocation = sizeof(FileGroupFilePoolNode)*MAX_OPENED_FILES + sizeof(CFileGroup)*(MAX_FILE_GROUPS);
  296. //DebugPrint("Approx filegroupsystem memory usage: %d\n", fileSystemMemAllocation);
  297. m_initComplete = true;
  298. }
  299. int CFileGroupSystem::AddFileGroup(const char* fileGroupName, bool useReadThread /* = true */, int* group_index /* = NULL */, bool usePreload /* = false */, int bufferSize /* = FILEGROUP_READ_CHUNK_SIZE */, int readChunkSize /* = FILEGROUP_READ_CHUNK_SIZE */)
  300. {
  301. Lock(); //Critical Section
  302. int retVal = -1;
  303. int fileGroupIndex = -1;
  304. if (group_index)
  305. {
  306. *group_index = -1;
  307. }
  308. if( bufferSize < FILEGROUP_READ_CHUNK_SIZE * 4 )
  309. {
  310. bufferSize = FILEGROUP_READ_CHUNK_SIZE * 4;
  311. }
  312. Assert(readChunkSize <= bufferSize);
  313. if(readChunkSize <= bufferSize)
  314. {
  315. if (!m_initComplete) //Delay initialisation until this point so that we don't allocate buffer memory unless it's needed
  316. {
  317. Init();
  318. }
  319. CFileGroup* newGroup = NULL;
  320. //Get free filegroup object
  321. for(int i=0; (i<MAX_FILE_GROUPS) && !newGroup ;i++)
  322. {
  323. if (!m_fileGroups[i]->IsPopulated())
  324. {
  325. newGroup = m_fileGroups[i];
  326. fileGroupIndex = i;
  327. }
  328. }
  329. if (newGroup)
  330. {
  331. newGroup->Clear();
  332. int entriesPopulated = newGroup->Populate(fileGroupName, usePreload);
  333. if (entriesPopulated > 0)
  334. {
  335. retVal = entriesPopulated;
  336. if (useReadThread)
  337. {
  338. newGroup->AllocateReadBuffer(bufferSize);
  339. newGroup->StartReadThread();
  340. }
  341. else
  342. {
  343. newGroup->AllocateReadBuffer(bufferSize);
  344. newGroup->SetReadChunkSize(readChunkSize);
  345. }
  346. if (fileGroupIndex > -1)
  347. {
  348. m_numFileGroups++;
  349. m_currentFileGroup = fileGroupIndex;
  350. if (group_index)
  351. {
  352. *group_index = fileGroupIndex; //No need to set last group populated - assume caller will specify the index on calls to deletefilegroup
  353. }
  354. else
  355. {
  356. m_lastGroupPopulated = fileGroupIndex;
  357. }
  358. }
  359. DebugPrint("CFileGroupSystem: Successfully opened file group named %s as index %d\n", fileGroupName, fileGroupIndex);
  360. if(usePreload)
  361. {
  362. DebugPrint(" using preload\n");
  363. }
  364. else
  365. {
  366. DebugPrint("\n");
  367. }
  368. }
  369. else
  370. {
  371. if(entriesPopulated < 0)
  372. {
  373. DebugPrint("CFileGroupSystem: Error opening file group named %s\n", fileGroupName);
  374. }
  375. else
  376. {
  377. DebugPrint("Error opening file group %s, no entries found.\n", fileGroupName);
  378. }
  379. newGroup->Clear();
  380. }
  381. }
  382. else
  383. {
  384. DebugPrint("CFileGroupSystem: Error opening file group %s. All %d file groups are already in use.\n", fileGroupName, MAX_FILE_GROUPS);
  385. }
  386. }
  387. Unlock(); //Critical Section End
  388. return retVal;
  389. }
  390. int CFileGroupSystem::CurrentFileGroup()
  391. {
  392. return m_lastGroupPopulated;
  393. }
  394. //Delete most recently added file group
  395. void CFileGroupSystem::DeleteFileGroup()
  396. {
  397. Lock();
  398. if (m_lastGroupPopulated > -1)
  399. {
  400. DeleteFileGroup(m_lastGroupPopulated);
  401. }
  402. else
  403. {
  404. DebugPrint("CFileGroupSystem::deleteFileGroup Error, no filegroups exist\n");
  405. }
  406. Unlock();
  407. }
  408. void CFileGroupSystem::DeleteFileGroup(int groupIndex)
  409. {
  410. Lock();
  411. if (groupIndex > -1 && m_fileGroups[groupIndex])
  412. {
  413. DeleteFileGroup(m_fileGroups[groupIndex], groupIndex);
  414. }
  415. else
  416. {
  417. DebugPrint("CFileGroupSystem::deleteFileGroup Error, filegroup %d does not exist\n", groupIndex);
  418. }
  419. Unlock();
  420. }
  421. void CFileGroupSystem::DeleteFileGroup(CFileGroup* fileGroup)
  422. {
  423. Lock();
  424. for(int i=0; i<MAX_FILE_GROUPS; i++)
  425. {
  426. if (m_fileGroups[i] == fileGroup)
  427. {
  428. DeleteFileGroup(fileGroup, i);
  429. }
  430. }
  431. Unlock();
  432. }
  433. #ifdef TIME_FILE_OPERATIONS
  434. void CFileGroup::PrintFileGroupStats()
  435. {
  436. DebugPrint("\n");
  437. DebugPrint("Stats for file group %s:\n", mReadBuffer.mFileName);
  438. DebugPrint("filegroup, Memcpy(s), fread(s), inflate(s), fsreads, fgets, inflates, rewinds, filejumps, bytes from buffer, bytes from file, fread(bytes)\n");
  439. DebugPrint("Level,%5.2f,%5.2f,%5.2f,%d,%d,%d,%d,%d,%d,%d,%d\n",
  440. float(m_memCopyTime)/1000000.0, float(GetfReadTime())/1000000.0, float(m_uncompressTime)/1000000.0,
  441. m_fsReads, m_fgets, m_uncompressCalls, m_rewinds, m_fileJumps,
  442. m_bytesReadFromBuffer, m_bytesReadFromFileByConsumer, GetfReadBytes());
  443. DebugPrint("\n");
  444. }
  445. #endif
  446. void CFileGroupSystem::DeleteFileGroup(CFileGroup* fileGroup, int groupIndex)
  447. {
  448. Lock();
  449. if (fileGroup->GetOpenedCount() == 0)
  450. {
  451. DebugPrint("Deleting file group %d\n", groupIndex);
  452. fileGroup->Clear();
  453. m_numFileGroups--;
  454. #ifdef TIME_FILE_OPERATIONS
  455. fileGroup->PrintFileGroupStats();
  456. #endif
  457. if(fileGroup->UsingReadThread())
  458. {
  459. fileGroup->StopReadThread();
  460. }
  461. else
  462. {
  463. fileGroup->CloseFile();
  464. fileGroup->FreeReadBuffer();
  465. }
  466. }
  467. else
  468. {
  469. DebugPrint("Flagging file group %d for deletion, %d files still open\n", groupIndex, fileGroup->GetOpenedCount());
  470. fileGroup->FlagForDeletion();
  471. }
  472. if (m_currentFileGroup == groupIndex)
  473. {
  474. m_currentFileGroup = 0;
  475. }
  476. if (m_lastGroupPopulated == groupIndex)
  477. {
  478. m_lastGroupPopulated = -1;
  479. }
  480. Unlock();
  481. }
  482. CFileGroupOpenedFile* CFileGroupSystem::FS_fopen( FileIdentifier *filename, const char *options, unsigned int flags, __int64 *size )
  483. {
  484. Lock(); //Critical section
  485. CFileGroupOpenedFile* retVal = NULL;
  486. if ( options[0] == 'r' ) //Filegroup files can only be opened for read
  487. {
  488. int iFileGroup = m_currentFileGroup; //Start at the current file group
  489. for(int i=0; (i<MAX_FILE_GROUPS) && (!retVal) ;i++, iFileGroup++)
  490. {
  491. //At the end of the list, loop back to the beginning:
  492. if (iFileGroup==MAX_FILE_GROUPS)
  493. {
  494. iFileGroup=0;
  495. }
  496. if (m_fileGroups[iFileGroup] && m_fileGroups[iFileGroup]->IsPopulated())
  497. {
  498. retVal = m_fileGroups[iFileGroup]->FS_fopen(filename,options,flags,size);
  499. if (retVal)
  500. {
  501. m_currentFileGroup = iFileGroup;
  502. }
  503. }
  504. }
  505. }
  506. Unlock();
  507. return retVal;
  508. }
  509. CFileGroupOpenedFile* CFileGroupSystem::FS_fopen( int filegroup_index, FileIdentifier *filename, const char *options, unsigned int flags, __int64 *size )
  510. {
  511. Lock(); //Critical section
  512. CFileGroupOpenedFile* retVal = NULL;
  513. if ( options[0] == 'r' ) //Filegroup files can only be opened for read
  514. {
  515. if (filegroup_index >= 0 && filegroup_index < MAX_FILE_GROUPS)
  516. {
  517. if (m_fileGroups[filegroup_index] && m_fileGroups[filegroup_index]->IsPopulated())
  518. {
  519. retVal = m_fileGroups[filegroup_index]->FS_fopen(filename,options,flags,size);
  520. }
  521. }
  522. }
  523. Unlock();
  524. return retVal;
  525. }
  526. int CFileGroupSystem::FS_stat( FileIdentifier *path, CellFsStat *buf )
  527. {
  528. Lock(); //Critical section
  529. int retVal = -1;
  530. int iFileGroup = m_currentFileGroup; //Start at the current file group
  531. for(int i=0; (i<MAX_FILE_GROUPS) && (retVal == -1) ;i++, iFileGroup++)
  532. {
  533. //At the end of the list, loop back to the beginning:
  534. if (iFileGroup==MAX_FILE_GROUPS)
  535. {
  536. iFileGroup=0;
  537. }
  538. if (m_fileGroups[i] && m_fileGroups[i]->IsPopulated())
  539. {
  540. retVal = m_fileGroups[i]->FS_stat(path,buf);
  541. }
  542. }
  543. Unlock();
  544. return retVal;
  545. }
  546. int CFileGroupSystem::FS_stat( int filegroup_index, FileIdentifier *path, CellFsStat *buf )
  547. {
  548. Lock(); //Critical section
  549. int retVal = -1;
  550. if (filegroup_index >= 0 && filegroup_index < MAX_FILE_GROUPS)
  551. {
  552. if (m_fileGroups[filegroup_index] && m_fileGroups[filegroup_index]->IsPopulated())
  553. {
  554. retVal = m_fileGroups[filegroup_index]->FS_stat(path,buf);
  555. }
  556. }
  557. Unlock();
  558. return retVal;
  559. }
  560. int CFileGroupSystem::FS_stat( FileIdentifier *path, struct stat *buf )
  561. {
  562. int ret;
  563. CellFsStat cellBuf;
  564. CellFsErrno retFs = FS_stat(path, &cellBuf);
  565. if(retFs == CELL_FS_SUCCEEDED)
  566. {
  567. buf->st_atime = cellBuf.st_atime;
  568. buf->st_blksize = cellBuf.st_blksize;
  569. buf->st_ctime = cellBuf.st_ctime;
  570. buf->st_gid = cellBuf.st_gid;
  571. buf->st_mode = cellBuf.st_mode;
  572. buf->st_mtime = cellBuf.st_mtime;
  573. buf->st_size = cellBuf.st_size;
  574. buf->st_uid = cellBuf.st_uid;
  575. buf->st_dev = 0;
  576. buf->st_ino = 0;
  577. buf->st_nlink = 0;
  578. buf->st_rdev = 0;
  579. buf->st_blocks = 0;
  580. ret = 0;
  581. }
  582. else
  583. {
  584. ret = -1;
  585. //TBD: SET ERRNO
  586. }
  587. return ret;
  588. }
  589. int CFileGroupSystem::FS_stat( int filegroup_index, FileIdentifier *path, struct stat *buf )
  590. {
  591. int ret;
  592. CellFsStat cellBuf;
  593. CellFsErrno retFs = FS_stat(filegroup_index, path, &cellBuf);
  594. if(retFs == CELL_FS_SUCCEEDED)
  595. {
  596. buf->st_atime = cellBuf.st_atime;
  597. buf->st_blksize = cellBuf.st_blksize;
  598. buf->st_ctime = cellBuf.st_ctime;
  599. buf->st_gid = cellBuf.st_gid;
  600. buf->st_mode = cellBuf.st_mode;
  601. buf->st_mtime = cellBuf.st_mtime;
  602. buf->st_size = cellBuf.st_size;
  603. buf->st_uid = cellBuf.st_uid;
  604. buf->st_dev = 0;
  605. buf->st_ino = 0;
  606. buf->st_nlink = 0;
  607. buf->st_rdev = 0;
  608. buf->st_blocks = 0;
  609. ret = 0;
  610. }
  611. else
  612. {
  613. ret = -1;
  614. //TBD: SET ERRNO
  615. }
  616. return ret;
  617. }
  618. CFileGroupOpenedFile* CFileGroupSystem::GetOpenedFile() //Get next available CFileGroupOpenedFile from pool
  619. {
  620. CFileGroupOpenedFile* retVal = NULL;
  621. Assert(m_availableFileNodes);
  622. if (m_availableFileNodes) //Take the next available node from the head of the list
  623. {
  624. FileGroupFilePoolNode* thisNode = m_availableFileNodes;
  625. retVal = &thisNode->thisFile;
  626. //Remove from list of available nodes
  627. m_availableFileNodes = thisNode->nextNode;
  628. //Add to list of opened nodes
  629. thisNode->nextNode = m_openedFileNodes;
  630. m_openedFileNodes = thisNode;
  631. m_totalOpenedFiles++;
  632. }
  633. return retVal;
  634. }
  635. void CFileGroupSystem::FreeOpenedFile(CFileGroupOpenedFile* freeFile) //Get next available CFileGroupOpenedFile from pool
  636. {
  637. FileGroupFilePoolNode* thisNode = m_openedFileNodes;
  638. FileGroupFilePoolNode* prevNode = NULL;
  639. //Find the node object in the list of opened files
  640. while (thisNode && (&thisNode->thisFile != freeFile))
  641. {
  642. prevNode = thisNode;
  643. thisNode = thisNode->nextNode;
  644. }
  645. Assert(thisNode); //Check that the node object was found
  646. if (thisNode)
  647. {
  648. //Remove from list of opened nodes
  649. if (prevNode)
  650. {
  651. prevNode->nextNode = thisNode->nextNode;
  652. }
  653. else
  654. {
  655. m_openedFileNodes = thisNode->nextNode;
  656. }
  657. m_totalOpenedFiles--;
  658. //Add to list of available nodes
  659. thisNode->nextNode = m_availableFileNodes;
  660. m_availableFileNodes = thisNode;
  661. }
  662. }
  663. CFileGroup::CFileGroup(CFileGroupSystem* pFs):
  664. mDirectoryEntries(NULL),
  665. mFs(pFs),
  666. mOpenedCount(0),
  667. mPreloadSection(NULL),
  668. mPreloadEntries(0)
  669. {
  670. #ifdef _DEBUG
  671. refCount++;
  672. #endif
  673. mReadBuffer.mFile = NULL;
  674. mReadBuffer.mFileBlockSize = 0;
  675. mReadBuffer.mFileSectorSize = 0;
  676. mReadBuffer.mReadThread = NULL;
  677. mReadBuffer.mAwaitingConsumer = false;
  678. mReadBuffer.mFileGroupDeleted = false;
  679. mReadBuffer.mNextConsumePos = 0;
  680. mReadBuffer.mBuffer = NULL;
  681. mReadBuffer.mBufferSize = 0;
  682. mReadBuffer.mCurrentByte = NULL;
  683. mReadBuffer.mBufferEndPos = 0;
  684. mReadBuffer.mBufferStartPos = 0;
  685. mReadBuffer.mCurrentPos = 0;
  686. mReadBuffer.mReadChunkSize = FILEGROUP_READ_CHUNK_SIZE;
  687. mFlaggedForDeletion = false;
  688. #ifdef TIME_FILE_OPERATIONS
  689. ResetFileTimings();
  690. #endif
  691. #ifdef MEMCMP_FILE_OPERATIONS
  692. mDirectoryExtraInfo = NULL;
  693. #endif
  694. #ifdef FILEGROUP_USE_HASH_DIRECTORY
  695. mHashDirectory = NULL;
  696. #endif
  697. }
  698. CFileGroup::~CFileGroup()
  699. {
  700. if (mDirectoryEntries)
  701. {
  702. delete[] mDirectoryEntries;
  703. }
  704. if (mReadBuffer.mFile)
  705. {
  706. cellFsClose(mReadBuffer.mFile);
  707. }
  708. #ifdef _DEBUG
  709. refCount--;
  710. #endif
  711. #ifdef MEMCMP_FILE_OPERATIONS
  712. if (mDirectoryExtraInfo)
  713. {
  714. delete[] mDirectoryExtraInfo;
  715. }
  716. #endif
  717. }
  718. unsigned int CFileGroup::HashFileName(const char * fName)
  719. {
  720. return HashStringCaselessConventional(fName);
  721. }
  722. #ifdef TIME_FILE_OPERATIONS
  723. void CFileGroup::ResetFileTimings()
  724. {
  725. m_memCopyTime = 0;
  726. mReadBuffer.m_fReadTime = 0;
  727. mReadBuffer.m_fReadBytes = 0;
  728. m_uncompressTime = 0;
  729. m_fsReads = 0;
  730. m_fgets = 0;
  731. m_uncompressCalls = 0;
  732. m_rewinds = 0;
  733. m_fileJumps = 0;
  734. m_bytesReadFromFileByConsumer = 0;
  735. m_bytesReadFromBuffer = 0;
  736. }
  737. #endif
  738. void CFileGroup::StartReadThread()
  739. {
  740. sys_lwmutex_attribute_initialize(mReadBuffer.mBufferStartEndPosMutexAttr);
  741. mReadBuffer.mBufferStartEndPosMutexAttr.attr_recursive = SYS_SYNC_RECURSIVE;
  742. int ret = sys_lwmutex_create(&mReadBuffer.mBufferStartEndPosMutex, &mReadBuffer.mBufferStartEndPosMutexAttr);
  743. if (ret != CELL_OK) {
  744. printf("CFileGroup::StartReadThread sys_lwmutex_create failed: %d\n", ret);
  745. exit(1);
  746. }
  747. //Create the condition object
  748. sys_mutex_attribute_initialize(mReadBuffer.mReadThreadSignalMutexAttr);
  749. ret = sys_mutex_create(&mReadBuffer.mReadThreadSignalMutex, &mReadBuffer.mReadThreadSignalMutexAttr);
  750. sys_cond_attribute_initialize(mReadBuffer.mReadThreadSignalAttr);
  751. ret = sys_cond_create(&mReadBuffer.mReadThreadSignal, mReadBuffer.mReadThreadSignalMutex, &mReadBuffer.mReadThreadSignalAttr);
  752. mReadBuffer.mCurrentPos = mPosOffset;
  753. mReadBuffer.mFileGroupDeleted = false;
  754. sys_ppu_thread_create(&mReadBuffer.mReadThread,
  755. thr_FileGroupRead, reinterpret_cast<uint64_t>(&mReadBuffer),
  756. FILEGROUP_READ_CMD_PRIO, FILEGROUP_READ_CMD_STACKSIZE,
  757. NULL, "Filegroup_ReadThread");
  758. }
  759. void CFileGroup::StopReadThread()
  760. {
  761. mReadBuffer.mFileGroupDeleted = true;
  762. sys_cond_signal_to(mReadBuffer.mReadThreadSignal,mReadBuffer.mReadThread);
  763. }
  764. void CFileGroup::Clear()
  765. {
  766. Lock();
  767. if (mOpenedCount > 0)
  768. {
  769. DebugPrint("WARNING: Clearing filegroup while %d entries are still open\n", mOpenedCount);
  770. }
  771. if (mDirectoryEntries)
  772. {
  773. delete[] mDirectoryEntries;
  774. mDirectoryEntries = NULL;
  775. }
  776. #ifdef FILEGROUP_USE_HASH_DIRECTORY
  777. if (mHashDirectory)
  778. {
  779. delete[] mHashDirectory;
  780. mHashDirectory = NULL;
  781. }
  782. memset(mHashBuckets,0,FILEGROUP_DIRECTORY_BUCKETS*sizeof(HashBucket));
  783. Assert((FILEGROUP_DIRECTORY_BUCKETS & FILEGROUP_BUCKET_MOD) == 0); //Confirm FILEGROUP_DIRECTORY_BUCKETS is power of two
  784. #endif
  785. #ifdef MEMCMP_FILE_OPERATIONS
  786. if (mDirectoryExtraInfo)
  787. {
  788. delete[] mDirectoryExtraInfo;
  789. mDirectoryExtraInfo = NULL;
  790. }
  791. #endif
  792. if (mPreloadSection)
  793. {
  794. free(mPreloadSection);
  795. mPreloadSection=NULL;
  796. }
  797. mPreloadEntries = 0;
  798. mLastFailedId = 0;
  799. mNumDirectoryEntries = 0;
  800. mLastOpenedDirectoryIndex = 0;
  801. mFlaggedForDeletion = false;
  802. mOpenedCount = 0;
  803. mReadBuffer.mReadChunkSize = FILEGROUP_READ_CHUNK_SIZE;
  804. Unlock();
  805. }
  806. char* CFileGroup::ReformatFileName(char* inputFileName)
  807. {
  808. //Sort out filename...
  809. //Fix slashes
  810. char* fname = inputFileName;
  811. char correctSeparator = '/';
  812. char incorrectSeparator = '\\';
  813. while ( *fname )
  814. {
  815. if ( *fname == incorrectSeparator || *fname == correctSeparator)
  816. {
  817. *fname = correctSeparator;
  818. if(fname[1] == incorrectSeparator || fname[1] == correctSeparator)
  819. {
  820. strcpy(fname+1,fname+2); //Remove multiple slashes from filenames
  821. }
  822. }
  823. fname++;
  824. }
  825. //Adjust filename to remove the initial "/...path.../game/...gamemode.../"
  826. fname = inputFileName;
  827. char* ptr = NULL;
  828. while ((ptr = strstr(fname,"/game/")) ||
  829. (ptr = strstr(fname,"/GAME/")))
  830. {
  831. fname = ptr + strlen("/game");
  832. }
  833. if (fname != inputFileName) //i.e. we located a game directory
  834. {
  835. if (ptr=strchr(fname+1,'/'))
  836. {
  837. fname = ptr+1; //Ignore subdirectory
  838. }
  839. }
  840. else
  841. {
  842. //instead search for stdshaders directory (to handle the special case where the shaders filegroup is generated within the src directory)
  843. while ((ptr = strstr(fname,"stdshaders/")) ||
  844. (ptr = strstr(fname,"STDSHADERS/")))
  845. {
  846. fname = ptr + strlen("stdshaders/");
  847. }
  848. }
  849. //Convert to upper case
  850. char *str = fname;
  851. while( str && *str )
  852. {
  853. *str = (char)toupper(*str);
  854. str++;
  855. }
  856. return fname;
  857. }
  858. CellFsErrno CFileGroup::PopulateDirectory(DirectoryHeader* hdr, int* entriesPopulated)
  859. {
  860. DirectoryEntry fullDirEntry;
  861. uint64_t bytesRead;
  862. mDirectoryEntries = new SmallDirectoryEntry[hdr->mNumEntries];
  863. mNumDirectoryEntries = hdr->mNumEntries;
  864. #ifdef FILEGROUP_USE_HASH_DIRECTORY
  865. mHashDirectory = new unsigned int[hdr->mNumEntries];
  866. #endif
  867. #ifdef MEMCMP_FILE_OPERATIONS
  868. mDirectoryExtraInfo = new DirectoryEntryExtraInfo[hdr->mNumEntries];
  869. #endif
  870. CellFsErrno retFs = CELL_FS_SUCCEEDED;
  871. *entriesPopulated = 0;
  872. if(hdr->mVersion == FILEGROUP_FORMAT_VERSION_COMPILED_DIRECTORY)
  873. {
  874. retFs = cellFsRead(mReadBuffer.mFile,mDirectoryEntries,(uint64_t)(sizeof(SmallDirectoryEntry)*hdr->mNumEntries),&bytesRead);
  875. mPosOffset += bytesRead;
  876. #ifdef FILEGROUP_USE_HASH_DIRECTORY
  877. if(retFs == CELL_FS_SUCCEEDED)
  878. {
  879. for(int i=0;i<hdr->mNumEntries;i++)
  880. {
  881. int bucketId = mDirectoryEntries[i].mNameId & FILEGROUP_BUCKET_MOD;
  882. ++(mHashBuckets[bucketId].mCount);
  883. }
  884. }
  885. #endif
  886. }
  887. else
  888. {
  889. for(int i=0;(i<hdr->mNumEntries)&&(mNumDirectoryEntries>0)&&(retFs == CELL_FS_SUCCEEDED);i++)
  890. {
  891. //bytesRead = fread(&fullDirEntry,1,sizeof(DirectoryEntry),mReadBuffer.mFile);
  892. retFs = cellFsRead(mReadBuffer.mFile,&fullDirEntry,(uint64_t)sizeof(DirectoryEntry),&bytesRead);
  893. if(retFs == CELL_FS_SUCCEEDED)
  894. {
  895. #ifdef MEMCMP_FILE_OPERATIONS
  896. strcpy(mDirectoryExtraInfo[i].mFullFileName,fullDirEntry.mName);
  897. #endif
  898. if (bytesRead != sizeof(DirectoryEntry))
  899. {
  900. //ERROR: abort at this point
  901. DebugPrint("ERROR: FilegroupSystem error reading directory entry\n");
  902. delete[] mDirectoryEntries;
  903. mDirectoryEntries = NULL;
  904. mNumDirectoryEntries = 0;
  905. return retFs;
  906. }
  907. else
  908. {
  909. mPosOffset += bytesRead;
  910. mDirectoryEntries[i].mCompressedLength = fullDirEntry.mCompressedLength;
  911. mDirectoryEntries[i].mLength = fullDirEntry.mLength;
  912. mDirectoryEntries[i].mPosition = fullDirEntry.mPosition;
  913. char* fname = ReformatFileName(fullDirEntry.mName);
  914. mDirectoryEntries[i].mNameId = HashFileName(fname);
  915. #ifdef FILEGROUP_USE_HASH_DIRECTORY
  916. int bucketId = mDirectoryEntries[i].mNameId & FILEGROUP_BUCKET_MOD;
  917. ++(mHashBuckets[bucketId].mCount);
  918. #endif
  919. } //if (bytesRead != sizeof(DirectoryEntry))
  920. } //if (retFs == CELL_FS_SUCCEEDED)
  921. } //for loop
  922. }
  923. if(retFs == CELL_FS_SUCCEEDED)
  924. {
  925. #ifdef FILEGROUP_USE_HASH_DIRECTORY
  926. //populate hash directory buckets
  927. int currentPos = 0;
  928. for(int j = 0; j<FILEGROUP_DIRECTORY_BUCKETS; j++)
  929. {
  930. if (mHashBuckets[j].mCount>0)
  931. {
  932. mHashBuckets[j].mPosition = currentPos;
  933. currentPos += mHashBuckets[j].mCount;
  934. mHashBuckets[j].mCount=0; //Reset for use as a counter in the next section
  935. }
  936. }
  937. for(int i = 0; i<mNumDirectoryEntries; i++)
  938. {
  939. int bucketId = mDirectoryEntries[i].mNameId & FILEGROUP_BUCKET_MOD;
  940. mHashDirectory[mHashBuckets[bucketId].mPosition + mHashBuckets[bucketId].mCount] = i;
  941. ++(mHashBuckets[bucketId].mCount);
  942. }
  943. #endif
  944. *entriesPopulated = mNumDirectoryEntries;
  945. }
  946. return retFs;
  947. }
  948. int CFileGroup::Populate(const char* fileGroupName, bool usePreload /*=false*/)
  949. {
  950. MEM_ALLOC_CREDIT();
  951. Lock();
  952. int entriesPopulated = 0;
  953. CellFsStat fileGroupStat;
  954. int fileGroupHandle = 0;
  955. DirectoryHeader hdr;
  956. uint64_t pos;
  957. bool firstFail = true;
  958. CellFsErrno retFs = CELL_FS_SUCCEEDED-1; //Initialise to a non-success value
  959. while(retFs != CELL_FS_SUCCEEDED) //Loop is repeated following any stat/read errors
  960. {
  961. if(fileGroupHandle)
  962. {
  963. //Clear up any previous half completed attempt
  964. cellFsClose(fileGroupHandle);
  965. Clear();
  966. sys_timer_usleep(250000); //Sleep for 0.25 seconds
  967. if(!firstFail)
  968. {
  969. PS3_DisplayDiskErrorDialog(); //Probably dirty disk if we hit this point
  970. }
  971. else
  972. {
  973. firstFail = false;
  974. }
  975. }
  976. retFs = PS3_RetryStatWhileDiskEjected(fileGroupName, &fileGroupStat);
  977. if(retFs != CELL_FS_SUCCEEDED)
  978. {
  979. entriesPopulated = -1;
  980. goto xit;
  981. }
  982. retFs = PS3_RetryOpenWhileDiskEjected(fileGroupName, CELL_FS_O_RDONLY, &fileGroupHandle);
  983. if(retFs != CELL_FS_SUCCEEDED)
  984. {
  985. entriesPopulated = -1;
  986. goto xit;
  987. }
  988. retFs = cellFsFGetBlockSize(fileGroupHandle,&mReadBuffer.mFileSectorSize,&mReadBuffer.mFileBlockSize);
  989. if(retFs == CELL_FS_SUCCEEDED)
  990. {
  991. //DebugPrint("Filegroup %s has blocksize %d, sectorsize %d\n", mReadBuffer.mFileName, mReadBuffer.mFileBlockSize, mReadBuffer.mFileSectorSize);
  992. mReadBuffer.mFile = fileGroupHandle;
  993. Q_strncpy(mReadBuffer.mFileName, fileGroupName, MAX_PATH);
  994. mFileStat = fileGroupStat;
  995. mPosOffset = 0;
  996. retFs = cellFsLseek(mReadBuffer.mFile,0,CELL_FS_SEEK_SET, &pos); //Ensure we are at the beginning of the file
  997. if(retFs == CELL_FS_SUCCEEDED)
  998. {
  999. uint64_t bytesRead;
  1000. retFs = cellFsRead(mReadBuffer.mFile,&hdr,(uint64_t)sizeof(hdr),&bytesRead);
  1001. if(retFs == CELL_FS_SUCCEEDED)
  1002. {
  1003. mPosOffset += bytesRead;
  1004. if (!usePreload)
  1005. {
  1006. hdr.mNumPreloadEntries = 0;
  1007. }
  1008. if ((hdr.mVersion >= FILEGROUP_FORMAT_VERSION) && (hdr.mNumEntries > 0) && (!mDirectoryEntries)) //Check that filegroup is not already populated, and that there are entries available to read
  1009. {
  1010. retFs = PopulateDirectory(&hdr,&entriesPopulated);
  1011. if(retFs == CELL_FS_SUCCEEDED && entriesPopulated > 0)
  1012. {
  1013. if (hdr.mNumPreloadEntries > 0)
  1014. {
  1015. if(mPreloadSection != NULL)
  1016. {
  1017. free(mPreloadSection);
  1018. }
  1019. mPreloadSection = malloc(mDirectoryEntries[hdr.mNumPreloadEntries].mPosition);
  1020. retFs = cellFsRead(mReadBuffer.mFile,mPreloadSection,(uint64_t)mDirectoryEntries[hdr.mNumPreloadEntries].mPosition,&bytesRead);
  1021. if ((retFs == CELL_FS_SUCCEEDED) && (bytesRead==mDirectoryEntries[hdr.mNumPreloadEntries].mPosition))
  1022. {
  1023. mPreloadEntries = hdr.mNumPreloadEntries;
  1024. }
  1025. else
  1026. {
  1027. printf("ERROR: Unable to read %d bytes of filegroup preload section. Preload disabled\n", mDirectoryEntries[hdr.mNumPreloadEntries].mPosition);
  1028. }
  1029. }
  1030. } //if(retFs == CELL_FS_SUCCEEDED && entriesPopulated > 0)
  1031. }//if ((hdr.mVersion == FILEGROUP_FORMAT_VERSION) && (hdr.mNumEntries > 0) && (!mDirectoryEntries))
  1032. } //if (retFs == CELL_FS_SUCCEEDED) cellfsread hdr
  1033. } //if (retFs == CELL_FS_SUCCEEDED) cellFsLseek
  1034. } //if (retFs == CELL_FS_SUCCEEDED) cellFsFGetBlockSize
  1035. } //while(retFs != CELL_FS_SUCCEEDED)
  1036. PS3_ClearDiskErrorDialog();
  1037. if(entriesPopulated > 0)
  1038. {
  1039. //Initialise mutex used for synchronising recovery from disk eject
  1040. sys_lwmutex_attribute_initialize(mReadBuffer.mEjectRecoveryMutexAttr);
  1041. int ret = sys_lwmutex_create(&mReadBuffer.mEjectRecoveryMutex, &mReadBuffer.mEjectRecoveryMutexAttr);
  1042. if (ret != CELL_OK) {
  1043. Msg("CFileGroup::Populate sys_lwmutex_create of mEjectRecoveryMutex failed: %d\n", ret);
  1044. }
  1045. //Initialise read buffer mutex
  1046. sys_lwmutex_attribute_initialize(mReadBuffer.mBufferMutexAttr);
  1047. mReadBuffer.mBufferMutexAttr.attr_recursive = SYS_SYNC_RECURSIVE;
  1048. ret = sys_lwmutex_create(&mReadBuffer.mBufferMutex, &mReadBuffer.mBufferMutexAttr);
  1049. if (ret != CELL_OK) {
  1050. printf("CFileGroup::Populate sys_lwmutex_create failed: %d\n", ret);
  1051. exit(1);
  1052. }
  1053. //Initialise read consumer mutex
  1054. sys_lwmutex_attribute_initialize(mReadBuffer.mNextConsumeByteMutexAttr);
  1055. mReadBuffer.mNextConsumeByteMutexAttr.attr_recursive = SYS_SYNC_RECURSIVE;
  1056. ret = sys_lwmutex_create(&mReadBuffer.mNextConsumeByteMutex, &mReadBuffer.mNextConsumeByteMutexAttr);
  1057. if (ret != CELL_OK) {
  1058. printf("CFileGroup::Populate sys_lwmutex_create failed: %d\n", ret);
  1059. exit(1);
  1060. }
  1061. mLastOpenedDirectoryIndex = 0;
  1062. #ifdef TIME_FILE_OPERATIONS
  1063. ResetFileTimings();
  1064. #endif
  1065. }
  1066. xit:
  1067. Unlock();
  1068. return entriesPopulated;
  1069. }
  1070. int CFileGroup::FindFile(FileIdentifier *pFileName)
  1071. {
  1072. int foundIndex = -1;
  1073. if (!mFlaggedForDeletion && !mReadBuffer.mFileGroupDeleted)
  1074. {
  1075. if(!pFileName->mNameIdSet)
  1076. {
  1077. pFileName->mNameId = HashFileName(pFileName->mName);
  1078. pFileName->mNameIdSet = true;
  1079. }
  1080. unsigned int index = mLastOpenedDirectoryIndex;
  1081. //Don't repeat the search if we already know this file doesn't exist
  1082. if (!mLastFailedId || (pFileName->mNameId != mLastFailedId))
  1083. {
  1084. //First check the current and next positions in the ordered list
  1085. if ((mDirectoryEntries[index].mNameId == pFileName->mNameId) || //current
  1086. ((++index < mNumDirectoryEntries) && (mDirectoryEntries[index].mNameId == pFileName->mNameId))) //next
  1087. {
  1088. foundIndex = index;
  1089. }
  1090. else
  1091. {
  1092. #ifdef FILEGROUP_USE_HASH_DIRECTORY
  1093. //At this point resort to the hash directory
  1094. int bucketId = pFileName->mNameId & FILEGROUP_BUCKET_MOD;
  1095. //printf("Using hash table to search %d entries for filename %d in bucket %d\n", mHashBuckets[bucketId].mCount, fileNameId, bucketId);
  1096. //Search through the relevant bucket
  1097. for (int i=mHashBuckets[bucketId].mPosition; i< (mHashBuckets[bucketId].mPosition + mHashBuckets[bucketId].mCount) && foundIndex < 0; i++)
  1098. {
  1099. if (mDirectoryEntries[mHashDirectory[i]].mNameId == pFileName->mNameId)
  1100. {
  1101. foundIndex = mHashDirectory[i];
  1102. }
  1103. }
  1104. #else
  1105. //Loop through the remaining directory entries, starting with the current entry
  1106. for(int i=index, j=0; j<(mNumDirectoryEntries-2) && foundIndex < 0; i++,j++)
  1107. {
  1108. //At the end of the list, loop back to the beginning:
  1109. if (i==mNumDirectoryEntries)
  1110. {
  1111. i=0;
  1112. }
  1113. if (mDirectoryEntries[i].mNameId == fileNameId)
  1114. {
  1115. foundIndex = i;
  1116. }
  1117. }
  1118. #endif
  1119. }
  1120. }
  1121. if(foundIndex < 0)
  1122. {
  1123. mLastFailedId = pFileName->mNameId;
  1124. }
  1125. }
  1126. return foundIndex;
  1127. }
  1128. CFileGroupOpenedFile* CFileGroup::FS_fopen( FileIdentifier *pFileName, const char *pOptions, unsigned int flags, __int64 *size )
  1129. {
  1130. Lock();
  1131. CFileGroupOpenedFile* retVal = NULL;
  1132. int foundIndex = FindFile(pFileName);
  1133. if (foundIndex>=0)
  1134. {
  1135. CFileGroupOpenedFile* openedFile = mFs->GetOpenedFile();
  1136. Assert(openedFile);
  1137. #ifdef MEMCMP_FILE_OPERATIONS
  1138. openedFile->Init(mDirectoryEntries[foundIndex],this,&mReadBuffer,mDirectoryExtraInfo[foundIndex].mFullFileName), (foundIndex<mPreloadEntries);
  1139. #else
  1140. openedFile->Init(mDirectoryEntries[foundIndex],this,&mReadBuffer, (foundIndex<mPreloadEntries));
  1141. #endif
  1142. if(!openedFile->IsPreloaded())
  1143. {
  1144. #ifdef TIME_FILE_OPERATIONS
  1145. if (!((foundIndex == mLastOpenedDirectoryIndex) || (foundIndex == mLastOpenedDirectoryIndex+1)))
  1146. {
  1147. ++m_fileJumps;
  1148. // if(mPreloadEntries>0)
  1149. // {
  1150. // DebugPrint("Jump from level load filegroup index %d to index %d\n", mLastOpenedDirectoryIndex, foundIndex );
  1151. // }
  1152. }
  1153. #endif
  1154. mLastOpenedDirectoryIndex = foundIndex;
  1155. }
  1156. if (size)
  1157. {
  1158. *size = mDirectoryEntries[foundIndex].mLength;
  1159. }
  1160. retVal = openedFile;
  1161. }
  1162. Unlock();
  1163. return retVal;
  1164. }
  1165. int CFileGroup::FS_stat( FileIdentifier *path, CellFsStat *buf )
  1166. {
  1167. Lock();
  1168. int retVal = -1;
  1169. int foundIndex = FindFile(path);
  1170. if (foundIndex > -1)
  1171. {
  1172. //Default the stat details to those of the parent group file
  1173. *buf = mFileStat;
  1174. buf->st_size = mDirectoryEntries[foundIndex].mLength; //Set the correct filesize
  1175. buf->st_mode = S_IFREG | S_IRUSR ; //Set the bitmask to indicate a read only file
  1176. //CM:TODO Set Block count????
  1177. retVal = 0;
  1178. }
  1179. Unlock();
  1180. return retVal;
  1181. }
  1182. void CFileGroup::DecrementOpenedCount()
  1183. {
  1184. Lock();
  1185. mOpenedCount--;
  1186. if (mFlaggedForDeletion && (mOpenedCount == 0))
  1187. {
  1188. mFs->DeleteFileGroup(this);
  1189. }
  1190. Unlock();
  1191. }
  1192. CFileGroupOpenedFile::CFileGroupOpenedFile()
  1193. : mEof(false), mSeekPosIndicator(-1), mActualPosIndicator(-1), mParentFileGroup(NULL), mDirEntry(NULL),
  1194. mPreloaded(false)
  1195. {
  1196. #ifdef _DEBUG
  1197. refCount++;
  1198. #endif
  1199. }
  1200. CFileGroupOpenedFile::~CFileGroupOpenedFile()
  1201. {
  1202. #ifdef _DEBUG
  1203. refCount--;
  1204. #endif
  1205. }
  1206. #ifdef MEMCMP_FILE_OPERATIONS
  1207. void CFileGroupOpenedFile::Init(const SmallDirectoryEntry& dirEntry, CFileGroup* parentFileGroup, FileGroupReadBuffer* parentBuffer, char* fullFileName, bool preloaded)
  1208. #else
  1209. void CFileGroupOpenedFile::Init(const SmallDirectoryEntry& dirEntry, CFileGroup* parentFileGroup, FileGroupReadBuffer* parentBuffer, bool preloaded)
  1210. #endif
  1211. {
  1212. mPreloaded=preloaded;
  1213. mDirEntry = &dirEntry;
  1214. mParentFileGroup = parentFileGroup;
  1215. mParentReadBuffer = parentBuffer;
  1216. mSeekPosIndicator = 0;
  1217. mActualPosIndicator = 0;
  1218. mCompressedPosIndicator = 0;
  1219. mUncompressedBufferStartPos = -1;
  1220. if (mDirEntry->mCompressedLength > 0)
  1221. {
  1222. //Zlib initialisation
  1223. mStrm.zalloc = Z_NULL;
  1224. mStrm.zfree = Z_NULL;
  1225. mStrm.opaque = Z_NULL;
  1226. mStrm.avail_in = 0;
  1227. mStrm.next_in = Z_NULL;
  1228. Assert( 0 );
  1229. //int InfRet = inflateInit(&mStrm);
  1230. }
  1231. #ifdef MEMCMP_FILE_OPERATIONS
  1232. if (!(strstr(fullFileName,"/Resource/")))
  1233. {
  1234. mOrdinaryFile = fopen(fullFileName,"rb");
  1235. }
  1236. else
  1237. {
  1238. mOrdinaryFile = NULL;
  1239. }
  1240. #endif
  1241. mParentFileGroup->IncrementOpenedCount();
  1242. }
  1243. void CFileGroupOpenedFile::FS_fclose()
  1244. {
  1245. if (mDirEntry->mCompressedLength > 0)
  1246. {
  1247. Assert( 0 );
  1248. //inflateEnd(&mStrm);
  1249. }
  1250. mParentFileGroup->Lock();
  1251. mParentFileGroup->DecrementOpenedCount();
  1252. mParentFileGroup->FreeOpenedFile(this);
  1253. #ifdef MEMCMP_FILE_OPERATIONS
  1254. if (mOrdinaryFile)
  1255. {
  1256. fclose(mOrdinaryFile);
  1257. mOrdinaryFile = NULL;
  1258. }
  1259. #endif
  1260. mParentFileGroup->Unlock();
  1261. }
  1262. void CFileGroupOpenedFile::FS_fseek( __int64 pos, int seekType )
  1263. {
  1264. //mParentFileGroup->Lock();
  1265. //CM:TODO Possibly change this so that seek isn't actually done until read????
  1266. __int64 absPosition;
  1267. switch (seekType)
  1268. {
  1269. case SEEK_CUR:
  1270. absPosition = mSeekPosIndicator + pos;
  1271. break;
  1272. case SEEK_END:
  1273. absPosition = mDirEntry->mLength + pos;
  1274. break;
  1275. default:
  1276. absPosition = pos;
  1277. }
  1278. bool eofSeek = false; //Record eof setting at this point, but only set mEof following a successful seek
  1279. if(absPosition > mDirEntry->mLength)
  1280. {
  1281. absPosition = mDirEntry->mLength;
  1282. eofSeek = true;
  1283. //CM:TODO Raise error condition?
  1284. }
  1285. //Don't actually do the seek at this point, wait until next read
  1286. mSeekPosIndicator = absPosition;
  1287. mEof = eofSeek;
  1288. #ifdef MEMCMP_FILE_OPERATIONS
  1289. if (mOrdinaryFile)
  1290. {
  1291. fseek(mOrdinaryFile,pos,seekType);
  1292. }
  1293. #endif
  1294. //if (!isCurrent)
  1295. //{
  1296. // mParentFileGroup->MakeCurrentEntry(this);
  1297. //}
  1298. //mParentFileGroup->Unlock();
  1299. }
  1300. long CFileGroupOpenedFile::FS_ftell()
  1301. {
  1302. return mSeekPosIndicator;
  1303. //CM:TODO If an error occurs, -1L is returned, and the global variable errno is set to a positive value.
  1304. }
  1305. int CFileGroupOpenedFile::FS_feof()
  1306. {
  1307. return mEof;
  1308. }
  1309. void CFileGroupOpenedFile::Rewind()
  1310. {
  1311. #ifdef TIME_FILE_OPERATIONS
  1312. mParentFileGroup->m_rewinds++;
  1313. #endif
  1314. Assert( 0 );
  1315. //inflateEnd(&mStrm);
  1316. mStrm.zalloc = Z_NULL;
  1317. mStrm.zfree = Z_NULL;
  1318. mStrm.opaque = Z_NULL;
  1319. mStrm.avail_in = 0;
  1320. mStrm.next_in = Z_NULL;
  1321. Assert( 0 );
  1322. //int InfRet = inflateInit(&mStrm);
  1323. mCompressedPosIndicator = 0;
  1324. mActualPosIndicator = 0;
  1325. mUncompressedBufferStartPos = -1;
  1326. }
  1327. void CFileGroupOpenedFile::TraceMemCopy(void* pDest, const void* pSource, size_t nBytes)
  1328. {
  1329. #ifdef TIME_FILE_OPERATIONS
  1330. system_time_t time1 = sys_time_get_system_time();
  1331. #endif
  1332. memcpy(pDest,pSource,nBytes);
  1333. #ifdef TIME_FILE_OPERATIONS
  1334. system_time_t time2 = sys_time_get_system_time();
  1335. mParentFileGroup->m_memCopyTime += (time2-time1);
  1336. #endif
  1337. }
  1338. //ASSUMPTIONS: destination has readSize bytes available
  1339. size_t CFileGroupOpenedFile::ReadFromCompressedData( void *dest, size_t readSize)
  1340. {
  1341. uint64_t bytesRead = 0;
  1342. bool dataCopied = false;
  1343. size_t destBytesWritten = 0;
  1344. size_t bytesToIgnore = 0;
  1345. if (mSeekPosIndicator < mActualPosIndicator) //Check for Rewind
  1346. {
  1347. //First check if there is any data left over from a previous inflate
  1348. if ((mUncompressedBufferStartPos > -1) && (mSeekPosIndicator >= mUncompressedBufferStartPos))
  1349. {
  1350. unsigned char* seekPosUncompressedBuffer = mUncompressedBuffer + (mSeekPosIndicator - mUncompressedBufferStartPos);
  1351. int bytesToCopy = MIN(mActualPosIndicator - mSeekPosIndicator, readSize);
  1352. TraceMemCopy(dest,seekPosUncompressedBuffer,bytesToCopy);
  1353. destBytesWritten += bytesToCopy;
  1354. }
  1355. else
  1356. {
  1357. Rewind();
  1358. }
  1359. }
  1360. else
  1361. {
  1362. bytesToIgnore = mSeekPosIndicator - mActualPosIndicator;
  1363. }
  1364. size_t parentCompressedPos = mParentFileGroup->GetPosOffset() + mDirEntry->mPosition + mCompressedPosIndicator;
  1365. size_t remainingBytesToIgnore;
  1366. size_t avail_in_before_inflate;
  1367. size_t remainingCompressedData = mDirEntry->mCompressedLength - mCompressedPosIndicator;
  1368. while((destBytesWritten < readSize) && (remainingCompressedData > 0))
  1369. {
  1370. bool compressedDataFound = false;
  1371. if (mPreloaded)
  1372. {
  1373. compressedDataFound=true;
  1374. mStrm.avail_in = remainingCompressedData;
  1375. mStrm.next_in = (Bytef*)mParentFileGroup->GetPreloadData() + mDirEntry->mPosition + mCompressedPosIndicator;
  1376. }
  1377. else
  1378. {
  1379. sys_lwmutex_lock(&mParentReadBuffer->mNextConsumeByteMutex,0); //Ensure that no other consumer updates the 'next consume byte'
  1380. if (parentCompressedPos < mParentReadBuffer->mCurrentPos)
  1381. {
  1382. if (mParentFileGroup->UsingReadThread())
  1383. {
  1384. size_t availablePos = 0;
  1385. sys_lwmutex_lock(&mParentReadBuffer->mBufferStartEndPosMutex,0); //Don't want read thread to 'wrap around' while we calculate the available data
  1386. //Compressed data may exist in read thread buffer
  1387. //First find the start of the section of the buffer which won't be overwritten:
  1388. if ((mParentReadBuffer->mBufferEndPos > 0) && (mParentReadBuffer->mBufferEndPos == mParentReadBuffer->mBufferStartPos)) //Include data from previous buffer cycle
  1389. {
  1390. if (mParentReadBuffer->mNextConsumePos > 0) //Read thread won't overwrite FILEGROUP_READ_STORE_SIZE bytes up to NextConsumeByte
  1391. {
  1392. if (mParentReadBuffer->mNextConsumePos > (mParentFileGroup->GetPosOffset() + FILEGROUP_READ_STORE_SIZE))
  1393. {
  1394. availablePos = mParentReadBuffer->mNextConsumePos - FILEGROUP_READ_STORE_SIZE;
  1395. }
  1396. else
  1397. {
  1398. availablePos = mParentFileGroup->GetPosOffset();
  1399. }
  1400. }
  1401. else
  1402. {
  1403. //This should only occur when read thread has filled buffer and no bytes have been read
  1404. Assert(mParentReadBuffer->mCurrentByte == mParentReadBuffer->mBuffer);
  1405. Assert(mParentReadBuffer->mAwaitingConsumer);
  1406. availablePos = mParentReadBuffer->mBufferStartPos;
  1407. }
  1408. }
  1409. else //No data available from previous cycle
  1410. {
  1411. if (mParentReadBuffer->mNextConsumePos > 0)
  1412. {
  1413. Assert(mParentReadBuffer->mNextConsumePos <= mParentReadBuffer->mCurrentPos);
  1414. if ((mParentReadBuffer->mNextConsumePos - mParentReadBuffer->mBufferStartPos) > FILEGROUP_READ_STORE_SIZE)
  1415. {
  1416. availablePos = mParentReadBuffer->mNextConsumePos - FILEGROUP_READ_STORE_SIZE;
  1417. }
  1418. else
  1419. {
  1420. availablePos = mParentReadBuffer->mBufferStartPos;
  1421. }
  1422. }
  1423. else
  1424. {
  1425. availablePos = mParentReadBuffer->mBufferStartPos;
  1426. }
  1427. }
  1428. //Now check if compressed data exists within the 'safe' portion of the buffer:
  1429. if (parentCompressedPos >= availablePos)
  1430. {
  1431. compressedDataFound = true;
  1432. if ((mParentReadBuffer->mBufferEndPos > 0) && (mParentReadBuffer->mBufferEndPos == mParentReadBuffer->mBufferStartPos) &&
  1433. (parentCompressedPos < mParentReadBuffer->mBufferEndPos)) //Data wraps round end of buffer
  1434. {
  1435. mStrm.avail_in = MIN((mParentReadBuffer->mBufferEndPos - parentCompressedPos),remainingCompressedData);
  1436. mStrm.next_in = (mParentReadBuffer->mBuffer + mParentReadBuffer->mBufferSize) - (mParentReadBuffer->mBufferEndPos - parentCompressedPos);
  1437. }
  1438. else
  1439. {
  1440. mStrm.avail_in = MIN((mParentReadBuffer->mCurrentPos - parentCompressedPos),remainingCompressedData);
  1441. mStrm.next_in = mParentReadBuffer->mBuffer + (parentCompressedPos - mParentReadBuffer->mBufferStartPos);
  1442. }
  1443. }
  1444. sys_lwmutex_unlock(&mParentReadBuffer->mBufferStartEndPosMutex); //Happy for read thread to 'wrap around' from this point on
  1445. }
  1446. else
  1447. {
  1448. //If not using read thread, we don't need to worry about data being overwritten, check whether the data exists anywhere in the buffer
  1449. if (parentCompressedPos >= mParentReadBuffer->mBufferStartPos)
  1450. {
  1451. compressedDataFound = true;
  1452. mStrm.avail_in = MIN((mParentReadBuffer->mCurrentPos - parentCompressedPos),remainingCompressedData);
  1453. mStrm.next_in = mParentReadBuffer->mBuffer + (parentCompressedPos - mParentReadBuffer->mBufferStartPos);
  1454. }
  1455. }
  1456. }
  1457. }
  1458. if (!compressedDataFound)
  1459. {
  1460. //Read compressed data from file
  1461. sys_lwmutex_lock(&mParentReadBuffer->mBufferMutex,0); //Lock buffer for write
  1462. #ifdef TIME_FILE_OPERATIONS
  1463. system_time_t time1 = sys_time_get_system_time();
  1464. #endif
  1465. uint64_t pos;
  1466. uint64_t alignedSeekPos = parentCompressedPos - parentCompressedPos%mParentReadBuffer->mFileBlockSize;
  1467. CellFsErrno retFs = cellFsLseek(mParentReadBuffer->mFile,alignedSeekPos,CELL_FS_SEEK_SET,&pos);
  1468. if(retFs == CELL_FS_SUCCEEDED)
  1469. {
  1470. retFs = cellFsRead(mParentReadBuffer->mFile,mParentReadBuffer->mBuffer,(uint64_t)FILEGROUP_READ_CHUNK_SIZE,&bytesRead);
  1471. }
  1472. while(retFs != CELL_FS_SUCCEEDED)
  1473. {
  1474. cellFsClose(mParentReadBuffer->mFile);
  1475. sys_timer_usleep(250000); //Sleep for 0.25 seconds
  1476. mParentReadBuffer->WaitOnDiskEjectRecovery();
  1477. retFs = cellFsLseek(mParentReadBuffer->mFile,(int64_t)alignedSeekPos,CELL_FS_SEEK_SET,&pos);
  1478. if(retFs == CELL_FS_SUCCEEDED)
  1479. {
  1480. retFs = cellFsRead(mParentReadBuffer->mFile,mParentReadBuffer->mBuffer,(uint64_t)FILEGROUP_READ_CHUNK_SIZE,&bytesRead);
  1481. }
  1482. if(retFs == CELL_FS_EIO)
  1483. {
  1484. PS3_DisplayDiskErrorDialog(); //Assume dirty disk, rather than disk eject if this point is reached
  1485. }
  1486. else if(retFs == CELL_FS_SUCCEEDED)
  1487. {
  1488. PS3_ClearDiskErrorDialog();
  1489. }
  1490. }
  1491. if (bytesRead > 0)
  1492. {
  1493. //Reset buffer data so that read thread continues from this point
  1494. mParentReadBuffer->mBufferEndPos = 0;
  1495. mParentReadBuffer->mBufferStartPos = alignedSeekPos;
  1496. mParentReadBuffer->mCurrentByte = mParentReadBuffer->mBuffer + (int)bytesRead;
  1497. mParentReadBuffer->mCurrentPos = alignedSeekPos + (int)bytesRead;
  1498. mParentReadBuffer->mNextConsumePos = 0;
  1499. if (mParentFileGroup->UsingReadThread() &&
  1500. mParentReadBuffer->mAwaitingConsumer &&
  1501. mParentReadBuffer->mCurrentPos < mParentFileGroup->Size())
  1502. {
  1503. int ret = sys_cond_signal_to(mParentReadBuffer->mReadThreadSignal,mParentFileGroup->GetReadThread());
  1504. }
  1505. }
  1506. #ifdef TIME_FILE_OPERATIONS
  1507. system_time_t time2 = sys_time_get_system_time();
  1508. mParentFileGroup->IncrReadTime(time2-time1);
  1509. mParentFileGroup->m_bytesReadFromFileByConsumer += (int)bytesRead;
  1510. mParentFileGroup->IncrReadBytes(bytesRead);
  1511. #endif
  1512. mStrm.avail_in = MIN((int)(bytesRead - (parentCompressedPos-alignedSeekPos)),remainingCompressedData);
  1513. mStrm.next_in = mParentReadBuffer->mBuffer+(parentCompressedPos-alignedSeekPos);
  1514. sys_lwmutex_unlock(&mParentReadBuffer->mBufferMutex); //Now safe for other threads to continue updating buffer
  1515. }
  1516. //mParentReadBuffer->mNextConsumeByte = mStrm.next_in; //This ensures bytes aren't overwritten during inflate SHOULD ONLY EVER INCREASE NEXT CONSUME BYTE
  1517. //Assert(((mParentReadBuffer->mNextConsumeByte - mParentReadBuffer->mBuffer) < FILEGROUP_READ_THREAD_BUFFER_SIZE));
  1518. // mStrm.avail_out = FILEGROUP_UNCOMPRESSED_BUFFER_SIZE;
  1519. // bool directInflate = ((bytesToIgnore <= 0) && (readSize - destBytesWritten) >= FILEGROUP_UNCOMPRESSED_BUFFER_SIZE);
  1520. // if (directInflate)
  1521. // {
  1522. // mStrm.next_out = (unsigned char*)dest + destBytesWritten;
  1523. // }
  1524. // else
  1525. // {
  1526. // mStrm.next_out = mUncompressedBuffer;
  1527. // }
  1528. // while((mStrm.avail_in > 0)&&(destBytesWritten < readSize))
  1529. // {
  1530. #ifdef TIME_FILE_OPERATIONS
  1531. system_time_t time1 = sys_time_get_system_time();
  1532. #endif
  1533. mStrm.avail_out = FILEGROUP_UNCOMPRESSED_BUFFER_SIZE;
  1534. mStrm.next_out = mUncompressedBuffer;
  1535. avail_in_before_inflate = mStrm.avail_in;
  1536. Assert( 0 );
  1537. int ret = 0;//inflate(&mStrm, Z_NO_FLUSH);
  1538. Assert(ret != Z_STREAM_ERROR); /* state not clobbered */
  1539. switch (ret)
  1540. {case Z_NEED_DICT:
  1541. ret = Z_DATA_ERROR; /* and fall through */
  1542. case Z_DATA_ERROR:
  1543. case Z_MEM_ERROR:
  1544. //(void)inflateEnd(&mStrm);
  1545. Assert(0);
  1546. printf("Error %d decompressing data, returning %d\n", ret, destBytesWritten);
  1547. return destBytesWritten;
  1548. }
  1549. #ifdef TIME_FILE_OPERATIONS
  1550. system_time_t time2 = sys_time_get_system_time();
  1551. mParentFileGroup->m_uncompressCalls++;
  1552. mParentFileGroup->m_bytesReadFromBuffer += (avail_in_before_inflate - mStrm.avail_in);
  1553. mParentFileGroup->m_uncompressTime += (time2-time1);
  1554. #endif
  1555. int bytesInflated = FILEGROUP_UNCOMPRESSED_BUFFER_SIZE - mStrm.avail_out;
  1556. // if (directInflate)
  1557. // {
  1558. mUncompressedBufferStartPos = mActualPosIndicator;
  1559. // }
  1560. // else
  1561. // {
  1562. // mUncompressedBufferStartPos = -1;
  1563. // }
  1564. mActualPosIndicator += bytesInflated;
  1565. if (bytesToIgnore > 0)
  1566. {
  1567. if (bytesInflated > bytesToIgnore)
  1568. {
  1569. int bytesOfInterest = MIN(readSize,(bytesInflated - bytesToIgnore));
  1570. // if (!directInflate)
  1571. // {
  1572. TraceMemCopy(dest, mUncompressedBuffer + bytesToIgnore, bytesOfInterest);
  1573. // }
  1574. destBytesWritten += bytesOfInterest;
  1575. bytesToIgnore = 0;
  1576. }
  1577. else
  1578. {
  1579. bytesToIgnore -= bytesInflated;
  1580. }
  1581. }
  1582. else
  1583. {
  1584. int bytesOfInterest = MIN((readSize-destBytesWritten),bytesInflated);
  1585. // if (!directInflate)
  1586. // {
  1587. TraceMemCopy((unsigned char*)dest + destBytesWritten, mUncompressedBuffer, bytesOfInterest);
  1588. // }
  1589. destBytesWritten += bytesOfInterest;
  1590. }
  1591. mCompressedPosIndicator += (avail_in_before_inflate - mStrm.avail_in);
  1592. parentCompressedPos += (avail_in_before_inflate - mStrm.avail_in);
  1593. remainingCompressedData -= (avail_in_before_inflate - mStrm.avail_in);
  1594. Assert(mStrm.next_in);
  1595. // } //while inflate loop
  1596. //Wait until this point before updating NextConsumePos, otherwise data may be overwritten during inflate.
  1597. //Only update "NextConsumePos" if it has increased, otherwise it is possible to get into a situation
  1598. // where some of the FILEGROUP_READ_STORE_SIZE bytes leading up to NextConsumePos are overwritten by the read thread.
  1599. if ((!mPreloaded) && (parentCompressedPos > mParentReadBuffer->mNextConsumePos))
  1600. {
  1601. mParentReadBuffer->mNextConsumePos = parentCompressedPos;
  1602. //Check if need to signal to read thread
  1603. if (mParentFileGroup->UsingReadThread() &&
  1604. mParentReadBuffer->mAwaitingConsumer &&
  1605. mParentReadBuffer->mCurrentPos < mParentFileGroup->Size() &&
  1606. ((mParentReadBuffer->mCurrentPos + FILEGROUP_READ_CHUNK_SIZE) - mParentReadBuffer->mNextConsumePos) <= (mParentReadBuffer->mBufferSize - FILEGROUP_READ_SIGNAL_SIZE))
  1607. {
  1608. int ret = sys_cond_signal_to(mParentReadBuffer->mReadThreadSignal,mParentFileGroup->GetReadThread());
  1609. }
  1610. }
  1611. if (!mPreloaded)
  1612. {
  1613. sys_lwmutex_unlock(&mParentReadBuffer->mNextConsumeByteMutex); //Release consumer lock
  1614. }
  1615. } //while check available data loop
  1616. return destBytesWritten;
  1617. }
  1618. size_t CFileGroupOpenedFile::ReadFromUncompressedData( void *dest, size_t readSize)
  1619. {
  1620. uint64_t bytesRead = 0;
  1621. bool dataCopied = false;
  1622. size_t dataSeekPos = mDirEntry->mPosition + mSeekPosIndicator;
  1623. size_t parentSeekPos = mParentFileGroup->GetPosOffset() + dataSeekPos;
  1624. size_t destBytesWritten = 0;
  1625. int ret;
  1626. if(mPreloaded)
  1627. {
  1628. TraceMemCopy((unsigned char*)dest, (Bytef*)mParentFileGroup->GetPreloadData() + dataSeekPos, readSize);
  1629. destBytesWritten = readSize;
  1630. mSeekPosIndicator += readSize;
  1631. }
  1632. else
  1633. {
  1634. sys_lwmutex_lock(&mParentReadBuffer->mNextConsumeByteMutex,0); //Ensure that no other consumer updates the 'next consume byte'
  1635. size_t dataAvailable = 0;
  1636. void* dataLocation = NULL;
  1637. size_t remainingData = mDirEntry->mLength - mSeekPosIndicator;
  1638. while(destBytesWritten < readSize)
  1639. {
  1640. bool dataFound = false;
  1641. if (parentSeekPos < mParentReadBuffer->mCurrentPos && remainingData > 0)
  1642. {
  1643. if (mParentFileGroup->UsingReadThread())
  1644. {
  1645. size_t availablePos = 0;
  1646. sys_lwmutex_lock(&mParentReadBuffer->mBufferStartEndPosMutex,0); //Don't want read thread to 'wrap around' while we calculate the available data
  1647. //Data may exist in read thread buffer
  1648. //First find the start of the section of the buffer which won't be overwritten:
  1649. if ((mParentReadBuffer->mBufferEndPos > 0) && (mParentReadBuffer->mBufferEndPos == mParentReadBuffer->mBufferStartPos)) //Include data from previous buffer cycle
  1650. {
  1651. if (mParentReadBuffer->mNextConsumePos > 0) //Read thread won't overwrite FILEGROUP_READ_STORE_SIZE bytes up to NextConsumeByte
  1652. {
  1653. if (mParentReadBuffer->mNextConsumePos > (mParentFileGroup->GetPosOffset() + FILEGROUP_READ_STORE_SIZE))
  1654. {
  1655. availablePos = mParentReadBuffer->mNextConsumePos - FILEGROUP_READ_STORE_SIZE;
  1656. }
  1657. else
  1658. {
  1659. availablePos = mParentFileGroup->GetPosOffset();
  1660. }
  1661. }
  1662. else
  1663. {
  1664. //This should only occur when read thread has filled buffer and no bytes have been read
  1665. Assert(mParentReadBuffer->mCurrentByte == mParentReadBuffer->mBuffer);
  1666. Assert(mParentReadBuffer->mAwaitingConsumer);
  1667. availablePos = mParentReadBuffer->mBufferStartPos;
  1668. }
  1669. }
  1670. else //No data available from previous cycle
  1671. {
  1672. if (mParentReadBuffer->mNextConsumePos > 0)
  1673. {
  1674. Assert(mParentReadBuffer->mNextConsumePos <= mParentReadBuffer->mCurrentPos);
  1675. if ((mParentReadBuffer->mNextConsumePos - mParentReadBuffer->mBufferStartPos) > FILEGROUP_READ_STORE_SIZE)
  1676. {
  1677. availablePos = mParentReadBuffer->mNextConsumePos - FILEGROUP_READ_STORE_SIZE;
  1678. }
  1679. else
  1680. {
  1681. availablePos = mParentReadBuffer->mBufferStartPos;
  1682. }
  1683. }
  1684. else
  1685. {
  1686. availablePos = mParentReadBuffer->mBufferStartPos;
  1687. }
  1688. }
  1689. //Now check if compressed data exists within the 'safe' portion of the buffer:
  1690. if (parentSeekPos >= availablePos)
  1691. {
  1692. dataFound = true;
  1693. if ((mParentReadBuffer->mBufferEndPos > 0) && (mParentReadBuffer->mBufferEndPos == mParentReadBuffer->mBufferStartPos) &&
  1694. (parentSeekPos < mParentReadBuffer->mBufferEndPos)) //Data wraps round end of buffer
  1695. {
  1696. dataAvailable = MIN((mParentReadBuffer->mBufferEndPos - parentSeekPos),remainingData);
  1697. dataLocation = (mParentReadBuffer->mBuffer + mParentReadBuffer->mBufferSize) - (mParentReadBuffer->mBufferEndPos - parentSeekPos);
  1698. }
  1699. else
  1700. {
  1701. dataAvailable = MIN((mParentReadBuffer->mCurrentPos - parentSeekPos),remainingData);
  1702. dataLocation = mParentReadBuffer->mBuffer + (parentSeekPos - mParentReadBuffer->mBufferStartPos);
  1703. }
  1704. }
  1705. sys_lwmutex_unlock(&mParentReadBuffer->mBufferStartEndPosMutex); //Happy for read thread to 'wrap around' from this point on
  1706. }
  1707. else
  1708. {
  1709. //Don't need to worry about read thread overwriting the buffer, check whether the data exists anywhere in the buffer
  1710. if (parentSeekPos >= mParentReadBuffer->mBufferStartPos)
  1711. {
  1712. dataFound = true;
  1713. dataAvailable = MIN((mParentReadBuffer->mCurrentPos - parentSeekPos),remainingData);
  1714. dataLocation = mParentReadBuffer->mBuffer + (parentSeekPos - mParentReadBuffer->mBufferStartPos);
  1715. }
  1716. }
  1717. }
  1718. if (!dataFound)
  1719. {
  1720. //Read data from file
  1721. sys_lwmutex_lock(&mParentReadBuffer->mBufferMutex,0); //Lock buffer for write
  1722. #ifdef TIME_FILE_OPERATIONS
  1723. system_time_t time1 = sys_time_get_system_time();
  1724. #endif
  1725. uint64_t pos;
  1726. uint64_t alignedSeekPos = parentSeekPos - parentSeekPos%mParentReadBuffer->mFileBlockSize;
  1727. uint64_t alignedReadSize = FILEGROUP_READ_CHUNK_SIZE;
  1728. if(mParentReadBuffer->mReadChunkSize>FILEGROUP_READ_CHUNK_SIZE)
  1729. {
  1730. uint64_t alignedRemainingData = (parentSeekPos + remainingData) - alignedSeekPos; //Locate the remaining data from the alignedseekpos up to the end of the file
  1731. if(alignedRemainingData > FILEGROUP_READ_CHUNK_SIZE)
  1732. {
  1733. alignedReadSize = MIN(mParentReadBuffer->mReadChunkSize,((((parentSeekPos + remainingData) - alignedSeekPos)/FILEGROUP_READ_CHUNK_SIZE)+1)*FILEGROUP_READ_CHUNK_SIZE);
  1734. }
  1735. }
  1736. CellFsErrno retFs = cellFsLseek(mParentReadBuffer->mFile,(int64_t)alignedSeekPos,CELL_FS_SEEK_SET,&pos);
  1737. if (retFs == CELL_FS_SUCCEEDED)
  1738. {
  1739. //snStopMarker(3);
  1740. //char tempText[100];
  1741. //snprintf(tempText, 100, "cellfsread aligned pos %d, seek pos %d, read size %d", alignedSeekPos, parentSeekPos, alignedReadSize);
  1742. //snStartMarker((unsigned int)mParentReadBuffer->mFile, tempText);
  1743. retFs = cellFsRead(mParentReadBuffer->mFile,mParentReadBuffer->mBuffer,alignedReadSize,&bytesRead);
  1744. //snStopMarker((unsigned int)mParentReadBuffer->mFile);
  1745. //snStartMarker(3, "SyncRead continue");
  1746. //DebugPrint("ReadFromUncompressedData: pos %d\n", parentSeekPos);
  1747. }
  1748. while(retFs != CELL_FS_SUCCEEDED)
  1749. {
  1750. cellFsClose(mParentReadBuffer->mFile);
  1751. sys_timer_usleep(250000); //Sleep for 0.25 seconds
  1752. mParentReadBuffer->WaitOnDiskEjectRecovery();
  1753. retFs = cellFsLseek(mParentReadBuffer->mFile,(int64_t)alignedSeekPos,CELL_FS_SEEK_SET,&pos);
  1754. if (retFs == CELL_FS_SUCCEEDED)
  1755. {
  1756. retFs = cellFsRead(mParentReadBuffer->mFile,mParentReadBuffer->mBuffer,alignedReadSize,&bytesRead);
  1757. }
  1758. if(retFs == CELL_FS_EIO)
  1759. {
  1760. PS3_DisplayDiskErrorDialog();
  1761. }
  1762. else if(retFs == CELL_FS_SUCCEEDED)
  1763. {
  1764. PS3_ClearDiskErrorDialog();
  1765. }
  1766. }
  1767. if (bytesRead > 0)
  1768. {
  1769. //Reset buffer data so that read thread continues from this point
  1770. mParentReadBuffer->mBufferEndPos = 0;
  1771. mParentReadBuffer->mBufferStartPos = alignedSeekPos;
  1772. mParentReadBuffer->mCurrentByte = mParentReadBuffer->mBuffer + (int)bytesRead;
  1773. mParentReadBuffer->mCurrentPos = alignedSeekPos + (int)bytesRead;
  1774. mParentReadBuffer->mNextConsumePos = 0;
  1775. if (mParentFileGroup->UsingReadThread() &&
  1776. mParentReadBuffer->mAwaitingConsumer &&
  1777. mParentReadBuffer->mCurrentPos < mParentFileGroup->Size())
  1778. {
  1779. int ret = sys_cond_signal_to(mParentReadBuffer->mReadThreadSignal,mParentFileGroup->GetReadThread());
  1780. }
  1781. }
  1782. #ifdef TIME_FILE_OPERATIONS
  1783. system_time_t time2 = sys_time_get_system_time();
  1784. mParentFileGroup->IncrReadTime(time2-time1);
  1785. mParentFileGroup->m_bytesReadFromFileByConsumer += (int)bytesRead;
  1786. mParentFileGroup->IncrReadBytes((int)bytesRead);
  1787. #endif
  1788. dataAvailable = MIN((int)(bytesRead-(parentSeekPos-alignedSeekPos)),remainingData);
  1789. dataLocation = mParentReadBuffer->mBuffer + (parentSeekPos-alignedSeekPos);
  1790. sys_lwmutex_unlock(&mParentReadBuffer->mBufferMutex); //Now safe for other threads to continue updating buffer
  1791. }
  1792. int bytesOfInterest = MIN((readSize-destBytesWritten),dataAvailable);
  1793. //snStartMarker(1, "MemCpy");
  1794. TraceMemCopy((unsigned char*)dest + destBytesWritten, dataLocation, bytesOfInterest);
  1795. //snStopMarker(1);
  1796. destBytesWritten += bytesOfInterest;
  1797. mSeekPosIndicator += bytesOfInterest;
  1798. parentSeekPos += bytesOfInterest;
  1799. remainingData = mDirEntry->mLength - mSeekPosIndicator;
  1800. #ifdef TIME_FILE_OPERATIONS
  1801. mParentFileGroup->m_bytesReadFromBuffer += bytesOfInterest;
  1802. #endif
  1803. //Wait until this point before updating NextConsumePos, otherwise data may be overwritten during inflate.
  1804. //Only update "NextConsumePos" if it has increased, otherwise it is possible to get into a situation
  1805. // where some of the FILEGROUP_READ_STORE_SIZE bytes leading up to NextConsumePos are overwritten by the read thread.
  1806. if (parentSeekPos > mParentReadBuffer->mNextConsumePos)
  1807. {
  1808. mParentReadBuffer->mNextConsumePos = parentSeekPos;
  1809. //Check if need to signal to read thread
  1810. if (mParentFileGroup->UsingReadThread() &&
  1811. mParentReadBuffer->mAwaitingConsumer &&
  1812. mParentReadBuffer->mCurrentPos < mParentFileGroup->Size() &&
  1813. ((mParentReadBuffer->mCurrentPos + FILEGROUP_READ_CHUNK_SIZE) - mParentReadBuffer->mNextConsumePos) <= (mParentReadBuffer->mBufferSize - FILEGROUP_READ_SIGNAL_SIZE))
  1814. {
  1815. int ret = sys_cond_signal_to(mParentReadBuffer->mReadThreadSignal,mParentFileGroup->GetReadThread());
  1816. }
  1817. }
  1818. } //while check available data loop
  1819. sys_lwmutex_unlock(&mParentReadBuffer->mNextConsumeByteMutex); //Release consumer lock
  1820. }
  1821. return destBytesWritten;
  1822. }
  1823. size_t CFileGroupOpenedFile::FS_fread( void *dest, size_t destSize, size_t size)
  1824. {
  1825. MEM_ALLOC_CREDIT();
  1826. // Assert(V_stristr(mDirEntry.mName,"bars001c") == NULL);
  1827. // mParentFileGroup->Lock();
  1828. // int readSize = MIN(destSize,size);//Ensure that we don't read more than destSize
  1829. if (mParentFileGroup->HasBeenDeleted())
  1830. {
  1831. printf("ERROR: Attempting to read from file after filegroup has been deleted\n");
  1832. }
  1833. int readSize = size; //Need to ignore destsize to ensure that we get the same behaviour from filegroups that we get from the ordinary filesystem
  1834. bool eofRead = false; //Record eof setting at this point, but only set mEof following a successful read
  1835. if(readSize > (mDirEntry->mLength - mSeekPosIndicator))
  1836. {
  1837. readSize = (mDirEntry->mLength - mSeekPosIndicator);
  1838. eofRead = true;
  1839. //CM:TODO Raise error condition?
  1840. }
  1841. size_t bytesRead;
  1842. if (mDirEntry->mCompressedLength > 0)
  1843. {
  1844. bytesRead = ReadFromCompressedData(dest,readSize);
  1845. mSeekPosIndicator = mSeekPosIndicator + bytesRead;
  1846. }
  1847. else
  1848. {
  1849. bytesRead = ReadFromUncompressedData(dest,readSize);
  1850. mActualPosIndicator = mSeekPosIndicator + bytesRead;
  1851. }
  1852. //CM:TODO Error handling
  1853. //CM:TODO If this number differs from the bytes requested, set ferror and feof accordingly.
  1854. //otherwise...
  1855. //mActualPosIndicator = mSeekPosIndicator + bytesRead;
  1856. mEof = eofRead;
  1857. //if (!mParentFileGroup->IsCurrentFile(this))
  1858. //{
  1859. // mParentFileGroup->MakeCurrentFile(this);
  1860. //}
  1861. //mParentFileGroup->Unlock();
  1862. #ifdef MEMCMP_FILE_OPERATIONS
  1863. if (mOrdinaryFile)
  1864. {
  1865. unsigned char* tmpDest = new unsigned char[size];
  1866. fread(tmpDest,1,size,mOrdinaryFile);
  1867. Assert((memcmp(tmpDest,dest,size)==0));
  1868. delete[] tmpDest;
  1869. }
  1870. #endif
  1871. #ifdef TIME_FILE_OPERATIONS
  1872. mParentFileGroup->m_fsReads++;
  1873. #endif
  1874. return bytesRead;
  1875. }
  1876. char * CFileGroupOpenedFile::FS_fgets( char *dest, int destSize )
  1877. {
  1878. //mParentFileGroup->Lock();
  1879. // char* retVal = NULL;
  1880. // int destLimit = MIN(destSize,((mDirEntry->mLength - mSeekPosIndicator) + 1));//Ensure that we don't read past the end of the file
  1881. // mEof = (destLimit<= 1);
  1882. // //fgets reads characters until (destLimit-1) characters have been read or either a newline or End-of-File is reached, whichever comes first.
  1883. // if (mEof)
  1884. // {
  1885. // //CM:TODO Set error conditions
  1886. // }
  1887. // else
  1888. // {
  1889. // if (mDirEntry->mCompressedLength > 0)
  1890. // {
  1891. // retVal = FgetsFromCompressedData(dest,destLimit);
  1892. // }
  1893. // else
  1894. // {
  1895. // retVal = FgetsFromUncompressedData(dest,destLimit);
  1896. // }
  1897. // }
  1898. // if (retVal)
  1899. // {
  1900. // mActualPosIndicator+=strlen(retVal);
  1901. // mSeekPosIndicator = mActualPosIndicator;
  1902. // //if (!mParentFileGroup->IsCurrentFile(this))
  1903. // //{
  1904. // // mParentFileGroup->MakeCurrentFile(this);
  1905. // //}
  1906. // }
  1907. // //CM:TODO Error handlng, do ferror and feof need to be set?????.
  1908. ////mParentFileGroup->Unlock();
  1909. //mParentFileGroup->m_fgets++;
  1910. Assert(0); //fgets not implemented
  1911. return NULL;
  1912. }
  1913. #endif