Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

748 lines
25 KiB

  1. #include "stdinc.h"
  2. #include "FusionBuffer.h"
  3. #include "Util.h"
  4. #include "FusionHandle.h"
  5. BOOL
  6. FusionpCreateDirectories(
  7. PCWSTR pszDirectory,
  8. SIZE_T cchDirectory
  9. )
  10. /*-----------------------------------------------------------------------------
  11. like ::CreateDirectoryW, but will create the parent directories as needed;
  12. origin of this code
  13. \\lang5\V5.PRO\src\ide5\shell\path.cpp ("MakeDirectory")
  14. \\kingbird\vseedev\src\vsee98\vsee\pkgs\scc\path.cpp ("MakeDirectory")
  15. then ported to \\kingbird\vseedev\src\vsee70\pkgs\scc\path.cpp ("MakeDirectory")
  16. then moved to \vsee\lib\io\io.cpp, converted to use exceptions ("NVseeLibIo::FCreateDirectories")
  17. then copied to fusion\dll\whistler\util.cpp, exceptions converted to BOOL/LastError ("SxspCreateDirectories")
  18. -----------------------------------------------------------------------------*/
  19. {
  20. BOOL fSuccess = FALSE;
  21. FN_TRACE_WIN32(fSuccess);
  22. CStringBuffer strBuffer;
  23. DWORD dwAttribs = 0;
  24. PARAMETER_CHECK(pszDirectory != NULL);
  25. PARAMETER_CHECK(cchDirectory != 0);
  26. IFW32FALSE_EXIT(strBuffer.Win32Assign(pszDirectory, cchDirectory));
  27. //::CreateDirectoryW will do the wrong thing if strBuffer has a trailing slash,
  28. //so we'll strip it off if it's there. (see bug VS7:31319) [MSantoro]
  29. strBuffer.RemoveTrailingPathSeparators();
  30. // cover the two common cases of its parent exists or it exists
  31. if ((!::CreateDirectoryW(strBuffer, NULL)) && (::FusionpGetLastWin32Error() != ERROR_ALREADY_EXISTS))
  32. {
  33. CStringBufferAccessor sbaBuffer;
  34. // now the slow path
  35. //
  36. // Try to create the subdirectories (if any) named in the path.
  37. //
  38. sbaBuffer.Attach(&strBuffer);
  39. WCHAR* pStart = sbaBuffer.GetBufferPtr();
  40. WCHAR* pCurr = pStart;
  41. // skip the leading drive or \\computer\share
  42. // this way we don't try to create C: in trying to create C:\
  43. // or \\computer\share in trying to create \\computer\share\dir
  44. // FUTURE This is not ideal.. (need NVseeLibPath)
  45. if (pCurr[0] != 0)
  46. {
  47. const static WCHAR rgchAZaz[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  48. C_ASSERT(NUMBER_OF(rgchAZaz) == 53);
  49. if ((pCurr[1] == L':') &&
  50. CUnicodeCharTraits::IsPathSeparator(pCurr[2]) &&
  51. (wcschr(rgchAZaz, pCurr[0]) != NULL))
  52. {
  53. pCurr += 3;
  54. }
  55. else if (CUnicodeCharTraits::IsPathSeparator(pCurr[0]) &&
  56. CUnicodeCharTraits::IsPathSeparator(pCurr[1]))
  57. {
  58. // skip to after the share, since we presumably can't create shares with CreateDirectory
  59. pCurr += wcsspn(pCurr, CUnicodeCharTraits::PathSeparators()); // skip leading two slashes
  60. pCurr += wcscspn(pCurr, CUnicodeCharTraits::PathSeparators()); // skip computer name
  61. pCurr += wcsspn(pCurr, CUnicodeCharTraits::PathSeparators()); // skip slashes after computer name
  62. pCurr += wcscspn(pCurr, CUnicodeCharTraits::PathSeparators()); // skip share name
  63. pCurr += wcsspn(pCurr, CUnicodeCharTraits::PathSeparators()); // skip slashes after share name
  64. }
  65. }
  66. while (*pCurr != L'\0')
  67. {
  68. pCurr += wcscspn(pCurr, CUnicodeCharTraits::PathSeparators()); // skip to next slash
  69. if (*pCurr != 0)
  70. {
  71. // [a-JayK April 2000] Why not just assume it's a backslash?
  72. WCHAR chSaved = *pCurr;
  73. *pCurr = 0;
  74. if (!::CreateDirectoryW(pStart, NULL))
  75. {
  76. // In trying to create c:\foo\bar,
  77. // we try to create c:\foo, which fails, but is ok.
  78. const DWORD dwLastError = ::FusionpGetLastWin32Error();
  79. const DWORD dwAttribs = ::GetFileAttributesW(pStart);
  80. if (dwAttribs == 0xFFFFFFFF || (dwAttribs & FILE_ATTRIBUTE_DIRECTORY) == 0)
  81. {
  82. ::SetLastError(dwLastError);
  83. goto Exit;
  84. }
  85. }
  86. *pCurr = chSaved;
  87. pCurr += 1;
  88. }
  89. }
  90. IFW32FALSE_ORIGINATE_AND_EXIT(::CreateDirectoryW(pStart, NULL));
  91. }
  92. //
  93. // Try again to see if the given directory exists and
  94. // return true if successful.
  95. //
  96. dwAttribs = ::GetFileAttributesW(strBuffer);
  97. if ((dwAttribs == 0xFFFFFFFF) || ((dwAttribs & FILE_ATTRIBUTE_DIRECTORY) == 0))
  98. goto Exit;
  99. fSuccess = TRUE;
  100. Exit:
  101. return fSuccess;
  102. }
  103. VOID
  104. CFusionDirectoryDifference::DbgPrint(
  105. PCWSTR dir1,
  106. PCWSTR dir2
  107. )
  108. {
  109. #if DBG // { {
  110. switch (m_e)
  111. {
  112. case eEqual:
  113. ::FusionpDbgPrintEx(
  114. FUSION_DBG_LEVEL_ERROR,
  115. "SXS.DLL: The directories %ls and %ls match size-wise recursively\n",
  116. dir1,
  117. dir2);
  118. break;
  119. case eExtraOrMissingFile:
  120. ::FusionpDbgPrintEx(
  121. FUSION_DBG_LEVEL_ERROR,
  122. "SXS.DLL: The directories %ls and %ls mismatch, the file %ls is only in one of them.\n",
  123. dir1,
  124. dir2,
  125. static_cast<PCWSTR>(*m_pstrExtraOrMissingFile));
  126. break;
  127. case eMismatchedFileSize:
  128. ::FusionpDbgPrintEx(
  129. FUSION_DBG_LEVEL_ERROR,
  130. "SXS.DLL: The directories %ls and %ls mismatch, file:%ls, size:%I64d, file:%ls, size:%I64d.\n",
  131. dir1,
  132. dir2,
  133. static_cast<PCWSTR>(*m_pstrMismatchedSizeFile1),
  134. m_nMismatchedFileSize1,
  135. static_cast<PCWSTR>(*m_pstrMismatchedSizeFile2),
  136. m_nMismatchedFileSize2);
  137. break;
  138. case eMismatchedFileCount:
  139. ::FusionpDbgPrintEx(
  140. FUSION_DBG_LEVEL_ERROR,
  141. "SXS.DLL: The directories %ls and %ls mismatch in number of files,"
  142. "subdirectory %ls has %I64d files, subdirectory %ls has %I64d files\n",
  143. dir1,
  144. dir2,
  145. static_cast<PCWSTR>(*m_pstrMismatchedCountDir1),
  146. m_nMismatchedFileCount1,
  147. static_cast<PCWSTR>(*m_pstrMismatchedCountDir2),
  148. m_nMismatchedFileCount2);
  149. break;
  150. case eFileDirectoryMismatch:
  151. ::FusionpDbgPrintEx(
  152. FUSION_DBG_LEVEL_ERROR,
  153. "SXS.DLL: The directories %ls and %ls mismatch, "
  154. "%ls is a file, %ls is a directory.\n",
  155. dir1,
  156. dir2,
  157. static_cast<PCWSTR>(*m_pstrFile),
  158. static_cast<PCWSTR>(*m_pstrDirectory));
  159. break;
  160. }
  161. #endif // } }
  162. }
  163. /*-----------------------------------------------------------------------------*/
  164. int __cdecl
  165. CFusionFilePathAndSize::QsortComparePath(
  166. const void* pvx,
  167. const void* pvy
  168. )
  169. {
  170. const CFusionFilePathAndSize* px = reinterpret_cast<const CFusionFilePathAndSize*>(pvx);
  171. const CFusionFilePathAndSize* py = reinterpret_cast<const CFusionFilePathAndSize*>(pvy);
  172. int i =
  173. ::FusionpCompareStrings(
  174. px->m_path,
  175. px->m_path.Cch(),
  176. py->m_path,
  177. py->m_path.Cch(),
  178. TRUE);
  179. return i;
  180. }
  181. int __cdecl
  182. CFusionFilePathAndSize::QsortIndirectComparePath(
  183. const void* ppvx,
  184. const void* ppvy
  185. )
  186. {
  187. const void* pv = *reinterpret_cast<void const* const*>(ppvx);
  188. const void* py = *reinterpret_cast<void const* const*>(ppvy);
  189. int i = QsortComparePath(pv, py);
  190. return i;
  191. }
  192. /*-----------------------------------------------------------------------------
  193. See FusionpCompareDirectoriesSizewiseRecursively for what this does;
  194. this function exists to reduce the stack usage of
  195. FusionpCompareDirectoriesSizewiseRecursively.
  196. -----------------------------------------------------------------------------*/
  197. static BOOL
  198. FusionpCompareDirectoriesSizewiseRecursivelyHelper(
  199. CFusionDirectoryDifference *pResult,
  200. CBaseStringBuffer &rdir1,
  201. CBaseStringBuffer &rdir2,
  202. WIN32_FIND_DATAW &rwfd
  203. )
  204. {
  205. BOOL fSuccess = FALSE;
  206. FN_TRACE_WIN32(fSuccess);
  207. // either or both directories can be on FAT, we can't assume that FindFirstFile
  208. // returns entries in any particular order, so we first enumerate one directory
  209. // entirely, storing the leaf names in an array, sort the array, then
  210. // walk the second directory doing a binary search in the first array
  211. // if the file is not in the array, we have an extra on one side
  212. // we count the elements in both directories, if the counts don't match,
  213. // we have a mismatch
  214. typedef CFusionArray<CFusionFilePathAndSize> CDirEntries;
  215. CDirEntries dir1Entries;
  216. typedef CFusionArray<CFusionFilePathAndSize*> CIndirectDirEntries;
  217. CIndirectDirEntries indirectDir1Entries;
  218. CFusionFilePathAndSize* pFoundDirEntry = NULL;
  219. CFusionFilePathAndSize** ppFoundDirEntry = NULL;
  220. CFindFile findFile;
  221. const SIZE_T dirSlash1Length = rdir1.Cch();
  222. const SIZE_T dirSlash2Length = rdir2.Cch();
  223. CFusionFilePathAndSize pathAndSize;
  224. CFusionFilePathAndSize* pPathAndSize = &pathAndSize;
  225. INT count1 = 0; // seperate from the array, because this includes directories, and the array does not
  226. INT count2 = 0;
  227. DWORD dwAttributes = 0;
  228. IFW32FALSE_EXIT(rdir1.Win32Append(L"*", 1));
  229. IFW32FALSE_EXIT(findFile.Win32FindFirstFile(rdir1, &rwfd));
  230. do
  231. {
  232. if (FusionpIsDotOrDotDot(rwfd.cFileName))
  233. continue;
  234. ++count1;
  235. if ((rwfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  236. {
  237. rdir1.Left(dirSlash1Length);
  238. rdir2.Left(dirSlash2Length);
  239. IFW32FALSE_EXIT(rdir1.Win32Append(rwfd.cFileName, ::wcslen(rwfd.cFileName)));
  240. IFW32FALSE_EXIT(rdir1.Win32EnsureTrailingPathSeparator());
  241. IFW32FALSE_EXIT(rdir2.Win32Append(rwfd.cFileName, ::wcslen(rwfd.cFileName)));
  242. dwAttributes = GetFileAttributesW(rdir2);
  243. if (dwAttributes == 0xFFFFFFFF)
  244. {
  245. IFW32FALSE_EXIT(pResult->m_str1.Win32Assign(rdir1, dirSlash1Length));
  246. IFW32FALSE_EXIT(pResult->m_str1.Win32Append(rwfd.cFileName, ::wcslen(rwfd.cFileName)));
  247. pResult->m_e = CFusionDirectoryDifference::eExtraOrMissingFile;
  248. fSuccess = TRUE;
  249. goto Exit;
  250. }
  251. if ((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  252. {
  253. SIZE_T cchTemp = ::wcslen(rwfd.cFileName);
  254. IFW32FALSE_EXIT(pResult->m_pstrDirectory->Win32Assign(rdir1, dirSlash1Length));
  255. IFW32FALSE_EXIT(pResult->m_pstrDirectory->Win32Append(rwfd.cFileName, cchTemp));
  256. IFW32FALSE_EXIT(pResult->m_pstrFile->Win32Assign(rdir2, dirSlash2Length));
  257. IFW32FALSE_EXIT(pResult->m_pstrFile->Win32Append(rwfd.cFileName, cchTemp));
  258. pResult->m_e = CFusionDirectoryDifference::eFileDirectoryMismatch;
  259. fSuccess = TRUE;
  260. goto Exit;
  261. }
  262. IFW32FALSE_EXIT(rdir2.Win32EnsureTrailingPathSeparator());
  263. IFW32FALSE_EXIT(
  264. ::FusionpCompareDirectoriesSizewiseRecursivelyHelper(
  265. pResult,
  266. rdir1,
  267. rdir2,
  268. rwfd));
  269. if (pResult->m_e != CFusionDirectoryDifference::eEqual)
  270. {
  271. fSuccess = TRUE;
  272. goto Exit;
  273. }
  274. }
  275. else
  276. {
  277. IFW32FALSE_EXIT(pathAndSize.m_path.Win32Assign(rwfd.cFileName, ::wcslen(rwfd.cFileName)));
  278. pathAndSize.m_size = ::FusionpFileSizeFromFindData(rwfd);
  279. IFW32FALSE_EXIT(dir1Entries.Win32Append(pathAndSize));
  280. }
  281. } while (FindNextFileW(findFile, &rwfd));
  282. if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_FILES)
  283. {
  284. goto Exit;
  285. }
  286. // dir1Entries cannot be sorted directly because it contains CStringBuffers.
  287. // first initialize the index to be an identity
  288. IFW32FALSE_EXIT(indirectDir1Entries.Win32SetSize(dir1Entries.GetSize()));
  289. ULONG i;
  290. for (i = 0 ; i != dir1Entries.GetSize() ; ++i)
  291. {
  292. indirectDir1Entries[i] = &dir1Entries[i];
  293. }
  294. qsort(
  295. &*indirectDir1Entries.Begin(),
  296. indirectDir1Entries.GetSize(),
  297. sizeof(CIndirectDirEntries::ValueType),
  298. CFusionFilePathAndSize::QsortIndirectComparePath);
  299. IFW32FALSE_EXIT(findFile.Win32Close());
  300. rdir2.Left(dirSlash2Length);
  301. IFW32FALSE_EXIT(rdir2.Win32Append(L"*", 1));
  302. IFW32FALSE_EXIT(findFile.Win32FindFirstFile(rdir2, &rwfd));
  303. do
  304. {
  305. if (::FusionpIsDotOrDotDot(rwfd.cFileName))
  306. continue;
  307. ++count2;
  308. if ((rwfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  309. continue;
  310. IFW32FALSE_EXIT(pathAndSize.m_path.Win32Assign(rwfd.cFileName, ::wcslen(rwfd.cFileName)));
  311. pathAndSize.m_size = ::FusionpFileSizeFromFindData(rwfd);
  312. ppFoundDirEntry = reinterpret_cast<CFusionFilePathAndSize**>(::bsearch(
  313. &pPathAndSize,
  314. &*indirectDir1Entries.Begin(),
  315. indirectDir1Entries.GetSize(),
  316. sizeof(CIndirectDirEntries::ValueType),
  317. CFusionFilePathAndSize::QsortIndirectComparePath));
  318. pFoundDirEntry = (ppFoundDirEntry != NULL) ? *ppFoundDirEntry : NULL;
  319. if (pFoundDirEntry == NULL)
  320. {
  321. IFW32FALSE_EXIT(pResult->m_str1.Win32Assign(rdir2, dirSlash2Length));
  322. IFW32FALSE_EXIT(pResult->m_str1.Win32Append(rwfd.cFileName, ::wcslen(rwfd.cFileName)));
  323. pResult->m_e = CFusionDirectoryDifference::eExtraOrMissingFile;
  324. fSuccess = TRUE;
  325. goto Exit;
  326. }
  327. if (pFoundDirEntry->m_size != pathAndSize.m_size)
  328. {
  329. SIZE_T cchTemp = ::wcslen(rwfd.cFileName);
  330. IFW32FALSE_EXIT(pResult->m_str1.Win32Assign(rdir1, dirSlash1Length));
  331. IFW32FALSE_EXIT(pResult->m_str1.Win32Append(rwfd.cFileName, cchTemp));
  332. pResult->m_nMismatchedFileSize1 = pFoundDirEntry->m_size;
  333. IFW32FALSE_EXIT(pResult->m_str2.Win32Assign(rdir2, dirSlash2Length));
  334. IFW32FALSE_EXIT(pResult->m_str2.Win32Append(rwfd.cFileName, cchTemp));
  335. pResult->m_nMismatchedFileSize2 = pathAndSize.m_size;
  336. pResult->m_e = CFusionDirectoryDifference::eMismatchedFileSize;
  337. fSuccess = TRUE;
  338. goto Exit;
  339. }
  340. } while (::FindNextFileW(findFile, &rwfd));
  341. if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_FILES)
  342. goto Exit;
  343. if (count1 != count2)
  344. {
  345. IFW32FALSE_EXIT(pResult->m_str1.Win32Assign(rdir1, dirSlash1Length - 1));
  346. IFW32FALSE_EXIT(pResult->m_str2.Win32Assign(rdir2, dirSlash2Length - 1));
  347. pResult->m_nMismatchedFileCount1 = count1;
  348. pResult->m_nMismatchedFileCount2 = count2;
  349. pResult->m_e = CFusionDirectoryDifference::eMismatchedFileCount;
  350. fSuccess = TRUE;
  351. goto Exit;
  352. }
  353. IFW32FALSE_EXIT(findFile.Win32Close());
  354. pResult->m_e = CFusionDirectoryDifference::eEqual;
  355. fSuccess = TRUE;
  356. Exit:
  357. // restore the paths for our caller
  358. rdir1.Left(dirSlash1Length);
  359. rdir2.Left(dirSlash2Length);
  360. return fSuccess;
  361. }
  362. /*-----------------------------------------------------------------------------
  363. walk dirSlash1 and dirSlash2 recursively
  364. for each file in either tree, see if it is in the other tree
  365. at the same analogous position, and has the same size
  366. if all files are present in both trees, no extra in either tree,
  367. all with same size, return true
  368. if any files are in one tree but not the other, or vice versa, or any
  369. sizes mis match, return false
  370. the algorithm short circuits
  371. but it also does a depth first recursion
  372. -----------------------------------------------------------------------------*/
  373. BOOL
  374. FusionpCompareDirectoriesSizewiseRecursively(
  375. CFusionDirectoryDifference* pResult,
  376. const CBaseStringBuffer &rdir1,
  377. const CBaseStringBuffer &rdir2
  378. )
  379. {
  380. BOOL fSuccess = FALSE;
  381. FN_TRACE_WIN32(fSuccess);
  382. // only hog one stack frame with these large variables, rather than
  383. // putting them in the recursive function
  384. WIN32_FIND_DATAW wfd = {0};
  385. CStringBuffer mutableDir1;
  386. CStringBuffer mutableDir2;
  387. pResult->m_e = pResult->eEqual;
  388. IFW32FALSE_EXIT(mutableDir1.Win32Assign(rdir1, rdir1.Cch()));
  389. IFW32FALSE_EXIT(mutableDir1.Win32EnsureTrailingPathSeparator());
  390. IFW32FALSE_EXIT(mutableDir2.Win32Assign(rdir2, rdir2.Cch()));
  391. IFW32FALSE_EXIT(mutableDir2.Win32EnsureTrailingPathSeparator());
  392. // if either directory is a subdirectory of the other,
  393. // (or a subdir of a subdir, any generation descendant)
  394. // return an error; we could also interpret this as unequal,
  395. // since they can't be equal, or we could do the comparison
  396. // but not recurse on the subdir that is also a root;
  397. //
  398. // must do this check after the slashes are in place, because
  399. // "c:\food" is not a subdir of "c:\foo", but "c:\foo\d" is a subdir of "c:\foo\"
  400. // (quotes avoid backslash line continuation)
  401. PARAMETER_CHECK(_wcsnicmp(mutableDir1, mutableDir2, mutableDir1.Cch()) != 0);
  402. PARAMETER_CHECK(_wcsnicmp(mutableDir1, mutableDir2, mutableDir2.Cch()) != 0);
  403. IFW32FALSE_EXIT(
  404. ::FusionpCompareDirectoriesSizewiseRecursivelyHelper(
  405. pResult,
  406. mutableDir1,
  407. mutableDir2,
  408. wfd));
  409. fSuccess = TRUE;
  410. Exit:
  411. return fSuccess;
  412. }
  413. static BOOL
  414. IsStarOrStarDotStar(
  415. PCWSTR str
  416. )
  417. {
  418. return (str[0] == '*'
  419. && (str[1] == 0 || (str[1] == '.' && str[2] == '*' && str[3] == 0)));
  420. }
  421. CDirWalk::ECallbackResult
  422. CDirWalk::WalkHelper(
  423. )
  424. {
  425. #if DBG
  426. #define SET_LINE() Line = __LINE__
  427. ULONG Line = 0;
  428. #else
  429. #define SET_LINE() /* nothing */
  430. #endif
  431. const PCWSTR* fileFilter = NULL;
  432. BOOL fGotAll = FALSE;
  433. BOOL fThisIsAll = FALSE;
  434. CFindFile hFind;
  435. SIZE_T directoryLength = m_strParent.Cch();
  436. ECallbackResult result = eKeepWalking;
  437. DWORD dwWalkDirFlags = 0;
  438. ::ZeroMemory(&m_fileData, sizeof(m_fileData));
  439. result |= m_callback(eBeginDirectory, this, dwWalkDirFlags);
  440. if (result & (eError | eSuccess))
  441. {
  442. SET_LINE();
  443. goto Exit;
  444. }
  445. if ((result & eStopWalkingFiles) == 0)
  446. {
  447. for (fileFilter = m_fileFiltersBegin ; fileFilter != m_fileFiltersEnd ; ++fileFilter)
  448. {
  449. //
  450. // FindFirstFile equates *.* with *, so we do too.
  451. //
  452. fThisIsAll = ::IsStarOrStarDotStar(*fileFilter);
  453. fGotAll = fGotAll || fThisIsAll;
  454. if (!m_strParent.Win32EnsureTrailingPathSeparator())
  455. goto Error;
  456. if (!m_strParent.Win32Append(*fileFilter, (*fileFilter != NULL) ? ::wcslen(*fileFilter) : 0))
  457. goto Error;
  458. hFind = ::FindFirstFileW(m_strParent, &m_fileData);
  459. m_strParent.Left(directoryLength);
  460. if (hFind != INVALID_HANDLE_VALUE)
  461. {
  462. do
  463. {
  464. if (::FusionpIsDotOrDotDot(m_fileData.cFileName))
  465. continue;
  466. if (!m_strLastObjectFound.Win32Assign(m_fileData.cFileName, ::wcslen(m_fileData.cFileName)))
  467. {
  468. SET_LINE();
  469. goto Error;
  470. }
  471. //
  472. // we recurse on directories only if we are getting all of them
  473. // otherwise we do them afterward
  474. //
  475. // the order directories are visited is therefore inconsistent, but
  476. // most applications should be happy enough with the eEndDirectory
  477. // notification (to implement rd /q/s)
  478. //
  479. if (m_fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  480. {
  481. if (fThisIsAll && (result & eStopWalkingDirectories) == 0)
  482. {
  483. if (!m_strParent.Win32Append("\\", 1))
  484. {
  485. SET_LINE();
  486. goto Error;
  487. }
  488. if (!m_strParent.Win32Append(m_fileData.cFileName, ::wcslen(m_fileData.cFileName)))
  489. {
  490. SET_LINE();
  491. goto Error;
  492. }
  493. result |= WalkHelper();
  494. }
  495. }
  496. else
  497. {
  498. if ((result & eStopWalkingFiles) == 0)
  499. {
  500. dwWalkDirFlags |= SXSP_DIR_WALK_FLAGS_FIND_AT_LEAST_ONE_FILEUNDER_CURRENTDIR;
  501. result |= m_callback(eFile, this, dwWalkDirFlags);
  502. if(result == (eStopWalkingFiles | eStopWalkingDirectories))
  503. dwWalkDirFlags |= SXSP_DIR_WALK_FLAGS_INSTALL_ASSEMBLY_UNDER_CURRECTDIR_SUCCEED;
  504. }
  505. }
  506. m_strParent.Left(directoryLength);
  507. if (result & (eError | eSuccess))
  508. {
  509. SET_LINE();
  510. goto Exit;
  511. }
  512. if (fThisIsAll)
  513. {
  514. if ((result & eStopWalkingDirectories) &&
  515. (result & eStopWalkingFiles))
  516. {
  517. if (!hFind.Win32Close())
  518. {
  519. SET_LINE();
  520. goto Error;
  521. }
  522. SET_LINE();
  523. goto StopWalking;
  524. }
  525. }
  526. else
  527. {
  528. if (result & eStopWalkingFiles)
  529. {
  530. if (!hFind.Win32Close())
  531. {
  532. SET_LINE();
  533. goto Error;
  534. }
  535. SET_LINE();
  536. goto StopWalking;
  537. }
  538. }
  539. } while(::FindNextFileW(hFind, &m_fileData));
  540. if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_FILES)
  541. {
  542. SET_LINE();
  543. goto Error;
  544. }
  545. if (!hFind.Win32Close())
  546. {
  547. SET_LINE();
  548. goto Error;
  549. }
  550. }
  551. }
  552. }
  553. StopWalking:;
  554. //
  555. // make another pass with * to get all directories, if we haven't already
  556. //
  557. if (!fGotAll && (result & eStopWalkingDirectories) == 0)
  558. {
  559. if (!m_strParent.Win32Append("\\*", 2))
  560. {
  561. SET_LINE();
  562. goto Error;
  563. }
  564. hFind = ::FindFirstFileW(m_strParent, &m_fileData);
  565. m_strParent.Left(directoryLength);
  566. if (hFind != INVALID_HANDLE_VALUE)
  567. {
  568. do
  569. {
  570. if (::FusionpIsDotOrDotDot(m_fileData.cFileName))
  571. continue;
  572. if (m_strLastObjectFound.Win32Assign(m_fileData.cFileName, ::wcslen(m_fileData.cFileName)))
  573. {
  574. SET_LINE();
  575. goto Error;
  576. }
  577. if ((m_fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  578. continue;
  579. if (!m_strParent.Win32Append("\\", 1))
  580. {
  581. SET_LINE();
  582. goto Error;
  583. }
  584. if (!m_strParent.Win32Append(m_fileData.cFileName, ::wcslen(m_fileData.cFileName)))
  585. {
  586. SET_LINE();
  587. goto Error;
  588. }
  589. result |= WalkHelper();
  590. m_strParent.Left(directoryLength);
  591. if (result & (eError | eSuccess))
  592. {
  593. SET_LINE();
  594. goto Exit;
  595. }
  596. if (result & eStopWalkingDirectories)
  597. {
  598. SET_LINE();
  599. goto StopWalkingDirs;
  600. }
  601. } while(::FindNextFileW(hFind, &m_fileData));
  602. if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_FILES)
  603. {
  604. SET_LINE();
  605. goto Error;
  606. }
  607. StopWalkingDirs:
  608. if (!hFind.Win32Close())
  609. {
  610. SET_LINE();
  611. goto Error;
  612. }
  613. }
  614. }
  615. ::ZeroMemory(&m_fileData, sizeof(m_fileData));
  616. result |= m_callback(eEndDirectory, this, dwWalkDirFlags);
  617. if (result & (eError | eSuccess))
  618. {
  619. SET_LINE();
  620. goto Exit;
  621. }
  622. result = eKeepWalking;
  623. Exit:
  624. if ((result & eStopWalkingDeep) == 0)
  625. {
  626. result &= ~(eStopWalkingFiles | eStopWalkingDirectories);
  627. }
  628. if (result & eError)
  629. {
  630. result |= (eStopWalkingFiles | eStopWalkingDirectories | eStopWalkingDeep);
  631. #if DBG
  632. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "%s(%lu): %s\n", __FILE__, Line, __FUNCTION__);
  633. #endif
  634. }
  635. return result;
  636. Error:
  637. result |= eError;
  638. goto Exit;
  639. #undef SET_LINE
  640. }
  641. CDirWalk::CDirWalk()
  642. {
  643. const static PCWSTR defaultFileFilter[] = { L"*" };
  644. m_fileFiltersBegin = defaultFileFilter;
  645. m_fileFiltersEnd = defaultFileFilter + NUMBER_OF(defaultFileFilter);
  646. }
  647. BOOL
  648. CDirWalk::Walk()
  649. {
  650. BOOL fSuccess = FALSE;
  651. //
  652. // Save off the original path length before we go twiddling m_strParent
  653. //
  654. m_cchOriginalPath = m_strParent.Cch();
  655. ECallbackResult result = WalkHelper();
  656. if (result & eError)
  657. {
  658. if (::FusionpGetLastWin32Error() == ERROR_SUCCESS) // forget to set lasterror ?
  659. ::SetLastError(ERROR_INSTALL_FAILURE);
  660. goto Exit;
  661. }
  662. fSuccess = TRUE;
  663. Exit:
  664. return fSuccess;
  665. }