FileList.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. #include "FileList.h"
  11. #if _RAKNET_SUPPORT_FileOperations==1
  12. #include <stdio.h> // RAKNET_DEBUG_PRINTF
  13. #include "RakAssert.h"
  14. #if defined(ANDROID)
  15. #include <asm/io.h>
  16. #elif defined(_WIN32) || defined(__CYGWIN__)
  17. #include <io.h>
  18. #elif !defined ( __APPLE__ ) && !defined ( __APPLE_CC__ ) && !defined ( __PPC__ ) && !defined ( __FreeBSD__ ) && !defined ( __S3E__ )
  19. #include <sys/io.h>
  20. #endif
  21. #ifdef _WIN32
  22. // For mkdir
  23. #include <direct.h>
  24. #else
  25. #include <sys/stat.h>
  26. #endif
  27. //#include "DR_SHA1.h"
  28. #include "DS_Queue.h"
  29. #include "StringCompressor.h"
  30. #include "BitStream.h"
  31. #include "FileOperations.h"
  32. #include "SuperFastHash.h"
  33. #include "RakAssert.h"
  34. #include "LinuxStrings.h"
  35. #define MAX_FILENAME_LENGTH 512
  36. static const unsigned HASH_LENGTH=4;
  37. using namespace RakNet;
  38. // alloca
  39. #if defined(_WIN32)
  40. #include <malloc.h>
  41. #else
  42. #if !defined ( __FreeBSD__ )
  43. #include <alloca.h>
  44. #endif
  45. #include <unistd.h>
  46. #include <stdlib.h>
  47. #include <sys/stat.h>
  48. #include "_FindFirst.h"
  49. #include <stdint.h> //defines intptr_t
  50. #endif
  51. #include "RakAlloca.h"
  52. //int RAK_DLL_EXPORT FileListNodeComp( char * const &key, const FileListNode &data )
  53. //{
  54. // return strcmp(key, data.filename);
  55. //}
  56. STATIC_FACTORY_DEFINITIONS(FileListProgress,FileListProgress)
  57. STATIC_FACTORY_DEFINITIONS(FLP_Printf,FLP_Printf)
  58. STATIC_FACTORY_DEFINITIONS(FileList,FileList)
  59. #ifdef _MSC_VER
  60. #pragma warning( push )
  61. #endif
  62. /// First callback called when FileList::AddFilesFromDirectory() starts
  63. void FLP_Printf::OnAddFilesFromDirectoryStarted(FileList *fileList, char *dir) {
  64. (void) fileList;
  65. RAKNET_DEBUG_PRINTF("Adding files from directory %s\n",dir);}
  66. /// Called for each directory, when that directory begins processing
  67. void FLP_Printf::OnDirectory(FileList *fileList, char *dir, unsigned int directoriesRemaining) {
  68. (void) fileList;
  69. RAKNET_DEBUG_PRINTF("Adding %s. %i remaining.\n", dir, directoriesRemaining);}
  70. void FLP_Printf::OnFilePushesComplete( SystemAddress systemAddress, unsigned short setID )
  71. {
  72. (void) setID;
  73. char str[32];
  74. systemAddress.ToString(true, (char*) str);
  75. RAKNET_DEBUG_PRINTF("File pushes complete to %s\n", str);
  76. }
  77. void FLP_Printf::OnSendAborted( SystemAddress systemAddress )
  78. {
  79. char str[32];
  80. systemAddress.ToString(true, (char*) str);
  81. RAKNET_DEBUG_PRINTF("Send aborted to %s\n", str);
  82. }
  83. FileList::FileList()
  84. {
  85. }
  86. FileList::~FileList()
  87. {
  88. Clear();
  89. }
  90. void FileList::AddFile(const char *filepath, const char *filename, FileListNodeContext context)
  91. {
  92. if (filepath==0 || filename==0)
  93. return;
  94. char *data;
  95. //std::fstream file;
  96. //file.open(filename, std::ios::in | std::ios::binary);
  97. FILE *fp = fopen(filepath, "rb");
  98. if (fp==0)
  99. return;
  100. fseek(fp, 0, SEEK_END);
  101. int length = ftell(fp);
  102. fseek(fp, 0, SEEK_SET);
  103. if (length > (int) ((unsigned int)-1 / 8))
  104. {
  105. // If this assert hits, split up your file. You could also change BitSize_t in RakNetTypes.h to unsigned long long but this is not recommended for performance reasons
  106. RakAssert("Cannot add files over 536 MB" && 0);
  107. fclose(fp);
  108. return;
  109. }
  110. #if USE_ALLOCA==1
  111. bool usedAlloca=false;
  112. if (length < MAX_ALLOCA_STACK_ALLOCATION)
  113. {
  114. data = ( char* ) alloca( length );
  115. usedAlloca=true;
  116. }
  117. else
  118. #endif
  119. {
  120. data = (char*) rakMalloc_Ex( length, _FILE_AND_LINE_ );
  121. RakAssert(data);
  122. }
  123. fread(data, 1, length, fp);
  124. AddFile(filename, filepath, data, length, length, context);
  125. fclose(fp);
  126. #if USE_ALLOCA==1
  127. if (usedAlloca==false)
  128. #endif
  129. rakFree_Ex(data, _FILE_AND_LINE_ );
  130. }
  131. void FileList::AddFile(const char *filename, const char *fullPathToFile, const char *data, const unsigned dataLength, const unsigned fileLength, FileListNodeContext context, bool isAReference, bool takeDataPointer)
  132. {
  133. if (filename==0)
  134. return;
  135. if (strlen(filename)>MAX_FILENAME_LENGTH)
  136. {
  137. // Should be enough for anyone
  138. RakAssert(0);
  139. return;
  140. }
  141. // If adding a reference, do not send data
  142. RakAssert(isAReference==false || data==0);
  143. // Avoid duplicate insertions unless the data is different, in which case overwrite the old data
  144. unsigned i;
  145. for (i=0; i<fileList.Size();i++)
  146. {
  147. if (strcmp(fileList[i].filename, filename)==0)
  148. {
  149. if (fileList[i].fileLengthBytes==fileLength && fileList[i].dataLengthBytes==dataLength &&
  150. (dataLength==0 || fileList[i].data==0 ||
  151. memcmp(fileList[i].data, data, dataLength)==0
  152. ))
  153. // Exact same file already here
  154. return;
  155. // File of the same name, but different contents, so overwrite
  156. rakFree_Ex(fileList[i].data, _FILE_AND_LINE_ );
  157. fileList.RemoveAtIndex(i);
  158. break;
  159. }
  160. }
  161. FileListNode n;
  162. // size_t fileNameLen = strlen(filename);
  163. if (dataLength && data)
  164. {
  165. if (takeDataPointer)
  166. {
  167. n.data=(char*) data;
  168. }
  169. else
  170. {
  171. n.data=(char*) rakMalloc_Ex( dataLength, _FILE_AND_LINE_ );
  172. RakAssert(n.data);
  173. memcpy(n.data, data, dataLength);
  174. }
  175. }
  176. else
  177. n.data=0;
  178. n.dataLengthBytes=dataLength;
  179. n.fileLengthBytes=fileLength;
  180. n.isAReference=isAReference;
  181. n.context=context;
  182. if (n.context.dataPtr==0)
  183. n.context.dataPtr=n.data;
  184. if (n.context.dataLength==0)
  185. n.context.dataLength=dataLength;
  186. n.filename=filename;
  187. n.fullPathToFile=fullPathToFile;
  188. fileList.Insert(n, _FILE_AND_LINE_);
  189. }
  190. void FileList::AddFilesFromDirectory(const char *applicationDirectory, const char *subDirectory, bool writeHash, bool writeData, bool recursive, FileListNodeContext context)
  191. {
  192. DataStructures::Queue<char*> dirList;
  193. char root[260];
  194. char fullPath[520];
  195. _finddata_t fileInfo;
  196. intptr_t dir;
  197. FILE *fp;
  198. char *dirSoFar, *fileData;
  199. dirSoFar=(char*) rakMalloc_Ex( 520, _FILE_AND_LINE_ );
  200. RakAssert(dirSoFar);
  201. if (applicationDirectory)
  202. strcpy(root, applicationDirectory);
  203. else
  204. root[0]=0;
  205. int rootLen=(int)strlen(root);
  206. if (rootLen)
  207. {
  208. strcpy(dirSoFar, root);
  209. if (FixEndingSlash(dirSoFar))
  210. rootLen++;
  211. }
  212. else
  213. dirSoFar[0]=0;
  214. if (subDirectory)
  215. {
  216. strcat(dirSoFar, subDirectory);
  217. FixEndingSlash(dirSoFar);
  218. }
  219. for (unsigned int flpcIndex=0; flpcIndex < fileListProgressCallbacks.Size(); flpcIndex++)
  220. fileListProgressCallbacks[flpcIndex]->OnAddFilesFromDirectoryStarted(this, dirSoFar);
  221. // RAKNET_DEBUG_PRINTF("Adding files from directory %s\n",dirSoFar);
  222. dirList.Push(dirSoFar, _FILE_AND_LINE_ );
  223. while (dirList.Size())
  224. {
  225. dirSoFar=dirList.Pop();
  226. strcpy(fullPath, dirSoFar);
  227. // Changed from *.* to * for Linux compatibility
  228. strcat(fullPath, "*");
  229. dir=_findfirst(fullPath, &fileInfo );
  230. if (dir==-1)
  231. {
  232. _findclose(dir);
  233. rakFree_Ex(dirSoFar, _FILE_AND_LINE_ );
  234. unsigned i;
  235. for (i=0; i < dirList.Size(); i++)
  236. rakFree_Ex(dirList[i], _FILE_AND_LINE_ );
  237. return;
  238. }
  239. // RAKNET_DEBUG_PRINTF("Adding %s. %i remaining.\n", fullPath, dirList.Size());
  240. for (unsigned int flpcIndex=0; flpcIndex < fileListProgressCallbacks.Size(); flpcIndex++)
  241. fileListProgressCallbacks[flpcIndex]->OnDirectory(this, fullPath, dirList.Size());
  242. do
  243. {
  244. // no guarantee these entries are first...
  245. if (strcmp("." , fileInfo.name) == 0 ||
  246. strcmp("..", fileInfo.name) == 0)
  247. {
  248. continue;
  249. }
  250. if ((fileInfo.attrib & (_A_HIDDEN | _A_SUBDIR | _A_SYSTEM))==0)
  251. {
  252. strcpy(fullPath, dirSoFar);
  253. strcat(fullPath, fileInfo.name);
  254. fileData=0;
  255. for (unsigned int flpcIndex=0; flpcIndex < fileListProgressCallbacks.Size(); flpcIndex++)
  256. fileListProgressCallbacks[flpcIndex]->OnFile(this, dirSoFar, fileInfo.name, fileInfo.size);
  257. if (writeData && writeHash)
  258. {
  259. fp = fopen(fullPath, "rb");
  260. if (fp)
  261. {
  262. fileData= (char*) rakMalloc_Ex( fileInfo.size+HASH_LENGTH, _FILE_AND_LINE_ );
  263. RakAssert(fileData);
  264. fread(fileData+HASH_LENGTH, fileInfo.size, 1, fp);
  265. fclose(fp);
  266. unsigned int hash = SuperFastHash(fileData+HASH_LENGTH, fileInfo.size);
  267. if (RakNet::BitStream::DoEndianSwap())
  268. RakNet::BitStream::ReverseBytesInPlace((unsigned char*) &hash, sizeof(hash));
  269. memcpy(fileData, &hash, HASH_LENGTH);
  270. // sha1.Reset();
  271. // sha1.Update( ( unsigned char* ) fileData+HASH_LENGTH, fileInfo.size );
  272. // sha1.Final();
  273. // memcpy(fileData, sha1.GetHash(), HASH_LENGTH);
  274. // File data and hash
  275. AddFile((const char*)fullPath+rootLen, fullPath, fileData, fileInfo.size+HASH_LENGTH, fileInfo.size, context);
  276. }
  277. }
  278. else if (writeHash)
  279. {
  280. // sha1.Reset();
  281. // DR_SHA1.hashFile((char*)fullPath);
  282. // sha1.Final();
  283. unsigned int hash = SuperFastHashFile(fullPath);
  284. if (RakNet::BitStream::DoEndianSwap())
  285. RakNet::BitStream::ReverseBytesInPlace((unsigned char*) &hash, sizeof(hash));
  286. // Hash only
  287. // AddFile((const char*)fullPath+rootLen, (const char*)sha1.GetHash(), HASH_LENGTH, fileInfo.size, context);
  288. AddFile((const char*)fullPath+rootLen, fullPath, (const char*)&hash, HASH_LENGTH, fileInfo.size, context);
  289. }
  290. else if (writeData)
  291. {
  292. fileData= (char*) rakMalloc_Ex( fileInfo.size, _FILE_AND_LINE_ );
  293. RakAssert(fileData);
  294. fp = fopen(fullPath, "rb");
  295. fread(fileData, fileInfo.size, 1, fp);
  296. fclose(fp);
  297. // File data only
  298. AddFile(fullPath+rootLen, fullPath, fileData, fileInfo.size, fileInfo.size, context);
  299. }
  300. else
  301. {
  302. // Just the filename
  303. AddFile(fullPath+rootLen, fullPath, 0, 0, fileInfo.size, context);
  304. }
  305. if (fileData)
  306. rakFree_Ex(fileData, _FILE_AND_LINE_ );
  307. }
  308. else if ((fileInfo.attrib & _A_SUBDIR) && (fileInfo.attrib & (_A_HIDDEN | _A_SYSTEM))==0 && recursive)
  309. {
  310. char *newDir=(char*) rakMalloc_Ex( 520, _FILE_AND_LINE_ );
  311. RakAssert(newDir);
  312. strcpy(newDir, dirSoFar);
  313. strcat(newDir, fileInfo.name);
  314. strcat(newDir, "/");
  315. dirList.Push(newDir, _FILE_AND_LINE_ );
  316. }
  317. } while (_findnext(dir, &fileInfo ) != -1);
  318. _findclose(dir);
  319. rakFree_Ex(dirSoFar, _FILE_AND_LINE_ );
  320. }
  321. }
  322. void FileList::Clear(void)
  323. {
  324. unsigned i;
  325. for (i=0; i<fileList.Size(); i++)
  326. {
  327. rakFree_Ex(fileList[i].data, _FILE_AND_LINE_ );
  328. }
  329. fileList.Clear(false, _FILE_AND_LINE_);
  330. }
  331. void FileList::Serialize(RakNet::BitStream *outBitStream)
  332. {
  333. outBitStream->WriteCompressed(fileList.Size());
  334. unsigned i;
  335. for (i=0; i < fileList.Size(); i++)
  336. {
  337. outBitStream->WriteCompressed(fileList[i].context.op);
  338. outBitStream->WriteCompressed(fileList[i].context.flnc_extraData1);
  339. outBitStream->WriteCompressed(fileList[i].context.flnc_extraData2);
  340. StringCompressor::Instance()->EncodeString(fileList[i].filename.C_String(), MAX_FILENAME_LENGTH, outBitStream);
  341. bool writeFileData = (fileList[i].dataLengthBytes>0)==true;
  342. outBitStream->Write(writeFileData);
  343. if (writeFileData)
  344. {
  345. outBitStream->WriteCompressed(fileList[i].dataLengthBytes);
  346. outBitStream->Write(fileList[i].data, fileList[i].dataLengthBytes);
  347. }
  348. outBitStream->Write((bool)(fileList[i].fileLengthBytes==fileList[i].dataLengthBytes));
  349. if (fileList[i].fileLengthBytes!=fileList[i].dataLengthBytes)
  350. outBitStream->WriteCompressed(fileList[i].fileLengthBytes);
  351. }
  352. }
  353. bool FileList::Deserialize(RakNet::BitStream *inBitStream)
  354. {
  355. bool b, dataLenNonZero=false, fileLenMatchesDataLen=false;
  356. char filename[512];
  357. uint32_t fileListSize;
  358. FileListNode n;
  359. b=inBitStream->ReadCompressed(fileListSize);
  360. #ifdef _DEBUG
  361. RakAssert(b);
  362. RakAssert(fileListSize < 10000);
  363. #endif
  364. if (b==false || fileListSize > 10000)
  365. return false; // Sanity check
  366. Clear();
  367. unsigned i;
  368. for (i=0; i < fileListSize; i++)
  369. {
  370. inBitStream->ReadCompressed(n.context.op);
  371. inBitStream->ReadCompressed(n.context.flnc_extraData1);
  372. inBitStream->ReadCompressed(n.context.flnc_extraData2);
  373. StringCompressor::Instance()->DecodeString((char*)filename, MAX_FILENAME_LENGTH, inBitStream);
  374. inBitStream->Read(dataLenNonZero);
  375. if (dataLenNonZero)
  376. {
  377. inBitStream->ReadCompressed(n.dataLengthBytes);
  378. // sanity check
  379. if (n.dataLengthBytes>2000000000)
  380. {
  381. #ifdef _DEBUG
  382. RakAssert(n.dataLengthBytes<=2000000000);
  383. #endif
  384. return false;
  385. }
  386. n.data=(char*) rakMalloc_Ex( (size_t) n.dataLengthBytes, _FILE_AND_LINE_ );
  387. RakAssert(n.data);
  388. inBitStream->Read(n.data, n.dataLengthBytes);
  389. }
  390. else
  391. {
  392. n.dataLengthBytes=0;
  393. n.data=0;
  394. }
  395. b=inBitStream->Read(fileLenMatchesDataLen);
  396. if (fileLenMatchesDataLen)
  397. n.fileLengthBytes=(unsigned) n.dataLengthBytes;
  398. else
  399. b=inBitStream->ReadCompressed(n.fileLengthBytes);
  400. #ifdef _DEBUG
  401. RakAssert(b);
  402. #endif
  403. if (b==0)
  404. {
  405. Clear();
  406. return false;
  407. }
  408. n.filename=filename;
  409. n.fullPathToFile=filename;
  410. fileList.Insert(n, _FILE_AND_LINE_);
  411. }
  412. return true;
  413. }
  414. void FileList::GetDeltaToCurrent(FileList *input, FileList *output, const char *dirSubset, const char *remoteSubdir)
  415. {
  416. // For all files in this list that do not match the input list, write them to the output list.
  417. // dirSubset allows checking only a portion of the files in this list.
  418. unsigned thisIndex, inputIndex;
  419. unsigned dirSubsetLen, localPathLen, remoteSubdirLen;
  420. bool match;
  421. if (dirSubset)
  422. dirSubsetLen = (unsigned int) strlen(dirSubset);
  423. else
  424. dirSubsetLen = 0;
  425. if (remoteSubdir && remoteSubdir[0])
  426. {
  427. remoteSubdirLen=(unsigned int) strlen(remoteSubdir);
  428. if (IsSlash(remoteSubdir[remoteSubdirLen-1]))
  429. remoteSubdirLen--;
  430. }
  431. else
  432. remoteSubdirLen=0;
  433. for (thisIndex=0; thisIndex < fileList.Size(); thisIndex++)
  434. {
  435. localPathLen = (unsigned int) fileList[thisIndex].filename.GetLength();
  436. while (localPathLen>0)
  437. {
  438. if (IsSlash(fileList[thisIndex].filename[localPathLen-1]))
  439. {
  440. localPathLen--;
  441. break;
  442. }
  443. localPathLen--;
  444. }
  445. // fileList[thisIndex].filename has to match dirSubset and be shorter or equal to it in length.
  446. if (dirSubsetLen>0 &&
  447. (localPathLen<dirSubsetLen ||
  448. _strnicmp(fileList[thisIndex].filename.C_String(), dirSubset, dirSubsetLen)!=0 ||
  449. (localPathLen>dirSubsetLen && IsSlash(fileList[thisIndex].filename[dirSubsetLen])==false)))
  450. continue;
  451. match=false;
  452. for (inputIndex=0; inputIndex < input->fileList.Size(); inputIndex++)
  453. {
  454. // If the filenames, hashes, and lengths match then skip this element in fileList. Otherwise write it to output
  455. if (_stricmp(input->fileList[inputIndex].filename.C_String()+remoteSubdirLen,fileList[thisIndex].filename.C_String()+dirSubsetLen)==0)
  456. {
  457. match=true;
  458. if (input->fileList[inputIndex].fileLengthBytes==fileList[thisIndex].fileLengthBytes &&
  459. input->fileList[inputIndex].dataLengthBytes==fileList[thisIndex].dataLengthBytes &&
  460. memcmp(input->fileList[inputIndex].data,fileList[thisIndex].data,(size_t) fileList[thisIndex].dataLengthBytes)==0)
  461. {
  462. // File exists on both machines and is the same.
  463. break;
  464. }
  465. else
  466. {
  467. // File exists on both machines and is not the same.
  468. output->AddFile(fileList[thisIndex].filename, fileList[thisIndex].fullPathToFile, 0,0, fileList[thisIndex].fileLengthBytes, FileListNodeContext(0,0,0,0), false);
  469. break;
  470. }
  471. }
  472. }
  473. if (match==false)
  474. {
  475. // Other system does not have the file at all
  476. output->AddFile(fileList[thisIndex].filename, fileList[thisIndex].fullPathToFile, 0,0, fileList[thisIndex].fileLengthBytes, FileListNodeContext(0,0,0,0), false);
  477. }
  478. }
  479. }
  480. void FileList::ListMissingOrChangedFiles(const char *applicationDirectory, FileList *missingOrChangedFiles, bool alwaysWriteHash, bool neverWriteHash)
  481. {
  482. unsigned fileLength;
  483. // CSHA1 sha1;
  484. FILE *fp;
  485. char fullPath[512];
  486. unsigned i;
  487. // char *fileData;
  488. for (i=0; i < fileList.Size(); i++)
  489. {
  490. strcpy(fullPath, applicationDirectory);
  491. FixEndingSlash(fullPath);
  492. strcat(fullPath,fileList[i].filename);
  493. fp=fopen(fullPath, "rb");
  494. if (fp==0)
  495. {
  496. missingOrChangedFiles->AddFile(fileList[i].filename, fileList[i].fullPathToFile, 0, 0, 0, FileListNodeContext(0,0,0,0), false);
  497. }
  498. else
  499. {
  500. fseek(fp, 0, SEEK_END);
  501. fileLength = ftell(fp);
  502. fseek(fp, 0, SEEK_SET);
  503. if (fileLength != fileList[i].fileLengthBytes && alwaysWriteHash==false)
  504. {
  505. missingOrChangedFiles->AddFile(fileList[i].filename, fileList[i].fullPathToFile, 0, 0, fileLength, FileListNodeContext(0,0,0,0), false);
  506. }
  507. else
  508. {
  509. // fileData= (char*) rakMalloc_Ex( fileLength, _FILE_AND_LINE_ );
  510. // fread(fileData, fileLength, 1, fp);
  511. // sha1.Reset();
  512. // sha1.Update( ( unsigned char* ) fileData, fileLength );
  513. // sha1.Final();
  514. // rakFree_Ex(fileData, _FILE_AND_LINE_ );
  515. unsigned int hash = SuperFastHashFilePtr(fp);
  516. if (RakNet::BitStream::DoEndianSwap())
  517. RakNet::BitStream::ReverseBytesInPlace((unsigned char*) &hash, sizeof(hash));
  518. //if (fileLength != fileList[i].fileLength || memcmp( sha1.GetHash(), fileList[i].data, HASH_LENGTH)!=0)
  519. if (fileLength != fileList[i].fileLengthBytes || memcmp( &hash, fileList[i].data, HASH_LENGTH)!=0)
  520. {
  521. if (neverWriteHash==false)
  522. // missingOrChangedFiles->AddFile((const char*)fileList[i].filename, (const char*)sha1.GetHash(), HASH_LENGTH, fileLength, 0);
  523. missingOrChangedFiles->AddFile((const char*)fileList[i].filename, (const char*)fileList[i].fullPathToFile, (const char *) &hash, HASH_LENGTH, fileLength, FileListNodeContext(0,0,0,0), false);
  524. else
  525. missingOrChangedFiles->AddFile((const char*)fileList[i].filename, (const char*)fileList[i].fullPathToFile, 0, 0, fileLength, FileListNodeContext(0,0,0,0), false);
  526. }
  527. }
  528. fclose(fp);
  529. }
  530. }
  531. }
  532. void FileList::PopulateDataFromDisk(const char *applicationDirectory, bool writeFileData, bool writeFileHash, bool removeUnknownFiles)
  533. {
  534. FILE *fp;
  535. char fullPath[512];
  536. unsigned i;
  537. // CSHA1 sha1;
  538. i=0;
  539. while (i < fileList.Size())
  540. {
  541. rakFree_Ex(fileList[i].data, _FILE_AND_LINE_ );
  542. strcpy(fullPath, applicationDirectory);
  543. FixEndingSlash(fullPath);
  544. strcat(fullPath,fileList[i].filename.C_String());
  545. fp=fopen(fullPath, "rb");
  546. if (fp)
  547. {
  548. if (writeFileHash || writeFileData)
  549. {
  550. fseek(fp, 0, SEEK_END);
  551. fileList[i].fileLengthBytes = ftell(fp);
  552. fseek(fp, 0, SEEK_SET);
  553. if (writeFileHash)
  554. {
  555. if (writeFileData)
  556. {
  557. // Hash + data so offset the data by HASH_LENGTH
  558. fileList[i].data=(char*) rakMalloc_Ex( fileList[i].fileLengthBytes+HASH_LENGTH, _FILE_AND_LINE_ );
  559. RakAssert(fileList[i].data);
  560. fread(fileList[i].data+HASH_LENGTH, fileList[i].fileLengthBytes, 1, fp);
  561. // sha1.Reset();
  562. // sha1.Update((unsigned char*)fileList[i].data+HASH_LENGTH, fileList[i].fileLength);
  563. // sha1.Final();
  564. unsigned int hash = SuperFastHash(fileList[i].data+HASH_LENGTH, fileList[i].fileLengthBytes);
  565. if (RakNet::BitStream::DoEndianSwap())
  566. RakNet::BitStream::ReverseBytesInPlace((unsigned char*) &hash, sizeof(hash));
  567. // memcpy(fileList[i].data, sha1.GetHash(), HASH_LENGTH);
  568. memcpy(fileList[i].data, &hash, HASH_LENGTH);
  569. }
  570. else
  571. {
  572. // Hash only
  573. fileList[i].dataLengthBytes=HASH_LENGTH;
  574. if (fileList[i].fileLengthBytes < HASH_LENGTH)
  575. fileList[i].data=(char*) rakMalloc_Ex( HASH_LENGTH, _FILE_AND_LINE_ );
  576. else
  577. fileList[i].data=(char*) rakMalloc_Ex( fileList[i].fileLengthBytes, _FILE_AND_LINE_ );
  578. RakAssert(fileList[i].data);
  579. fread(fileList[i].data, fileList[i].fileLengthBytes, 1, fp);
  580. // sha1.Reset();
  581. // sha1.Update((unsigned char*)fileList[i].data, fileList[i].fileLength);
  582. // sha1.Final();
  583. unsigned int hash = SuperFastHash(fileList[i].data, fileList[i].fileLengthBytes);
  584. if (RakNet::BitStream::DoEndianSwap())
  585. RakNet::BitStream::ReverseBytesInPlace((unsigned char*) &hash, sizeof(hash));
  586. // memcpy(fileList[i].data, sha1.GetHash(), HASH_LENGTH);
  587. memcpy(fileList[i].data, &hash, HASH_LENGTH);
  588. }
  589. }
  590. else
  591. {
  592. // Data only
  593. fileList[i].dataLengthBytes=fileList[i].fileLengthBytes;
  594. fileList[i].data=(char*) rakMalloc_Ex( fileList[i].fileLengthBytes, _FILE_AND_LINE_ );
  595. RakAssert(fileList[i].data);
  596. fread(fileList[i].data, fileList[i].fileLengthBytes, 1, fp);
  597. }
  598. fclose(fp);
  599. i++;
  600. }
  601. else
  602. {
  603. fileList[i].data=0;
  604. fileList[i].dataLengthBytes=0;
  605. }
  606. }
  607. else
  608. {
  609. if (removeUnknownFiles)
  610. {
  611. fileList.RemoveAtIndex(i);
  612. }
  613. else
  614. i++;
  615. }
  616. }
  617. }
  618. void FileList::FlagFilesAsReferences(void)
  619. {
  620. for (unsigned int i=0; i < fileList.Size(); i++)
  621. {
  622. fileList[i].isAReference=true;
  623. fileList[i].dataLengthBytes=fileList[i].fileLengthBytes;
  624. }
  625. }
  626. void FileList::WriteDataToDisk(const char *applicationDirectory)
  627. {
  628. char fullPath[512];
  629. unsigned i,j;
  630. for (i=0; i < fileList.Size(); i++)
  631. {
  632. strcpy(fullPath, applicationDirectory);
  633. FixEndingSlash(fullPath);
  634. strcat(fullPath,fileList[i].filename.C_String());
  635. // Security - Don't allow .. in the filename anywhere so you can't write outside of the root directory
  636. for (j=1; j < fileList[i].filename.GetLength(); j++)
  637. {
  638. if (fileList[i].filename[j]=='.' && fileList[i].filename[j-1]=='.')
  639. {
  640. #ifdef _DEBUG
  641. RakAssert(0);
  642. #endif
  643. // Just cancel the write entirely
  644. return;
  645. }
  646. }
  647. WriteFileWithDirectories(fullPath, fileList[i].data, (unsigned int) fileList[i].dataLengthBytes);
  648. }
  649. }
  650. #ifdef _MSC_VER
  651. #pragma warning( disable : 4996 ) // unlink declared deprecated by Microsoft in order to make it harder to be cross platform. I don't agree it's deprecated.
  652. #endif
  653. void FileList::DeleteFiles(const char *applicationDirectory)
  654. {
  655. char fullPath[512];
  656. unsigned i,j;
  657. for (i=0; i < fileList.Size(); i++)
  658. {
  659. // The filename should not have .. in the path - if it does ignore it
  660. for (j=1; j < fileList[i].filename.GetLength(); j++)
  661. {
  662. if (fileList[i].filename[j]=='.' && fileList[i].filename[j-1]=='.')
  663. {
  664. #ifdef _DEBUG
  665. RakAssert(0);
  666. #endif
  667. // Just cancel the deletion entirely
  668. return;
  669. }
  670. }
  671. strcpy(fullPath, applicationDirectory);
  672. FixEndingSlash(fullPath);
  673. strcat(fullPath, fileList[i].filename.C_String());
  674. // Do not rename to _unlink as linux uses unlink
  675. #if defined(WINDOWS_PHONE_8) || defined(WINDOWS_STORE_RT)
  676. int result = _unlink(fullPath);
  677. #else
  678. int result = unlink(fullPath);
  679. #endif
  680. if (result!=0)
  681. {
  682. RAKNET_DEBUG_PRINTF("FileList::DeleteFiles: unlink (%s) failed.\n", fullPath);
  683. }
  684. }
  685. }
  686. void FileList::AddCallback(FileListProgress *cb)
  687. {
  688. if (cb==0)
  689. return;
  690. if ((unsigned int) fileListProgressCallbacks.GetIndexOf(cb)==(unsigned int)-1)
  691. fileListProgressCallbacks.Push(cb, _FILE_AND_LINE_);
  692. }
  693. void FileList::RemoveCallback(FileListProgress *cb)
  694. {
  695. unsigned int idx = fileListProgressCallbacks.GetIndexOf(cb);
  696. if (idx!=(unsigned int) -1)
  697. fileListProgressCallbacks.RemoveAtIndex(idx);
  698. }
  699. void FileList::ClearCallbacks(void)
  700. {
  701. fileListProgressCallbacks.Clear(true, _FILE_AND_LINE_);
  702. }
  703. void FileList::GetCallbacks(DataStructures::List<FileListProgress*> &callbacks)
  704. {
  705. callbacks = fileListProgressCallbacks;
  706. }
  707. bool FileList::FixEndingSlash(char *str)
  708. {
  709. #ifdef _WIN32
  710. if (str[strlen(str)-1]!='/' && str[strlen(str)-1]!='\\')
  711. {
  712. strcat(str, "\\"); // Only \ works with system commands, used by AutopatcherClient
  713. return true;
  714. }
  715. #else
  716. if (str[strlen(str)-1]!='\\' && str[strlen(str)-1]!='/')
  717. {
  718. strcat(str, "/"); // Only / works with Linux
  719. return true;
  720. }
  721. #endif
  722. return false;
  723. }
  724. #ifdef _MSC_VER
  725. #pragma warning( pop )
  726. #endif
  727. #endif // _RAKNET_SUPPORT_FileOperations
粤ICP备19079148号