Leaked source code of windows server 2003
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.

2477 lines
78 KiB

  1. //*************************************************************
  2. //
  3. // Functions to copy the profile directory
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1995
  7. // All rights reserved
  8. //
  9. //*************************************************************
  10. #include "uenv.h"
  11. #include "strsafe.h"
  12. //
  13. // Local function proto-types
  14. //
  15. BOOL RecurseDirectory (HANDLE hTokenUser, LPTSTR lpSrcDir, DWORD cchSrcDir, LPTSTR lpDestDir, DWORD cchDestDir,
  16. DWORD dwFlags, LPFILEINFO *llSrcDirs, LPFILEINFO *llSrcFiles,
  17. BOOL bSkipNtUser, LPTSTR lpExcludeList, BOOL bRecurseDest);
  18. BOOL AddFileInfoNode (LPFILEINFO *lpFileInfo, LPTSTR lpSrcFile,
  19. LPTSTR lpDestFile, LPFILETIME ftLastWrite, LPFILETIME ftCreate,
  20. DWORD dwFileSize, DWORD dwFileAttribs, BOOL bHive);
  21. BOOL FreeFileInfoList (LPFILEINFO lpFileInfo);
  22. BOOL SyncItems (LPFILEINFO lpSrcItems, LPFILEINFO lpDestItems,
  23. BOOL bFile, LPFILETIME ftDelRefTime);
  24. void CopyFileFunc (LPTHREADINFO lpThreadInfo);
  25. LPTSTR ConvertExclusionList (LPCTSTR lpSourceDir, LPCTSTR lpExclusionList);
  26. DWORD FindDirectorySize(LPTSTR lpDir, LPFILEINFO lpFiles, DWORD dwFlags, DWORD* pdwLargestHiveFile, DWORD* pdwTotalFiles);
  27. DWORD FindTotalDiskSpaceNeeded(DWORD dwTotalSrcFiles,
  28. DWORD dwTotalDestFiles,
  29. DWORD dwLargestHiveFile,
  30. LPFILEINFO lpSrcFiles,
  31. DWORD dwFlags);
  32. DWORD FindTotalNMaxFileSize(LPFILEINFO lpSrcFiles, DWORD dwNumOfFiles);
  33. BOOL ReconcileDirectory(LPTSTR lpSrcDir, LPTSTR lpDestDir,
  34. DWORD dwFlags, DWORD dwSrcAttribs);
  35. //*************************************************************
  36. //
  37. // CopyProfileDirectoryEx()
  38. //
  39. // Purpose: Copies the profile directory from the source
  40. // to the destination
  41. //
  42. //
  43. // Parameters: LPCTSTR lpSourceDir - Source directory
  44. // LPCTSTR lpDestDir - Destination directory
  45. // DWORD dwFlags - Flags
  46. // LPFILETIME ftDelRefTime - Delete file reference time
  47. // LPCTSTR lpExclusionList - List of directories to exclude
  48. //
  49. //
  50. // Return: (BOOL) TRUE if successful
  51. // FALSE if an error occurs
  52. //
  53. //
  54. // Comments: Called after impersonating the user.
  55. //
  56. //
  57. // History: Date Author Comment
  58. // 5/24/95 ericflo Created
  59. // 4/09/98 ericflo Converted to CopyProfileDirectoryEx
  60. // 9/28/98 ushaji Modified to check for free space
  61. // 3/14/00 weiruc Modified to copy hive file even if
  62. // hive is still loaded and ignore copy
  63. // hive file errors.
  64. //
  65. //*************************************************************
  66. BOOL CopyProfileDirectoryEx (LPCTSTR lpSourceDir,
  67. LPCTSTR lpDestinationDir,
  68. DWORD dwFlags,
  69. LPFILETIME ftDelRefTime,
  70. LPCTSTR lpExclusionList)
  71. {
  72. LPTSTR lpSrcDir = NULL, lpDestDir = NULL;
  73. LPTSTR lpSrcEnd, lpDestEnd;
  74. LPTSTR lpExcludeListSrc = NULL;
  75. LPTSTR lpExcludeListDest = NULL;
  76. LPFILEINFO lpSrcFiles = NULL, lpDestFiles = NULL;
  77. LPFILEINFO lpSrcDirs = NULL, lpDestDirs = NULL;
  78. LPFILEINFO lpTemp;
  79. THREADINFO ThreadInfo = {0, NULL, NULL, 0, NULL, NULL, NULL, NULL};
  80. DWORD dwThreadId;
  81. HANDLE hThreads[NUM_COPY_THREADS];
  82. HANDLE hStatusThread = 0;
  83. DWORD dwThreadCount = 0;
  84. HANDLE hFile;
  85. WIN32_FIND_DATA fd;
  86. BOOL bResult = FALSE;
  87. BOOL bSynchronize = FALSE;
  88. UINT i;
  89. DWORD dwTotalSrcFiles = 0;
  90. DWORD dwTotalDestFiles = 0;
  91. DWORD dwLargestHiveFile;
  92. DWORD dwTotalDiskSpaceNeeded;
  93. ULARGE_INTEGER ulFreeBytesAvailableToCaller, ulTotalNumberOfBytes, ulTotalNumberOfFreeBytes;
  94. DWORD dwErr, dwErr1=0;
  95. TCHAR szErr[MAX_PATH];
  96. TCHAR szTmpHive[MAX_PATH];
  97. BOOL bReconcileHiveSucceeded;
  98. HKEY hkCurrentUser = NULL;
  99. HANDLE hTokenUser = NULL;
  100. size_t cchSrc, cchDest;
  101. DWORD cchSrcEnd, cchDestEnd;
  102. HRESULT hr;
  103. dwErr = GetLastError();
  104. //
  105. // Validate parameters
  106. //
  107. if (!lpSourceDir || !lpDestinationDir) {
  108. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: received NULL pointer")));
  109. SetLastError(ERROR_INVALID_PARAMETER);
  110. return FALSE;
  111. }
  112. hr = StringCchLength((LPTSTR)lpSourceDir, MAX_PATH, &cchSrc);
  113. if (FAILED(hr))
  114. {
  115. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: invalid src dir")));
  116. SetLastError(HRESULT_CODE(hr));
  117. return FALSE;
  118. }
  119. hr = StringCchLength((LPTSTR)lpDestinationDir, MAX_PATH, &cchDest);
  120. if (FAILED(hr))
  121. {
  122. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: invalid dest dir")));
  123. SetLastError(HRESULT_CODE(hr));
  124. return FALSE;
  125. }
  126. //
  127. // Verbose output
  128. //
  129. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: Entering, lpSourceDir = <%s>, lpDestinationDir = <%s>, dwFlags = 0x%x"),
  130. lpSourceDir, lpDestinationDir, dwFlags));
  131. //
  132. // Get the caller's token
  133. //
  134. if (!OpenThreadToken (GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE, TRUE, &hTokenUser)) {
  135. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE, &hTokenUser)) {
  136. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: Fail to get process token with error %d."), GetLastError()));
  137. return FALSE;
  138. }
  139. }
  140. //
  141. // If there is an exclusion list, convert it into an array of null
  142. // terminate strings (double null at the end) based upon the source
  143. // directory
  144. //
  145. if ((dwFlags & CPD_USEEXCLUSIONLIST) && lpExclusionList) {
  146. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: lpExclusionList = <%s>"),
  147. lpExclusionList));
  148. lpExcludeListSrc = ConvertExclusionList (lpSourceDir, lpExclusionList);
  149. if (!lpExcludeListSrc) {
  150. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: Failed to convert exclusion list for source")));
  151. dwErr = ERROR_INVALID_DATA;
  152. goto Exit;
  153. }
  154. if (!(dwFlags & CPD_DELDESTEXCLUSIONS)) {
  155. lpExcludeListDest = ConvertExclusionList (lpDestinationDir, lpExclusionList);
  156. if (!lpExcludeListDest) {
  157. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: Failed to convert exclusion list for destination")));
  158. dwErr = ERROR_INVALID_DATA;
  159. goto Exit;
  160. }
  161. }
  162. }
  163. //
  164. // Get the desktop handle
  165. //
  166. ThreadInfo.hDesktop = GetThreadDesktop(GetCurrentThreadId());
  167. //
  168. // Is this a full sync copy (delete extra files / directories in dest).
  169. //
  170. if (dwFlags & CPD_SYNCHRONIZE) {
  171. bSynchronize = TRUE;
  172. }
  173. //
  174. // Test / Create the destination directory
  175. //
  176. if (!CreateNestedDirectory(lpDestinationDir, NULL)) {
  177. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: Failed to create the destination directory. Error = %d"),
  178. GetLastError()));
  179. dwErr = GetLastError();
  180. goto Exit;
  181. }
  182. //
  183. // Create and set up the directory buffers
  184. //
  185. cchSrc = cchDest = 2 * MAX_PATH;
  186. lpSrcDir = LocalAlloc(LPTR, cchSrc * sizeof(TCHAR));
  187. lpDestDir = LocalAlloc(LPTR, cchDest * sizeof(TCHAR));
  188. if (!lpSrcDir || !lpDestDir) {
  189. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: Failed to allocate memory for working directories")));
  190. dwErr = GetLastError();
  191. goto Exit;
  192. }
  193. StringCchCopy (lpSrcDir, cchSrc, lpSourceDir);
  194. StringCchCopy (lpDestDir, cchDest, lpDestinationDir);
  195. //
  196. // Setup ending pointers
  197. //
  198. lpSrcEnd = CheckSlashEx (lpSrcDir, cchSrc, &cchSrcEnd);
  199. lpDestEnd = CheckSlashEx (lpDestDir, cchDest, &cchDestEnd);
  200. //
  201. // Recurse through the folders gathering info
  202. //
  203. if (!(dwFlags & CPD_COPYHIVEONLY)) {
  204. //
  205. // Recurse the source directory
  206. //
  207. if (!RecurseDirectory(hTokenUser, lpSrcDir, cchSrc, lpDestDir, cchDest, dwFlags,
  208. &lpSrcDirs, &lpSrcFiles, TRUE, lpExcludeListSrc, FALSE)) {
  209. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: RecurseDirectory returned FALSE")));
  210. dwErr = GetLastError();
  211. goto Exit;
  212. }
  213. if (bSynchronize) {
  214. //
  215. // Recurse the destination directory
  216. //
  217. if (!RecurseDirectory(hTokenUser, lpDestDir, cchDest, lpSrcDir, cchSrc, dwFlags,
  218. &lpDestDirs, &lpDestFiles, TRUE, lpExcludeListDest, TRUE)) {
  219. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: RecurseDirectory returned FALSE")));
  220. dwErr = GetLastError();
  221. goto Exit;
  222. }
  223. }
  224. }
  225. //
  226. // determine the source and destination sizes
  227. //
  228. if(FindDirectorySize(lpSrcDir, lpSrcFiles, dwFlags, &dwLargestHiveFile, &dwTotalSrcFiles) != ERROR_SUCCESS) {
  229. DebugMsg((DM_WARNING, TEXT("FindDirectorySize: Error = %08x"), GetLastError()));
  230. dwErr = GetLastError();
  231. goto Exit;
  232. }
  233. if(FindDirectorySize(lpDestDir, lpDestFiles, dwFlags, NULL, &dwTotalDestFiles) != ERROR_SUCCESS) {
  234. DebugMsg((DM_WARNING, TEXT("FindDirectorySize: Error = %08x"), GetLastError()));
  235. dwErr = GetLastError();
  236. goto Exit;
  237. }
  238. //
  239. // determine the disk space needed
  240. //
  241. dwTotalDiskSpaceNeeded = FindTotalDiskSpaceNeeded(dwTotalSrcFiles,
  242. dwTotalDestFiles,
  243. dwLargestHiveFile,
  244. lpSrcFiles,
  245. dwFlags);
  246. //
  247. // CopyProfileDirectoryEx is called with impersonation on
  248. //
  249. if (!GetDiskFreeSpaceEx(lpDestDir, &ulFreeBytesAvailableToCaller, &ulTotalNumberOfBytes, &ulTotalNumberOfFreeBytes)) {
  250. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: Failed to get the Free Disk Space <%s>. Error = %d"),
  251. lpDestDir, GetLastError()));
  252. dwErr = GetLastError();
  253. goto Exit;
  254. }
  255. DebugMsg((DM_VERBOSE, TEXT("Available\t\t%d"), ulFreeBytesAvailableToCaller.QuadPart));
  256. DebugMsg((DM_VERBOSE, TEXT("Needed\t\t%d"), dwTotalDiskSpaceNeeded));
  257. DebugMsg((DM_VERBOSE, TEXT("Src size\t\t%d"), dwTotalSrcFiles));
  258. DebugMsg((DM_VERBOSE, TEXT("Dest size\t\t%d"), dwTotalDestFiles));
  259. DebugMsg((DM_VERBOSE, TEXT("Largest hive file\t\t%d"), dwLargestHiveFile));
  260. if(dwTotalDiskSpaceNeeded > ulFreeBytesAvailableToCaller.QuadPart) {
  261. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: Not enough disk space on <%s>"), lpDestDir));
  262. dwErr = ERROR_DISK_FULL;
  263. goto Exit;
  264. }
  265. //
  266. // Synchronize the directories and files if appropriate
  267. //
  268. if (bSynchronize) {
  269. //
  270. // Files first...
  271. //
  272. SyncItems (lpSrcFiles, lpDestFiles, TRUE,
  273. (dwFlags & CPD_USEDELREFTIME) ? ftDelRefTime : NULL);
  274. //
  275. // Now the directories...
  276. //
  277. SyncItems (lpSrcDirs, lpDestDirs, FALSE,
  278. (dwFlags & CPD_USEDELREFTIME) ? ftDelRefTime : NULL);
  279. }
  280. //
  281. // Copy the actual hive, log, ini files first
  282. //
  283. if (!(dwFlags & CPD_IGNOREHIVE)) {
  284. //
  285. // Search for all user hives
  286. //
  287. if (dwFlags & CPD_WIN95HIVE) {
  288. StringCchCopy (lpSrcEnd, cchSrcEnd, c_szUserStar);
  289. } else {
  290. StringCchCopy (lpSrcEnd, cchSrcEnd, c_szNTUserStar);
  291. }
  292. //
  293. // Enumerate
  294. //
  295. hFile = FindFirstFile(lpSrcDir, &fd);
  296. if (hFile != INVALID_HANDLE_VALUE) {
  297. do {
  298. //
  299. // Setup the filename
  300. //
  301. if((dwFlags & CPD_USETMPHIVEFILE) &&
  302. (lstrcmpi(fd.cFileName, c_szNTUserMan) == 0 ||
  303. lstrcmpi(fd.cFileName, c_szNTUserDat) == 0)) {
  304. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: Hive is still loaded, use temporary hive file")));
  305. //
  306. // Use temporary hive file because unloading hive failed.
  307. //
  308. StringCchCopy(lpSrcEnd, cchSrcEnd, c_szNTUserTmp);
  309. }
  310. else {
  311. StringCchCopy (lpSrcEnd, cchSrcEnd, fd.cFileName);
  312. }
  313. StringCchCopy (lpDestEnd, cchDestEnd, fd.cFileName);
  314. //
  315. // Do not reconcile the log file if we are using the tmp hive
  316. // file. Skip it.
  317. //
  318. if((dwFlags & CPD_USETMPHIVEFILE) &&
  319. lstrcmpi(fd.cFileName + lstrlen(fd.cFileName) - lstrlen(c_szLog), c_szLog) == 0) {
  320. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: Log file %s skipped"), lpDestDir));
  321. continue;
  322. }
  323. //
  324. // Skip the temporary hive file here. Will deal with it when
  325. // we find an actual hive file.
  326. //
  327. if(lstrcmpi(fd.cFileName, c_szNTUserTmp) == 0) {
  328. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: %s skipped"), fd.cFileName));
  329. continue;
  330. }
  331. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: Found hive file %s"), fd.cFileName));
  332. if(!ReconcileFile(lpSrcDir, lpDestDir, dwFlags, NULL,
  333. fd.nFileSizeLow, TRUE)) {
  334. dwErr1 = GetLastError();
  335. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: ReconcileFile failed with error = %d"), dwErr1));
  336. if (!(dwFlags & CPD_IGNORECOPYERRORS)) {
  337. dwErr = dwErr1;
  338. ReportError(hTokenUser,
  339. PI_NOUI,
  340. 3,
  341. EVENT_COPYERROR,
  342. lpSrcDir,
  343. lpDestDir,
  344. GetErrString(dwErr, szErr));
  345. FindClose(hFile);
  346. goto Exit;
  347. }
  348. else {
  349. ReportError(hTokenUser,
  350. PI_NOUI | EVENT_WARNING_TYPE,
  351. 3,
  352. EVENT_COPYERROR,
  353. lpSrcDir,
  354. lpDestDir,
  355. GetErrString(dwErr1, szErr));
  356. }
  357. }
  358. //
  359. // Find the next entry
  360. //
  361. } while (FindNextFile(hFile, &fd));
  362. FindClose(hFile);
  363. dwErr = ERROR_SUCCESS;
  364. } else {
  365. dwErr = GetLastError();
  366. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: FindFirstFile failed to find a hive!. Error = %d"),
  367. dwErr));
  368. }
  369. }
  370. //
  371. // Create all the directories
  372. //
  373. if (!(dwFlags & CPD_COPYHIVEONLY)) {
  374. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: Calling ReconcileDirectory for all Directories")));
  375. lpTemp = lpSrcDirs;
  376. while (lpTemp) {
  377. if (!ReconcileDirectory(lpTemp->szSrc, lpTemp->szDest, dwFlags, lpTemp->dwFileAttribs)) {
  378. dwErr1 = GetLastError();
  379. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: Failed to create the destination directory <%s>. Error = %d"),
  380. lpTemp->szDest, GetLastError()));
  381. if (!(dwFlags & CPD_IGNORECOPYERRORS)) {
  382. //
  383. // Show the error UI and bail out.
  384. //
  385. ReportError(hTokenUser, ((dwFlags & CPD_NOERRORUI)? PI_NOUI:0), 3, EVENT_COPYERROR,
  386. lpTemp->szSrc, lpTemp->szDest, GetErrString(dwErr1, szErr));
  387. dwErr = dwErr1;
  388. goto Exit;
  389. }
  390. else {
  391. ReportError(hTokenUser, PI_NOUI | EVENT_WARNING_TYPE, 3, EVENT_COPYERROR,
  392. lpTemp->szSrc, lpTemp->szDest, GetErrString(dwErr1, szErr));
  393. }
  394. }
  395. lpTemp = lpTemp->pNext;
  396. }
  397. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: Reconcile Directory Done for all Directories")));
  398. //
  399. // Copy the files
  400. //
  401. if (dwFlags & CPD_SLOWCOPY) {
  402. //
  403. // Copy the files one at a time...
  404. //
  405. lpTemp = lpSrcFiles;
  406. while (lpTemp) {
  407. if (lpTemp->bHive) {
  408. //
  409. // Hive files have already been copied..
  410. //
  411. lpTemp = lpTemp->pNext;
  412. continue;
  413. }
  414. if (!ReconcileFile (lpTemp->szSrc, lpTemp->szDest, dwFlags,
  415. &lpTemp->ftLastWrite,
  416. lpTemp->dwFileSize, FALSE)) {
  417. dwErr1 = GetLastError();
  418. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: Failed to copy the file <%s> to <%s> due to error = %d"),
  419. lpTemp->szSrc, lpTemp->szDest, GetLastError()));
  420. if (!(dwFlags & CPD_IGNORECOPYERRORS)) {
  421. //
  422. // Show the error UI and since the user picks to abort
  423. // then we leave now.
  424. //
  425. ReportError(hTokenUser, ((dwFlags & CPD_NOERRORUI)? PI_NOUI:0), 3, EVENT_COPYERROR,
  426. lpTemp->szSrc, lpTemp->szDest, GetErrString(dwErr1, szErr));
  427. dwErr = dwErr1;
  428. goto Exit;
  429. }
  430. else {
  431. ReportError(hTokenUser, PI_NOUI | EVENT_WARNING_TYPE, 3, EVENT_COPYERROR,
  432. lpTemp->szSrc, lpTemp->szDest, GetErrString(dwErr1, szErr));
  433. }
  434. }
  435. lpTemp = lpTemp->pNext;
  436. }
  437. } else {
  438. if (lpSrcFiles) {
  439. HANDLE hThreadToken=NULL;
  440. if (!OpenThreadToken (GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE,
  441. TRUE, &hThreadToken)) {
  442. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: Failed to get token with %d. This is ok if thread is not impersonating"),
  443. GetLastError()));
  444. }
  445. //
  446. // Multi-threaded copy
  447. //
  448. // Null sd, auto set, initially signalled, unnamed..
  449. if (!(ThreadInfo.hCopyEvent = CreateEvent(NULL, FALSE, TRUE, NULL))) {
  450. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: CreateEvent for CopyEvent failed with error %d"), GetLastError()));
  451. dwErr = GetLastError();
  452. goto Exit;
  453. }
  454. ThreadInfo.dwFlags = dwFlags;
  455. ThreadInfo.lpSrcFiles = lpSrcFiles;
  456. ThreadInfo.hTokenUser = hTokenUser;
  457. //
  458. // Required for PrivCopyFileEx to work, threads should be created using the
  459. // process token
  460. //
  461. RevertToSelf();
  462. //
  463. // Create the file copy threads
  464. //
  465. for (i = 0; i < NUM_COPY_THREADS; i++) {
  466. if (hThreads[dwThreadCount] = CreateThread (NULL,
  467. 0,
  468. (LPTHREAD_START_ROUTINE) CopyFileFunc,
  469. (LPVOID) &ThreadInfo,
  470. CREATE_SUSPENDED,
  471. &dwThreadId)) {
  472. dwThreadCount++;
  473. }
  474. }
  475. //
  476. // Put the token back.
  477. //
  478. if (!SetThreadToken(NULL, hThreadToken)) {
  479. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: Impersonation failed with error %d"), GetLastError()));
  480. dwErr = GetLastError();
  481. // terminate and close handles for all the threads
  482. for (i = 0; i < dwThreadCount; i++) {
  483. TerminateThread (hThreads[i], 1);
  484. CloseHandle (hThreads[i]);
  485. }
  486. if (hThreadToken)
  487. CloseHandle (hThreadToken);
  488. goto Exit;
  489. }
  490. for (i = 0; i < dwThreadCount; i++) {
  491. if (!SetThreadToken(&hThreads[i], hThreadToken) || !ResumeThread (hThreads[i])) {
  492. ThreadInfo.dwError = GetLastError();
  493. TerminateThread(hThreads[i], 1);
  494. }
  495. }
  496. //
  497. // Wait for the threads to finish
  498. //
  499. if (WaitForMultipleObjects (dwThreadCount, hThreads, TRUE, INFINITE) == WAIT_FAILED) {
  500. ThreadInfo.dwError = GetLastError();
  501. }
  502. //
  503. // Clean up
  504. //
  505. if (hThreadToken)
  506. CloseHandle (hThreadToken);
  507. for (i = 0; i < dwThreadCount; i++) {
  508. CloseHandle (hThreads[i]);
  509. }
  510. if (ThreadInfo.dwError) {
  511. dwErr = ThreadInfo.dwError;
  512. goto Exit;
  513. }
  514. }
  515. }
  516. }
  517. //
  518. // Restore the time on the directories to be the same as from Src.
  519. // This is required because the times on directory have been modified by
  520. // creation and deletion of files above.
  521. //
  522. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: Setting Directory TimeStamps all Directories")));
  523. lpTemp = lpSrcDirs;
  524. while (lpTemp) {
  525. HANDLE hDestFile;
  526. SetFileAttributes (lpTemp->szDest, FILE_ATTRIBUTE_NORMAL);
  527. hDestFile = CreateFile(lpTemp->szDest, GENERIC_WRITE,
  528. FILE_SHARE_DELETE | FILE_SHARE_WRITE,
  529. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL);
  530. if (hDestFile != INVALID_HANDLE_VALUE) {
  531. if (!SetFileTime(hDestFile, NULL, NULL, &(lpTemp->ftLastWrite))) {
  532. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: Failed to set the write time on the directory <%s>. Error = %d"),
  533. lpTemp->szDest, GetLastError()));
  534. }
  535. CloseHandle(hDestFile);
  536. }
  537. else {
  538. DebugMsg((DM_WARNING, TEXT("CopyProfileDirectoryEx: CreateFile failed for directory %s with error %d"), lpTemp->szDest,
  539. GetLastError()));
  540. }
  541. SetFileAttributes (lpTemp->szDest, lpTemp->dwFileAttribs);
  542. lpTemp = lpTemp->pNext;
  543. }
  544. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: Set times on all directories")));
  545. //
  546. // Success
  547. //
  548. bResult = TRUE;
  549. Exit:
  550. if (ThreadInfo.hCopyEvent) {
  551. CloseHandle (ThreadInfo.hCopyEvent);
  552. }
  553. if ( ThreadInfo.hDesktop ) {
  554. CloseDesktop( ThreadInfo.hDesktop );
  555. }
  556. //
  557. // Free the memory allocated above
  558. //
  559. if (hTokenUser) {
  560. CloseHandle(hTokenUser);
  561. }
  562. if (lpSrcDir) {
  563. LocalFree(lpSrcDir);
  564. }
  565. if (lpDestDir) {
  566. LocalFree(lpDestDir);
  567. }
  568. if (lpExcludeListSrc) {
  569. LocalFree (lpExcludeListSrc);
  570. }
  571. if (lpExcludeListDest) {
  572. LocalFree (lpExcludeListDest);
  573. }
  574. if (lpSrcFiles) {
  575. FreeFileInfoList(lpSrcFiles);
  576. }
  577. if (lpDestFiles) {
  578. FreeFileInfoList(lpDestFiles);
  579. }
  580. if (lpSrcDirs) {
  581. FreeFileInfoList(lpSrcDirs);
  582. }
  583. if (lpDestDirs) {
  584. FreeFileInfoList(lpDestDirs);
  585. }
  586. SetLastError(dwErr);
  587. //
  588. // Verbose output
  589. //
  590. DebugMsg((DM_VERBOSE, TEXT("CopyProfileDirectoryEx: Leaving with a return value of %d"), bResult));
  591. return bResult;
  592. }
  593. //*************************************************************
  594. //
  595. // RecurseDirectory()
  596. //
  597. // Purpose: Recurses through the subdirectory coping files.
  598. //
  599. // Parameters: hTokenUser - User's token
  600. // lpSrcDir - Source directory working buffer
  601. // lpDestDir - Destination directory working buffer
  602. // dwFlags - dwFlags
  603. // llSrcDirs - Link list of directories
  604. // llSrcFiles - Link list of files
  605. // bSkipNtUser - Skip ntuser.* files
  606. // lpExcludeList - List of directories to exclude
  607. // bRecurseDest - The destination Dir is being recursed
  608. //
  609. // Return: TRUE if successful
  610. // FALSE if an error occurs
  611. //
  612. // Comments: 1) The source and dest directories will already have
  613. // the trailing backslash when entering this function.
  614. // 2) The current working directory is the source directory.
  615. //
  616. //
  617. // Notes:
  618. // CPD_SYSTEMDIRSONLY Do not keep track of anything unless the dir is
  619. // marked with system bit.
  620. // CPD_SYSTEMFILES Only Systemfiles
  621. // CPD_NONENCRYPTEDONLY Only Non EncryptedFile/Directory.
  622. //
  623. // History: Date Author Comment
  624. // 5/25/95 ericflo Created
  625. //
  626. //*************************************************************
  627. BOOL RecurseDirectory (HANDLE hTokenUser, LPTSTR lpSrcDir, DWORD cchSrcDir,
  628. LPTSTR lpDestDir, DWORD cchDestDir, DWORD dwFlags,
  629. LPFILEINFO *llSrcDirs, LPFILEINFO *llSrcFiles,
  630. BOOL bMarkNtUser, LPTSTR lpExcludeList, BOOL bRecurseDest)
  631. {
  632. HANDLE hFile = INVALID_HANDLE_VALUE;
  633. LPTSTR lpSrcEnd, lpDestEnd, lpTemp;
  634. BOOL bResult = FALSE;
  635. BOOL bSkip;
  636. DWORD dwErr, dwErr1 = 0;
  637. LPTSTR szErr = NULL;
  638. WIN32_FIND_DATA* pfd = NULL;
  639. BOOL bHive;
  640. DWORD cchSrcEnd, cchDestEnd;
  641. HRESULT hr;
  642. dwErr = GetLastError();
  643. //
  644. // Setup the ending pointers
  645. //
  646. lpSrcEnd = CheckSlashEx (lpSrcDir, cchSrcDir, &cchSrcEnd);
  647. if (!lpSrcEnd)
  648. {
  649. dwErr = ERROR_INSUFFICIENT_BUFFER;
  650. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: failed to append slash to src dir.")));
  651. goto RecurseDir_Exit;
  652. }
  653. lpDestEnd = CheckSlashEx (lpDestDir, cchDestDir, &cchDestEnd);
  654. if (!lpDestEnd)
  655. {
  656. dwErr = ERROR_INSUFFICIENT_BUFFER;
  657. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: failed to append slash to dest dir.")));
  658. goto RecurseDir_Exit;
  659. }
  660. //
  661. // Append *.* to the source directory
  662. //
  663. hr = StringCchCopy (lpSrcEnd, cchSrcEnd, c_szStarDotStar);
  664. if (FAILED(hr))
  665. {
  666. dwErr = HRESULT_CODE(hr);
  667. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: failed to append '*.*' to src dir.")));
  668. goto RecurseDir_Exit;
  669. }
  670. //
  671. // Allocate fd. Since this is a recursive func, we don't want to use a lot of stack space
  672. //
  673. pfd = (WIN32_FIND_DATA *) LocalAlloc (LPTR, sizeof(WIN32_FIND_DATA));
  674. if (!pfd)
  675. {
  676. dwErr = GetLastError();
  677. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: failed to allocate WIN32_FIND_DATA.")));
  678. goto RecurseDir_Exit;
  679. }
  680. //
  681. // Allocate szErr.
  682. //
  683. szErr = (LPTSTR) LocalAlloc (LPTR, MAX_PATH * sizeof(TCHAR));
  684. if (!szErr)
  685. {
  686. dwErr = GetLastError();
  687. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: failed to allocate szErr.")));
  688. goto RecurseDir_Exit;
  689. }
  690. //
  691. // Search through the source directory
  692. //
  693. hFile = FindFirstFile(lpSrcDir, pfd);
  694. if (hFile == INVALID_HANDLE_VALUE) {
  695. if ( (GetLastError() == ERROR_FILE_NOT_FOUND) ||
  696. (GetLastError() == ERROR_PATH_NOT_FOUND) ) {
  697. bResult = TRUE;
  698. } else {
  699. dwErr1 = GetLastError();
  700. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: FindFirstFile failed. Error = %d"), dwErr1));
  701. *lpSrcEnd = TEXT('\0');
  702. *lpDestEnd = TEXT('\0');
  703. if (!(dwFlags & CPD_IGNORECOPYERRORS)) {
  704. if (!bRecurseDest) {
  705. ReportError(hTokenUser, ((dwFlags & CPD_NOERRORUI)? PI_NOUI:0), 3, EVENT_COPYERROR,
  706. lpSrcDir, lpDestDir, GetErrString(dwErr1, szErr));
  707. }
  708. else {
  709. ReportError(hTokenUser, ((dwFlags & CPD_NOERRORUI)? PI_NOUI:0), 3, EVENT_COPYERROR,
  710. lpDestDir, lpSrcDir, GetErrString(dwErr1, szErr));
  711. }
  712. dwErr = dwErr1;
  713. bResult = FALSE;
  714. }
  715. else // Ignore copy error, so we just set return value to TRUE
  716. {
  717. bResult = TRUE;
  718. }
  719. }
  720. goto RecurseDir_Exit;
  721. }
  722. do {
  723. bHive = FALSE;
  724. //
  725. // Check whether we have enough space in our buffers
  726. //
  727. *lpSrcEnd = TEXT('\0');
  728. *lpDestEnd = TEXT('\0');
  729. if ((lstrlen(lpSrcDir)+lstrlen(pfd->cFileName) >= MAX_PATH) ||
  730. (lstrlen(lpDestDir)+lstrlen(pfd->cFileName) >= MAX_PATH)) {
  731. LPTSTR lpErrSrc=NULL, lpErrDest=NULL;
  732. DWORD cchErrSrc, cchErrDest;
  733. BOOL bRet;
  734. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: %s is too long. src = %s, dest = %s"), pfd->cFileName, lpSrcDir, lpDestDir));
  735. if (dwFlags & CPD_IGNORELONGFILENAMES)
  736. continue;
  737. //
  738. // Allocate a buffer to show the file names
  739. //
  740. cchErrSrc = lstrlen(lpSrcDir)+lstrlen(pfd->cFileName)+1;
  741. cchErrDest = lstrlen(lpDestDir)+lstrlen(pfd->cFileName)+1;
  742. lpErrSrc = LocalAlloc(LPTR, cchErrSrc * sizeof(TCHAR));
  743. lpErrDest = LocalAlloc(LPTR, cchErrDest * sizeof(TCHAR));
  744. //
  745. // Show the UI
  746. //
  747. if ((!lpErrSrc) || (!lpErrDest)) {
  748. if (!bRecurseDest) {
  749. ReportError(hTokenUser, ((dwFlags & CPD_NOERRORUI)? PI_NOUI:0), 3, EVENT_COPYERROR,
  750. lpSrcDir, lpDestDir, GetErrString(ERROR_FILENAME_EXCED_RANGE, szErr));
  751. } else {
  752. ReportError(hTokenUser, ((dwFlags & CPD_NOERRORUI)? PI_NOUI:0), 3, EVENT_COPYERROR,
  753. lpDestDir, lpSrcDir, GetErrString(ERROR_FILENAME_EXCED_RANGE, szErr));
  754. }
  755. }
  756. else {
  757. StringCchCopy(lpErrSrc, cchErrSrc, lpSrcDir);
  758. StringCchCat(lpErrSrc, cchErrSrc, pfd->cFileName);
  759. StringCchCopy(lpErrDest, cchErrDest, lpDestDir);
  760. StringCchCat(lpErrDest, cchErrDest, pfd->cFileName);
  761. if (!bRecurseDest) {
  762. ReportError(hTokenUser, ((dwFlags & CPD_NOERRORUI)? PI_NOUI:0), 3, EVENT_COPYERROR,
  763. lpErrSrc, lpErrDest, GetErrString(ERROR_FILENAME_EXCED_RANGE, szErr));
  764. } else {
  765. ReportError(hTokenUser, ((dwFlags & CPD_NOERRORUI)? PI_NOUI:0), 3, EVENT_COPYERROR,
  766. lpErrDest, lpErrSrc, GetErrString(ERROR_FILENAME_EXCED_RANGE, szErr));
  767. }
  768. }
  769. if (lpErrSrc)
  770. LocalFree(lpErrSrc);
  771. if (lpErrDest)
  772. LocalFree(lpErrDest);
  773. //
  774. // Set the error and quit.
  775. //
  776. dwErr = ERROR_FILENAME_EXCED_RANGE;
  777. bResult = FALSE;
  778. goto RecurseDir_Exit;
  779. }
  780. //
  781. // Append the file / directory name to the working buffers
  782. //
  783. StringCchCopy (lpSrcEnd, cchSrcEnd, pfd->cFileName);
  784. StringCchCopy (lpDestEnd, cchDestEnd, pfd->cFileName);
  785. if (pfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  786. //
  787. // Check for "." and ".."
  788. //
  789. if (!lstrcmpi(pfd->cFileName, c_szDot)) {
  790. continue;
  791. }
  792. if (!lstrcmpi(pfd->cFileName, c_szDotDot)) {
  793. continue;
  794. }
  795. //
  796. // Check for reparse point
  797. //
  798. if (pfd->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
  799. {
  800. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: Found a reparse point <%s>, skip it!"), lpSrcDir));
  801. continue;
  802. }
  803. //
  804. // Check if this directory should be excluded
  805. //
  806. if (lpExcludeList) {
  807. bSkip = FALSE;
  808. lpTemp = lpExcludeList;
  809. while (*lpTemp) {
  810. if (lstrcmpi (lpTemp, lpSrcDir) == 0) {
  811. bSkip = TRUE;
  812. break;
  813. }
  814. lpTemp += lstrlen (lpTemp) + 1;
  815. }
  816. if (bSkip) {
  817. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Skipping <%s> due to exclusion list."),
  818. lpSrcDir));
  819. continue;
  820. }
  821. }
  822. //
  823. // Found a directory.
  824. //
  825. // 1) Change into that subdirectory on the source drive.
  826. // 2) Recurse down that tree.
  827. // 3) Back up one level.
  828. //
  829. //
  830. // Add to the list of directories
  831. //
  832. if (dwFlags & CPD_SYSTEMDIRSONLY) {
  833. //
  834. // if it is encrypted, don't recurse into it
  835. //
  836. if (!(pfd->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  837. DWORD dwNewFlags = dwFlags;
  838. //
  839. // Add to the list of directories only if marked as system, o/w just recurse through
  840. //
  841. if (pfd->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
  842. if (!AddFileInfoNode (llSrcDirs, lpSrcDir, lpDestDir, &pfd->ftLastWriteTime,
  843. &pfd->ftCreationTime, 0, pfd->dwFileAttributes, bHive)) {
  844. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: AddFileInfoNode failed")));
  845. dwErr = GetLastError();
  846. goto RecurseDir_Exit;
  847. }
  848. dwNewFlags ^= CPD_SYSTEMDIRSONLY;
  849. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Adding %s to the list of directories because system bit is on"), lpSrcDir));
  850. }
  851. //
  852. // Recurse the subdirectory
  853. //
  854. if (!RecurseDirectory(hTokenUser, lpSrcDir, cchSrcDir, lpDestDir, cchDestDir, dwNewFlags,
  855. llSrcDirs, llSrcFiles, FALSE, lpExcludeList, bRecurseDest)) {
  856. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: RecurseDirectory returned FALSE")));
  857. bResult = FALSE;
  858. dwErr = GetLastError();
  859. goto RecurseDir_Exit;
  860. }
  861. } else {
  862. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Skipping <%s> since the encrypted attribute is set."),
  863. lpSrcDir));
  864. }
  865. continue;
  866. }
  867. //
  868. // Popup time
  869. //
  870. if (dwFlags & CPD_NONENCRYPTEDONLY) {
  871. if (pfd->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  872. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Detected Encrypted file %s, Aborting.."), lpSrcDir));
  873. dwErr = ERROR_FILE_ENCRYPTED;
  874. bResult = FALSE;
  875. goto RecurseDir_Exit;
  876. }
  877. }
  878. //
  879. // Ignore encrypted file
  880. //
  881. if (dwFlags & CPD_IGNOREENCRYPTEDFILES) {
  882. if (pfd->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  883. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Skipping <%s> since the encrypted attribute is set..."),
  884. lpSrcDir));
  885. continue;
  886. }
  887. }
  888. //
  889. // Add it to the list
  890. //
  891. if (!AddFileInfoNode (llSrcDirs, lpSrcDir, lpDestDir, &pfd->ftLastWriteTime,
  892. &pfd->ftCreationTime, 0, pfd->dwFileAttributes, bHive)) {
  893. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: AddFileInfoNode failed")));
  894. dwErr = GetLastError();
  895. goto RecurseDir_Exit;
  896. }
  897. //
  898. // Recurse the subdirectory
  899. //
  900. if (!RecurseDirectory(hTokenUser, lpSrcDir, cchSrcDir, lpDestDir, cchDestDir, dwFlags,
  901. llSrcDirs, llSrcFiles, FALSE, lpExcludeList, bRecurseDest)) {
  902. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: RecurseDirectory returned FALSE")));
  903. bResult = FALSE;
  904. dwErr = GetLastError();
  905. goto RecurseDir_Exit;
  906. }
  907. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Adding %s to the list of directories"), lpSrcDir));
  908. } else {
  909. //
  910. // if the directories only bit is set, don't copy anything else
  911. //
  912. if (dwFlags & CPD_SYSTEMDIRSONLY) {
  913. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Skipping <%s> since the system directories only attribute is set."),
  914. lpSrcDir));
  915. continue;
  916. }
  917. //
  918. // If the filename found starts with "ntuser", then ignore
  919. // it because the hive will be copied below (if appropriate).
  920. //
  921. if (bMarkNtUser && lstrlen(pfd->cFileName) >= 6) {
  922. if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
  923. pfd->cFileName, 6,
  924. TEXT("ntuser"), 6) == CSTR_EQUAL) {
  925. bHive = TRUE;
  926. }
  927. }
  928. //
  929. // Check if this file should be excluded
  930. //
  931. if (dwFlags & CPD_SYSTEMFILES) {
  932. if (!(pfd->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) {
  933. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Skipping <%s> since the system attribute is not set."),
  934. lpSrcDir));
  935. continue;
  936. }
  937. }
  938. //
  939. // if it is systemfile, it can not be encrypted.
  940. //
  941. if (dwFlags & CPD_NONENCRYPTEDONLY) {
  942. if (pfd->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  943. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Detected Encrypted file %s, Aborting..."), lpSrcDir));
  944. dwErr = ERROR_FILE_ENCRYPTED;
  945. bResult = FALSE;
  946. goto RecurseDir_Exit;
  947. }
  948. }
  949. if (dwFlags & CPD_IGNOREENCRYPTEDFILES) {
  950. if (pfd->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  951. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Skipping <%s> since the encrypted attribute is set."),
  952. lpSrcDir));
  953. continue;
  954. }
  955. }
  956. //
  957. // We found a file. Add it to the list.
  958. //
  959. if (!AddFileInfoNode (llSrcFiles, lpSrcDir, lpDestDir,
  960. &pfd->ftLastWriteTime, &pfd->ftCreationTime,
  961. pfd->nFileSizeLow, pfd->dwFileAttributes, bHive)) {
  962. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: AddFileInfoNode failed")));
  963. dwErr = GetLastError();
  964. goto RecurseDir_Exit;
  965. }
  966. }
  967. //
  968. // Find the next entry
  969. //
  970. } while (FindNextFile(hFile, pfd));
  971. bResult = TRUE;
  972. RecurseDir_Exit:
  973. if (pfd)
  974. LocalFree(pfd);
  975. if (szErr)
  976. LocalFree(szErr);
  977. //
  978. // Remove the file / directory name appended above
  979. //
  980. if (lpSrcEnd)
  981. *lpSrcEnd = TEXT('\0');
  982. if (lpDestEnd)
  983. *lpDestEnd = TEXT('\0');
  984. //
  985. // Close the search handle
  986. //
  987. if (hFile != INVALID_HANDLE_VALUE) {
  988. FindClose(hFile);
  989. }
  990. SetLastError(dwErr);
  991. return bResult;
  992. }
  993. //*************************************************************
  994. //
  995. // CopyProgressRoutine()
  996. //
  997. // Purpose: Callback function for CopyFileEx
  998. //
  999. // Parameters: See doc's.
  1000. //
  1001. // Return: PROGRESS_CONTINUE
  1002. //
  1003. //*************************************************************
  1004. DWORD WINAPI CopyProgressRoutine(LARGE_INTEGER TotalFileSize,
  1005. LARGE_INTEGER TotalBytesTransferred,
  1006. LARGE_INTEGER StreamSize,
  1007. LARGE_INTEGER StreamBytesTransferred,
  1008. DWORD dwStreamNumber,
  1009. DWORD dwCallbackReason,
  1010. HANDLE hSourceFile,
  1011. HANDLE hDestinationFile,
  1012. LPVOID lpData)
  1013. {
  1014. switch (dwCallbackReason)
  1015. {
  1016. case PRIVCALLBACK_ENCRYPTION_FAILED:
  1017. case PRIVCALLBACK_COMPRESSION_FAILED:
  1018. case PRIVCALLBACK_SPARSE_FAILED:
  1019. case PRIVCALLBACK_OWNER_GROUP_FAILED:
  1020. case PRIVCALLBACK_DACL_ACCESS_DENIED:
  1021. case PRIVCALLBACK_SACL_ACCESS_DENIED:
  1022. case PRIVCALLBACK_OWNER_GROUP_ACCESS_DENIED:
  1023. return PROGRESS_CANCEL;
  1024. default:
  1025. return PROGRESS_CONTINUE; //all other conditions can be safely ignored
  1026. }
  1027. }
  1028. //*************************************************************
  1029. //
  1030. // ReconcileDirectory()
  1031. //
  1032. // Purpose: Compares the source and destination file.
  1033. // If the source is newer, then it is copied
  1034. // over the destination.
  1035. //
  1036. // Parameters: lpSrcDir - source filename
  1037. // lpDestDir - destination filename
  1038. // dwFlags - flags
  1039. // dwSrcAttribs Source Attributes for decompression,
  1040. // decryption later on.
  1041. //
  1042. //
  1043. // Return: 1 if successful (no file copied)
  1044. // 0 if an error occurs
  1045. //
  1046. // Comments:
  1047. //
  1048. // History: Date Author Comment
  1049. // 2/26/99 ushaji Created
  1050. //
  1051. //*************************************************************
  1052. BOOL ReconcileDirectory(LPTSTR lpSrcDir, LPTSTR lpDestDir,
  1053. DWORD dwFlags, DWORD dwSrcAttribs)
  1054. {
  1055. DWORD dwCopyFlags=0, dwErr;
  1056. BOOL bCancel = FALSE;
  1057. //
  1058. // Clear any existing attributes
  1059. //
  1060. SetFileAttributes (lpDestDir, FILE_ATTRIBUTE_NORMAL);
  1061. if (!CreateNestedDirectory(lpDestDir, NULL)) {
  1062. DebugMsg((DM_WARNING, TEXT("ReconcileDirectory: Failed to create the destination directory <%s>. Error = %d"),
  1063. lpDestDir, GetLastError()));
  1064. return FALSE;
  1065. }
  1066. //
  1067. // Set up the copy flags to copy the encryption/compression on dirs over.
  1068. //
  1069. if (!(dwFlags & CPD_IGNORESECURITY))
  1070. dwCopyFlags = PRIVCOPY_FILE_METADATA | PRIVCOPY_FILE_SKIP_DACL;
  1071. dwCopyFlags |= PRIVCOPY_FILE_DIRECTORY | PRIVCOPY_FILE_SUPERSEDE;
  1072. if (!PrivCopyFileExW(lpSrcDir, lpDestDir,
  1073. (LPPROGRESS_ROUTINE) CopyProgressRoutine,
  1074. NULL, &bCancel, dwCopyFlags)) {
  1075. dwErr = GetLastError();
  1076. DebugMsg((DM_WARNING, TEXT("ReconcileDirectory: Failed to copy over the attributes src <%s> to destination directory <%s>. Error = %d"),
  1077. lpSrcDir, lpDestDir, dwErr));
  1078. RemoveDirectory(lpDestDir);
  1079. SetLastError(dwErr);
  1080. return FALSE;
  1081. }
  1082. return TRUE;
  1083. }
  1084. //*************************************************************
  1085. //
  1086. // ReconcileFile()
  1087. //
  1088. // Purpose: Compares the source and destination file.
  1089. // If the source is newer, then it is copied
  1090. // over the destination.
  1091. //
  1092. // Parameters: lpSrcFile - source filename
  1093. // lpDestFile - destination filename
  1094. // dwFlags - flags
  1095. // ftSrcTime - Src file time (can be NULL)
  1096. // dwFileSize - File size
  1097. // bHiveFile - Flag to indicate hive file
  1098. //
  1099. //
  1100. // Return: 1 if successful (no file copied)
  1101. // 2 if successful (and a file was copied)
  1102. // 0 if an error occurs
  1103. //
  1104. // Comments:
  1105. //
  1106. // History: Date Author Comment
  1107. // 5/25/95 ericflo Created
  1108. // 7/20/00 santanuc added flag bHiveFile
  1109. //
  1110. //*************************************************************
  1111. INT ReconcileFile (LPCTSTR lpSrcFile, LPCTSTR lpDestFile,
  1112. DWORD dwFlags, LPFILETIME ftSrcTime,
  1113. DWORD dwFileSize, BOOL bHiveFile)
  1114. {
  1115. WIN32_FILE_ATTRIBUTE_DATA fad;
  1116. FILETIME ftWriteSrc, ftWriteDest;
  1117. INT iCopyFile = 0;
  1118. DWORD dwErr = ERROR_SUCCESS, dwErr1 = 0;
  1119. //
  1120. // If the flags have CPD_FORCECOPY, then skip to the
  1121. // copy file call without checking the timestamps.
  1122. //
  1123. if (!(dwFlags & CPD_FORCECOPY)) {
  1124. //
  1125. // If we were given a source file time, use that
  1126. //
  1127. if (ftSrcTime) {
  1128. ftWriteSrc.dwLowDateTime = ftSrcTime->dwLowDateTime;
  1129. ftWriteSrc.dwHighDateTime = ftSrcTime->dwHighDateTime;
  1130. } else {
  1131. //
  1132. // Query for the source file time
  1133. //
  1134. if (!GetFileAttributesEx (lpSrcFile, GetFileExInfoStandard, &fad)) {
  1135. dwErr = GetLastError();
  1136. DebugMsg((DM_WARNING, TEXT("ReconcileFile: GetFileAttributes on the source failed with error = %d"),
  1137. dwErr));
  1138. goto Exit;
  1139. }
  1140. ftWriteSrc.dwLowDateTime = fad.ftLastWriteTime.dwLowDateTime;
  1141. ftWriteSrc.dwHighDateTime = fad.ftLastWriteTime.dwHighDateTime;
  1142. }
  1143. //
  1144. // Attempt to open the destination file
  1145. //
  1146. if (!GetFileAttributesEx (lpDestFile, GetFileExInfoStandard, &fad)) {
  1147. DWORD dwError;
  1148. //
  1149. // GetFileAttributesEx failed to query the destination
  1150. // file. If the last error is file not found
  1151. // then we automaticaly will copy the file.
  1152. //
  1153. dwError = GetLastError();
  1154. if (dwError == ERROR_FILE_NOT_FOUND) {
  1155. iCopyFile = 1;
  1156. } else {
  1157. //
  1158. // GetFileAttributesEx failed with some other error
  1159. //
  1160. DebugMsg((DM_WARNING, TEXT("ReconcileFile: GetFileAttributesEx on the destination failed with error = %d"),
  1161. dwError));
  1162. dwErr = dwError;
  1163. goto Exit;
  1164. }
  1165. } else {
  1166. ftWriteDest.dwLowDateTime = fad.ftLastWriteTime.dwLowDateTime;
  1167. ftWriteDest.dwHighDateTime = fad.ftLastWriteTime.dwHighDateTime;
  1168. }
  1169. } else {
  1170. //
  1171. // The CPD_FORCECOPY flag is turned on, set iCopyFile to 1.
  1172. //
  1173. iCopyFile = 1;
  1174. }
  1175. //
  1176. // If iCopyFile is still zero, then we need to compare
  1177. // the last write time stamps.
  1178. //
  1179. if (!iCopyFile) {
  1180. LONG lResult;
  1181. //
  1182. // If the source is later than the destination
  1183. // we need to copy the file.
  1184. //
  1185. lResult = CompareFileTime(&ftWriteSrc, &ftWriteDest);
  1186. if (lResult == 1) {
  1187. iCopyFile = 1;
  1188. }
  1189. if ( (dwFlags & CPD_COPYIFDIFFERENT) && (lResult == -1) ) {
  1190. iCopyFile = 1;
  1191. }
  1192. }
  1193. //
  1194. // Copy the file if appropriate
  1195. //
  1196. if (iCopyFile) {
  1197. BOOL bCancel = FALSE;
  1198. TCHAR szTempFile[MAX_PATH];
  1199. TCHAR szTempDir[MAX_PATH];
  1200. LPTSTR lpTemp;
  1201. DWORD dwCopyFlags;
  1202. //
  1203. // Clear any existing attributes
  1204. //
  1205. SetFileAttributes (lpDestFile, FILE_ATTRIBUTE_NORMAL);
  1206. if (!(dwFlags & CPD_IGNORESECURITY))
  1207. dwCopyFlags = PRIVCOPY_FILE_METADATA | PRIVCOPY_FILE_SKIP_DACL;
  1208. else
  1209. dwCopyFlags = 0;
  1210. dwCopyFlags |= PRIVCOPY_FILE_SUPERSEDE;
  1211. //
  1212. // Figure out what the destination directory is
  1213. //
  1214. StringCchCopy (szTempDir, ARRAYSIZE(szTempDir), lpDestFile);
  1215. lpTemp = szTempDir + lstrlen (szTempDir);
  1216. while ((lpTemp > szTempDir) && (*lpTemp != TEXT('\\'))) {
  1217. lpTemp--;
  1218. }
  1219. if (lpTemp == szTempDir) {
  1220. StringCchCopy (szTempDir, ARRAYSIZE(szTempDir), TEXT("."));
  1221. } else {
  1222. *lpTemp = TEXT('\0');
  1223. }
  1224. //
  1225. // Generate a temporary file name
  1226. //
  1227. if (GetTempFileName (szTempDir, TEXT("prf"), 0, szTempFile)) {
  1228. //
  1229. // Copy the file to the temp file name
  1230. //
  1231. if (PrivCopyFileExW(lpSrcFile, szTempFile,
  1232. (LPPROGRESS_ROUTINE) CopyProgressRoutine,
  1233. NULL, &bCancel, dwCopyFlags)) {
  1234. // If it is hive file then open the temporary file, flush and close it to make it more transacted
  1235. if (bHiveFile) {
  1236. HANDLE hTempFile;
  1237. hTempFile = CreateFile(szTempFile, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1238. if ( hTempFile != INVALID_HANDLE_VALUE ) {
  1239. if ( !FlushFileBuffers(hTempFile) )
  1240. DebugMsg((DM_WARNING, TEXT("ReconcileFile: Unable to flush temporary file")));
  1241. if ( !CloseHandle(hTempFile) )
  1242. DebugMsg((DM_WARNING, TEXT("ReconcileFile: Unable to close temporary file handle")));
  1243. }
  1244. else
  1245. DebugMsg((DM_WARNING, TEXT("ReconcileFile: Unable to open temporary file")));
  1246. }
  1247. //
  1248. // Delete the original file
  1249. //
  1250. if (!DeleteFile (lpDestFile)) {
  1251. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  1252. dwErr1 = GetLastError();
  1253. DebugMsg((DM_WARNING, TEXT("ReconcileFile: Failed to delete file <%s> with error = %d"),
  1254. lpDestFile, dwErr1));
  1255. DeleteFile(szTempFile);
  1256. goto CopyError;
  1257. }
  1258. }
  1259. //
  1260. // Rename the temp file to the original file name
  1261. //
  1262. if (!MoveFile (szTempFile, lpDestFile)) {
  1263. DWORD dwError = ERROR_SUCCESS; //isolate MoveFile error from other below
  1264. dwErr1 = GetLastError();
  1265. //
  1266. // If we get access denied, let's try to remove the READ ONLY attribute (can't rename files
  1267. // with +r attribute on a Netware Server) from the temp file, do the rename and restore the
  1268. // attributes
  1269. //
  1270. if ( dwErr1 == ERROR_ACCESS_DENIED ) {
  1271. if (!GetFileAttributesEx (szTempFile, GetFileExInfoStandard, &fad)) {
  1272. dwError = GetLastError();
  1273. DebugMsg((DM_WARNING, TEXT("ReconcileFile: GetFileAttributes on file <%s> failed with error = %d\n"),
  1274. szTempFile,dwError));
  1275. } else {
  1276. if ( fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY ) {
  1277. dwErr1 = ERROR_SUCCESS ;
  1278. if (!SetFileAttributes (szTempFile, fad.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) {
  1279. dwError = GetLastError();
  1280. DebugMsg((DM_WARNING, TEXT("ReconcileFile: SetFileAttributes on file <%s> failed with error = %d\n"),
  1281. szTempFile,dwError));
  1282. } else {
  1283. if (!MoveFile (szTempFile,lpDestFile)) {
  1284. // Debug message displayed below
  1285. dwErr1 = GetLastError();
  1286. } else {
  1287. if ( !SetFileAttributes (lpDestFile,fad.dwFileAttributes) ) {
  1288. dwError = GetLastError();
  1289. DebugMsg((DM_WARNING, TEXT("ReconcileFile: SetFileAttributes on file <%s> failed with error = %d\n"),
  1290. szTempFile,dwError));
  1291. }
  1292. }
  1293. }
  1294. }
  1295. }
  1296. } // End of ERROR_ACCESS_DENIED test
  1297. if (dwErr1 != ERROR_SUCCESS || dwError != ERROR_SUCCESS) {
  1298. DebugMsg((DM_WARNING, TEXT("ReconcileFile: Failed to rename file <%s> to <%s> with error = %d"),
  1299. szTempFile, lpDestFile, dwErr1));
  1300. // do not remove it in this case.
  1301. goto CopyError;
  1302. }
  1303. }
  1304. DebugMsg((DM_VERBOSE, TEXT("ReconcileFile: %s ==> %s [OK]"),
  1305. lpSrcFile, lpDestFile));
  1306. iCopyFile = 2;
  1307. } else {
  1308. dwErr1 = GetLastError();
  1309. DeleteFile(szTempFile);
  1310. DebugMsg((DM_WARNING, TEXT("ReconcileFile: %s ==> %s [FAILED!!!]"),
  1311. lpSrcFile, szTempFile));
  1312. DebugMsg((DM_WARNING, TEXT("ReconcileFile: CopyFile failed with error = %d"),
  1313. dwErr1));
  1314. goto CopyError;
  1315. }
  1316. } else {
  1317. dwErr1 = GetLastError();
  1318. DebugMsg((DM_WARNING, TEXT("ReconcileFile: GetTempFileName failed with %d"),
  1319. dwErr1));
  1320. goto CopyError;
  1321. }
  1322. } else {
  1323. //
  1324. // No need to copy the file since the time stamps are the same
  1325. // Set iCopyFile to 1 so the return value is success without
  1326. // copying a file.
  1327. //
  1328. iCopyFile = 1;
  1329. }
  1330. goto Exit;
  1331. CopyError:
  1332. iCopyFile = 0;
  1333. dwErr = dwErr1;
  1334. Exit:
  1335. SetLastError(dwErr);
  1336. return iCopyFile;
  1337. }
  1338. //*************************************************************
  1339. //
  1340. // AddFileInfoNode()
  1341. //
  1342. // Purpose: Adds a node to the linklist of files
  1343. //
  1344. // Parameters: lpFileInfo - Link list to add to
  1345. // lpSrcFile - Source filename
  1346. // lpDestFile - Destination filename
  1347. // ftLastWrite - Last write time stamp
  1348. // ftCreationTime - File creation time
  1349. // dwFileSize - Size of the file
  1350. // dwFileAttribs - File attributes
  1351. //
  1352. // Return: TRUE if successful
  1353. // FALSE if an error occurs
  1354. //
  1355. // Comments:
  1356. //
  1357. // History: Date Author Comment
  1358. // 9/28/95 ericflo Created
  1359. //
  1360. //*************************************************************
  1361. BOOL AddFileInfoNode (LPFILEINFO *lpFileInfo, LPTSTR lpSrcFile,
  1362. LPTSTR lpDestFile, LPFILETIME ftLastWrite,
  1363. LPFILETIME ftCreationTime, DWORD dwFileSize,
  1364. DWORD dwFileAttribs, BOOL bHive)
  1365. {
  1366. LPFILEINFO lpNode;
  1367. lpNode = (LPFILEINFO) LocalAlloc(LPTR, sizeof(FILEINFO));
  1368. if (!lpNode) {
  1369. return FALSE;
  1370. }
  1371. StringCchCopy (lpNode->szSrc, MAX_PATH, lpSrcFile);
  1372. StringCchCopy (lpNode->szDest, MAX_PATH, lpDestFile);
  1373. lpNode->ftLastWrite.dwLowDateTime = ftLastWrite->dwLowDateTime;
  1374. lpNode->ftLastWrite.dwHighDateTime = ftLastWrite->dwHighDateTime;
  1375. lpNode->ftCreationTime.dwLowDateTime = ftCreationTime->dwLowDateTime;
  1376. lpNode->ftCreationTime.dwHighDateTime = ftCreationTime->dwHighDateTime;
  1377. lpNode->dwFileSize = dwFileSize;
  1378. lpNode->bHive = bHive;
  1379. lpNode->dwFileAttribs = (dwFileAttribs & ~FILE_ATTRIBUTE_DIRECTORY);
  1380. lpNode->pNext = *lpFileInfo;
  1381. *lpFileInfo = lpNode;
  1382. return TRUE;
  1383. }
  1384. //*************************************************************
  1385. //
  1386. // FreeFileInfoList()
  1387. //
  1388. // Purpose: Free's a file info link list
  1389. //
  1390. // Parameters: lpFileInfo - List to be freed
  1391. //
  1392. // Return: TRUE if successful
  1393. // FALSE if an error occurs
  1394. //
  1395. // Comments:
  1396. //
  1397. // History: Date Author Comment
  1398. // 9/28/95 ericflo Created
  1399. //
  1400. //*************************************************************
  1401. BOOL FreeFileInfoList (LPFILEINFO lpFileInfo)
  1402. {
  1403. LPFILEINFO lpNext;
  1404. if (!lpFileInfo) {
  1405. return TRUE;
  1406. }
  1407. lpNext = lpFileInfo->pNext;
  1408. while (lpFileInfo) {
  1409. LocalFree (lpFileInfo);
  1410. lpFileInfo = lpNext;
  1411. if (lpFileInfo) {
  1412. lpNext = lpFileInfo->pNext;
  1413. }
  1414. }
  1415. return TRUE;
  1416. }
  1417. //*************************************************************
  1418. //
  1419. // SyncItems()
  1420. //
  1421. // Purpose: Removes unnecessary items from the destination
  1422. // directory tree
  1423. //
  1424. // Parameters: lpSrcItems - Link list of source items
  1425. // lpDestItems - Link list of dest items
  1426. // bFile - File or directory list
  1427. //
  1428. // Return: TRUE if successful
  1429. // FALSE if an error occurs
  1430. // Comments:
  1431. //
  1432. // History: Date Author Comment
  1433. // 9/28/95 ericflo Created
  1434. //
  1435. //*************************************************************
  1436. BOOL SyncItems (LPFILEINFO lpSrcItems, LPFILEINFO lpDestItems,
  1437. BOOL bFile, LPFILETIME ftDelRefTime)
  1438. {
  1439. LPFILEINFO lpTempSrc, lpTempDest;
  1440. //
  1441. // Check for NULL pointers
  1442. //
  1443. #ifdef DBG
  1444. if (ftDelRefTime)
  1445. {
  1446. SYSTEMTIME SystemTime;
  1447. FileTimeToSystemTime(ftDelRefTime, &SystemTime);
  1448. DebugMsg((DM_VERBOSE, TEXT("SyncItems: DelRefTime. Year: %d, Month %d, Day %d, Hour %d, Minute %d"), SystemTime.wYear,
  1449. SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute));
  1450. }
  1451. #endif
  1452. if (!lpSrcItems || !lpDestItems) {
  1453. return TRUE;
  1454. }
  1455. //
  1456. // Loop through everyitem in lpDestItems to see if it
  1457. // is in lpSrcItems. If not, delete it.
  1458. //
  1459. lpTempDest = lpDestItems;
  1460. while (lpTempDest) {
  1461. lpTempSrc = lpSrcItems;
  1462. while (lpTempSrc) {
  1463. if (lstrcmpi(lpTempDest->szSrc, lpTempSrc->szDest) == 0) {
  1464. break;
  1465. }
  1466. lpTempSrc = lpTempSrc->pNext;
  1467. }
  1468. //
  1469. // If lpTempSrc is NULL, then this file / directory is a candidate
  1470. // for being deleted
  1471. //
  1472. if (!lpTempSrc) {
  1473. BOOL bDelete = TRUE;
  1474. //
  1475. // If a delete reference time was offered, compare the
  1476. // source time with the ref time and only delete files
  1477. // which have a source time older than the ref time
  1478. //
  1479. if (ftDelRefTime) {
  1480. if (CompareFileTime (&lpTempDest->ftLastWrite, ftDelRefTime) == 1) {
  1481. bDelete = FALSE;
  1482. }
  1483. else if (CompareFileTime (&lpTempDest->ftCreationTime, ftDelRefTime) == 1) {
  1484. bDelete = FALSE;
  1485. }
  1486. }
  1487. if (bDelete) {
  1488. //
  1489. // Delete the file / directory
  1490. //
  1491. DebugMsg((DM_VERBOSE, TEXT("SyncItems: removing <%s>"),
  1492. lpTempDest->szSrc));
  1493. if (bFile) {
  1494. SetFileAttributes(lpTempDest->szSrc, FILE_ATTRIBUTE_NORMAL);
  1495. if (!DeleteFile (lpTempDest->szSrc)) {
  1496. DebugMsg((DM_WARNING, TEXT("SyncItems: Failed to delete <%s>. Error = %d."),
  1497. lpTempDest->szSrc, GetLastError()));
  1498. }
  1499. } else {
  1500. SetFileAttributes(lpTempDest->szSrc, FILE_ATTRIBUTE_NORMAL);
  1501. if (!RemoveDirectory (lpTempDest->szSrc)) {
  1502. DebugMsg((DM_WARNING, TEXT("SyncItems: Failed to remove <%s>. Error = %d"),
  1503. lpTempDest->szSrc, GetLastError()));
  1504. }
  1505. }
  1506. }
  1507. else
  1508. {
  1509. DebugMsg((DM_VERBOSE, TEXT("SyncItems: New file or directory <%s> in destination since this profile was loaded. This will NOT be deleted."),
  1510. lpTempDest->szSrc));
  1511. #ifdef DBG
  1512. {
  1513. SYSTEMTIME SystemTime;
  1514. FileTimeToSystemTime(&lpTempDest->ftLastWrite, &SystemTime);
  1515. DebugMsg((DM_VERBOSE, TEXT("SyncItems: File WriteTime. Year: %d, Month %d, Day %d, Hour %d, Minute %d"), SystemTime.wYear,
  1516. SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute));
  1517. FileTimeToSystemTime(&lpTempDest->ftCreationTime, &SystemTime);
  1518. DebugMsg((DM_VERBOSE, TEXT("SyncItems: File CreationTime. Year: %d, Month %d, Day %d, Hour %d, Minute %d"), SystemTime.wYear,
  1519. SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute));
  1520. }
  1521. #endif
  1522. }
  1523. }
  1524. lpTempDest = lpTempDest->pNext;
  1525. }
  1526. return TRUE;
  1527. }
  1528. //*************************************************************
  1529. //
  1530. // CopyFileFunc()
  1531. //
  1532. // Purpose: Copies files
  1533. //
  1534. // Parameters: lpThreadInfo - Thread information
  1535. //
  1536. // Return: void
  1537. //
  1538. // Comments:
  1539. //
  1540. // History: Date Author Comment
  1541. // 2/23/96 ericflo Created
  1542. //
  1543. //*************************************************************
  1544. void CopyFileFunc (LPTHREADINFO lpThreadInfo)
  1545. {
  1546. HANDLE hInstDll;
  1547. LPFILEINFO lpSrcFile;
  1548. BOOL bRetVal = TRUE;
  1549. DWORD dwError;
  1550. TCHAR szErr[MAX_PATH];
  1551. hInstDll = LoadLibrary (TEXT("userenv.dll"));
  1552. SetThreadDesktop (lpThreadInfo->hDesktop);
  1553. while (TRUE) {
  1554. if (lpThreadInfo->dwError) {
  1555. break;
  1556. }
  1557. //
  1558. // Query for the next file to copy..
  1559. // ignore the hive file since it is already copied..
  1560. //
  1561. WaitForSingleObject(lpThreadInfo->hCopyEvent, INFINITE);
  1562. do {
  1563. lpSrcFile = lpThreadInfo->lpSrcFiles;
  1564. if (lpSrcFile)
  1565. lpThreadInfo->lpSrcFiles = lpThreadInfo->lpSrcFiles->pNext;
  1566. } while (lpSrcFile && (lpSrcFile->bHive));
  1567. SetEvent(lpThreadInfo->hCopyEvent);
  1568. //
  1569. // If NULL, then we're finished.
  1570. //
  1571. if (!lpSrcFile || lpThreadInfo->dwError) {
  1572. break;
  1573. }
  1574. //
  1575. // Copy the file
  1576. //
  1577. if (!ReconcileFile (lpSrcFile->szSrc, lpSrcFile->szDest,
  1578. lpThreadInfo->dwFlags, &lpSrcFile->ftLastWrite,
  1579. lpSrcFile->dwFileSize, FALSE)) {
  1580. if (!(lpThreadInfo->dwFlags & CPD_IGNORECOPYERRORS)) {
  1581. WaitForSingleObject(lpThreadInfo->hCopyEvent, INFINITE);
  1582. if (!(lpThreadInfo->dwError)) {
  1583. dwError = GetLastError();
  1584. ReportError(lpThreadInfo->hTokenUser, ((lpThreadInfo->dwFlags & CPD_NOERRORUI) ? PI_NOUI:0), 3, EVENT_COPYERROR,
  1585. lpSrcFile->szSrc, lpSrcFile->szDest, GetErrString(dwError, szErr));
  1586. lpThreadInfo->dwError = dwError;
  1587. bRetVal = FALSE;
  1588. }
  1589. SetEvent(lpThreadInfo->hCopyEvent);
  1590. break;
  1591. }
  1592. else {
  1593. dwError = GetLastError();
  1594. ReportError(lpThreadInfo->hTokenUser, PI_NOUI | EVENT_WARNING_TYPE, 3, EVENT_COPYERROR,
  1595. lpSrcFile->szSrc, lpSrcFile->szDest, GetErrString(dwError, szErr));
  1596. }
  1597. }
  1598. }
  1599. //
  1600. // Clean up
  1601. //
  1602. if (hInstDll) {
  1603. FreeLibraryAndExitThread(hInstDll, bRetVal);
  1604. } else {
  1605. ExitThread (bRetVal);
  1606. }
  1607. }
  1608. //*************************************************************
  1609. //
  1610. // ConvertExclusionList()
  1611. //
  1612. // Purpose: Converts the semi-colon profile relative exclusion
  1613. // list to fully qualified null terminated exclusion
  1614. // list
  1615. //
  1616. // Parameters: lpSourceDir - Profile root directory
  1617. // lpExclusionList - List of directories to exclude
  1618. //
  1619. // Return: List if successful
  1620. // NULL if an error occurs
  1621. //
  1622. //*************************************************************
  1623. LPTSTR ConvertExclusionList (LPCTSTR lpSourceDir, LPCTSTR lpExclusionList)
  1624. {
  1625. LPTSTR lpExcludeList = NULL, lpInsert, lpEnd, lpTempList;
  1626. LPCTSTR lpTemp, lpDir;
  1627. TCHAR szTemp[MAX_PATH];
  1628. DWORD dwSize = 2; // double null terminator
  1629. DWORD dwStrLen;
  1630. HRESULT hr = E_FAIL;
  1631. DWORD cchEnd;
  1632. //
  1633. // Setup a temp buffer to work with
  1634. //
  1635. hr = StringCchCopy (szTemp, ARRAYSIZE(szTemp), lpSourceDir);
  1636. if (FAILED(hr))
  1637. {
  1638. DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to copy src dir.")));
  1639. goto Exit;
  1640. }
  1641. lpEnd = CheckSlashEx (szTemp, ARRAYSIZE(szTemp), &cchEnd);
  1642. if (!lpEnd)
  1643. {
  1644. hr = E_FAIL;
  1645. DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to append slash.")));
  1646. goto Exit;
  1647. }
  1648. //
  1649. // Loop through the list
  1650. //
  1651. lpTemp = lpDir = lpExclusionList;
  1652. while (*lpTemp) {
  1653. //
  1654. // Look for the semicolon separator
  1655. //
  1656. while (*lpTemp && ((*lpTemp) != TEXT(';'))) {
  1657. lpTemp++;
  1658. }
  1659. //
  1660. // Remove any leading spaces
  1661. //
  1662. while (*lpDir && ((*lpDir) == TEXT(' '))) {
  1663. lpDir++;
  1664. }
  1665. //
  1666. // Skip empty entry
  1667. //
  1668. if (lpTemp != lpDir)
  1669. {
  1670. //
  1671. // Note:
  1672. // Empty Spaces will not make the whole profile dir excluded
  1673. // in RecurseDirectory.
  1674. //
  1675. //
  1676. // Put the directory name on the temp buffer, not include ';'
  1677. //
  1678. *lpEnd = TEXT('\0');
  1679. hr = StringCchCatN (lpEnd, cchEnd, lpDir, (int)(lpTemp - lpDir));
  1680. if (FAILED(hr))
  1681. {
  1682. DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to append new list item.")));
  1683. goto Exit;
  1684. }
  1685. DebugMsg((DM_VERBOSE, TEXT("ConvertExclusionList: Adding %s to ExclusionList"), szTemp));
  1686. //
  1687. // Add the string to the exclusion list
  1688. //
  1689. if (lpExcludeList) {
  1690. dwStrLen = lstrlen (szTemp) + 1;
  1691. dwSize += dwStrLen;
  1692. lpTempList = LocalReAlloc (lpExcludeList, dwSize * sizeof(TCHAR),
  1693. LMEM_MOVEABLE | LMEM_ZEROINIT);
  1694. if (!lpTempList) {
  1695. hr = E_FAIL;
  1696. DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to realloc memory with %d"), GetLastError()));
  1697. goto Exit;
  1698. }
  1699. lpExcludeList = lpTempList;
  1700. lpInsert = lpExcludeList + dwSize - dwStrLen - 1;
  1701. StringCchCopy (lpInsert, dwStrLen, szTemp);
  1702. } else {
  1703. dwSize += lstrlen (szTemp);
  1704. lpExcludeList = LocalAlloc (LPTR, dwSize * sizeof(TCHAR));
  1705. if (!lpExcludeList) {
  1706. hr = E_FAIL;
  1707. DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to alloc memory with %d"), GetLastError()));
  1708. goto Exit;
  1709. }
  1710. StringCchCopy (lpExcludeList, dwSize, szTemp);
  1711. lpExcludeList[dwSize - 1] = TEXT('\0'); // The last null terminator
  1712. }
  1713. }
  1714. //
  1715. // If we are at the end of the exclusion list, we're done
  1716. //
  1717. if (!(*lpTemp)) {
  1718. break;
  1719. }
  1720. //
  1721. // Prep for the next entry
  1722. //
  1723. lpTemp++;
  1724. lpDir = lpTemp;
  1725. }
  1726. hr = S_OK;
  1727. Exit:
  1728. if (FAILED(hr))
  1729. {
  1730. if (lpExcludeList)
  1731. {
  1732. LocalFree(lpExcludeList);
  1733. lpExcludeList = NULL;
  1734. }
  1735. }
  1736. return lpExcludeList;
  1737. }
  1738. //*************************************************************
  1739. //
  1740. // FindDirectorySize()
  1741. //
  1742. // Purpose: Takes the Directory Name and the list of files
  1743. // returned by RecurseDir and gets the total size.
  1744. //
  1745. // Parameters: lpDir - '\' terminated Source Directory
  1746. // lpFiles - List of files to be copied
  1747. // dwFlags - Flags
  1748. // pdwLargestHiveFile - optional parameter that
  1749. // returns the largest hive
  1750. // file size.
  1751. // pdwTotalFiles - the size of the directory
  1752. //
  1753. // Return: Win32 error code.
  1754. //
  1755. //*************************************************************
  1756. DWORD FindDirectorySize(LPTSTR lpDir, LPFILEINFO lpFiles, DWORD dwFlags, DWORD* pdwLargestHiveFile, DWORD* pdwTotalFiles)
  1757. {
  1758. LPFILEINFO lpTemp = NULL;
  1759. if(pdwLargestHiveFile) {
  1760. *pdwLargestHiveFile = 0;
  1761. }
  1762. if(!pdwTotalFiles) {
  1763. SetLastError(ERROR_INVALID_PARAMETER);
  1764. return ERROR_INVALID_PARAMETER;
  1765. }
  1766. else {
  1767. *pdwTotalFiles = 0;
  1768. }
  1769. lpTemp = lpFiles;
  1770. while (lpTemp) {
  1771. if (lpTemp->bHive) {
  1772. if (!(dwFlags & CPD_IGNOREHIVE)) {
  1773. if(pdwLargestHiveFile && (*pdwLargestHiveFile < lpTemp->dwFileSize)) {
  1774. *pdwLargestHiveFile = lpTemp->dwFileSize;
  1775. }
  1776. *pdwTotalFiles += lpTemp->dwFileSize;
  1777. }
  1778. }
  1779. else {
  1780. *pdwTotalFiles += lpTemp->dwFileSize;
  1781. }
  1782. lpTemp = lpTemp->pNext;
  1783. }
  1784. return ERROR_SUCCESS;
  1785. }
  1786. //*************************************************************
  1787. //
  1788. // FindTotalDiskSpaceNeeded()
  1789. //
  1790. // Purpose: Calculate the maximum amount of disk space on the
  1791. // destination drive that is needed to reconcile the
  1792. // source and the destination directories. The
  1793. // algorithm is as follows:
  1794. // max(source size, destination size) +
  1795. // NUM_COPY_THREADS * size of the largest file in source dir -
  1796. // destination size
  1797. // The reason for this algorithm is that the copy
  1798. // operation is done by NUM_COPY_THREADS threads.
  1799. // They copy the files to a temp file and then delete
  1800. // the destination file and rename the temp file.
  1801. //
  1802. // Parameters: dwTotalSrcFiles total size of the source files
  1803. // dwTotalDestFiles total size of the destination files
  1804. // dwLargestHiveFile largest hive file
  1805. // lpSrcFiles List of source files
  1806. // dwFlags - Flags
  1807. //
  1808. // Return: Disk space needed.
  1809. //
  1810. // History: Created WeiruC 2/10/2000
  1811. //
  1812. //*************************************************************
  1813. DWORD FindTotalDiskSpaceNeeded(DWORD dwTotalSrcFiles,
  1814. DWORD dwTotalDestFiles,
  1815. DWORD dwLargestHiveFile,
  1816. LPFILEINFO lpSrcFiles,
  1817. DWORD dwFlags)
  1818. {
  1819. DWORD dwNumOfCopyThreads = NUM_COPY_THREADS;
  1820. DWORD dwDiskSpaceNeeded = 0;
  1821. LPFILEINFO lpCur = lpSrcFiles;
  1822. DWORD i, j; // loop counters
  1823. //
  1824. // Check for empty file list.
  1825. //
  1826. if(!lpSrcFiles) {
  1827. return dwLargestHiveFile;
  1828. }
  1829. //
  1830. // How many copy threads are there actually?
  1831. //
  1832. if(dwFlags & CPD_SLOWCOPY) {
  1833. dwNumOfCopyThreads = 1;
  1834. }
  1835. //
  1836. // Find the size of the largest file in the source file list. The hive
  1837. // files are not in this file list, be careful not to forget them. Hive
  1838. // files have to be treated very carefully because they are always copied
  1839. // over before we create those copy threads.
  1840. //
  1841. dwDiskSpaceNeeded = FindTotalNMaxFileSize(lpSrcFiles, dwNumOfCopyThreads);
  1842. DebugMsg((DM_VERBOSE, TEXT("FindTotalDiskSpaceNeeded: Largest %d file size is %d"), dwNumOfCopyThreads, dwDiskSpaceNeeded));
  1843. //
  1844. // The actual disk space needed.
  1845. //
  1846. if(dwDiskSpaceNeeded < dwLargestHiveFile) {
  1847. dwDiskSpaceNeeded = dwLargestHiveFile;
  1848. }
  1849. if(dwTotalSrcFiles > dwTotalDestFiles) {
  1850. dwDiskSpaceNeeded += dwTotalSrcFiles - dwTotalDestFiles;
  1851. }
  1852. //
  1853. // It is too much of a pain to actually figure out cluster size impact.
  1854. // We'll just add an extra 10% of the disk space needed.
  1855. //
  1856. dwDiskSpaceNeeded += dwDiskSpaceNeeded / 10;
  1857. return dwDiskSpaceNeeded;
  1858. }
  1859. //*************************************************************
  1860. //
  1861. // FindTotalNMaxFileSize()
  1862. //
  1863. // Purpose: Calculates the total size for dwNumOfFiles
  1864. // number of largest files.
  1865. //
  1866. // Parameters: lpSrcFiles - List of source files
  1867. // dwNumOfFiles - Number of files.
  1868. // dwNumOfFiles <= NUM_COPY_THREADS
  1869. //
  1870. // Return: Disk space needed for n largest files.
  1871. //
  1872. // History: Created santanuc 10/03/2000
  1873. //
  1874. //*************************************************************
  1875. DWORD FindTotalNMaxFileSize(LPFILEINFO lpSrcFiles, DWORD dwNumOfFiles)
  1876. {
  1877. DWORD pdwNMaxVal[NUM_COPY_THREADS], dwIndex;
  1878. LPFILEINFO lpCur;
  1879. DWORD dwTotalSize = 0, dwTmp;
  1880. if (!lpSrcFiles)
  1881. return 0;
  1882. for(dwIndex = 0; dwIndex < dwNumOfFiles; dwIndex++) {
  1883. pdwNMaxVal[dwIndex] = 0;
  1884. }
  1885. for(lpCur = lpSrcFiles; lpCur; lpCur = lpCur->pNext) {
  1886. if (!lpCur->bHive) {
  1887. dwIndex = dwNumOfFiles-1;
  1888. if (lpCur->dwFileSize > pdwNMaxVal[dwIndex]) {
  1889. pdwNMaxVal[dwIndex] = lpCur->dwFileSize;
  1890. while (dwIndex > 0 && pdwNMaxVal[dwIndex] > pdwNMaxVal[dwIndex-1]) {
  1891. dwTmp = pdwNMaxVal[dwIndex-1];
  1892. pdwNMaxVal[dwIndex-1] = pdwNMaxVal[dwIndex];
  1893. pdwNMaxVal[dwIndex] = dwTmp;
  1894. dwIndex--;
  1895. }
  1896. }
  1897. }
  1898. }
  1899. for(dwIndex = 0; dwIndex < dwNumOfFiles; dwIndex++) {
  1900. dwTotalSize += pdwNMaxVal[dwIndex];
  1901. }
  1902. return dwTotalSize;
  1903. }