FileSimpleComp.h 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  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. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("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. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("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. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("stat dir for %s failed: %d ", tempFilePath, errno);
  198. continue;
  199. }
  200. if (S_ISDIR(fileStat.st_mode)) {
  201. if (nDepth + 1 >= 0) {
  202. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("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. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("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. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("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. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("stat dir for %s failed: %d ", tempFilePath, errno);
  243. continue;
  244. }
  245. if (S_ISDIR(fileStat.st_mode)) {
  246. if (nDepth + 1 >= 0) {
  247. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("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. filePath = tmpPath;
  327. return !filePath.IsNullOrEmpty();
  328. }
  329. static BOOL GetSubFileName(const PFILE_LAYOUT_ENTRY Entry, int nSubIndex, CSimpleStringA& csOutPath)
  330. {
  331. if(Entry == NULL)
  332. return FALSE;
  333. if(Entry->FileNamesBuffer.GetCount() == 0)
  334. return FALSE;
  335. if(nSubIndex < 0 || nSubIndex >= Entry->SubFiles.GetCount())
  336. return FALSE;
  337. const CSimpleFileComponent item = Entry->SubFiles[nSubIndex];
  338. csOutPath = "";
  339. if(item.mNameLength != 0)
  340. {
  341. ULARGE_INTEGER uliOffsetLength;
  342. uliOffsetLength.u.LowPart = item.mNameOffset;
  343. uliOffsetLength.u.HighPart = item.mNameLength;
  344. GetSubFileName(Entry->FileNamesBuffer, Entry->FileNamesBuffer.GetCount(),
  345. csOutPath, &uliOffsetLength);
  346. }
  347. return !(csOutPath.IsNullOrEmpty());
  348. }
  349. static int GetAttributeFormat(const DWORD& fileAttributes, CSimpleStringA& csAttributes)
  350. {
  351. #define ATTR_NUM 17
  352. static char szAttributes[ATTR_NUM] = {
  353. 'R', //0x00000001
  354. 'H', //0x00000002
  355. 'S', //0x00000004
  356. '*', //0x00000008
  357. 'D', //0x00000010
  358. 'A', //0x00000020
  359. 'V', //0x00000040
  360. 'N', //0x00000080
  361. 'T', //0x00000100
  362. 'P', //0x00000200
  363. 'L', //0x00000400
  364. 'C', //0x00000800
  365. 'O', //0x00001000
  366. 'I', //0x00002000
  367. 'E', //0x00004000
  368. '#', //0x00008000
  369. 'U', //0x00010000
  370. };
  371. static char szBelongs[ATTR_NUM+1];
  372. memset(szBelongs, 0, sizeof(szBelongs));
  373. int cnt = 0;
  374. DWORD attbitutes = fileAttributes;
  375. for(int i=0; attbitutes != 0; attbitutes >>=1, ++i)
  376. {
  377. if((attbitutes & 0x1))
  378. {
  379. szBelongs[cnt++] = szAttributes[i];
  380. }
  381. }
  382. szBelongs[cnt] = '\0';
  383. csAttributes = szBelongs;
  384. return cnt;
  385. }
  386. static BOOL GetFullFilePath(const PFILE_LAYOUT_ENTRY Entry,
  387. int nSubIndex, CSimpleStringA& csOutPath)
  388. {
  389. if(Entry == NULL)
  390. return FALSE;
  391. if(Entry->FileNamesBuffer.GetCount() == 0)
  392. return FALSE;
  393. if(nSubIndex < 0 || nSubIndex >= Entry->SubFiles.GetCount())
  394. return FALSE;
  395. const CSimpleFileComponent item = Entry->SubFiles[nSubIndex];
  396. CSimpleStringA csFileName;
  397. csOutPath = "";
  398. if(item.mNameLength != 0)
  399. {
  400. ULARGE_INTEGER uliOffsetLength;
  401. uliOffsetLength.u.LowPart = item.mNameOffset;
  402. uliOffsetLength.u.HighPart = item.mNameLength;
  403. GetSubFileName(Entry->FileNamesBuffer, Entry->FileNamesBuffer.GetCount(),
  404. csFileName, &uliOffsetLength);
  405. }
  406. if(!csFileName.IsNullOrEmpty())
  407. {
  408. CSimpleStringA csParentPath;
  409. if((const BYTE*)Entry->FileNamesBuffer != NULL)
  410. {
  411. csParentPath = CSimpleStringA((LPCTSTR)(const BYTE*)Entry->FileNamesBuffer, Entry->Current.mNameLength);
  412. }
  413. if(!csParentPath.IsNullOrEmpty() && (csParentPath.IsEndWith("\\") || csParentPath.IsEndWith("/")))
  414. csOutPath = csParentPath + csFileName;
  415. else if(csParentPath.IsNullOrEmpty())
  416. csOutPath = csFileName;
  417. else
  418. csOutPath = csParentPath + SPLIT_SLASH_STR + csFileName;
  419. }
  420. return !(csOutPath.IsNullOrEmpty());
  421. }
  422. static BOOL GetFullFilePath(const CSimpleStringA& parentPath, const BYTE* btBuffer, const DWORD bufSize,
  423. CSimpleStringA& fullFilePath, PULARGE_INTEGER pUliOffsetLength)
  424. {
  425. CSimpleStringA csFileName;
  426. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("parentPath: %s", (LPCTSTR)csFileName);
  427. if(GetSubFileName(btBuffer, bufSize, csFileName, pUliOffsetLength))
  428. {
  429. if(!parentPath.IsNullOrEmpty()
  430. && (
  431. parentPath[parentPath.GetLength()-1] == '\\'
  432. || parentPath[parentPath.GetLength()-1] == '/')
  433. )
  434. fullFilePath = parentPath + csFileName;
  435. else if(parentPath.IsNullOrEmpty())
  436. fullFilePath = csFileName;
  437. else
  438. fullFilePath = parentPath + SPLIT_SLASH_STR + csFileName;
  439. }
  440. return !(fullFilePath.IsNullOrEmpty());
  441. }
  442. static CSimpleFileShell RetriveSubFile(
  443. const PFILE_LAYOUT_ENTRY Entry,
  444. int nSubIndex)
  445. {
  446. if(Entry == NULL)
  447. return CSimpleFileShell();
  448. if(Entry->FileNamesBuffer.GetCount() == 0)
  449. return CSimpleFileShell();
  450. if(nSubIndex < 0 || nSubIndex >= Entry->SubFiles.GetCount())
  451. return CSimpleFileShell();
  452. return CSimpleFileShell(Entry->SubFiles[nSubIndex]);
  453. }
  454. static inline int _GetDirSplitMarkPos(LPCTSTR lpszPath, bool bReverse = false)
  455. {
  456. if(lpszPath == NULL) return -1;
  457. if(!bReverse)
  458. {
  459. const char* pch1 = strchr(lpszPath, '\\');
  460. const char* pch2 = strchr(lpszPath, '/');
  461. if(pch1 && pch2)
  462. {
  463. if(pch2 - pch1 > 0) return (pch1 - lpszPath);
  464. else return (pch2 - lpszPath);
  465. }
  466. else if(pch2) return (pch2 - lpszPath);
  467. else if(pch1) return (pch1 - lpszPath);
  468. }
  469. else
  470. {
  471. const char* pch1 = strrchr(lpszPath, '\\');
  472. const char* pch2 = strrchr(lpszPath, '/');
  473. if(pch1 && pch2)
  474. {
  475. if(pch2 - pch1 > 0) return (pch2 - lpszPath);
  476. else return (pch1 - lpszPath);
  477. }
  478. else if(pch2) return (pch2 - lpszPath);
  479. else if(pch1) return (pch1 - lpszPath);
  480. }
  481. return -1;
  482. }
  483. static int GetPathDepth(LPCTSTR lpszPath)
  484. {
  485. if(lpszPath == NULL || strlen(lpszPath) == 0) return -1;
  486. int len = strlen(lpszPath);
  487. #if defined(_MSC_VER)
  488. if (!((lpszPath[0] <= 'z' && lpszPath[0] >= 'a') || (lpszPath[0] <= 'Z' && lpszPath[0] >= 'A')))
  489. return -2;
  490. if ((len == 2 && lpszPath[1] != ':') || (len == 3 && (lpszPath[1] != ':' || (lpszPath[2] != '\\' && lpszPath[2] != '/'))))
  491. return -3;
  492. #else
  493. if (lpszPath[0] != '/') return -2;
  494. #endif //_MSC_VER
  495. CSimpleStringA strPath(lpszPath);
  496. bool bEndWith = (lpszPath[len-1] == '\\' || lpszPath[len-1] == '/') ? true : false;
  497. int count = 0;
  498. int pos = _GetDirSplitMarkPos(lpszPath), tmp;
  499. const char* pch = NULL;
  500. while(pos != -1)
  501. {
  502. pch = lpszPath + pos;
  503. count++;
  504. if(pos+1 >= len) break;
  505. tmp = _GetDirSplitMarkPos(pch+1);
  506. if(tmp == 0) {
  507. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("Test: %d [%s]", pos, lpszPath);
  508. return -4;
  509. }
  510. pos = tmp > 0 ? tmp + pos + 1 : tmp;
  511. }
  512. if(!bEndWith) count++;
  513. if(count > 0) return count-1;
  514. return count;
  515. }
  516. static DWORD InitialFileEntity(PFILE_LAYOUT_ENTRY Entry, LPCTSTR lpszPath)
  517. {
  518. if(lpszPath == NULL || Entry == NULL)
  519. return 0;
  520. Entry->SubFiles.Clear();
  521. Entry->FileNamesBuffer.Clear();
  522. Entry->Current.Clear();
  523. DWORD dwLocate;
  524. Append(Entry->FileNamesBuffer, (PBYTE)lpszPath, strlen(lpszPath), dwLocate);
  525. Entry->Current.mNameOffset = dwLocate;
  526. Entry->Current.mNameLength = strlen(lpszPath);
  527. DWORD dwDir, dwFile;
  528. GetSubFileInfors(Entry, dwDir, dwFile);
  529. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("dwDir:%u,dwFile:%u", dwDir, dwFile);
  530. DisplayFileEntities(Entry);
  531. return dwFile+dwFile;
  532. }
  533. static UINT GetDirSplitPath(LPCTSTR lpszPath, const int back_num, LPTSTR lpszRetPath, const size_t path_max_size)
  534. {
  535. if(lpszRetPath == NULL) return FALSE;
  536. memset(lpszRetPath, 0, path_max_size);
  537. if(lpszPath == 0 || strlen(lpszPath) == 0) return FALSE;
  538. int depth = GetPathDepth(lpszPath);
  539. if(depth < back_num) return FALSE;
  540. const size_t pathLen = strlen(lpszPath);
  541. if(pathLen+1 > path_max_size) return FALSE;
  542. char* pPath = lpszRetPath;
  543. if(pPath)
  544. {
  545. memcpy_s(pPath, path_max_size, lpszPath, pathLen);
  546. int pos = pathLen-1;
  547. for(; pos>=0 && (pPath[pos] == '\\' || pPath[pos] == '/'); --pos)
  548. pPath[pos] = '\0';
  549. pPath[pos+1] = '\0';
  550. int len = strlen(pPath);
  551. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("PathLen(%d) VS RealLen(%d)", pathLen, len);
  552. int schedule = 0, aim = back_num, maxi = depth + 1;
  553. char* pch = NULL;
  554. pos = 0;
  555. while(schedule < aim && schedule < maxi)
  556. {
  557. pos = _GetDirSplitMarkPos(pPath, true);
  558. LOG_ASSERT(pos != -1);
  559. pPath[pos] = '\0';
  560. schedule++;
  561. }
  562. }
  563. return strlen(pPath);
  564. }
  565. //UpLevel > 0: means children index for current entry (Warning: the first child index is 1)
  566. //UpLevel < 0: means track back ancstor for current entry.
  567. //UpLevel = 0: do nothing.
  568. //Return true if succeed otherwise failed.
  569. static BOOL TraceExtend(PFILE_LAYOUT_ENTRY Entry, int UpLevel)
  570. {
  571. if(Entry == NULL) return FALSE;
  572. if(UpLevel == 0) return TRUE;
  573. if(UpLevel > 0 && UpLevel > Entry->SubFiles.GetCount())
  574. return FALSE;
  575. BOOL bRet = FALSE;
  576. CSimpleStringA strPath;
  577. CSimpleStringA strParentPath;
  578. ULARGE_INTEGER uliOffsetLength;
  579. uliOffsetLength.u.LowPart = 0;
  580. uliOffsetLength.u.HighPart = Entry->Current.mNameLength;
  581. if(GetSubFileName(Entry->FileNamesBuffer,
  582. Entry->FileNamesBuffer.GetCount(), strParentPath, &uliOffsetLength))
  583. {
  584. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("TraceExtend::GetSubFileName suc: %d", UpLevel);
  585. if(UpLevel < 0)
  586. {
  587. UpLevel = 0-UpLevel;
  588. int depth = GetPathDepth(strParentPath);
  589. if(depth >= 0 && depth + 1 - UpLevel > 0)
  590. {
  591. const int pathLen = strParentPath.GetLength();
  592. char* pPath = new char[pathLen+1];
  593. if(pPath)
  594. {
  595. GetDirSplitPath(strParentPath, UpLevel, pPath, pathLen+1);
  596. strPath = pPath;
  597. delete[] pPath;
  598. pPath = NULL;
  599. }
  600. }
  601. }
  602. else
  603. {
  604. CSimpleFileShell item = RetriveSubFile(Entry, UpLevel-1);
  605. if((CSimpleFileComponent*)item)
  606. {
  607. uliOffsetLength.u.LowPart = item->mNameOffset;
  608. uliOffsetLength.u.HighPart = item->mNameLength;
  609. if(GetFullFilePath(strParentPath, Entry->FileNamesBuffer
  610. ,Entry->FileNamesBuffer.GetCount(), strPath, &uliOffsetLength))
  611. {
  612. }
  613. }
  614. }
  615. }
  616. if(!strPath.IsNullOrEmpty())
  617. {
  618. Entry->SubFiles.Clear();
  619. Entry->FileNamesBuffer.Clear();
  620. Entry->Current.Clear();
  621. DWORD dwLocate;
  622. Append(Entry->FileNamesBuffer, (PBYTE)(LPCTSTR)strPath, strPath.GetLength(), dwLocate);
  623. assert(dwLocate == 0);
  624. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("TraceExtend::dwLocate %d", dwLocate);
  625. Entry->Current.mNameOffset = dwLocate;
  626. Entry->Current.mNameLength = strPath.GetLength();
  627. bRet = TRUE;
  628. DWORD dwDir, dwFile;
  629. GetSubFileInfors(Entry, dwDir, dwFile);
  630. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("dwDir:%u,dwFile:%u", dwDir, dwFile);
  631. DisplayFileEntities(Entry);
  632. }
  633. return bRet;
  634. }
  635. /*return the count of current dir(folder and file)*/
  636. ULONGLONG GetSubFileInfors(PFILE_LAYOUT_ENTRY Entry, DWORD& dwDirCount, DWORD& dwFileCount, const DWORD dwFilterMask)
  637. {
  638. dwDirCount = dwFileCount = 0;
  639. if(Entry == NULL) {
  640. return 0;
  641. }
  642. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("dwFilter: 0x%08X", dwFilterMask);
  643. const BYTE* buffer = (const BYTE*)Entry->FileNamesBuffer;
  644. int nLength = Entry->Current.mNameLength;
  645. int nLengthSuffix = nLength + 3;
  646. char* pszParentPah = new char[nLengthSuffix];
  647. if(pszParentPah == NULL) {
  648. LogWarn(Severity_Middle, Error_Resource, 0, "New char-type buffer failed.");
  649. return 0;
  650. }
  651. ZeroMemory(pszParentPah, nLengthSuffix);
  652. memcpy_s(pszParentPah, nLength, buffer + Entry->Current.mNameOffset, nLength);
  653. #if defined(_MSC_VER)
  654. pszParentPah[nLength] = '\\';
  655. pszParentPah[nLength + 1] = '\0';
  656. CSimpleStringA csPath(pszParentPah);
  657. csPath += "\\*";
  658. WIN32_FIND_DATA wfd;
  659. HANDLE hFind;
  660. hFind = FindFirstFileA(csPath, &wfd);
  661. if (hFind == INVALID_HANDLE_VALUE) {
  662. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("FindFirstFile failed GLE = %u.", GetLastError());
  663. delete[] pszParentPah;
  664. return 0;
  665. }
  666. do {
  667. if (((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY
  668. && wfd.cFileName[0] != '.')
  669. || !(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  670. if ((wfd.dwFileAttributes & dwFilterMask) == 0) {
  671. CSimpleFileComponent folder;
  672. ULARGE_INTEGER ulTmpValue;
  673. folder.mAttributes = wfd.dwFileAttributes;
  674. ulTmpValue.HighPart = wfd.ftLastAccessTime.dwHighDateTime;
  675. ulTmpValue.LowPart = wfd.ftLastAccessTime.dwLowDateTime;
  676. folder.mftAccess = ulTmpValue.QuadPart;
  677. ulTmpValue.HighPart = wfd.ftCreationTime.dwHighDateTime;
  678. ulTmpValue.LowPart = wfd.ftCreationTime.dwLowDateTime;
  679. folder.mftCreate = ulTmpValue.QuadPart;
  680. ulTmpValue.HighPart = wfd.ftLastWriteTime.dwHighDateTime;
  681. ulTmpValue.LowPart = wfd.ftLastWriteTime.dwLowDateTime;
  682. folder.mftModified = ulTmpValue.QuadPart;
  683. ulTmpValue.HighPart = wfd.nFileSizeHigh;
  684. ulTmpValue.LowPart = wfd.nFileSizeLow;
  685. folder.mFileSize = ulTmpValue.QuadPart;
  686. const DWORD dwNameLen = strlen(wfd.cFileName);
  687. Append(Entry->FileNamesBuffer, (PBYTE)wfd.cFileName, dwNameLen, folder.mNameOffset);
  688. folder.mNameLength = dwNameLen;
  689. Entry->SubFiles.Append(&folder, 0, 1);
  690. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) dwDirCount++;
  691. else dwFileCount++;
  692. } else {
  693. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("flag1:%s - 0x%08X", wfd.cFileName, wfd.dwFileAttributes);
  694. }
  695. } else {
  696. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("flag2:%s - 0x%08X", wfd.cFileName, wfd.dwFileAttributes);
  697. }
  698. } while (FindNextFileA(hFind, &wfd));
  699. FindClose(hFind);
  700. #else
  701. CSimpleStringA csPath(pszParentPah);
  702. struct stat fileStat;
  703. if (stat(csPath, &fileStat) < 0 || !S_ISDIR(fileStat.st_mode)) {
  704. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("stat for %s failed or is not dir", csPath.GetData());
  705. delete[] pszParentPah;
  706. return 0;
  707. }
  708. DIR* d = opendir(csPath);
  709. if (!d) {
  710. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("opendir %s failed: %s", (LPCTSTR)csPath, strerror(errno));
  711. delete[] pszParentPah;
  712. return 0;
  713. }
  714. struct dirent* dp = NULL;
  715. while ((dp = readdir(d)) != NULL) {
  716. if ((!strcmp(dp->d_name, ".")) || (!strcmp(dp->d_name, ".."))) {
  717. continue;
  718. }
  719. char tempFilePath[MAX_PATH*2] = { 0 };
  720. strcpy(tempFilePath, pszParentPah);
  721. if (strlen(tempFilePath) + strlen(dp->d_name) + 3 >= MAX_PATH * 2) {
  722. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("filePath is too long for current.");
  723. continue;
  724. }
  725. strcat(tempFilePath, "/");
  726. strcat(tempFilePath, dp->d_name);
  727. stat(tempFilePath, &fileStat);
  728. CSimpleFileComponent folder;
  729. folder.mAttributes = 0;
  730. if (S_ISDIR(fileStat.st_mode)) {
  731. folder.mAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  732. folder.mFileSize = GetDirectoryItemCount(tempFilePath); //GetDirectorySize(tempFilePath);
  733. } else {
  734. folder.mFileSize = fileStat.st_size;
  735. }
  736. if (folder.mAttributes == 0)
  737. folder.mAttributes = FILE_ATTRIBUTE_ARCHIVE;
  738. if (!(fileStat.st_mode & S_IWUSR))
  739. folder.mAttributes |= FILE_ATTRIBUTE_READONLY;
  740. folder.mftAccess = fileStat.st_atime;
  741. folder.mftCreate = fileStat.st_ctime;
  742. folder.mftModified = fileStat.st_mtime;
  743. const DWORD dwNameLen = strlen(dp->d_name);
  744. Append(Entry->FileNamesBuffer, (PBYTE)dp->d_name, dwNameLen, folder.mNameOffset);
  745. folder.mNameLength = dwNameLen;
  746. Entry->SubFiles.Append(&folder, 0, 1);
  747. if (folder.mAttributes & FILE_ATTRIBUTE_DIRECTORY) { dwDirCount++; }
  748. else dwFileCount++;
  749. }
  750. closedir(d);
  751. #endif //_MSC_VER
  752. delete[] pszParentPah;
  753. return ( dwDirCount + dwFileCount);
  754. }
  755. void DisplayFileEntities(const PFILE_LAYOUT_ENTRY Entry)
  756. {
  757. if(Entry == NULL) return;
  758. CSimpleStringA csParentName, csFileName, csAttributes, csFilePath;
  759. ULARGE_INTEGER uliOffsetLength;
  760. uliOffsetLength.u.LowPart = Entry->Current.mNameOffset;
  761. uliOffsetLength.u.HighPart = Entry->Current.mNameLength;
  762. GetSubFileName(Entry->FileNamesBuffer, Entry->FileNamesBuffer.GetCount(),
  763. csParentName, &uliOffsetLength);
  764. char szFormat[128] = {0};
  765. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("FileCount under [%s]: (%d)", (LPCTSTR)csParentName, Entry->SubFiles.GetCount());
  766. #if 0
  767. for(int i=0; i<Entry->SubFiles.GetCount(); ++i)
  768. {
  769. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("***********************************************");
  770. const CSimpleFileComponent& cur = Entry->SubFiles[i];
  771. uliOffsetLength.LowPart = cur.mNameOffset;
  772. uliOffsetLength.HighPart = cur.mNameLength;
  773. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("mNameOffset: %u, mNameLength: %u.", cur.mNameOffset, cur.mNameLength);
  774. GetSubFileName(Entry->FileNamesBuffer, Entry->FileNamesBuffer.GetCount(),
  775. csFileName, &uliOffsetLength);
  776. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("[%d] %s =>", i, (LPCTSTR)csFileName);
  777. GetTimeFormatStr(szFormat, 128, (FILETIME*)&cur.mftCreate);
  778. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("Create: %s", szFormat);
  779. //GetTimeFormatStr(szFormat, 128, (FILETIME*)&cur.mftModified);
  780. //DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("Modifi: %s", szFormat);
  781. //GetTimeFormatStr(szFormat, 128, (FILETIME*)&cur.mftAccess);
  782. //DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("Access: %s", szFormat);
  783. GetAttributeFormat(cur.mAttributes, csAttributes);
  784. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("Attributes(0x%X): %s", cur.mAttributes, (LPCTSTR)csAttributes);
  785. GetFullFilePath(Entry, i, csFilePath);
  786. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("FullPath1: %s", (LPCTSTR)csFilePath);
  787. //GetFullFilePath(csParentName, Entry->FileNamesBuffer, Entry->FileNamesBuffer.GetCount(),
  788. // csFilePath, &uliOffsetLength);
  789. //DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("FullPath2: %s", (LPCTSTR)csFilePath);
  790. //DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("PathDepth: %d", GetPathDepth(csFilePath));
  791. }
  792. #endif
  793. }
  794. static BOOL IsPathExisted(LPCTSTR lpszPath, FileType& retType)
  795. {
  796. retType = FT_Unknown;
  797. size_t len = 0;
  798. if (lpszPath == NULL || (len = strlen(lpszPath)) == 0)
  799. return FALSE;
  800. #if defined(RVC_OS_WIN)
  801. if (len == 1) {
  802. if (!((lpszPath[0] <= 'z' && lpszPath[0] >= 'a') || (lpszPath[0] <= 'Z' && lpszPath[0] >= 'A')))
  803. return FALSE;
  804. }
  805. if (len >= 2 && lpszPath[1] != ':')
  806. return FALSE;
  807. if (len >= 3 && (lpszPath[2] != '\\' && lpszPath[2] != '/'))
  808. return FALSE;
  809. if (len <= 3) {
  810. char disk = lpszPath[0];
  811. if (disk >= 'a' && disk <= 'z') disk -= 32;
  812. int no = disk - 'A';
  813. DWORD dwRes = GetLogicalDrives();
  814. if ((dwRes & (1 << no)) == 0)
  815. return FALSE;
  816. retType = FT_Volume;
  817. return TRUE;
  818. }
  819. #else
  820. if (len == 1 && lpszPath[0] != '/') {
  821. return FALSE;
  822. }
  823. #endif //RVC_OS_WIN
  824. char* path = new char[len + 1];
  825. LOG_ASSERT(path != NULL);
  826. memset(path, 0, sizeof(char) * (len + 1));
  827. memcpy(path, lpszPath, len);
  828. path[len] = '\0';
  829. int pos = len - 1;
  830. for (; pos >= 0 && (path[pos] == '\\' || path[pos] == '/'); --pos) {
  831. ;//
  832. }
  833. path[pos + 1] = '\0';
  834. #if defined(_MSC_VER)
  835. WIN32_FIND_DATA wfd = { 0 };
  836. HANDLE hFile = FindFirstFileA(path, &wfd);
  837. if (hFile == INVALID_HANDLE_VALUE) {
  838. delete[] path;
  839. return FALSE;
  840. }
  841. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) retType = FT_Directory;
  842. else retType = FT_File;
  843. FindClose(hFile);
  844. #else
  845. if (ExistsDirA(path)) {
  846. retType = FT_Directory;
  847. } else if (ExistsFileA(path)) {
  848. retType = FT_File;
  849. } else {
  850. delete[] path;
  851. return FALSE;
  852. }
  853. #endif //_MSC_VER
  854. delete[] path;
  855. return TRUE;
  856. }
  857. static bool _CompareFunc(CSimpleFileShell lhs, CSimpleFileShell rhs) {
  858. if(lhs->mftModified > rhs->mftModified)
  859. return true;
  860. return false;
  861. }
  862. #endif //_TWINKLE_CICOMPONENT_INTERFACE_H__