FileSimpleComp.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. #ifndef _TWINKLE_CICOMPONENT_INTERFACE_H__
  2. #define _TWINKLE_CICOMPONENT_INTERFACE_H__
  3. #pragma once
  4. #if defined(_MSC_VER)
  5. #include <Windows.h>
  6. #else
  7. #include <winpr/wtypes.h>
  8. #ifndef FILE_ATTRIBUTE_READONLY
  9. #define FILE_ATTRIBUTE_READONLY 0x00000001
  10. #define FILE_ATTRIBUTE_HIDDEN 0x00000002
  11. #define FILE_ATTRIBUTE_SYSTEM 0x00000004
  12. #define FILE_ATTRIBUTE_DIRECTORY 0x00000010
  13. #define FILE_ATTRIBUTE_ARCHIVE 0x00000020
  14. #define FILE_ATTRIBUTE_DEVICE 0x00000040
  15. #define FILE_ATTRIBUTE_NORMAL 0x00000080
  16. #define FILE_ATTRIBUTE_TEMPORARY 0x00000100
  17. #define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
  18. #define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
  19. #define FILE_ATTRIBUTE_COMPRESSED 0x00000800
  20. #define FILE_ATTRIBUTE_OFFLINE 0x00001000
  21. #define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
  22. #define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
  23. #define FILE_ATTRIBUTE_VIRTUAL 0x00010000
  24. #endif
  25. #endif //_MSC_VER
  26. #include <vector>
  27. #include <map>
  28. #include <string>
  29. #include <algorithm>
  30. #include "AutoArray.h"
  31. #include "fileutil.h"
  32. using namespace std;
  33. enum FileType
  34. {
  35. FT_Unknown,
  36. FT_Root,
  37. FT_Volume,
  38. FT_Directory,
  39. FT_File
  40. };
  41. class CSimpleFileComponent
  42. {
  43. public:
  44. CSimpleFileComponent()
  45. :mftCreate(0)
  46. ,mftModified(0)
  47. ,mftAccess(0)
  48. ,mAttributes(0)
  49. ,mFileSize(0)
  50. ,mLevel(-1)
  51. ,mNameOffset(0)
  52. ,mNameLength(0)
  53. {
  54. }
  55. //For CFileShell, the inherent class must re-implement the function.
  56. //as is: return new CInherentClass(*this);
  57. virtual CSimpleFileComponent* Clone() const
  58. {
  59. return new CSimpleFileComponent(*this);
  60. }
  61. virtual void Clear()
  62. {
  63. mftCreate = mftAccess = mftModified = 0;
  64. mAttributes = 0;
  65. mLevel = -1;
  66. mNameLength = 0;
  67. mNameOffset = 0;
  68. }
  69. virtual FileType GetFileType() const
  70. {
  71. if(mAttributes != 0)
  72. {
  73. if(mAttributes & FILE_ATTRIBUTE_DIRECTORY)
  74. return FT_Directory;
  75. return FT_File;
  76. }
  77. if(mLevel == 0)
  78. return FT_Volume;
  79. else if(mLevel == -2)
  80. return FT_Root;
  81. return FT_Unknown;
  82. }
  83. public:
  84. ULONGLONG mftCreate;
  85. ULONGLONG mftModified;
  86. ULONGLONG mftAccess;
  87. ULONGLONG mFileSize;
  88. DWORD mAttributes;
  89. int mLevel; //file's hierarchy display in volume.
  90. DWORD mNameOffset;
  91. DWORD mNameLength;
  92. };
  93. //Use Handle Class for the CFileComponent hierarchy
  94. class CSimpleFileShell
  95. {
  96. public:
  97. CSimpleFileShell()
  98. :_pointer(0)
  99. , _count(new size_t(1))
  100. {}
  101. CSimpleFileShell(const CSimpleFileShell& rhs)
  102. :_pointer(rhs._pointer)
  103. , _count(rhs._count)
  104. {
  105. ++*_count;
  106. }
  107. CSimpleFileShell(const CSimpleFileComponent& rhs)
  108. :_pointer(rhs.Clone())
  109. , _count(new size_t(1))
  110. {}
  111. ~CSimpleFileShell()
  112. {
  113. removeRef();
  114. }
  115. CSimpleFileShell& operator=(const CSimpleFileShell& rhs)
  116. {
  117. ++*rhs._count;
  118. removeRef();
  119. _pointer = rhs._pointer;
  120. _count = rhs._count;
  121. return *this;
  122. }
  123. operator CSimpleFileComponent* () const {
  124. if (_pointer) return _pointer;
  125. else return NULL; //throw logic_error("unbound CFileComponent !");
  126. }
  127. CSimpleFileComponent* operator->() {
  128. if (_pointer) return _pointer;
  129. else throw logic_error("unbound CFileComponent !");
  130. }
  131. const CSimpleFileComponent* operator->() const {
  132. if (_pointer) return _pointer;
  133. else throw logic_error("unbound CFileComponent !");
  134. }
  135. const CSimpleFileComponent& operator*() const {
  136. if (_pointer) return *_pointer;
  137. else throw logic_error("unbound CFileComponent !");
  138. }
  139. CSimpleFileComponent& operator*() {
  140. if (_pointer) return *_pointer;
  141. else throw logic_error("unbound CFileComponent !");
  142. }
  143. private:
  144. CSimpleFileComponent* _pointer;
  145. size_t* _count;
  146. void removeRef()
  147. {
  148. if (--*_count == 0)
  149. {
  150. delete _pointer;
  151. delete _count;
  152. }
  153. }
  154. };
  155. typedef CAutoArray<CSimpleFileComponent> CAutoFiles;
  156. typedef struct FILE_LAYOUT_ENTRY {
  157. //Always Volume or Directory informaiton
  158. CSimpleFileComponent Current;
  159. //Sub directory or file informaion
  160. CAutoFiles SubFiles;
  161. //Contain file name stream
  162. CAutoBuffer FileNamesBuffer;
  163. } FILE_LAYOUT_ENTRY, *PFILE_LAYOUT_ENTRY;
  164. //Premise: Should be initialize entry->current first.
  165. static ULONGLONG GetSubFileInfors(PFILE_LAYOUT_ENTRY Entry, DWORD& dwDirCount, DWORD& dwFileCount, const DWORD dwFilterMask = 0);
  166. static unsigned long long GetDirectorySize(LPCTSTR dirPath, int nDepth = -1024);
  167. inline static DWORD GetDirectoryItemCount(LPCTSTR dirPath, int nDepth = -1024);
  168. static void DisplayFileEntities(const PFILE_LAYOUT_ENTRY Entry);
  169. DWORD GetDirectoryItemCount(LPCTSTR dirPath, int nDepth)
  170. {
  171. #if defined(RVC_OS_LINUX)
  172. DIR* d;
  173. struct dirent* entry;
  174. struct stat statbuf;
  175. DWORD result = 0;
  176. if ((d = opendir(dirPath)) == NULL) {
  177. Dbg("opendir %s failed: %s", dirPath, strerror(errno));
  178. return 0;
  179. }
  180. struct dirent* dp = NULL;
  181. while ((dp = readdir(d)) != NULL) {
  182. if ((!strcmp(dp->d_name, ".")) || (!strcmp(dp->d_name, ".."))) {
  183. continue;
  184. }
  185. result++;
  186. continue;
  187. char tempFilePath[MAX_PATH * 2] = { 0 };
  188. strcpy(tempFilePath, dirPath);
  189. if (strlen(tempFilePath) + strlen(dp->d_name) + 3 >= MAX_PATH * 2) {
  190. Dbg("filePath is too long for current.");
  191. continue;
  192. }
  193. strcat(tempFilePath, "/");
  194. strcat(tempFilePath, dp->d_name);
  195. struct stat fileStat;
  196. if (stat(tempFilePath, &fileStat) < 0) {
  197. Dbg("stat dir for %s failed: %d ", tempFilePath, errno);
  198. continue;
  199. }
  200. if (S_ISDIR(fileStat.st_mode)) {
  201. if (nDepth + 1 >= 0) {
  202. Dbg("exceed the deepest dir, do not recursive at all: %s", tempFilePath);
  203. } else {
  204. result += GetDirectoryItemCount(tempFilePath, nDepth + 1);
  205. }
  206. }
  207. }
  208. closedir(d);
  209. return result;
  210. #else
  211. return 0;
  212. #endif //RVC_OS_LINUX
  213. }
  214. unsigned long long GetDirectorySize(LPCTSTR dirPath, int nDepth)
  215. {
  216. #if defined(RVC_OS_LINUX)
  217. DIR * d;
  218. struct dirent* entry;
  219. struct stat statbuf;
  220. unsigned long long result = 0;
  221. if ((d = opendir(dirPath)) == NULL) {
  222. Dbg("opendir %s failed: %s", dirPath, strerror(errno));
  223. return 0;
  224. }
  225. lstat(dirPath, &statbuf);
  226. result += statbuf.st_size;
  227. struct dirent* dp = NULL;
  228. while ((dp = readdir(d)) != NULL) {
  229. if ((!strcmp(dp->d_name, ".")) || (!strcmp(dp->d_name, ".."))) {
  230. continue;
  231. }
  232. char tempFilePath[MAX_PATH * 2] = { 0 };
  233. strcpy(tempFilePath, dirPath);
  234. if (strlen(tempFilePath) + strlen(dp->d_name) + 3 >= MAX_PATH * 2) {
  235. Dbg("filePath is too long for current.");
  236. continue;
  237. }
  238. strcat(tempFilePath, "/");
  239. strcat(tempFilePath, dp->d_name);
  240. struct stat fileStat;
  241. if (stat(tempFilePath, &fileStat) < 0) {
  242. Dbg("stat dir for %s failed: %d ", tempFilePath, errno);
  243. continue;
  244. }
  245. if (S_ISDIR(fileStat.st_mode)) {
  246. if (nDepth + 1 >= 0) {
  247. Dbg("exceed the deepest dir, do not recursive at all: %s", tempFilePath);
  248. } else {
  249. result += GetDirectorySize(tempFilePath, nDepth + 1);
  250. }
  251. } else {
  252. result += fileStat.st_size;
  253. }
  254. }
  255. closedir(d);
  256. return result;
  257. #else
  258. return 0;
  259. #endif //RVC_OS_LINUX
  260. }
  261. static UINT GetErrorMessage(CSimpleStringA& retMessage, LPCTSTR lpDefault, DWORD error = GetLastError())
  262. {
  263. #if defined(_MSC_VER)
  264. if (error == 0) {
  265. retMessage = lpDefault;
  266. return strlen(lpDefault);
  267. }
  268. LPVOID lpMsgBuf;
  269. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  270. | FORMAT_MESSAGE_FROM_SYSTEM
  271. | FORMAT_MESSAGE_IGNORE_INSERTS,
  272. NULL,
  273. error,
  274. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  275. (LPTSTR)&lpMsgBuf,
  276. 0,
  277. NULL);
  278. if (lpMsgBuf == NULL) {
  279. retMessage = lpDefault;
  280. return strlen(lpDefault);
  281. }
  282. retMessage = (LPCTSTR)lpMsgBuf;
  283. LocalFree((LPVOID)lpMsgBuf);
  284. return retMessage.GetLength();
  285. #else
  286. retMessage = lpDefault;
  287. return strlen(lpDefault);
  288. #endif //_MSC_VER
  289. }
  290. #if defined(_MSC_VER)
  291. static void GetTimeFormatStr(LPTSTR lpszString, DWORD dwSize, FILETIME* ftWrite)
  292. {
  293. SYSTEMTIME stUTC, stLocal;
  294. // Convert the last-write time to local time.
  295. FileTimeToSystemTime(ftWrite, &stUTC);
  296. SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
  297. // Build a string showing the date and time.
  298. sprintf_s(lpszString, dwSize, "%02d/%02d/%d %02d:%02d:%02d",
  299. stLocal.wMonth, stLocal.wDay, stLocal.wYear,
  300. stLocal.wHour, stLocal.wMinute, stLocal.wSecond);
  301. return;
  302. }
  303. #else
  304. static void GetTimeFormatStr(LPTSTR lpszString, DWORD dwSize, const time_t* ftWrite)
  305. {
  306. tm* curTime = localtime(ftWrite);
  307. sprintf(lpszString, "%02d/%02d/%d %02d:%02d:%02d", (1 + curTime->tm_mon),
  308. curTime->tm_mday, (1900 + curTime->tm_year), curTime->tm_hour, curTime->tm_min, curTime->tm_sec);
  309. return;
  310. }
  311. #endif //_MSC_VER
  312. static BOOL Append(CAutoBuffer& buffer, const BYTE* const btContent, const DWORD dwSizeInByte, DWORD& dwLocate)
  313. {
  314. DWORD dwStart = buffer.GetCount();
  315. buffer.Append(btContent, 0, dwSizeInByte);
  316. assert(buffer.GetCount() - dwStart == dwSizeInByte);
  317. dwLocate = dwStart;
  318. return TRUE;
  319. }
  320. static BOOL GetSubFileName(const BYTE* btBuffer, const DWORD bufSize, CSimpleStringA& filePath, PULARGE_INTEGER pUliOffsetLength)
  321. {
  322. if(btBuffer == NULL || bufSize == 0) return FALSE;
  323. if(pUliOffsetLength == NULL) return FALSE;
  324. if(bufSize < pUliOffsetLength->u.LowPart + pUliOffsetLength->u.HighPart) return FALSE;
  325. CSimpleStringA tmpPath((LPCTSTR)btBuffer+pUliOffsetLength->u.LowPart, pUliOffsetLength->u.HighPart);
  326. //Dbg("GetSubFileName::tmpPath: %d", tmpPath.GetLength());
  327. filePath = tmpPath;
  328. return !filePath.IsNullOrEmpty();
  329. }
  330. static BOOL GetSubFileName(const PFILE_LAYOUT_ENTRY Entry, int nSubIndex, CSimpleStringA& csOutPath)
  331. {
  332. if(Entry == NULL)
  333. return FALSE;
  334. if(Entry->FileNamesBuffer.GetCount() == 0)
  335. return FALSE;
  336. if(nSubIndex < 0 || nSubIndex >= Entry->SubFiles.GetCount())
  337. return FALSE;
  338. const CSimpleFileComponent item = Entry->SubFiles[nSubIndex];
  339. csOutPath = "";
  340. if(item.mNameLength != 0)
  341. {
  342. ULARGE_INTEGER uliOffsetLength;
  343. uliOffsetLength.u.LowPart = item.mNameOffset;
  344. uliOffsetLength.u.HighPart = item.mNameLength;
  345. GetSubFileName(Entry->FileNamesBuffer, Entry->FileNamesBuffer.GetCount(),
  346. csOutPath, &uliOffsetLength);
  347. }
  348. return !(csOutPath.IsNullOrEmpty());
  349. }
  350. static int GetAttributeFormat(const DWORD& fileAttributes, CSimpleStringA& csAttributes)
  351. {
  352. #define ATTR_NUM 17
  353. static char szAttributes[ATTR_NUM] = {
  354. 'R', //0x00000001
  355. 'H', //0x00000002
  356. 'S', //0x00000004
  357. '*', //0x00000008
  358. 'D', //0x00000010
  359. 'A', //0x00000020
  360. 'V', //0x00000040
  361. 'N', //0x00000080
  362. 'T', //0x00000100
  363. 'P', //0x00000200
  364. 'L', //0x00000400
  365. 'C', //0x00000800
  366. 'O', //0x00001000
  367. 'I', //0x00002000
  368. 'E', //0x00004000
  369. '#', //0x00008000
  370. 'U', //0x00010000
  371. };
  372. static char szBelongs[ATTR_NUM+1];
  373. memset(szBelongs, 0, sizeof(szBelongs));
  374. int cnt = 0;
  375. DWORD attbitutes = fileAttributes;
  376. for(int i=0; attbitutes != 0; attbitutes >>=1, ++i)
  377. {
  378. if((attbitutes & 0x1))
  379. {
  380. szBelongs[cnt++] = szAttributes[i];
  381. }
  382. }
  383. szBelongs[cnt] = '\0';
  384. csAttributes = szBelongs;
  385. return cnt;
  386. }
  387. static BOOL GetFullFilePath(const PFILE_LAYOUT_ENTRY Entry,
  388. int nSubIndex, CSimpleStringA& csOutPath)
  389. {
  390. if(Entry == NULL)
  391. return FALSE;
  392. if(Entry->FileNamesBuffer.GetCount() == 0)
  393. return FALSE;
  394. if(nSubIndex < 0 || nSubIndex >= Entry->SubFiles.GetCount())
  395. return FALSE;
  396. const CSimpleFileComponent item = Entry->SubFiles[nSubIndex];
  397. CSimpleStringA csFileName;
  398. csOutPath = "";
  399. if(item.mNameLength != 0)
  400. {
  401. ULARGE_INTEGER uliOffsetLength;
  402. uliOffsetLength.u.LowPart = item.mNameOffset;
  403. uliOffsetLength.u.HighPart = item.mNameLength;
  404. GetSubFileName(Entry->FileNamesBuffer, Entry->FileNamesBuffer.GetCount(),
  405. csFileName, &uliOffsetLength);
  406. }
  407. if(!csFileName.IsNullOrEmpty())
  408. {
  409. CSimpleStringA csParentPath;
  410. if((const BYTE*)Entry->FileNamesBuffer != NULL)
  411. {
  412. csParentPath = CSimpleStringA((LPCTSTR)(const BYTE*)Entry->FileNamesBuffer, Entry->Current.mNameLength);
  413. }
  414. if(!csParentPath.IsNullOrEmpty() && (csParentPath.IsEndWith("\\") || csParentPath.IsEndWith("/")))
  415. csOutPath = csParentPath + csFileName;
  416. else if(csParentPath.IsNullOrEmpty())
  417. csOutPath = csFileName;
  418. else
  419. csOutPath = csParentPath + SPLIT_SLASH_STR + csFileName;
  420. }
  421. return !(csOutPath.IsNullOrEmpty());
  422. }
  423. static BOOL GetFullFilePath(const CSimpleStringA& parentPath, const BYTE* btBuffer, const DWORD bufSize,
  424. CSimpleStringA& fullFilePath, PULARGE_INTEGER pUliOffsetLength)
  425. {
  426. CSimpleStringA csFileName;
  427. Dbg("parentPath: %s", (LPCTSTR)csFileName);
  428. if(GetSubFileName(btBuffer, bufSize, csFileName, pUliOffsetLength))
  429. {
  430. if(!parentPath.IsNullOrEmpty()
  431. && (
  432. parentPath[parentPath.GetLength()-1] == '\\'
  433. || parentPath[parentPath.GetLength()-1] == '/')
  434. )
  435. fullFilePath = parentPath + csFileName;
  436. else if(parentPath.IsNullOrEmpty())
  437. fullFilePath = csFileName;
  438. else
  439. fullFilePath = parentPath + SPLIT_SLASH_STR + csFileName;
  440. }
  441. return !(fullFilePath.IsNullOrEmpty());
  442. }
  443. static CSimpleFileShell RetriveSubFile(
  444. const PFILE_LAYOUT_ENTRY Entry,
  445. int nSubIndex)
  446. {
  447. if(Entry == NULL)
  448. return CSimpleFileShell();
  449. if(Entry->FileNamesBuffer.GetCount() == 0)
  450. return CSimpleFileShell();
  451. if(nSubIndex < 0 || nSubIndex >= Entry->SubFiles.GetCount())
  452. return CSimpleFileShell();
  453. return CSimpleFileShell(Entry->SubFiles[nSubIndex]);
  454. }
  455. static inline int _GetDirSplitMarkPos(LPCTSTR lpszPath, bool bReverse = false)
  456. {
  457. if(lpszPath == NULL) return -1;
  458. if(!bReverse)
  459. {
  460. const char* pch1 = strchr(lpszPath, '\\');
  461. const char* pch2 = strchr(lpszPath, '/');
  462. if(pch1 && pch2)
  463. {
  464. if(pch2 - pch1 > 0) return (pch1 - lpszPath);
  465. else return (pch2 - lpszPath);
  466. }
  467. else if(pch2) return (pch2 - lpszPath);
  468. else if(pch1) return (pch1 - lpszPath);
  469. }
  470. else
  471. {
  472. const char* pch1 = strrchr(lpszPath, '\\');
  473. const char* pch2 = strrchr(lpszPath, '/');
  474. if(pch1 && pch2)
  475. {
  476. if(pch2 - pch1 > 0) return (pch2 - lpszPath);
  477. else return (pch1 - lpszPath);
  478. }
  479. else if(pch2) return (pch2 - lpszPath);
  480. else if(pch1) return (pch1 - lpszPath);
  481. }
  482. return -1;
  483. }
  484. static int GetPathDepth(LPCTSTR lpszPath)
  485. {
  486. if(lpszPath == NULL || strlen(lpszPath) == 0) return -1;
  487. int len = strlen(lpszPath);
  488. #if defined(_MSC_VER)
  489. if (!((lpszPath[0] <= 'z' && lpszPath[0] >= 'a') || (lpszPath[0] <= 'Z' && lpszPath[0] >= 'A')))
  490. return -2;
  491. if ((len == 2 && lpszPath[1] != ':') || (len == 3 && (lpszPath[1] != ':' || (lpszPath[2] != '\\' && lpszPath[2] != '/'))))
  492. return -3;
  493. #else
  494. if (lpszPath[0] != '/') return -2;
  495. #endif //_MSC_VER
  496. CSimpleStringA strPath(lpszPath);
  497. bool bEndWith = (lpszPath[len-1] == '\\' || lpszPath[len-1] == '/') ? true : false;
  498. int count = 0;
  499. int pos = _GetDirSplitMarkPos(lpszPath), tmp;
  500. const char* pch = NULL;
  501. while(pos != -1)
  502. {
  503. //Dbg("Test: %d", pos);
  504. pch = lpszPath + pos;
  505. count++;
  506. if(pos+1 >= len) break;
  507. tmp = _GetDirSplitMarkPos(pch+1);
  508. if(tmp == 0) {
  509. Dbg("Test: %d [%s]", pos, lpszPath);
  510. return -4;
  511. }
  512. pos = tmp > 0 ? tmp + pos + 1 : tmp;
  513. }
  514. if(!bEndWith) count++;
  515. if(count > 0) return count-1;
  516. return count;
  517. }
  518. static DWORD InitialFileEntity(PFILE_LAYOUT_ENTRY Entry, LPCTSTR lpszPath)
  519. {
  520. if(lpszPath == NULL || Entry == NULL)
  521. return 0;
  522. Entry->SubFiles.Clear();
  523. Entry->FileNamesBuffer.Clear();
  524. Entry->Current.Clear();
  525. DWORD dwLocate;
  526. Append(Entry->FileNamesBuffer, (PBYTE)lpszPath, strlen(lpszPath), dwLocate);
  527. Entry->Current.mNameOffset = dwLocate;
  528. Entry->Current.mNameLength = strlen(lpszPath);
  529. DWORD dwDir, dwFile;
  530. GetSubFileInfors(Entry, dwDir, dwFile);
  531. Dbg("dwDir:%u,dwFile:%u", dwDir, dwFile);
  532. DisplayFileEntities(Entry);
  533. return dwFile+dwFile;
  534. }
  535. static UINT GetDirSplitPath(LPCTSTR lpszPath, const int back_num, LPTSTR lpszRetPath, const size_t path_max_size)
  536. {
  537. if(lpszRetPath == NULL) return FALSE;
  538. memset(lpszRetPath, 0, path_max_size);
  539. if(lpszPath == 0 || strlen(lpszPath) == 0) return FALSE;
  540. int depth = GetPathDepth(lpszPath);
  541. if(depth < back_num) return FALSE;
  542. const size_t pathLen = strlen(lpszPath);
  543. if(pathLen+1 > path_max_size) return FALSE;
  544. char* pPath = lpszRetPath;
  545. if(pPath)
  546. {
  547. memcpy_s(pPath, path_max_size, lpszPath, pathLen);
  548. int pos = pathLen-1;
  549. for(; pos>=0 && (pPath[pos] == '\\' || pPath[pos] == '/'); --pos)
  550. pPath[pos] = '\0';
  551. pPath[pos+1] = '\0';
  552. int len = strlen(pPath);
  553. Dbg("PathLen(%d) VS RealLen(%d)", pathLen, len);
  554. int schedule = 0, aim = back_num, maxi = depth + 1;
  555. char* pch = NULL;
  556. pos = 0;
  557. while(schedule < aim && schedule < maxi)
  558. {
  559. pos = _GetDirSplitMarkPos(pPath, true);
  560. LOG_ASSERT(pos != -1);
  561. pPath[pos] = '\0';
  562. schedule++;
  563. }
  564. }
  565. return strlen(pPath);
  566. }
  567. //UpLevel > 0: means children index for current entry (Warning: the first child index is 1)
  568. //UpLevel < 0: means track back ancstor for current entry.
  569. //UpLevel = 0: do nothing.
  570. //Return true if succeed otherwise failed.
  571. static BOOL TraceExtend(PFILE_LAYOUT_ENTRY Entry, int UpLevel)
  572. {
  573. if(Entry == NULL) return FALSE;
  574. if(UpLevel == 0) return TRUE;
  575. if(UpLevel > 0 && UpLevel > Entry->SubFiles.GetCount())
  576. return FALSE;
  577. BOOL bRet = FALSE;
  578. CSimpleStringA strPath;
  579. CSimpleStringA strParentPath;
  580. ULARGE_INTEGER uliOffsetLength;
  581. uliOffsetLength.u.LowPart = 0;
  582. uliOffsetLength.u.HighPart = Entry->Current.mNameLength;
  583. if(GetSubFileName(Entry->FileNamesBuffer,
  584. Entry->FileNamesBuffer.GetCount(), strParentPath, &uliOffsetLength))
  585. {
  586. Dbg("TraceExtend::GetSubFileName suc: %d", UpLevel);
  587. if(UpLevel < 0)
  588. {
  589. UpLevel = 0-UpLevel;
  590. int depth = GetPathDepth(strParentPath);
  591. if(depth >= 0 && depth + 1 - UpLevel > 0)
  592. {
  593. const int pathLen = strParentPath.GetLength();
  594. char* pPath = new char[pathLen+1];
  595. if(pPath)
  596. {
  597. GetDirSplitPath(strParentPath, UpLevel, pPath, pathLen+1);
  598. strPath = pPath;
  599. delete[] pPath;
  600. pPath = NULL;
  601. }
  602. }
  603. }
  604. else
  605. {
  606. CSimpleFileShell item = RetriveSubFile(Entry, UpLevel-1);
  607. if((CSimpleFileComponent*)item)
  608. {
  609. uliOffsetLength.u.LowPart = item->mNameOffset;
  610. uliOffsetLength.u.HighPart = item->mNameLength;
  611. if(GetFullFilePath(strParentPath, Entry->FileNamesBuffer
  612. ,Entry->FileNamesBuffer.GetCount(), strPath, &uliOffsetLength))
  613. {
  614. }
  615. }
  616. }
  617. }
  618. if(!strPath.IsNullOrEmpty())
  619. {
  620. Entry->SubFiles.Clear();
  621. Entry->FileNamesBuffer.Clear();
  622. Entry->Current.Clear();
  623. DWORD dwLocate;
  624. Append(Entry->FileNamesBuffer, (PBYTE)(LPCTSTR)strPath, strPath.GetLength(), dwLocate);
  625. assert(dwLocate == 0);
  626. Dbg("TraceExtend::dwLocate %d", dwLocate);
  627. Entry->Current.mNameOffset = dwLocate;
  628. Entry->Current.mNameLength = strPath.GetLength();
  629. bRet = TRUE;
  630. DWORD dwDir, dwFile;
  631. GetSubFileInfors(Entry, dwDir, dwFile);
  632. Dbg("dwDir:%u,dwFile:%u", dwDir, dwFile);
  633. DisplayFileEntities(Entry);
  634. }
  635. return bRet;
  636. }
  637. /*返回该目录下的文件数量(文件+文件夹)*/
  638. ULONGLONG GetSubFileInfors(PFILE_LAYOUT_ENTRY Entry, DWORD& dwDirCount, DWORD& dwFileCount, const DWORD dwFilterMask)
  639. {
  640. dwDirCount = dwFileCount = 0;
  641. if(Entry == NULL) {
  642. return 0;
  643. }
  644. Dbg("dwFilter: 0x%08X", dwFilterMask);
  645. const BYTE* buffer = (const BYTE*)Entry->FileNamesBuffer;
  646. int nLength = Entry->Current.mNameLength;
  647. int nLengthSuffix = nLength + 3;
  648. char* pszParentPah = new char[nLengthSuffix];
  649. if(pszParentPah == NULL) {
  650. LogWarn(Severity_Middle, Error_Resource, 0, "New char-type buffer failed.");
  651. return 0;
  652. }
  653. ZeroMemory(pszParentPah, nLengthSuffix);
  654. memcpy_s(pszParentPah, nLength, buffer + Entry->Current.mNameOffset, nLength);
  655. #if defined(_MSC_VER)
  656. pszParentPah[nLength] = '\\';
  657. pszParentPah[nLength + 1] = '\0';
  658. CSimpleStringA csPath(pszParentPah);
  659. csPath += "\\*";
  660. WIN32_FIND_DATA wfd;
  661. HANDLE hFind;
  662. hFind = FindFirstFileA(csPath, &wfd);
  663. if (hFind == INVALID_HANDLE_VALUE) {
  664. Dbg("FindFirstFile failed GLE = %u.", GetLastError());
  665. delete[] pszParentPah;
  666. return 0;
  667. }
  668. do {
  669. if (((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY
  670. && wfd.cFileName[0] != '.')
  671. || !(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  672. //Dbg("%s", wfd.cFileName);
  673. if ((wfd.dwFileAttributes & dwFilterMask) == 0) {
  674. CSimpleFileComponent folder;
  675. ULARGE_INTEGER ulTmpValue;
  676. folder.mAttributes = wfd.dwFileAttributes;
  677. ulTmpValue.HighPart = wfd.ftLastAccessTime.dwHighDateTime;
  678. ulTmpValue.LowPart = wfd.ftLastAccessTime.dwLowDateTime;
  679. folder.mftAccess = ulTmpValue.QuadPart;
  680. ulTmpValue.HighPart = wfd.ftCreationTime.dwHighDateTime;
  681. ulTmpValue.LowPart = wfd.ftCreationTime.dwLowDateTime;
  682. folder.mftCreate = ulTmpValue.QuadPart;
  683. ulTmpValue.HighPart = wfd.ftLastWriteTime.dwHighDateTime;
  684. ulTmpValue.LowPart = wfd.ftLastWriteTime.dwLowDateTime;
  685. folder.mftModified = ulTmpValue.QuadPart;
  686. ulTmpValue.HighPart = wfd.nFileSizeHigh;
  687. ulTmpValue.LowPart = wfd.nFileSizeLow;
  688. folder.mFileSize = ulTmpValue.QuadPart;
  689. const DWORD dwNameLen = strlen(wfd.cFileName);
  690. Append(Entry->FileNamesBuffer, (PBYTE)wfd.cFileName, dwNameLen, folder.mNameOffset);
  691. folder.mNameLength = dwNameLen;
  692. Entry->SubFiles.Append(&folder, 0, 1);
  693. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) dwDirCount++;
  694. else dwFileCount++;
  695. } else {
  696. Dbg("flag1:%s - 0x%08X", wfd.cFileName, wfd.dwFileAttributes);
  697. }
  698. } else {
  699. Dbg("flag2:%s - 0x%08X", wfd.cFileName, wfd.dwFileAttributes);
  700. }
  701. } while (FindNextFileA(hFind, &wfd));
  702. FindClose(hFind);
  703. #else
  704. CSimpleStringA csPath(pszParentPah);
  705. struct stat fileStat;
  706. if (stat(csPath, &fileStat) < 0 || !S_ISDIR(fileStat.st_mode)) {
  707. Dbg("stat for %s failed or is not dir", csPath.GetData());
  708. delete[] pszParentPah;
  709. return 0;
  710. }
  711. DIR* d = opendir(csPath);
  712. if (!d) {
  713. Dbg("opendir %s failed: %s", (LPCTSTR)csPath, strerror(errno));
  714. delete[] pszParentPah;
  715. return 0;
  716. }
  717. struct dirent* dp = NULL;
  718. while ((dp = readdir(d)) != NULL) {
  719. if ((!strcmp(dp->d_name, ".")) || (!strcmp(dp->d_name, ".."))) {
  720. continue;
  721. }
  722. char tempFilePath[MAX_PATH*2] = { 0 };
  723. strcpy(tempFilePath, pszParentPah);
  724. if (strlen(tempFilePath) + strlen(dp->d_name) + 3 >= MAX_PATH * 2) {
  725. Dbg("filePath is too long for current.");
  726. continue;
  727. }
  728. strcat(tempFilePath, "/");
  729. strcat(tempFilePath, dp->d_name);
  730. stat(tempFilePath, &fileStat);
  731. CSimpleFileComponent folder;
  732. folder.mAttributes = 0;
  733. if (S_ISDIR(fileStat.st_mode)) {
  734. folder.mAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  735. folder.mFileSize = GetDirectoryItemCount(tempFilePath); //GetDirectorySize(tempFilePath);
  736. } else {
  737. folder.mFileSize = fileStat.st_size;
  738. }
  739. if (folder.mAttributes == 0)
  740. folder.mAttributes = FILE_ATTRIBUTE_ARCHIVE;
  741. if (!(fileStat.st_mode & S_IWUSR))
  742. folder.mAttributes |= FILE_ATTRIBUTE_READONLY;
  743. folder.mftAccess = fileStat.st_atime;
  744. folder.mftCreate = fileStat.st_ctime;
  745. folder.mftModified = fileStat.st_mtime;
  746. const DWORD dwNameLen = strlen(dp->d_name);
  747. Append(Entry->FileNamesBuffer, (PBYTE)dp->d_name, dwNameLen, folder.mNameOffset);
  748. folder.mNameLength = dwNameLen;
  749. Entry->SubFiles.Append(&folder, 0, 1);
  750. if (folder.mAttributes & FILE_ATTRIBUTE_DIRECTORY) { dwDirCount++; }
  751. else dwFileCount++;
  752. }
  753. closedir(d);
  754. #endif //_MSC_VER
  755. delete[] pszParentPah;
  756. return ( dwDirCount + dwFileCount);
  757. }
  758. void DisplayFileEntities(const PFILE_LAYOUT_ENTRY Entry)
  759. {
  760. if(Entry == NULL) return;
  761. CSimpleStringA csParentName, csFileName, csAttributes, csFilePath;
  762. ULARGE_INTEGER uliOffsetLength;
  763. uliOffsetLength.u.LowPart = Entry->Current.mNameOffset;
  764. uliOffsetLength.u.HighPart = Entry->Current.mNameLength;
  765. GetSubFileName(Entry->FileNamesBuffer, Entry->FileNamesBuffer.GetCount(),
  766. csParentName, &uliOffsetLength);
  767. char szFormat[128] = {0};
  768. Dbg("FileCount under [%s]: (%d)", (LPCTSTR)csParentName, Entry->SubFiles.GetCount());
  769. #if 0
  770. for(int i=0; i<Entry->SubFiles.GetCount(); ++i)
  771. {
  772. Dbg("***********************************************");
  773. const CSimpleFileComponent& cur = Entry->SubFiles[i];
  774. uliOffsetLength.LowPart = cur.mNameOffset;
  775. uliOffsetLength.HighPart = cur.mNameLength;
  776. Dbg("mNameOffset: %u, mNameLength: %u.", cur.mNameOffset, cur.mNameLength);
  777. GetSubFileName(Entry->FileNamesBuffer, Entry->FileNamesBuffer.GetCount(),
  778. csFileName, &uliOffsetLength);
  779. Dbg("[%d] %s =>", i, (LPCTSTR)csFileName);
  780. GetTimeFormatStr(szFormat, 128, (FILETIME*)&cur.mftCreate);
  781. Dbg("Create: %s", szFormat);
  782. //GetTimeFormatStr(szFormat, 128, (FILETIME*)&cur.mftModified);
  783. //Dbg("Modifi: %s", szFormat);
  784. //GetTimeFormatStr(szFormat, 128, (FILETIME*)&cur.mftAccess);
  785. //Dbg("Access: %s", szFormat);
  786. GetAttributeFormat(cur.mAttributes, csAttributes);
  787. Dbg("Attributes(0x%X): %s", cur.mAttributes, (LPCTSTR)csAttributes);
  788. GetFullFilePath(Entry, i, csFilePath);
  789. Dbg("FullPath1: %s", (LPCTSTR)csFilePath);
  790. //GetFullFilePath(csParentName, Entry->FileNamesBuffer, Entry->FileNamesBuffer.GetCount(),
  791. // csFilePath, &uliOffsetLength);
  792. //Dbg("FullPath2: %s", (LPCTSTR)csFilePath);
  793. //Dbg("PathDepth: %d", GetPathDepth(csFilePath));
  794. }
  795. #endif
  796. }
  797. static BOOL IsPathExisted(LPCTSTR lpszPath, FileType& retType)
  798. {
  799. retType = FT_Unknown;
  800. size_t len = 0;
  801. if (lpszPath == NULL || (len = strlen(lpszPath)) == 0)
  802. return FALSE;
  803. #if defined(RVC_OS_WIN)
  804. if (len == 1) {
  805. if (!((lpszPath[0] <= 'z' && lpszPath[0] >= 'a') || (lpszPath[0] <= 'Z' && lpszPath[0] >= 'A')))
  806. return FALSE;
  807. }
  808. if (len >= 2 && lpszPath[1] != ':')
  809. return FALSE;
  810. if (len >= 3 && (lpszPath[2] != '\\' && lpszPath[2] != '/'))
  811. return FALSE;
  812. if (len <= 3) {
  813. char disk = lpszPath[0];
  814. if (disk >= 'a' && disk <= 'z') disk -= 32;
  815. int no = disk - 'A';
  816. DWORD dwRes = GetLogicalDrives();
  817. if ((dwRes & (1 << no)) == 0)
  818. return FALSE;
  819. retType = FT_Volume;
  820. return TRUE;
  821. }
  822. #else
  823. if (len == 1 && lpszPath[0] != '/') {
  824. return FALSE;
  825. }
  826. #endif //RVC_OS_WIN
  827. char* path = new char[len + 1];
  828. LOG_ASSERT(path != NULL);
  829. memset(path, 0, sizeof(char) * (len + 1));
  830. memcpy(path, lpszPath, len);
  831. path[len] = '\0';
  832. int pos = len - 1;
  833. for (; pos >= 0 && (path[pos] == '\\' || path[pos] == '/'); --pos) {
  834. ;//
  835. }
  836. path[pos + 1] = '\0';
  837. #if defined(_MSC_VER)
  838. WIN32_FIND_DATA wfd = { 0 };
  839. HANDLE hFile = FindFirstFileA(path, &wfd);
  840. if (hFile == INVALID_HANDLE_VALUE) {
  841. delete[] path;
  842. return FALSE;
  843. }
  844. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) retType = FT_Directory;
  845. else retType = FT_File;
  846. FindClose(hFile);
  847. #else
  848. if (ExistsDirA(path)) {
  849. retType = FT_Directory;
  850. } else if (ExistsFileA(path)) {
  851. retType = FT_File;
  852. } else {
  853. delete[] path;
  854. return FALSE;
  855. }
  856. #endif //_MSC_VER
  857. delete[] path;
  858. return TRUE;
  859. }
  860. static bool _CompareFunc(CSimpleFileShell lhs, CSimpleFileShell rhs) {
  861. if(lhs->mftModified > rhs->mftModified)
  862. return true;
  863. return false;
  864. }
  865. #endif //_TWINKLE_CICOMPONENT_INTERFACE_H__