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.

3037 lines
86 KiB

  1. /*
  2. Module Name:
  3. mirror.c
  4. Abstract:
  5. This module implements routines to copy up a tree to a destination.
  6. Author:
  7. Andy Herron May 27 1998
  8. Revision History:
  9. */
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. #define RNDM_CONSTANT 314159269 /* default scrambling constant */
  13. #define RNDM_PRIME 1000000007 /* prime number for scrambling */
  14. //
  15. // Compute a string hash value that is invariant to case
  16. //
  17. #define COMPUTE_STRING_HASH( _pus, _phash ) { \
  18. PWCHAR _p = _pus; \
  19. ULONG _chHolder =0; \
  20. \
  21. while( *_p != L'\0' ) { \
  22. _chHolder = 37 * _chHolder + (unsigned int) *(_p++); \
  23. } \
  24. \
  25. *(_phash) = abs(RNDM_CONSTANT * _chHolder) % RNDM_PRIME; \
  26. }
  27. #ifdef DEBUGLOG
  28. #define DEBUG_LOG_BUFFER_SIZE 1024
  29. extern HANDLE hDebugLogFile;
  30. extern CRITICAL_SECTION DebugFileLock;
  31. UCHAR DebugLogFileBuffer[DEBUG_LOG_BUFFER_SIZE];
  32. ULONG DebugLogFileOffset = 0;
  33. #endif
  34. BOOLEAN IMirrorUpdatedTokens = FALSE;
  35. //
  36. // this is the structure we use to track what files already exist on the
  37. // destination
  38. //
  39. typedef struct _EXISTING_MIRROR_FILE {
  40. LIST_ENTRY ListEntry;
  41. DWORD NameHashValue;
  42. DWORD FileAttributes;
  43. LARGE_INTEGER CreationTime;
  44. LARGE_INTEGER LastWriteTime;
  45. LARGE_INTEGER ChangeTime;
  46. LARGE_INTEGER EndOfFile;
  47. ULONG FileNameLength;
  48. ULONG EaSize;
  49. WCHAR FileName[1];
  50. } EXISTING_MIRROR_FILE, *PEXISTING_MIRROR_FILE;
  51. //
  52. // this is the structure we use to track the directories that we still need
  53. // to copy.
  54. //
  55. typedef struct _COPY_DIRECTORY {
  56. LIST_ENTRY ListEntry;
  57. PCOPY_TREE_CONTEXT CopyContext;
  58. BOOLEAN DirectoryRoot; // is this the root of the volume?
  59. DWORD SourceAttributes;
  60. PWCHAR Source;
  61. PWCHAR Dest;
  62. PWCHAR NtSourceName;
  63. PWCHAR NtDestName;
  64. WCHAR SourceBuffer[1];
  65. } COPY_DIRECTORY, *PCOPY_DIRECTORY;
  66. DWORD
  67. CreateMatchingDirectory (
  68. PIMIRROR_THREAD_CONTEXT ThreadContext,
  69. PCOPY_DIRECTORY DirectoryInfo
  70. );
  71. DWORD
  72. MirrorFile(
  73. PIMIRROR_THREAD_CONTEXT ThreadContext,
  74. PWCHAR SourceFileName,
  75. PFILE_FULL_DIR_INFORMATION SourceFindData,
  76. PWCHAR DestFileName,
  77. PEXISTING_MIRROR_FILE ExistingMirrorFile
  78. );
  79. DWORD
  80. UnconditionalDelete (
  81. PIMIRROR_THREAD_CONTEXT ThreadContext,
  82. PWCHAR SourceFile,
  83. PWCHAR FileToDelete,
  84. DWORD Attributes,
  85. PWCHAR NameBuffer
  86. );
  87. DWORD
  88. StoreOurSecurityStream (
  89. PIMIRROR_THREAD_CONTEXT ThreadContext,
  90. PWCHAR Source,
  91. PWCHAR Dest,
  92. DWORD AttributesToStore,
  93. LARGE_INTEGER ChangeTime
  94. );
  95. DWORD
  96. StoreOurSFNStream (
  97. PIMIRROR_THREAD_CONTEXT ThreadContext,
  98. PWCHAR Source,
  99. PWCHAR Dest,
  100. PWCHAR ShortFileName
  101. );
  102. DWORD
  103. GetOurSecurityStream (
  104. PIMIRROR_THREAD_CONTEXT ThreadContext,
  105. PWCHAR Dest,
  106. PMIRROR_ACL_STREAM MirrorAclStream
  107. );
  108. DWORD
  109. GetOurSFNStream (
  110. PIMIRROR_THREAD_CONTEXT ThreadContext,
  111. PWCHAR Dest,
  112. PMIRROR_SFN_STREAM MirrorSFNStream,
  113. PWCHAR SFNBuffer,
  114. DWORD SFNBufferSize
  115. );
  116. DWORD
  117. CopySubtree(
  118. PIMIRROR_THREAD_CONTEXT ThreadContext,
  119. PCOPY_DIRECTORY DirectoryInfo
  120. );
  121. BOOL
  122. IMSetFileTime(
  123. HANDLE hFile,
  124. CONST FILETIME *lpCreationTime,
  125. CONST FILETIME *lpLastAccessTime,
  126. CONST FILETIME *lpLastWriteTime,
  127. CONST FILETIME *lpChangeTime
  128. );
  129. DWORD
  130. IMirrorOpenDirectory (
  131. HANDLE *Handle,
  132. PWCHAR NtDirName,
  133. DWORD Disposition,
  134. BOOLEAN IsSource,
  135. DWORD SourceAttributes,
  136. PFILE_BASIC_INFORMATION BasicDirInfo OPTIONAL
  137. );
  138. #ifdef IMIRROR_SUPPORT_ENCRYPTED
  139. DWORD
  140. IMCopyEncryptFile(
  141. PCOPY_TREE_CONTEXT CopyContext,
  142. LPWSTR SourceFileName,
  143. LPWSTR DestFileName
  144. );
  145. #endif
  146. NTSTATUS
  147. CanHandleReparsePoint (
  148. PIMIRROR_THREAD_CONTEXT ThreadContext,
  149. PWCHAR SourceFileName,
  150. DWORD FileAttributes
  151. );
  152. DWORD
  153. AllocateCopyTreeContext (
  154. PCOPY_TREE_CONTEXT *CopyContext,
  155. BOOLEAN DeleteOtherFiles
  156. )
  157. /*++
  158. Description:
  159. This routine allocates the necessary structure that we pass around
  160. that contains all of our "global" data during copying a large tree.
  161. Parameters:
  162. CopyContext : Location to put allocated structure.
  163. DeleteOtherFiles : Do we remove files and dirs that aren't on the master?
  164. Return Value:
  165. Win32 error code
  166. ++*/
  167. {
  168. PCOPY_TREE_CONTEXT context;
  169. *CopyContext = IMirrorAllocMem(sizeof( COPY_TREE_CONTEXT ));
  170. context = *CopyContext;
  171. if (context == NULL) {
  172. return GetLastError();
  173. }
  174. InitializeListHead( &(context->PendingDirectoryList) );
  175. InitializeCriticalSection( &(context->Lock) );
  176. context->Cancelled = FALSE;
  177. context->DeleteOtherFiles = DeleteOtherFiles;
  178. return ERROR_SUCCESS;
  179. }
  180. VOID
  181. FreeCopyTreeContext (
  182. PCOPY_TREE_CONTEXT CopyContext
  183. )
  184. /*++
  185. Description:
  186. This routine frees the necessary structures that we pass around
  187. that contains all of our "global" data during copying a large tree.
  188. Parameters:
  189. CopyContext : Structure that is no longer needed.
  190. Return Value:
  191. None
  192. ++*/
  193. {
  194. while (IsListEmpty( &(CopyContext->PendingDirectoryList) ) == FALSE) {
  195. PCOPY_DIRECTORY copyDir;
  196. PLIST_ENTRY listEntry = RemoveHeadList( &(CopyContext->PendingDirectoryList) );
  197. copyDir = (PCOPY_DIRECTORY) CONTAINING_RECORD( listEntry,
  198. COPY_DIRECTORY,
  199. ListEntry );
  200. IMirrorFreeMem( copyDir );
  201. }
  202. DeleteCriticalSection( &CopyContext->Lock );
  203. return;
  204. }
  205. DWORD
  206. CopyTree (
  207. PCOPY_TREE_CONTEXT CopyContext,
  208. BOOLEAN IsNtfs,
  209. PWCHAR SourceRoot,
  210. PWCHAR DestRoot
  211. )
  212. /*++
  213. Description:
  214. This is the main routine that initiates the full subtree copy.
  215. Parameters:
  216. CopyContext : Structure that is no longer needed.
  217. SourceRoot : source tree to copy in NT format, not DOS format.
  218. DestRoot : location to copy it to
  219. Return Value:
  220. Win32 error code
  221. ++*/
  222. {
  223. DWORD err;
  224. DWORD sourceAttributes;
  225. IMIRROR_THREAD_CONTEXT threadContext;
  226. COPY_DIRECTORY rootDir;
  227. //
  228. // if we were to create multiple threads handling copying this subtree,
  229. // this is where we'll setup the threads where each has their own
  230. // thread context.
  231. //
  232. if (! IMirrorUpdatedTokens) {
  233. HANDLE hToken;
  234. // Enable the privileges necessary to copy security information.
  235. err = GetTokenHandle(&hToken);
  236. if (err == ERROR_SUCCESS) {
  237. SetPrivs(hToken, TEXT("SeSecurityPrivilege"));
  238. // SetPrivs(hToken, TEXT("SeBackupPrivilege"));
  239. // SetPrivs(hToken, TEXT("SeRestorePrivilege"));
  240. // SetPrivs(hToken, TEXT("SeTakeOwnershipPrivilege"));
  241. IMirrorUpdatedTokens = TRUE;
  242. }
  243. }
  244. retryCopyTree:
  245. RtlZeroMemory( &threadContext, sizeof( threadContext ));
  246. threadContext.CopyContext = CopyContext;
  247. threadContext.IsNTFS = IsNtfs;
  248. threadContext.SourceDirHandle = INVALID_HANDLE_VALUE;
  249. threadContext.DestDirHandle = INVALID_HANDLE_VALUE;
  250. threadContext.SDBufferLength = IMIRROR_INITIAL_SD_LENGTH;
  251. threadContext.SFNBufferLength = IMIRROR_INITIAL_SFN_LENGTH;
  252. InitializeListHead( &threadContext.FilesToIgnore );
  253. sourceAttributes = GetFileAttributes( SourceRoot );
  254. if (sourceAttributes == (DWORD) -1) {
  255. ULONG action;
  256. err = GetLastError();
  257. action = ReportCopyError( CopyContext,
  258. SourceRoot,
  259. COPY_ERROR_ACTION_GETATTR,
  260. err );
  261. if (action == STATUS_RETRY) {
  262. goto retryCopyTree;
  263. } else if (action == STATUS_REQUEST_ABORTED) {
  264. goto exitCopyTree;
  265. }
  266. //
  267. // the user told us to ignore the error. we'll do our best.
  268. //
  269. sourceAttributes = FILE_ATTRIBUTE_DIRECTORY;
  270. }
  271. GetRegistryFileList( &threadContext.FilesToIgnore );
  272. RtlZeroMemory( &rootDir, sizeof( COPY_DIRECTORY ));
  273. rootDir.CopyContext = CopyContext;
  274. rootDir.DirectoryRoot = TRUE;
  275. rootDir.SourceAttributes = sourceAttributes;
  276. rootDir.Source = SourceRoot;
  277. rootDir.Dest = DestRoot;
  278. err = CopySubtree( &threadContext,
  279. &rootDir
  280. );
  281. ASSERT( threadContext.SourceDirHandle == INVALID_HANDLE_VALUE );
  282. ASSERT( threadContext.DestDirHandle == INVALID_HANDLE_VALUE );
  283. EnterCriticalSection( &CopyContext->Lock );
  284. while ((CopyContext->Cancelled == FALSE) &&
  285. (IsListEmpty( &(CopyContext->PendingDirectoryList) ) == FALSE)) {
  286. PCOPY_DIRECTORY copyDir;
  287. PLIST_ENTRY listEntry = RemoveHeadList( &(CopyContext->PendingDirectoryList) );
  288. copyDir = (PCOPY_DIRECTORY) CONTAINING_RECORD( listEntry,
  289. COPY_DIRECTORY,
  290. ListEntry );
  291. LeaveCriticalSection( &CopyContext->Lock );
  292. err = CopySubtree( &threadContext,
  293. copyDir
  294. );
  295. ASSERT( threadContext.SourceDirHandle == INVALID_HANDLE_VALUE );
  296. ASSERT( threadContext.DestDirHandle == INVALID_HANDLE_VALUE );
  297. IMirrorFreeMem( copyDir );
  298. EnterCriticalSection( &CopyContext->Lock );
  299. }
  300. exitCopyTree:
  301. if (threadContext.SDBuffer) {
  302. IMirrorFreeMem( threadContext.SDBuffer );
  303. }
  304. if (threadContext.SFNBuffer) {
  305. IMirrorFreeMem( threadContext.SFNBuffer );
  306. }
  307. if (threadContext.DirectoryBuffer) {
  308. IMirrorFreeMem( threadContext.DirectoryBuffer );
  309. }
  310. if ( threadContext.FindBufferBase ) {
  311. IMirrorFreeMem( threadContext.FindBufferBase );
  312. }
  313. while (IsListEmpty( &(threadContext.FilesToIgnore) ) == FALSE) {
  314. PIMIRROR_IGNORE_FILE_LIST ignoreListEntry;
  315. PLIST_ENTRY listEntry = RemoveHeadList( &(threadContext.FilesToIgnore) );
  316. ignoreListEntry = (PIMIRROR_IGNORE_FILE_LIST)
  317. CONTAINING_RECORD( listEntry,
  318. IMIRROR_IGNORE_FILE_LIST,
  319. ListEntry );
  320. IMirrorFreeMem( ignoreListEntry );
  321. }
  322. return err;
  323. }
  324. DWORD
  325. CopySubtree(
  326. PIMIRROR_THREAD_CONTEXT ThreadContext,
  327. PCOPY_DIRECTORY DirectoryInfo
  328. )
  329. /*++
  330. Description:
  331. This routine enumerates the directories on the client to continue
  332. traversing the tree. It then enumerates the files on the slave
  333. ( to compare them against what is on the master ), it then ensures
  334. that all files on the master are up on the slave. It then deletes all
  335. files on the slave that are not on the master.
  336. Parameters:
  337. ThreadContext : data for this instance of copying a tree
  338. DirectoryInfo : information on the source and dest that we know of
  339. Return Value:
  340. Win32 error code
  341. ++*/
  342. {
  343. DWORD err;
  344. PWCHAR destFileName;
  345. PWCHAR sourceFileName;
  346. ULONG destFileNameSize;
  347. ULONG sourceFileNameSize;
  348. PWCHAR endOfSourcePath;
  349. PWCHAR endOfDestPath;
  350. LIST_ENTRY existingMirrorFilesList;
  351. PLIST_ENTRY listEntry;
  352. PEXISTING_MIRROR_FILE existingMirrorFile;
  353. BOOLEAN deleteExistingMirrorFilesNotInMaster;
  354. PCOPY_TREE_CONTEXT copyContext;
  355. UNICODE_STRING ntSourcePath;
  356. UNICODE_STRING ntDestPath;
  357. PFILE_FULL_DIR_INFORMATION findData;
  358. ULONG errorCase;
  359. retryCopySubtree:
  360. errorCase = ERROR_SUCCESS;
  361. destFileName = NULL;
  362. sourceFileName = NULL;
  363. deleteExistingMirrorFilesNotInMaster = FALSE;
  364. copyContext = ThreadContext->CopyContext;
  365. InitializeListHead( &existingMirrorFilesList );
  366. RtlInitUnicodeString( &ntSourcePath, NULL );
  367. RtlInitUnicodeString( &ntDestPath, NULL );
  368. //
  369. // since some of the NT specific calls use the NT format of the name,
  370. // we grab that up front so as not to have to do it every time.
  371. //
  372. if (RtlDosPathNameToNtPathName_U( DirectoryInfo->Source,
  373. &ntSourcePath,
  374. NULL,
  375. NULL ) == FALSE) {
  376. err = STATUS_OBJECT_PATH_NOT_FOUND;
  377. errorCase = ReportCopyError( copyContext,
  378. DirectoryInfo->Source,
  379. COPY_ERROR_ACTION_OPEN_DIR,
  380. err );
  381. goto exitCopySubtree;
  382. }
  383. if (RtlDosPathNameToNtPathName_U( DirectoryInfo->Dest,
  384. &ntDestPath,
  385. NULL,
  386. NULL ) == FALSE) {
  387. err = STATUS_OBJECT_PATH_NOT_FOUND;
  388. errorCase = ReportCopyError( copyContext,
  389. DirectoryInfo->Dest,
  390. COPY_ERROR_ACTION_OPEN_DIR,
  391. err );
  392. goto exitCopySubtree;
  393. }
  394. DirectoryInfo->NtSourceName = ntSourcePath.Buffer;
  395. DirectoryInfo->NtDestName = ntDestPath.Buffer;
  396. //
  397. // Create a directory on the slave that matches this one. This will
  398. // open handles to both the source and dest directories. We cache the
  399. // handle in case other operations need it.
  400. //
  401. err = CreateMatchingDirectory( ThreadContext, DirectoryInfo );
  402. if (err != ERROR_SUCCESS) {
  403. goto exitCopySubtree;
  404. }
  405. destFileNameSize = (lstrlenW( DirectoryInfo->Dest ) + 5 + MAX_PATH) * sizeof(WCHAR);
  406. destFileName = IMirrorAllocMem( destFileNameSize );
  407. if (destFileName == NULL) {
  408. err = GetLastError();
  409. errorCase = ReportCopyError( copyContext,
  410. DirectoryInfo->Dest,
  411. COPY_ERROR_ACTION_MALLOC,
  412. err );
  413. goto exitCopySubtree;
  414. }
  415. lstrcpyW( destFileName, DirectoryInfo->Dest );
  416. lstrcatW( destFileName, L"\\" );
  417. // track the next character after the trailing backslash
  418. endOfDestPath = destFileName + lstrlenW( destFileName );
  419. sourceFileNameSize = (lstrlenW( DirectoryInfo->Source ) + 5 + MAX_PATH) * sizeof(WCHAR);
  420. sourceFileName = IMirrorAllocMem( sourceFileNameSize );
  421. if (sourceFileName == NULL) {
  422. err = GetLastError();
  423. errorCase = ReportCopyError( copyContext,
  424. DirectoryInfo->Source,
  425. COPY_ERROR_ACTION_MALLOC,
  426. err );
  427. goto exitCopySubtree;
  428. }
  429. lstrcpyW( sourceFileName, DirectoryInfo->Source );
  430. if (!DirectoryInfo->DirectoryRoot) {
  431. lstrcatW( sourceFileName, L"\\" );
  432. }
  433. // track the next character after the trailing backslash
  434. endOfSourcePath = sourceFileName + lstrlenW( sourceFileName );
  435. //
  436. // enumerate all files/directories on the target so that we have the
  437. // details to grovel correctly.
  438. //
  439. err = IMFindFirstFile( ThreadContext,
  440. ThreadContext->DestDirHandle,
  441. &findData );
  442. while ( findData != NULL &&
  443. err == ERROR_SUCCESS &&
  444. copyContext->Cancelled == FALSE) {
  445. InterlockedIncrement( &copyContext->DestFilesScanned );
  446. if (((findData->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) &&
  447. (findData->FileName[0] == L'.')) {
  448. if ((findData->FileNameLength == sizeof(WCHAR)) ||
  449. (findData->FileName[1] == L'.' &&
  450. findData->FileNameLength == 2*sizeof(WCHAR))) {
  451. goto skipToNextDir1;
  452. }
  453. }
  454. if (DirectoryInfo->DirectoryRoot &&
  455. ((findData->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) &&
  456. ((!_wcsnicmp(&findData->FileName[0],
  457. L"pagefile.sys",
  458. findData->FileNameLength)) ||
  459. (!_wcsnicmp(&findData->FileName[0],
  460. L"hiberfil.sys",
  461. findData->FileNameLength)))) {
  462. goto skipToNextDir1;
  463. }
  464. existingMirrorFile = (PEXISTING_MIRROR_FILE) IMirrorAllocMem(
  465. sizeof(EXISTING_MIRROR_FILE) +
  466. findData->FileNameLength);
  467. if (existingMirrorFile == NULL) {
  468. err = GetLastError();
  469. errorCase = ReportCopyError( copyContext,
  470. destFileName,
  471. COPY_ERROR_ACTION_MALLOC,
  472. err );
  473. goto exitCopySubtree;
  474. }
  475. existingMirrorFile->FileAttributes = findData->FileAttributes;
  476. existingMirrorFile->CreationTime = findData->CreationTime;
  477. existingMirrorFile->LastWriteTime = findData->LastWriteTime;
  478. existingMirrorFile->ChangeTime = findData->ChangeTime;
  479. existingMirrorFile->EndOfFile = findData->EndOfFile;
  480. existingMirrorFile->EaSize = findData->EaSize;
  481. existingMirrorFile->FileNameLength = findData->FileNameLength;
  482. RtlCopyMemory( &existingMirrorFile->FileName[0],
  483. &findData->FileName[0],
  484. findData->FileNameLength );
  485. existingMirrorFile->FileName[ findData->FileNameLength / sizeof(WCHAR) ] = UNICODE_NULL;
  486. COMPUTE_STRING_HASH( &existingMirrorFile->FileName[0],
  487. &existingMirrorFile->NameHashValue );
  488. InsertTailList( &existingMirrorFilesList, &existingMirrorFile->ListEntry );
  489. skipToNextDir1:
  490. err = IMFindNextFile( ThreadContext,
  491. ThreadContext->DestDirHandle,
  492. &findData );
  493. }
  494. //
  495. // copy all files up from the source to the dest
  496. //
  497. err = IMFindFirstFile( ThreadContext,
  498. ThreadContext->SourceDirHandle,
  499. &findData );
  500. if (err != ERROR_SUCCESS) {
  501. if (err == STATUS_NO_MORE_FILES) {
  502. err = ERROR_SUCCESS;
  503. } else {
  504. errorCase = ReportCopyError( copyContext,
  505. DirectoryInfo->Source,
  506. COPY_ERROR_ACTION_ENUMERATE,
  507. err );
  508. goto exitCopySubtree;
  509. }
  510. }
  511. while ( findData != NULL &&
  512. err == ERROR_SUCCESS &&
  513. copyContext->Cancelled == FALSE) {
  514. DWORD nameHashValue;
  515. if (((findData->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) &&
  516. (findData->FileName[0] == L'.')) {
  517. if ((findData->FileNameLength == sizeof(WCHAR)) ||
  518. (findData->FileName[1] == L'.' &&
  519. findData->FileNameLength == 2*sizeof(WCHAR))) {
  520. goto skipToNextDir;
  521. }
  522. }
  523. if (DirectoryInfo->DirectoryRoot &&
  524. ((findData->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) &&
  525. (!_wcsnicmp(&findData->FileName[0],
  526. L"pagefile.sys",
  527. findData->FileNameLength))) {
  528. goto skipToNextDir;
  529. }
  530. InterlockedIncrement( &copyContext->SourceFilesScanned );
  531. RtlCopyMemory( endOfSourcePath,
  532. findData->FileName,
  533. findData->FileNameLength );
  534. *(endOfSourcePath+(findData->FileNameLength/sizeof(WCHAR))) = UNICODE_NULL;
  535. RtlCopyMemory( endOfDestPath,
  536. findData->FileName,
  537. findData->FileNameLength );
  538. *(endOfDestPath+(findData->FileNameLength/sizeof(WCHAR))) = UNICODE_NULL;
  539. //
  540. // search the list of existing files on the target to see if
  541. // it's already there.
  542. //
  543. COMPUTE_STRING_HASH( endOfDestPath, &nameHashValue );
  544. listEntry = existingMirrorFilesList.Flink;
  545. existingMirrorFile = NULL;
  546. while (listEntry != &existingMirrorFilesList) {
  547. existingMirrorFile = (PEXISTING_MIRROR_FILE) CONTAINING_RECORD(
  548. listEntry,
  549. EXISTING_MIRROR_FILE,
  550. ListEntry );
  551. listEntry = listEntry->Flink;
  552. if ((existingMirrorFile->NameHashValue == nameHashValue) &&
  553. (existingMirrorFile->FileNameLength == findData->FileNameLength) &&
  554. (CompareStringW( LOCALE_SYSTEM_DEFAULT,
  555. NORM_IGNORECASE,
  556. endOfDestPath,
  557. findData->FileNameLength / sizeof(WCHAR),
  558. &existingMirrorFile->FileName[0],
  559. existingMirrorFile->FileNameLength / sizeof(WCHAR)) == 2)) {
  560. break;
  561. }
  562. existingMirrorFile = NULL;
  563. }
  564. if ((findData->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  565. //
  566. // this is a file, let's mirror it up from the master.
  567. //
  568. (VOID)MirrorFile( ThreadContext,
  569. sourceFileName,
  570. findData,
  571. destFileName,
  572. existingMirrorFile
  573. );
  574. } else {
  575. //
  576. // it's a directory, put it on the pending list.
  577. //
  578. PCOPY_DIRECTORY copyDir;
  579. ULONG sourceLength;
  580. sourceLength = lstrlenW( sourceFileName ) + 1; // space for null
  581. copyDir = (PCOPY_DIRECTORY) IMirrorAllocMem(
  582. sizeof( COPY_DIRECTORY ) +
  583. (( sourceLength +
  584. lstrlenW( destFileName ) + 1 )
  585. * sizeof(WCHAR)));
  586. if (copyDir == NULL) {
  587. err = GetLastError();
  588. errorCase = ReportCopyError( copyContext,
  589. sourceFileName,
  590. COPY_ERROR_ACTION_MALLOC,
  591. err );
  592. goto exitCopySubtree;
  593. }
  594. //
  595. // we save off all info we know about both the source and the
  596. // dest so that we don't have to go read it again.
  597. //
  598. copyDir->CopyContext = copyContext;
  599. copyDir->DirectoryRoot = FALSE;
  600. copyDir->SourceAttributes = findData->FileAttributes;
  601. copyDir->Source = &copyDir->SourceBuffer[0];
  602. lstrcpyW( copyDir->Source, sourceFileName );
  603. copyDir->Dest = &copyDir->SourceBuffer[sourceLength];
  604. lstrcpyW( copyDir->Dest, destFileName );
  605. EnterCriticalSection( &copyContext->Lock );
  606. InsertHeadList( &(copyContext->PendingDirectoryList), &copyDir->ListEntry );
  607. LeaveCriticalSection( &copyContext->Lock );
  608. }
  609. if (existingMirrorFile != NULL) {
  610. RemoveEntryList( &existingMirrorFile->ListEntry );
  611. IMirrorFreeMem( existingMirrorFile );
  612. }
  613. skipToNextDir:
  614. err = IMFindNextFile( ThreadContext,
  615. ThreadContext->SourceDirHandle,
  616. &findData );
  617. if (err != ERROR_SUCCESS) {
  618. if (err == STATUS_NO_MORE_FILES) {
  619. err = ERROR_SUCCESS;
  620. } else {
  621. errorCase = ReportCopyError( copyContext,
  622. DirectoryInfo->Source,
  623. COPY_ERROR_ACTION_ENUMERATE,
  624. err );
  625. goto exitCopySubtree;
  626. }
  627. }
  628. }
  629. if (err == ERROR_SUCCESS) {
  630. //
  631. // now go through list of remaining files and directories that were on
  632. // the destination but not on the source to delete them. We only do
  633. // that if we successfully made it through all existing master files.
  634. //
  635. if (copyContext->DeleteOtherFiles) {
  636. deleteExistingMirrorFilesNotInMaster = TRUE;
  637. }
  638. }
  639. exitCopySubtree:
  640. while (IsListEmpty( &existingMirrorFilesList ) == FALSE) {
  641. listEntry = RemoveHeadList( &existingMirrorFilesList );
  642. existingMirrorFile = (PEXISTING_MIRROR_FILE) CONTAINING_RECORD( listEntry,
  643. EXISTING_MIRROR_FILE,
  644. ListEntry );
  645. if ((errorCase == STATUS_SUCCESS) &&
  646. deleteExistingMirrorFilesNotInMaster &&
  647. (copyContext->Cancelled == FALSE)) {
  648. lstrcpyW( endOfDestPath, &existingMirrorFile->FileName[0] );
  649. UnconditionalDelete( ThreadContext,
  650. DirectoryInfo->Source,
  651. destFileName,
  652. existingMirrorFile->FileAttributes,
  653. NULL );
  654. }
  655. IMirrorFreeMem( existingMirrorFile );
  656. }
  657. if (destFileName != NULL) {
  658. IMirrorFreeMem( destFileName );
  659. }
  660. if (sourceFileName != NULL) {
  661. IMirrorFreeMem( sourceFileName );
  662. }
  663. if ( ThreadContext->SourceDirHandle != INVALID_HANDLE_VALUE ) {
  664. NtClose( ThreadContext->SourceDirHandle );
  665. ThreadContext->SourceDirHandle = INVALID_HANDLE_VALUE;
  666. }
  667. if ( ThreadContext->DestDirHandle != INVALID_HANDLE_VALUE ) {
  668. NtClose( ThreadContext->DestDirHandle );
  669. ThreadContext->DestDirHandle = INVALID_HANDLE_VALUE;
  670. }
  671. if (ntSourcePath.Buffer) {
  672. RtlFreeHeap( RtlProcessHeap(), 0, ntSourcePath.Buffer );
  673. }
  674. if (ntDestPath.Buffer) {
  675. RtlFreeHeap( RtlProcessHeap(), 0, ntDestPath.Buffer );
  676. }
  677. if (errorCase == STATUS_RETRY) {
  678. goto retryCopySubtree;
  679. }
  680. if ( errorCase == ERROR_SUCCESS ) {
  681. err = ERROR_SUCCESS; // we ignore all errors if user told us to
  682. }
  683. return err;
  684. }
  685. DWORD
  686. CreateMatchingDirectory (
  687. PIMIRROR_THREAD_CONTEXT ThreadContext,
  688. PCOPY_DIRECTORY DirectoryInfo
  689. )
  690. /*++
  691. Description:
  692. This routine ensures that the destination directory on the mirror
  693. matches the source directory. It doesn't handle the files
  694. or subdirectories, just the actual directory itself.
  695. Parameters:
  696. ThreadContext : instance data for this thread copying a tree
  697. DirectoryInfo : structure containing all the info for the directory
  698. Return Value:
  699. Win32 error code
  700. ++*/
  701. {
  702. FILE_BASIC_INFORMATION sourceDirInfo;
  703. FILE_BASIC_INFORMATION destDirInfo;
  704. DWORD err;
  705. BOOLEAN updateBasic;
  706. BOOLEAN updateStoredSecurityAttributes;
  707. BOOLEAN createdDir;
  708. IO_STATUS_BLOCK IoStatusBlock;
  709. ULONG errorCase;
  710. retryCreateDir:
  711. updateBasic = FALSE;
  712. updateStoredSecurityAttributes = FALSE;
  713. createdDir = FALSE;
  714. err = IMirrorOpenDirectory( &ThreadContext->SourceDirHandle,
  715. DirectoryInfo->NtSourceName,
  716. FILE_OPEN,
  717. TRUE,
  718. DirectoryInfo->SourceAttributes,
  719. &sourceDirInfo
  720. );
  721. if (err != ERROR_SUCCESS) {
  722. errorCase = ReportCopyError( ThreadContext->CopyContext,
  723. DirectoryInfo->Source,
  724. COPY_ERROR_ACTION_OPEN_DIR,
  725. err );
  726. if (errorCase == STATUS_RETRY) {
  727. goto retryCreateDir;
  728. }
  729. if (errorCase == ERROR_SUCCESS) {
  730. err = ERROR_SUCCESS;
  731. }
  732. return err;
  733. }
  734. if (DirectoryInfo->SourceAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  735. errorCase = ReportCopyError( ThreadContext->CopyContext,
  736. DirectoryInfo->Source,
  737. COPY_ERROR_ACTION_OPEN_DIR,
  738. ERROR_REPARSE_ATTRIBUTE_CONFLICT );
  739. err = ERROR_REPARSE_ATTRIBUTE_CONFLICT;
  740. if (errorCase == STATUS_RETRY) {
  741. goto retryCreateDir;
  742. }
  743. //
  744. // we can't ever succeed a create request, so don't allow the
  745. // code to return ERROR_SUCCESS, instead always force an abort
  746. //
  747. if (errorCase == ERROR_SUCCESS) {
  748. //err = ERROR_SUCCESS;
  749. err = ERROR_REQUEST_ABORTED;
  750. }
  751. return err;
  752. }
  753. ASSERT( (DirectoryInfo->SourceAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
  754. err = IMirrorOpenDirectory( &ThreadContext->DestDirHandle,
  755. DirectoryInfo->NtDestName,
  756. FILE_OPEN,
  757. FALSE,
  758. FILE_ATTRIBUTE_DIRECTORY,
  759. &destDirInfo
  760. );
  761. if (err == STATUS_NOT_A_DIRECTORY) {
  762. DWORD DestAttributes = GetFileAttributes( DirectoryInfo->Dest );
  763. //
  764. // this is not a directory on the dest, let's delete it.
  765. //
  766. DestAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; // be real sure of this
  767. err = UnconditionalDelete( ThreadContext,
  768. DirectoryInfo->Source,
  769. DirectoryInfo->Dest,
  770. DestAttributes,
  771. NULL );
  772. if (err != ERROR_SUCCESS) {
  773. return err;
  774. }
  775. }
  776. if (ThreadContext->DestDirHandle == INVALID_HANDLE_VALUE) {
  777. //
  778. // try to create the destination directory from the source
  779. //
  780. err = IMirrorOpenDirectory( &ThreadContext->DestDirHandle,
  781. DirectoryInfo->NtDestName,
  782. FILE_CREATE,
  783. FALSE,
  784. FILE_ATTRIBUTE_DIRECTORY,
  785. &destDirInfo
  786. );
  787. // report either success or failure up to the caller
  788. if (!NT_SUCCESS( err )) {
  789. errorCase = ReportCopyError( ThreadContext->CopyContext,
  790. DirectoryInfo->Dest,
  791. COPY_ERROR_ACTION_CREATE_DIR,
  792. err );
  793. if (errorCase == STATUS_RETRY) {
  794. goto retryCreateDir;
  795. }
  796. if (errorCase == ERROR_SUCCESS) {
  797. err = ERROR_SUCCESS;
  798. }
  799. return err;
  800. }
  801. //
  802. // this is for the success case so it won't fail.
  803. //
  804. ReportCopyError( ThreadContext->CopyContext,
  805. DirectoryInfo->Dest,
  806. COPY_ERROR_ACTION_CREATE_DIR,
  807. ERROR_SUCCESS );
  808. InterlockedIncrement( &ThreadContext->CopyContext->DirectoriesCreated );
  809. createdDir = TRUE;
  810. updateBasic = TRUE;
  811. updateStoredSecurityAttributes = TRUE;
  812. } else {
  813. MIRROR_ACL_STREAM aclStream;
  814. //
  815. // let's get the security descriptor and extended attributes to
  816. // see if we need to update our alternate data stream on the target.
  817. //
  818. err = GetOurSecurityStream( ThreadContext, DirectoryInfo->Dest, &aclStream );
  819. if (!NT_SUCCESS( err )) {
  820. updateStoredSecurityAttributes = TRUE;
  821. } else {
  822. destDirInfo.ChangeTime = aclStream.ChangeTime;
  823. if (( aclStream.ChangeTime.QuadPart != sourceDirInfo.ChangeTime.QuadPart ) ||
  824. ( aclStream.ExtendedAttributes != DirectoryInfo->SourceAttributes ) ) {
  825. updateStoredSecurityAttributes = TRUE;
  826. }
  827. }
  828. //
  829. // if the creation time or lastwrite time is different, then we'll
  830. // update them on the target to match the source.
  831. //
  832. if (( destDirInfo.CreationTime.QuadPart != sourceDirInfo.CreationTime.QuadPart ) ||
  833. ( destDirInfo.LastWriteTime.QuadPart != sourceDirInfo.LastWriteTime.QuadPart )) {
  834. updateBasic = TRUE;
  835. }
  836. }
  837. //
  838. // Save the complete attribute values in the alternate data stream
  839. // on the slave file.
  840. //
  841. if (updateStoredSecurityAttributes || DirectoryInfo->DirectoryRoot) {
  842. err = StoreOurSecurityStream( ThreadContext,
  843. DirectoryInfo->Source,
  844. DirectoryInfo->Dest,
  845. DirectoryInfo->SourceAttributes,
  846. sourceDirInfo.ChangeTime
  847. );
  848. updateBasic = TRUE;
  849. }
  850. if ((err == ERROR_SUCCESS) &&
  851. updateBasic &&
  852. (DirectoryInfo->DirectoryRoot == FALSE)) {
  853. destDirInfo.CreationTime = sourceDirInfo.CreationTime;
  854. destDirInfo.LastWriteTime = sourceDirInfo.LastWriteTime;
  855. destDirInfo.ChangeTime = sourceDirInfo.ChangeTime;
  856. destDirInfo.FileAttributes = 0; // leave dir attributes alone.
  857. err = NtSetInformationFile( ThreadContext->DestDirHandle,
  858. &IoStatusBlock,
  859. &destDirInfo,
  860. sizeof( FILE_BASIC_INFORMATION ),
  861. FileBasicInformation
  862. );
  863. err = IMConvertNT2Win32Error( err );
  864. if ( err != ERROR_SUCCESS) {
  865. errorCase = ReportCopyError( ThreadContext->CopyContext,
  866. DirectoryInfo->Dest,
  867. COPY_ERROR_ACTION_SETATTR,
  868. GetLastError() );
  869. if (errorCase == STATUS_RETRY) {
  870. goto retryCreateDir;
  871. }
  872. if (errorCase == ERROR_SUCCESS) {
  873. err = ERROR_SUCCESS;
  874. }
  875. } else if (! createdDir ) {
  876. InterlockedIncrement( &ThreadContext->CopyContext->AttributesModified );
  877. }
  878. }
  879. //
  880. // Save off our SFN information too.
  881. //
  882. if( (err == ERROR_SUCCESS) && (DirectoryInfo->DirectoryRoot == FALSE) ) {
  883. WCHAR ShortFileNameInStream[MAX_PATH*2];
  884. WCHAR *p = NULL;
  885. //
  886. // Get the short file name on the source directory.
  887. //
  888. ShortFileNameInStream[0] = L'\0';
  889. //
  890. // It's likely that our path looks like \??\C:\xxxxx,
  891. // which GetShortPathName will fail on. We need to fix
  892. // up the path so it looks like a good ol' DOS path.
  893. //
  894. if( p = wcsrchr(DirectoryInfo->NtSourceName, L':') ) {
  895. p -= 1;
  896. } else {
  897. p = DirectoryInfo->NtSourceName;
  898. }
  899. err = GetShortPathName( p,
  900. ShortFileNameInStream,
  901. sizeof(ShortFileNameInStream)/sizeof(WCHAR) );
  902. //
  903. // If we got a short file name, then go set that information in
  904. // the alternate stream in our destination file.
  905. //
  906. if( err == 0 ) {
  907. err = GetLastError();
  908. } else {
  909. if( wcscmp(ShortFileNameInStream, p) ) {
  910. //
  911. // The short file name is different from the name of
  912. // our source file, so better save it off.
  913. //
  914. if( p = wcsrchr(ShortFileNameInStream, L'\\') ) {
  915. p += 1;
  916. } else {
  917. p = ShortFileNameInStream;
  918. }
  919. if( *p != '\0' ) {
  920. WCHAR SavedCharacter = L'\0';
  921. PWSTR q = NULL;
  922. //
  923. // Incredibly nausiating hack where CreateFile explodes
  924. // when we send him a "\??\UNC\...." path, which is exactly
  925. // what we're probably going to send him when we call into
  926. // StoreOurSFNStream(). We'll need to patch the NtDestName
  927. // here, then restore it when we come back.
  928. //
  929. if( q = wcsstr(DirectoryInfo->NtDestName, L"\\??\\UNC\\") ) {
  930. SavedCharacter = DirectoryInfo->NtDestName[6];
  931. DirectoryInfo->NtDestName[6] = L'\\';
  932. q = &DirectoryInfo->NtDestName[6];
  933. } else {
  934. q = DirectoryInfo->NtDestName;
  935. }
  936. err = StoreOurSFNStream( ThreadContext,
  937. DirectoryInfo->NtSourceName,
  938. q,
  939. p );
  940. if( SavedCharacter != L'\0' ) {
  941. // restore the destination path.
  942. DirectoryInfo->NtDestName[6] = SavedCharacter;
  943. }
  944. }
  945. }
  946. }
  947. //
  948. // Cover up any errors here because it's certainly not fatal.
  949. //
  950. err = ERROR_SUCCESS;
  951. }
  952. return err;
  953. }
  954. DWORD
  955. IMirrorOpenDirectory (
  956. HANDLE *Handle,
  957. PWCHAR NtDirName,
  958. DWORD Disposition,
  959. BOOLEAN IsSource,
  960. DWORD SourceAttributes,
  961. PFILE_BASIC_INFORMATION BasicDirInfo OPTIONAL
  962. )
  963. {
  964. NTSTATUS Status;
  965. OBJECT_ATTRIBUTES Obja;
  966. IO_STATUS_BLOCK IoStatusBlock;
  967. UNICODE_STRING UnicodeInput;
  968. DWORD createOptions;
  969. DWORD desiredAccess;
  970. BOOLEAN TranslationStatus;
  971. BOOLEAN StrippedTrailingSlash;
  972. ASSERT( Handle != NULL );
  973. ASSERT( *Handle == INVALID_HANDLE_VALUE );
  974. RtlInitUnicodeString(&UnicodeInput,NtDirName);
  975. if ((UnicodeInput.Length > 2 * sizeof(WCHAR)) &&
  976. (UnicodeInput.Buffer[(UnicodeInput.Length>>1)-1] == L'\\') &&
  977. (UnicodeInput.Buffer[(UnicodeInput.Length>>1)-2] != L':' )) {
  978. UnicodeInput.Length -= sizeof(UNICODE_NULL);
  979. StrippedTrailingSlash = TRUE;
  980. } else {
  981. StrippedTrailingSlash = FALSE;
  982. }
  983. createOptions = FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT;
  984. desiredAccess = FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_TRAVERSE | FILE_READ_ATTRIBUTES;
  985. if (IsSource) {
  986. createOptions |= FILE_OPEN_FOR_BACKUP_INTENT;
  987. } else {
  988. desiredAccess |= FILE_ADD_FILE |
  989. FILE_ADD_SUBDIRECTORY |
  990. FILE_WRITE_ATTRIBUTES |
  991. FILE_DELETE_CHILD;
  992. }
  993. retryCreate:
  994. InitializeObjectAttributes(
  995. &Obja,
  996. &UnicodeInput,
  997. OBJ_CASE_INSENSITIVE,
  998. NULL,
  999. NULL
  1000. );
  1001. //
  1002. // Open the directory for the desired access. This may create it.
  1003. //
  1004. Status = NtCreateFile(
  1005. Handle,
  1006. desiredAccess,
  1007. &Obja,
  1008. &IoStatusBlock,
  1009. NULL,
  1010. SourceAttributes,
  1011. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1012. Disposition,
  1013. createOptions,
  1014. NULL,
  1015. 0 );
  1016. if ( Status == STATUS_INVALID_PARAMETER && StrippedTrailingSlash ) {
  1017. //
  1018. // open of a pnp style path failed, so try putting back the trailing slash
  1019. //
  1020. UnicodeInput.Length += sizeof(UNICODE_NULL);
  1021. StrippedTrailingSlash = FALSE;
  1022. goto retryCreate;
  1023. }
  1024. if (*Handle == NULL) {
  1025. *Handle = INVALID_HANDLE_VALUE;
  1026. }
  1027. if (NT_SUCCESS( Status ) && BasicDirInfo != NULL) {
  1028. //
  1029. // read the attributes for the caller too
  1030. //
  1031. Status = NtQueryInformationFile( *Handle,
  1032. &IoStatusBlock,
  1033. BasicDirInfo,
  1034. sizeof( FILE_BASIC_INFORMATION ),
  1035. FileBasicInformation
  1036. );
  1037. }
  1038. return IMConvertNT2Win32Error( Status );
  1039. }
  1040. DWORD
  1041. MirrorFile(
  1042. PIMIRROR_THREAD_CONTEXT ThreadContext,
  1043. PWCHAR SourceFileName,
  1044. PFILE_FULL_DIR_INFORMATION SourceFindData,
  1045. PWCHAR DestFileName,
  1046. PEXISTING_MIRROR_FILE ExistingMirrorFile
  1047. )
  1048. {
  1049. DWORD err;
  1050. BOOLEAN fileIsAlreadyThere;
  1051. PCOPY_TREE_CONTEXT copyContext;
  1052. BOOLEAN updateStoredSecurityAttributes;
  1053. BOOLEAN updateStoredSFNAttributes;
  1054. BOOLEAN updateBasic;
  1055. BOOLEAN isEncrypted;
  1056. FILE_BASIC_INFORMATION fileBasicInfo;
  1057. IO_STATUS_BLOCK IoStatusBlock;
  1058. HANDLE fileHandle = INVALID_HANDLE_VALUE;
  1059. MIRROR_ACL_STREAM aclStream;
  1060. MIRROR_SFN_STREAM SFNStream;
  1061. ULONG errorCase;
  1062. static FARPROC pSetFileShortName = NULL;
  1063. static BOOL AlreadyCheckedForExport = FALSE;
  1064. WCHAR ShortFileNameInStream[32];
  1065. WCHAR ShortFileName[MAX_PATH],*p;
  1066. retryMirrorFile:
  1067. if ( fileHandle != INVALID_HANDLE_VALUE ) {
  1068. CloseHandle( fileHandle );
  1069. fileHandle = INVALID_HANDLE_VALUE;
  1070. }
  1071. errorCase = STATUS_SUCCESS;
  1072. err = STATUS_SUCCESS;
  1073. fileIsAlreadyThere = FALSE;
  1074. copyContext = ThreadContext->CopyContext;
  1075. updateStoredSecurityAttributes = TRUE;
  1076. updateStoredSFNAttributes = TRUE;
  1077. updateBasic = TRUE;
  1078. isEncrypted = FALSE;
  1079. ShortFileName[0] = L'\0';
  1080. GetShortPathName(
  1081. SourceFileName,
  1082. ShortFileName,
  1083. sizeof(ShortFileName)/sizeof(WCHAR) );
  1084. if (p = wcsrchr(ShortFileName, L'\\')) {
  1085. p += 1;
  1086. } else {
  1087. p = ShortFileName;
  1088. }
  1089. if (!AlreadyCheckedForExport) {
  1090. HMODULE hKernel32 = GetModuleHandle(L"kernel32.dll");
  1091. if (hKernel32) {
  1092. pSetFileShortName = GetProcAddress(
  1093. hKernel32,
  1094. "SetFileShortNameW");
  1095. }
  1096. AlreadyCheckedForExport = TRUE;
  1097. }
  1098. // don't copy file if callback says not to
  1099. if ((err = IMirrorNowDoing(CopyFiles, SourceFileName)) != ERROR_SUCCESS) {
  1100. if (err == STATUS_REQUEST_ABORTED) {
  1101. copyContext->Cancelled = TRUE;
  1102. }
  1103. return STATUS_SUCCESS;
  1104. }
  1105. #ifndef IMIRROR_SUPPORT_ENCRYPTED
  1106. //
  1107. // sorry, for this release we currently don't support encrypted files.
  1108. //
  1109. if (SourceFindData->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  1110. errorCase = ReportCopyError( copyContext,
  1111. SourceFileName,
  1112. COPY_ERROR_ACTION_CREATE_FILE,
  1113. ERROR_FILE_ENCRYPTED );
  1114. if (errorCase == STATUS_RETRY) {
  1115. SourceFindData->FileAttributes = GetFileAttributes( SourceFileName );
  1116. goto retryMirrorFile;
  1117. }
  1118. if (errorCase == ERROR_SUCCESS) {
  1119. err = STATUS_SUCCESS;
  1120. } else {
  1121. err = ERROR_FILE_ENCRYPTED;
  1122. }
  1123. return err;
  1124. }
  1125. #endif
  1126. fileBasicInfo.FileAttributes = 0; // by default, leave them alone
  1127. if (SourceFindData->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  1128. err = CanHandleReparsePoint( ThreadContext,
  1129. SourceFileName,
  1130. SourceFindData->FileAttributes
  1131. );
  1132. if (!NT_SUCCESS(err)) {
  1133. errorCase = ReportCopyError( copyContext,
  1134. SourceFileName,
  1135. COPY_ERROR_ACTION_CREATE_FILE,
  1136. err );
  1137. if (errorCase == STATUS_RETRY) {
  1138. SourceFindData->FileAttributes = GetFileAttributes( SourceFileName );
  1139. goto retryMirrorFile;
  1140. }
  1141. if (errorCase == ERROR_SUCCESS) {
  1142. err = STATUS_SUCCESS;
  1143. }
  1144. return err;
  1145. }
  1146. SourceFindData->FileAttributes &= ~FILE_ATTRIBUTE_REPARSE_POINT;
  1147. }
  1148. if (ExistingMirrorFile) {
  1149. if ((ExistingMirrorFile->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
  1150. ((ExistingMirrorFile->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) !=
  1151. (SourceFindData->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED))) {
  1152. //
  1153. // it exists as a directory. Master is always right, let's
  1154. // delete the directory.
  1155. //
  1156. // Also, if the master and slave differ in whether the file is
  1157. // encrypted or not, delete the slave.
  1158. //
  1159. err = UnconditionalDelete( ThreadContext,
  1160. SourceFileName,
  1161. DestFileName,
  1162. ExistingMirrorFile->FileAttributes,
  1163. NULL );
  1164. if (err != ERROR_SUCCESS) {
  1165. return err;
  1166. }
  1167. ExistingMirrorFile = NULL;
  1168. } else {
  1169. //
  1170. // if the files are the same, leave it be.
  1171. //
  1172. if ((SourceFindData->CreationTime.QuadPart == ExistingMirrorFile->CreationTime.QuadPart ) &&
  1173. (SourceFindData->LastWriteTime.QuadPart == ExistingMirrorFile->LastWriteTime.QuadPart) &&
  1174. (SourceFindData->EaSize == ExistingMirrorFile->EaSize) &&
  1175. (SourceFindData->EndOfFile.QuadPart == ExistingMirrorFile->EndOfFile.QuadPart)) {
  1176. fileIsAlreadyThere = TRUE;
  1177. updateBasic = FALSE;
  1178. //
  1179. // let's get the security descriptor and extended attributes to
  1180. // see if we need to update our alternate data stream on the target.
  1181. //
  1182. err = GetOurSecurityStream( ThreadContext, DestFileName, &aclStream );
  1183. if ((err == ERROR_SUCCESS) &&
  1184. (aclStream.ChangeTime.QuadPart == SourceFindData->ChangeTime.QuadPart) &&
  1185. (SourceFindData->FileAttributes == aclStream.ExtendedAttributes)) {
  1186. updateStoredSecurityAttributes = FALSE;
  1187. } else {
  1188. err = ERROR_SUCCESS;
  1189. }
  1190. //
  1191. // let's get the short file name to see if we need to update
  1192. // our alternate data stream on the target.
  1193. //
  1194. err = GetOurSFNStream(
  1195. ThreadContext,
  1196. DestFileName,
  1197. &SFNStream,
  1198. ShortFileNameInStream,
  1199. sizeof(ShortFileNameInStream) );
  1200. if ((err == ERROR_SUCCESS) &&
  1201. *p != L'\0' &&
  1202. (wcscmp(ShortFileNameInStream, p) == 0)) {
  1203. updateStoredSFNAttributes = FALSE;
  1204. } else {
  1205. err = ERROR_SUCCESS;
  1206. }
  1207. }
  1208. }
  1209. }
  1210. //
  1211. // if the file already exists but it's not current or our alternate
  1212. // stream needs updating, let's update the attributes such that we can
  1213. // modify the file.
  1214. //
  1215. fileBasicInfo.CreationTime.QuadPart = SourceFindData->CreationTime.QuadPart;
  1216. fileBasicInfo.LastWriteTime.QuadPart = SourceFindData->LastWriteTime.QuadPart;
  1217. fileBasicInfo.LastAccessTime.QuadPart = SourceFindData->LastAccessTime.QuadPart;
  1218. fileBasicInfo.ChangeTime.QuadPart = SourceFindData->ChangeTime.QuadPart;
  1219. err = ERROR_SUCCESS;
  1220. if (! fileIsAlreadyThere) {
  1221. #ifdef IMIRROR_SUPPORT_ENCRYPTED
  1222. if (SourceFindData->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  1223. err = IMCopyEncryptFile( ThreadContext->CopyContext,
  1224. SourceFileName,
  1225. DestFileName );
  1226. isEncrypted = TRUE;
  1227. } else {
  1228. #endif
  1229. if (CopyFile( SourceFileName, DestFileName, FALSE) == FALSE) {
  1230. err = GetLastError();
  1231. } else {
  1232. err = ERROR_SUCCESS;
  1233. }
  1234. #ifdef IMIRROR_SUPPORT_ENCRYPTED
  1235. }
  1236. #endif
  1237. if (err == ERROR_SHARING_VIOLATION) {
  1238. //
  1239. // we ignore sharing violations for the following files :
  1240. // system registry files
  1241. // tracking.log
  1242. // ntuser.dat & ntuser.dat.log
  1243. // usrclass.dat & usrclass.dat.log
  1244. //
  1245. PWCHAR fileName = SourceFileName;
  1246. PIMIRROR_IGNORE_FILE_LIST ignoreListEntry;
  1247. ULONG componentLength;
  1248. PLIST_ENTRY listEntry;
  1249. if (_wcsicmp(SourceFileName, L"\\\\?\\")) {
  1250. PWCHAR firstSlash;
  1251. fileName += 4; // now fileName points to L"C:\WINNT..."
  1252. firstSlash = fileName;
  1253. while (*firstSlash != L'\\' && *firstSlash != L'\0') {
  1254. firstSlash++;
  1255. }
  1256. if (*firstSlash != L'\0') {
  1257. fileName = firstSlash+1; // now fileName points to L"WINNT\..."
  1258. }
  1259. }
  1260. componentLength = lstrlenW( fileName );
  1261. listEntry = ThreadContext->FilesToIgnore.Flink;
  1262. while (listEntry != &(ThreadContext->FilesToIgnore)) {
  1263. ignoreListEntry = (PIMIRROR_IGNORE_FILE_LIST)
  1264. CONTAINING_RECORD( listEntry,
  1265. IMIRROR_IGNORE_FILE_LIST,
  1266. ListEntry );
  1267. if (CompareStringW( LOCALE_SYSTEM_DEFAULT,
  1268. NORM_IGNORECASE,
  1269. fileName,
  1270. min( componentLength, ignoreListEntry->FileNameLength),
  1271. &ignoreListEntry->FileName[0],
  1272. ignoreListEntry->FileNameLength) == 2) {
  1273. // it matched one of our special files. we'll ignore the
  1274. // error but also not set the attributes on the image.
  1275. return err;
  1276. }
  1277. listEntry = listEntry->Flink;
  1278. }
  1279. }
  1280. // report either success or failure up to the caller
  1281. if (err == ERROR_SUCCESS) {
  1282. ReportCopyError( ThreadContext->CopyContext,
  1283. SourceFileName,
  1284. COPY_ERROR_ACTION_CREATE_FILE,
  1285. err );
  1286. InterlockedIncrement( &copyContext->FilesCopied );
  1287. copyContext->BytesCopied.QuadPart += SourceFindData->EndOfFile.QuadPart;
  1288. } else {
  1289. errorCase = ReportCopyError( ThreadContext->CopyContext,
  1290. SourceFileName,
  1291. COPY_ERROR_ACTION_CREATE_FILE,
  1292. err );
  1293. if (errorCase == STATUS_RETRY) {
  1294. goto retryMirrorFile;
  1295. }
  1296. if (errorCase == ERROR_SUCCESS) {
  1297. err = STATUS_SUCCESS;
  1298. }
  1299. return err;
  1300. }
  1301. updateStoredSecurityAttributes = TRUE;
  1302. updateStoredSFNAttributes = TRUE;
  1303. updateBasic = TRUE;
  1304. fileBasicInfo.FileAttributes = 0; // don't set the attribute again.
  1305. if (err == STATUS_SUCCESS) {
  1306. //
  1307. // we just created the file so we'll just give it the archive
  1308. // bit as an attribute since we've saved off the rest in the
  1309. // stream.
  1310. //
  1311. if (! SetFileAttributes( DestFileName, FILE_ATTRIBUTE_ARCHIVE )) {
  1312. err = GetLastError();
  1313. errorCase = ReportCopyError( copyContext,
  1314. DestFileName,
  1315. COPY_ERROR_ACTION_SETATTR,
  1316. err );
  1317. if (errorCase == STATUS_RETRY) {
  1318. goto retryMirrorFile;
  1319. }
  1320. if (errorCase == ERROR_SUCCESS) {
  1321. err = STATUS_SUCCESS;
  1322. }
  1323. }
  1324. }
  1325. }
  1326. if ((err == ERROR_SUCCESS) && updateStoredSFNAttributes && (*p != L'\0')) {
  1327. err = StoreOurSFNStream( ThreadContext,
  1328. SourceFileName,
  1329. DestFileName,
  1330. p
  1331. );
  1332. updateBasic = TRUE;
  1333. }
  1334. if ((err == ERROR_SUCCESS) && updateStoredSecurityAttributes) {
  1335. err = StoreOurSecurityStream( ThreadContext,
  1336. SourceFileName,
  1337. DestFileName,
  1338. SourceFindData->FileAttributes,
  1339. SourceFindData->ChangeTime
  1340. );
  1341. updateBasic = TRUE;
  1342. }
  1343. if ((err == ERROR_SUCCESS) && updateBasic) {
  1344. //
  1345. // set create date and lastUpdate date to correct values
  1346. //
  1347. fileHandle = CreateFile( DestFileName,
  1348. FILE_WRITE_ATTRIBUTES | DELETE,
  1349. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1350. NULL,
  1351. OPEN_EXISTING,
  1352. 0,
  1353. NULL );
  1354. if (fileHandle == INVALID_HANDLE_VALUE) {
  1355. err = GetLastError();
  1356. } else {
  1357. //
  1358. // first try to set the short name. If this fails, we just ignore
  1359. // the error.
  1360. //
  1361. if (pSetFileShortName) {
  1362. pSetFileShortName( fileHandle, p );
  1363. }
  1364. //
  1365. // if we're making a change to an existing file, update the ARCHIVE bit.
  1366. //
  1367. if (fileIsAlreadyThere &&
  1368. 0 == (fileBasicInfo.FileAttributes & FILE_ATTRIBUTE_ARCHIVE)) {
  1369. fileBasicInfo.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
  1370. }
  1371. //
  1372. // set create date and lastUpdate date to correct values
  1373. //
  1374. err = NtSetInformationFile( fileHandle,
  1375. &IoStatusBlock,
  1376. &fileBasicInfo,
  1377. sizeof( FILE_BASIC_INFORMATION ),
  1378. FileBasicInformation
  1379. );
  1380. err = IMConvertNT2Win32Error( err );
  1381. }
  1382. if (err != STATUS_SUCCESS) {
  1383. errorCase = ReportCopyError( copyContext,
  1384. DestFileName,
  1385. COPY_ERROR_ACTION_SETTIME,
  1386. err );
  1387. if (errorCase == STATUS_RETRY) {
  1388. goto retryMirrorFile;
  1389. }
  1390. if (errorCase == ERROR_SUCCESS) {
  1391. err = STATUS_SUCCESS;
  1392. }
  1393. } else if (fileIsAlreadyThere) {
  1394. InterlockedIncrement( &copyContext->AttributesModified );
  1395. }
  1396. }
  1397. if (err == STATUS_SUCCESS) {
  1398. //
  1399. // report that we succeeded in copying the file
  1400. //
  1401. (VOID)ReportCopyError( copyContext,
  1402. SourceFileName,
  1403. COPY_ERROR_ACTION_CREATE_FILE,
  1404. err );
  1405. }
  1406. if ( fileHandle != INVALID_HANDLE_VALUE ) {
  1407. CloseHandle( fileHandle );
  1408. }
  1409. return err;
  1410. }
  1411. DWORD
  1412. UnconditionalDelete (
  1413. PIMIRROR_THREAD_CONTEXT ThreadContext,
  1414. PWCHAR SourceFile,
  1415. PWCHAR FileToDelete,
  1416. DWORD Attributes,
  1417. PWCHAR NameBuffer
  1418. )
  1419. {
  1420. DWORD err;
  1421. BOOLEAN allocatedBuffer;
  1422. BOOLEAN reportError;
  1423. PCOPY_TREE_CONTEXT copyContext;
  1424. retryDelete:
  1425. err = ERROR_SUCCESS;
  1426. allocatedBuffer = FALSE;
  1427. reportError = TRUE;
  1428. copyContext = ThreadContext->CopyContext;
  1429. if (copyContext->DeleteOtherFiles == FALSE) {
  1430. err = ERROR_WRITE_PROTECT;
  1431. goto exitWithError;
  1432. }
  1433. if ((Attributes & (FILE_ATTRIBUTE_READONLY |
  1434. FILE_ATTRIBUTE_HIDDEN |
  1435. FILE_ATTRIBUTE_SYSTEM)) != 0) {
  1436. // set the attributes back to normal
  1437. Attributes &= ~FILE_ATTRIBUTE_READONLY;
  1438. Attributes &= ~FILE_ATTRIBUTE_HIDDEN;
  1439. Attributes &= ~FILE_ATTRIBUTE_SYSTEM;
  1440. SetFileAttributesW( FileToDelete, Attributes );
  1441. }
  1442. if ((Attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  1443. if (! DeleteFile( FileToDelete )) {
  1444. err = GetLastError();
  1445. } else {
  1446. InterlockedIncrement( &copyContext->FilesDeleted );
  1447. }
  1448. } else {
  1449. //
  1450. // remove all files and subdirectories recursively here...
  1451. //
  1452. HANDLE fileEnum = INVALID_HANDLE_VALUE;
  1453. WIN32_FIND_DATA findData;
  1454. PWCHAR startFileName;
  1455. ULONG dirLength;
  1456. if (NameBuffer == NULL) {
  1457. NameBuffer = IMirrorAllocMem( TMP_BUFFER_SIZE );
  1458. if (NameBuffer == NULL) {
  1459. err = STATUS_NO_MEMORY;
  1460. goto exitWithError;
  1461. }
  1462. lstrcpyW( NameBuffer, FileToDelete );
  1463. allocatedBuffer = TRUE;
  1464. }
  1465. dirLength = lstrlenW( NameBuffer );
  1466. lstrcatW( NameBuffer, L"\\*" );
  1467. // remember the start of the char after the backslash to slap in the name
  1468. startFileName = NameBuffer + dirLength + 1;
  1469. err = ERROR_SUCCESS;
  1470. fileEnum = FindFirstFile( NameBuffer, &findData );
  1471. if (fileEnum != INVALID_HANDLE_VALUE) {
  1472. while (copyContext->Cancelled == FALSE) {
  1473. if (((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) &&
  1474. (findData.cFileName[0] == L'.')) {
  1475. if ((findData.cFileName[1] == L'\0') ||
  1476. (findData.cFileName[1] == L'.' &&
  1477. findData.cFileName[2] == L'\0')) {
  1478. goto skipToNextDir;
  1479. }
  1480. }
  1481. lstrcpyW( startFileName, &findData.cFileName[0] );
  1482. err = UnconditionalDelete( ThreadContext,
  1483. SourceFile,
  1484. NameBuffer,
  1485. findData.dwFileAttributes,
  1486. NameBuffer );
  1487. if (err != ERROR_SUCCESS) {
  1488. reportError = FALSE;
  1489. break;
  1490. }
  1491. skipToNextDir:
  1492. if (! FindNextFile( fileEnum, &findData)) {
  1493. err = GetLastError();
  1494. if (err == ERROR_NO_MORE_FILES) {
  1495. err = ERROR_SUCCESS;
  1496. break;
  1497. }
  1498. }
  1499. }
  1500. FindClose( fileEnum );
  1501. *(NameBuffer+dirLength) = L'\0';
  1502. }
  1503. if (err == ERROR_SUCCESS) {
  1504. if (! RemoveDirectory( FileToDelete ) ) {
  1505. err = GetLastError();
  1506. } else {
  1507. InterlockedIncrement( &copyContext->DirectoriesDeleted );
  1508. }
  1509. }
  1510. }
  1511. exitWithError:
  1512. // we report the error for both success and failure
  1513. if (allocatedBuffer && NameBuffer != NULL) {
  1514. IMirrorFreeMem( NameBuffer );
  1515. }
  1516. if (reportError) {
  1517. DWORD errorCase;
  1518. errorCase = ReportCopyError( copyContext,
  1519. FileToDelete,
  1520. COPY_ERROR_ACTION_DELETE,
  1521. err );
  1522. if (errorCase == STATUS_RETRY) {
  1523. goto retryDelete;
  1524. }
  1525. if (errorCase == ERROR_SUCCESS) {
  1526. err = ERROR_SUCCESS;
  1527. }
  1528. }
  1529. return err;
  1530. }
  1531. DWORD
  1532. StoreOurSecurityStream (
  1533. PIMIRROR_THREAD_CONTEXT ThreadContext,
  1534. PWCHAR Source,
  1535. PWCHAR Dest,
  1536. DWORD AttributesToStore,
  1537. LARGE_INTEGER ChangeTime
  1538. )
  1539. //
  1540. // This routine stores off the acl from the master into a named alternate
  1541. // data stream on the destination. It saves off both the ACL and a few
  1542. // file attributes that couldn't be stored in the normal directory entry.
  1543. //
  1544. {
  1545. PSECURITY_DESCRIPTOR SourceSD;
  1546. PCOPY_TREE_CONTEXT copyContext;
  1547. DWORD err;
  1548. DWORD requiredLength;
  1549. HANDLE hAclFile;
  1550. PWCHAR aclFileName;
  1551. ULONG action;
  1552. MIRROR_ACL_STREAM mirrorAclStream;
  1553. DWORD BytesWritten;
  1554. DWORD deleteAclFile;
  1555. DWORD errorCase;
  1556. retryWriteStream:
  1557. errorCase = STATUS_SUCCESS;
  1558. SourceSD = NULL;
  1559. copyContext = ThreadContext->CopyContext;
  1560. err = ERROR_SUCCESS;
  1561. requiredLength = 0;
  1562. hAclFile = INVALID_HANDLE_VALUE;
  1563. action = COPY_ERROR_ACTION_GETACL;
  1564. deleteAclFile = FALSE;
  1565. //
  1566. // We use the SDBuffer on the thread context to store not only the
  1567. // security descriptor but also the file name of the alternate data stream.
  1568. //
  1569. requiredLength = (lstrlenW( Dest ) + lstrlenW( IMIRROR_ACL_STREAM_NAME ) + 1) * sizeof(WCHAR);
  1570. if (ThreadContext->SDBuffer == NULL || requiredLength > ThreadContext->SDBufferLength) {
  1571. if (ThreadContext->SDBuffer != NULL) {
  1572. IMirrorFreeMem( ThreadContext->SDBuffer );
  1573. ThreadContext->SDBuffer = NULL;
  1574. ThreadContext->SDBufferLength = requiredLength;
  1575. }
  1576. if (requiredLength > ThreadContext->SDBufferLength) {
  1577. ThreadContext->SDBufferLength = requiredLength;
  1578. }
  1579. ThreadContext->SDBuffer = IMirrorAllocMem( ThreadContext->SDBufferLength );
  1580. if (ThreadContext->SDBuffer == NULL) {
  1581. err = GetLastError();
  1582. errorCase = ReportCopyError( copyContext,
  1583. Source,
  1584. COPY_ERROR_ACTION_MALLOC,
  1585. err );
  1586. goto IMCEExit;
  1587. }
  1588. }
  1589. aclFileName = (PWCHAR) ThreadContext->SDBuffer;
  1590. lstrcpyW( aclFileName, Dest );
  1591. lstrcatW( aclFileName, IMIRROR_ACL_STREAM_NAME );
  1592. hAclFile = CreateFile( aclFileName,
  1593. GENERIC_WRITE,
  1594. 0, // Exclusive access.
  1595. NULL, // Default security descriptor.
  1596. CREATE_ALWAYS, // Overrides if file exists.
  1597. 0, // no special attributes
  1598. NULL
  1599. );
  1600. if (hAclFile == INVALID_HANDLE_VALUE) {
  1601. err = GetLastError();
  1602. errorCase = ReportCopyError( copyContext,
  1603. Source,
  1604. COPY_ERROR_ACTION_CREATE_FILE,
  1605. err );
  1606. goto IMCEExit;
  1607. }
  1608. //
  1609. // read the source security descriptor into the buffer allocated off the
  1610. // thread context.
  1611. //
  1612. if (ThreadContext->IsNTFS == FALSE) {
  1613. requiredLength = 0;
  1614. } else {
  1615. err = ERROR_INSUFFICIENT_BUFFER;
  1616. while (err == ERROR_INSUFFICIENT_BUFFER) {
  1617. if (ThreadContext->SDBuffer == NULL) {
  1618. ThreadContext->SDBuffer = IMirrorAllocMem( ThreadContext->SDBufferLength );
  1619. if (ThreadContext->SDBuffer == NULL) {
  1620. err = GetLastError();
  1621. break;
  1622. }
  1623. }
  1624. SourceSD = (PSECURITY_DESCRIPTOR) ThreadContext->SDBuffer;
  1625. //
  1626. // get SD of the SourceRoot file. This comes back self relative.
  1627. //
  1628. if (GetFileSecurity( Source,
  1629. (DACL_SECURITY_INFORMATION |
  1630. GROUP_SECURITY_INFORMATION |
  1631. SACL_SECURITY_INFORMATION |
  1632. OWNER_SECURITY_INFORMATION),
  1633. SourceSD,
  1634. ThreadContext->SDBufferLength,
  1635. &requiredLength )) {
  1636. err = ERROR_SUCCESS;
  1637. } else {
  1638. err = GetLastError();
  1639. if ((err == ERROR_INSUFFICIENT_BUFFER) ||
  1640. (requiredLength > ThreadContext->SDBufferLength)) {
  1641. // let's try it again with a bigger buffer.
  1642. ThreadContext->SDBufferLength = requiredLength;
  1643. IMirrorFreeMem( ThreadContext->SDBuffer );
  1644. ThreadContext->SDBuffer = NULL;
  1645. err = ERROR_INSUFFICIENT_BUFFER;
  1646. }
  1647. }
  1648. }
  1649. if (err != ERROR_SUCCESS) {
  1650. errorCase = ReportCopyError( copyContext,
  1651. Source,
  1652. COPY_ERROR_ACTION_GETACL,
  1653. err );
  1654. goto IMCEExit;
  1655. }
  1656. InterlockedIncrement( &copyContext->SourceSecurityDescriptorsRead );
  1657. ASSERT( IsValidSecurityDescriptor(SourceSD) );
  1658. }
  1659. mirrorAclStream.StreamVersion = IMIRROR_ACL_STREAM_VERSION;
  1660. mirrorAclStream.StreamLength = sizeof( MIRROR_ACL_STREAM ) +
  1661. requiredLength;
  1662. mirrorAclStream.ChangeTime.QuadPart = ChangeTime.QuadPart;
  1663. mirrorAclStream.ExtendedAttributes = AttributesToStore;
  1664. mirrorAclStream.SecurityDescriptorLength = requiredLength;
  1665. if ((WriteFile( hAclFile,
  1666. &mirrorAclStream,
  1667. sizeof( MIRROR_ACL_STREAM ),
  1668. &BytesWritten,
  1669. NULL // No overlap.
  1670. ) == FALSE) ||
  1671. (BytesWritten < sizeof( MIRROR_ACL_STREAM ))) {
  1672. deleteAclFile = TRUE;
  1673. err = GetLastError();
  1674. errorCase = ReportCopyError( copyContext,
  1675. Source,
  1676. COPY_ERROR_ACTION_SETACL,
  1677. err );
  1678. goto IMCEExit;
  1679. }
  1680. if (ThreadContext->IsNTFS) {
  1681. if ((WriteFile( hAclFile,
  1682. SourceSD,
  1683. requiredLength,
  1684. &BytesWritten,
  1685. NULL // No overlap.
  1686. ) == FALSE) ||
  1687. (BytesWritten < requiredLength )) {
  1688. deleteAclFile = TRUE;
  1689. err = GetLastError();
  1690. errorCase = ReportCopyError( copyContext,
  1691. Source,
  1692. COPY_ERROR_ACTION_SETACL,
  1693. err );
  1694. goto IMCEExit;
  1695. }
  1696. InterlockedIncrement( &copyContext->SecurityDescriptorsWritten );
  1697. }
  1698. IMCEExit:
  1699. if (hAclFile != INVALID_HANDLE_VALUE) {
  1700. CloseHandle( hAclFile );
  1701. if (deleteAclFile) {
  1702. // the file didn't get written properly, let's delete
  1703. aclFileName = (PWCHAR) ThreadContext->SDBuffer;
  1704. lstrcpyW( aclFileName, Dest );
  1705. lstrcatW( aclFileName, IMIRROR_ACL_STREAM_NAME );
  1706. DeleteFile( aclFileName );
  1707. }
  1708. }
  1709. if (errorCase == STATUS_RETRY) {
  1710. goto retryWriteStream;
  1711. }
  1712. if (errorCase == ERROR_SUCCESS) {
  1713. err = ERROR_SUCCESS;
  1714. }
  1715. return err;
  1716. }
  1717. DWORD
  1718. StoreOurSFNStream (
  1719. PIMIRROR_THREAD_CONTEXT ThreadContext,
  1720. PWCHAR Source,
  1721. PWCHAR Dest,
  1722. PWCHAR ShortFileName
  1723. )
  1724. //
  1725. // This routine stores off the short file name from the master into a named
  1726. // alternate data stream on the destination.
  1727. //
  1728. {
  1729. PCOPY_TREE_CONTEXT copyContext;
  1730. DWORD err;
  1731. DWORD requiredLength;
  1732. DWORD ShortFileNameLength;
  1733. HANDLE hSFNFile;
  1734. PWCHAR SFNFileName;
  1735. ULONG action;
  1736. MIRROR_SFN_STREAM mirrorSFNStream;
  1737. DWORD BytesWritten;
  1738. BOOL deleteSFNFile;
  1739. DWORD errorCase;
  1740. retryWriteStream:
  1741. errorCase = STATUS_SUCCESS;
  1742. copyContext = ThreadContext->CopyContext;
  1743. err = ERROR_SUCCESS;
  1744. requiredLength = 0;
  1745. hSFNFile = INVALID_HANDLE_VALUE;
  1746. action = COPY_ERROR_ACTION_GETSFN;
  1747. deleteSFNFile = FALSE;
  1748. ShortFileNameLength = (wcslen(ShortFileName)+1)*sizeof(WCHAR);
  1749. //
  1750. // We use the SFNBuffer on the thread context to store the file name of the
  1751. // alternate data stream.
  1752. //
  1753. requiredLength = (lstrlenW( Dest ) + lstrlenW( IMIRROR_SFN_STREAM_NAME ) + 1) * sizeof(WCHAR);
  1754. if (requiredLength < ShortFileNameLength) {
  1755. requiredLength = ShortFileNameLength;
  1756. }
  1757. if (ThreadContext->SFNBuffer == NULL || (requiredLength > ThreadContext->SFNBufferLength)) {
  1758. if (ThreadContext->SFNBuffer != NULL) {
  1759. IMirrorFreeMem( ThreadContext->SFNBuffer );
  1760. ThreadContext->SFNBuffer = NULL;
  1761. }
  1762. if (requiredLength > ThreadContext->SFNBufferLength) {
  1763. ThreadContext->SFNBufferLength = requiredLength;
  1764. }
  1765. ThreadContext->SFNBuffer = IMirrorAllocMem( ThreadContext->SFNBufferLength );
  1766. if (ThreadContext->SFNBuffer == NULL) {
  1767. err = GetLastError();
  1768. errorCase = ReportCopyError( copyContext,
  1769. Source,
  1770. COPY_ERROR_ACTION_MALLOC,
  1771. err );
  1772. goto IMCEExit;
  1773. }
  1774. }
  1775. SFNFileName = (PWCHAR) ThreadContext->SFNBuffer;
  1776. lstrcpyW( SFNFileName, Dest );
  1777. lstrcatW( SFNFileName, IMIRROR_SFN_STREAM_NAME );
  1778. hSFNFile = CreateFile( SFNFileName,
  1779. GENERIC_WRITE,
  1780. 0, // Exclusive access.
  1781. NULL, // Default security descriptor.
  1782. CREATE_ALWAYS, // Overrides if file exists.
  1783. FILE_FLAG_BACKUP_SEMANTICS, // Open directories too.
  1784. NULL
  1785. );
  1786. if (hSFNFile == INVALID_HANDLE_VALUE) {
  1787. err = GetLastError();
  1788. errorCase = ReportCopyError( copyContext,
  1789. Source,
  1790. COPY_ERROR_ACTION_CREATE_FILE,
  1791. err );
  1792. goto IMCEExit;
  1793. }
  1794. mirrorSFNStream.StreamVersion = IMIRROR_SFN_STREAM_VERSION;
  1795. mirrorSFNStream.StreamLength = sizeof( MIRROR_SFN_STREAM ) + ShortFileNameLength;
  1796. if ((WriteFile( hSFNFile,
  1797. &mirrorSFNStream,
  1798. sizeof( MIRROR_SFN_STREAM ),
  1799. &BytesWritten,
  1800. NULL // No overlap.
  1801. ) == FALSE) ||
  1802. (BytesWritten < sizeof( MIRROR_SFN_STREAM ))) {
  1803. deleteSFNFile = TRUE;
  1804. err = GetLastError();
  1805. errorCase = ReportCopyError( copyContext,
  1806. Source,
  1807. COPY_ERROR_ACTION_SETSFN,
  1808. err );
  1809. goto IMCEExit;
  1810. }
  1811. if ((WriteFile( hSFNFile,
  1812. ShortFileName,
  1813. ShortFileNameLength,
  1814. &BytesWritten,
  1815. NULL // No overlap.
  1816. ) == FALSE) ||
  1817. (BytesWritten < ShortFileNameLength )) {
  1818. deleteSFNFile = TRUE;
  1819. err = GetLastError();
  1820. errorCase = ReportCopyError( copyContext,
  1821. Source,
  1822. COPY_ERROR_ACTION_SETSFN,
  1823. err );
  1824. goto IMCEExit;
  1825. }
  1826. InterlockedIncrement( &copyContext->SFNWritten );
  1827. IMCEExit:
  1828. if (hSFNFile != INVALID_HANDLE_VALUE) {
  1829. CloseHandle( hSFNFile );
  1830. if (deleteSFNFile) {
  1831. // the file didn't get written properly, let's delete
  1832. SFNFileName = (PWCHAR) ThreadContext->SFNBuffer;
  1833. lstrcpyW( SFNFileName, Dest );
  1834. lstrcatW( SFNFileName, IMIRROR_SFN_STREAM_NAME );
  1835. DeleteFile( SFNFileName );
  1836. }
  1837. }
  1838. if (errorCase == STATUS_RETRY) {
  1839. goto retryWriteStream;
  1840. }
  1841. if (errorCase == ERROR_SUCCESS) {
  1842. err = ERROR_SUCCESS;
  1843. }
  1844. return err;
  1845. }
  1846. DWORD
  1847. GetOurSFNStream (
  1848. PIMIRROR_THREAD_CONTEXT ThreadContext,
  1849. PWCHAR Dest,
  1850. PMIRROR_SFN_STREAM MirrorSFNStream,
  1851. PWCHAR SFNBuffer,
  1852. DWORD SFNBufferSize
  1853. )
  1854. //
  1855. // This routine reads the short filename stream header from the destination. We do this
  1856. // to get the fields out of it so that we can determine if it needs updating.
  1857. //
  1858. {
  1859. DWORD err = ERROR_SUCCESS;
  1860. DWORD requiredLength = 0;
  1861. HANDLE hSFNFile = INVALID_HANDLE_VALUE;
  1862. PWCHAR SFNFileName;
  1863. DWORD BytesRead;
  1864. //
  1865. // We use the SFNBuffer on the thread context to store not only the
  1866. // security descriptor but also the file name of the alternate data stream.
  1867. //
  1868. if (!Dest || *Dest == L'\0') {
  1869. err = ERROR_INVALID_PARAMETER;
  1870. goto IMCEExit;
  1871. }
  1872. requiredLength = (lstrlenW( Dest ) + lstrlenW( IMIRROR_SFN_STREAM_NAME ) + 1) * sizeof(WCHAR);
  1873. if (ThreadContext->SFNBuffer == NULL || requiredLength > ThreadContext->SFNBufferLength) {
  1874. if (ThreadContext->SFNBuffer != NULL) {
  1875. IMirrorFreeMem( ThreadContext->SFNBuffer );
  1876. ThreadContext->SFNBuffer = NULL;
  1877. ThreadContext->SFNBufferLength = requiredLength;
  1878. }
  1879. if (requiredLength > ThreadContext->SFNBufferLength) {
  1880. ThreadContext->SFNBufferLength = requiredLength;
  1881. }
  1882. ThreadContext->SFNBuffer = IMirrorAllocMem( ThreadContext->SFNBufferLength );
  1883. if (ThreadContext->SFNBuffer == NULL) {
  1884. err = GetLastError();
  1885. goto IMCEExit;
  1886. }
  1887. }
  1888. SFNFileName = (PWCHAR) ThreadContext->SFNBuffer;
  1889. lstrcpyW( SFNFileName, Dest );
  1890. lstrcatW( SFNFileName, IMIRROR_SFN_STREAM_NAME );
  1891. hSFNFile = CreateFile( SFNFileName,
  1892. GENERIC_READ,
  1893. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1894. NULL, // Default security descriptor.
  1895. OPEN_EXISTING,
  1896. 0, // no special attributes
  1897. NULL
  1898. );
  1899. if (hSFNFile == INVALID_HANDLE_VALUE) {
  1900. err = GetLastError();
  1901. goto IMCEExit;
  1902. }
  1903. if ((ReadFile( hSFNFile,
  1904. MirrorSFNStream,
  1905. sizeof( MIRROR_SFN_STREAM ),
  1906. &BytesRead,
  1907. NULL // No overlap.
  1908. ) == FALSE) ||
  1909. (BytesRead < sizeof( MIRROR_SFN_STREAM )) ||
  1910. (MirrorSFNStream->StreamVersion != IMIRROR_SFN_STREAM_VERSION) ||
  1911. (MirrorSFNStream->StreamLength < sizeof( MIRROR_SFN_STREAM ))) {
  1912. err = ERROR_INVALID_DATA;
  1913. }
  1914. if ((MirrorSFNStream->StreamLength - sizeof(MIRROR_SFN_STREAM)) > SFNBufferSize) {
  1915. err = ERROR_INSUFFICIENT_BUFFER;
  1916. } else {
  1917. if ((ReadFile( hSFNFile,
  1918. SFNBuffer,
  1919. MirrorSFNStream->StreamLength - sizeof(MIRROR_SFN_STREAM),
  1920. &BytesRead,
  1921. NULL ) == FALSE) ||
  1922. (BytesRead != (MirrorSFNStream->StreamLength - sizeof(MIRROR_SFN_STREAM)))) {
  1923. err = ERROR_INVALID_DATA;
  1924. }
  1925. }
  1926. IMCEExit:
  1927. if (hSFNFile != INVALID_HANDLE_VALUE) {
  1928. CloseHandle( hSFNFile );
  1929. }
  1930. return err;
  1931. }
  1932. DWORD
  1933. GetOurSecurityStream (
  1934. PIMIRROR_THREAD_CONTEXT ThreadContext,
  1935. PWCHAR Dest,
  1936. PMIRROR_ACL_STREAM MirrorAclStream
  1937. )
  1938. //
  1939. // This routine reads the stream header from the destination. We do this
  1940. // to get the fields out of it so that we can determine if it needs updating.
  1941. //
  1942. {
  1943. PSECURITY_DESCRIPTOR SourceSD = NULL;
  1944. DWORD err = ERROR_SUCCESS;
  1945. DWORD requiredLength = 0;
  1946. HANDLE hAclFile = INVALID_HANDLE_VALUE;
  1947. PWCHAR aclFileName;
  1948. DWORD BytesRead;
  1949. //
  1950. // We use the SDuffer on the thread context to store not only the
  1951. // security descriptor but also the file name of the alternate data stream.
  1952. //
  1953. if (!Dest || *Dest == L'\0') {
  1954. err = ERROR_INVALID_PARAMETER;
  1955. goto IMCEExit;
  1956. }
  1957. requiredLength = (lstrlenW( Dest ) + lstrlenW( IMIRROR_ACL_STREAM_NAME ) + 1) * sizeof(WCHAR);
  1958. if (ThreadContext->SDBuffer == NULL || requiredLength > ThreadContext->SDBufferLength) {
  1959. if (ThreadContext->SDBuffer != NULL) {
  1960. IMirrorFreeMem( ThreadContext->SDBuffer );
  1961. ThreadContext->SDBuffer = NULL;
  1962. ThreadContext->SDBufferLength = requiredLength;
  1963. }
  1964. if (requiredLength > ThreadContext->SDBufferLength) {
  1965. ThreadContext->SDBufferLength = requiredLength;
  1966. }
  1967. ThreadContext->SDBuffer = IMirrorAllocMem( ThreadContext->SDBufferLength );
  1968. if (ThreadContext->SDBuffer == NULL) {
  1969. err = GetLastError();
  1970. goto IMCEExit;
  1971. }
  1972. }
  1973. aclFileName = (PWCHAR) ThreadContext->SDBuffer;
  1974. lstrcpyW( aclFileName, Dest );
  1975. lstrcatW( aclFileName, IMIRROR_ACL_STREAM_NAME );
  1976. hAclFile = CreateFile( aclFileName,
  1977. GENERIC_READ,
  1978. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1979. NULL, // Default security descriptor.
  1980. OPEN_EXISTING,
  1981. 0, // no special attributes
  1982. NULL
  1983. );
  1984. if (hAclFile == INVALID_HANDLE_VALUE) {
  1985. err = GetLastError();
  1986. goto IMCEExit;
  1987. }
  1988. //
  1989. // read the header of the stream. We don't bother reading the security
  1990. // descriptor because all we need is the ChangeTime (which changes with
  1991. // the security descriptor).
  1992. //
  1993. if ((ReadFile( hAclFile,
  1994. MirrorAclStream,
  1995. sizeof( MIRROR_ACL_STREAM ),
  1996. &BytesRead,
  1997. NULL // No overlap.
  1998. ) == FALSE) ||
  1999. (BytesRead < sizeof( MIRROR_ACL_STREAM )) ||
  2000. (MirrorAclStream->StreamVersion != IMIRROR_ACL_STREAM_VERSION) ||
  2001. (MirrorAclStream->StreamLength < sizeof( MIRROR_ACL_STREAM ))) {
  2002. err = ERROR_INVALID_DATA;
  2003. }
  2004. IMCEExit:
  2005. if (hAclFile != INVALID_HANDLE_VALUE) {
  2006. CloseHandle( hAclFile );
  2007. }
  2008. return err;
  2009. }
  2010. #ifdef DEBUGLOG
  2011. VOID
  2012. IMLogToFile(
  2013. PSTR Buffer
  2014. )
  2015. /*++
  2016. Routine Description:
  2017. Write message to log file.
  2018. Arguments:
  2019. Buffer - NULL terminated message.
  2020. Return Value:
  2021. None
  2022. --*/
  2023. {
  2024. ULONG Len;
  2025. ULONG NumWritten;
  2026. AcquireCriticalSection( &DebugFileLock );
  2027. if (hDebugLogFile == INVALID_HANDLE_VALUE){
  2028. ReleaseCriticalSection( &DebugFileLock );
  2029. return;
  2030. }
  2031. Len = strlen(Buffer);
  2032. //
  2033. // this check also accounts for NULL byte that is added
  2034. //
  2035. if (DebugLogFileOffset + Len >= (DEBUG_LOG_BUFFER_SIZE-1) ){
  2036. WriteFile(hDebugLogFile, DebugLogFileBuffer, DebugLogFileOffset + 1, &NumWritten, NULL);
  2037. DebugLogFileOffset = 0;
  2038. }
  2039. memcpy(&DebugLogFileBuffer[DebugLogFileOffset], Buffer, Len);
  2040. DebugLogFileOffset += Len;
  2041. DebugLogFileBuffer[DebugLogFileOffset++]='\0';
  2042. ReleaseCriticalSection( &DebugFileLock );
  2043. return;
  2044. }
  2045. VOID
  2046. IMFlushAndCloseLog(
  2047. VOID
  2048. )
  2049. {
  2050. ULONG NumWritten;
  2051. AcquireCriticalSection( &DebugFileLock );
  2052. if (hDebugLogFile != INVALID_HANDLE_VALUE) {
  2053. WriteFile(hDebugLogFile, DebugLogFileBuffer, DebugLogFileOffset + 1, &NumWritten, NULL);
  2054. CloseHandle(hDebugLogFile);
  2055. hDebugLogFile = INVALID_HANDLE_VALUE;
  2056. }
  2057. ReleaseCriticalSection( &DebugFileLock );
  2058. }
  2059. #endif
  2060. ULONG
  2061. ReportCopyError (
  2062. PCOPY_TREE_CONTEXT CopyContext OPTIONAL,
  2063. PWCHAR File,
  2064. DWORD ActionCode,
  2065. DWORD Err
  2066. )
  2067. //
  2068. // This returns either ERROR_SUCCESS, STATUS_RETRY, or STATUS_REQUEST_ABORTED
  2069. //
  2070. // ERROR_SUCCESS means we just continue on and ignore the error.
  2071. // STATUS_RETRY means we retry the operation
  2072. // STATUS_REQUEST_ABORTED means we bail.
  2073. //
  2074. {
  2075. ULONG ntErr = ERROR_SUCCESS;
  2076. if (CopyContext != NULL) {
  2077. if (Err != ERROR_SUCCESS) {
  2078. InterlockedIncrement( &CopyContext->ErrorsEncountered );
  2079. }
  2080. }
  2081. if (Callbacks.FileCreateFn == NULL) {
  2082. if (Err != ERROR_SUCCESS) {
  2083. if (ActionCode == COPY_ERROR_ACTION_DELETE) {
  2084. printf( "error %u while deleting %S\n", Err, File );
  2085. } else {
  2086. printf( "error %u while copying %S\n", Err, File );
  2087. }
  2088. } else {
  2089. if (ActionCode == COPY_ERROR_ACTION_DELETE) {
  2090. printf( "deleted %S\n", File );
  2091. } else {
  2092. printf( "copied %S\n", File );
  2093. }
  2094. }
  2095. }
  2096. if (Err != STATUS_SUCCESS) {
  2097. ntErr = IMirrorFileCreate(File, ActionCode, Err);
  2098. if (ntErr == STATUS_REQUEST_ABORTED ||
  2099. ntErr == ERROR_REQUEST_ABORTED) {
  2100. ntErr = STATUS_REQUEST_ABORTED;
  2101. CopyContext->Cancelled = TRUE;
  2102. } else if ((ntErr != STATUS_RETRY) &&
  2103. (ntErr != ERROR_SUCCESS)) {
  2104. ntErr = ERROR_SUCCESS;
  2105. }
  2106. }
  2107. return ntErr;
  2108. }
  2109. #ifdef IMIRROR_SUPPORT_ENCRYPTED
  2110. DWORD
  2111. IMReadRawCallback(
  2112. PBYTE pData,
  2113. PVOID pCallbackContext,
  2114. ULONG Length
  2115. )
  2116. /*++
  2117. Routine Description
  2118. Call back function registered by IMCopyEncryptFile
  2119. Arguments:
  2120. pData - Data to copied
  2121. pCallbackContext - call back context
  2122. Length - size, in bytes, of Data to be copied.
  2123. Return value:
  2124. Win 32 error code on failure, otherwise ERROR_SUCCESS
  2125. --*/
  2126. {
  2127. DWORD Status = ERROR_SUCCESS;
  2128. DWORD BytesWritten = Length;
  2129. if ( Length &&
  2130. !WriteFile( (HANDLE) pCallbackContext,
  2131. pData,
  2132. Length,
  2133. &BytesWritten,
  2134. NULL // No overlap.
  2135. )){
  2136. Status = GetLastError();
  2137. }
  2138. return Status;
  2139. }
  2140. DWORD
  2141. IMCopyEncryptFile(
  2142. PCOPY_TREE_CONTEXT CopyContext,
  2143. LPWSTR SourceFileName,
  2144. LPWSTR DestFileName
  2145. )
  2146. /*++
  2147. Routine Description
  2148. Copies the source file to destination file while preserving the encryption information.
  2149. Arguments:
  2150. CopyContext - global data for this instance of copying a tree
  2151. SourceFileName - source file name
  2152. DestFileName - destination file name
  2153. Return value:
  2154. Win 32 error code on failure, otherwise ERROR_SUCCESS
  2155. --*/
  2156. {
  2157. DWORD Error;
  2158. PVOID pContext = NULL;
  2159. HANDLE hDestFile = INVALID_HANDLE_VALUE;
  2160. ULONG errorCase;
  2161. retryCopyEncrypt:
  2162. hDestFile = INVALID_HANDLE_VALUE;
  2163. pContext = NULL;
  2164. Error = ERROR_SUCCESS;
  2165. errorCase = ERROR_SUCCESS;
  2166. hDestFile = CreateFile( DestFileName,
  2167. GENERIC_WRITE | GENERIC_READ,
  2168. 0, // Exclusive access.
  2169. NULL, // Default security descriptor.
  2170. CREATE_ALWAYS, // Overrides if file exists.
  2171. FILE_ATTRIBUTE_ARCHIVE,
  2172. NULL
  2173. );
  2174. if (hDestFile == INVALID_HANDLE_VALUE) {
  2175. Error = GetLastError() ;
  2176. errorCase = ReportCopyError( CopyContext,
  2177. DestFileName,
  2178. COPY_ERROR_ACTION_CREATE_FILE,
  2179. Error );
  2180. goto IMCEExit;
  2181. }
  2182. Error = OpenEncryptedFileRawW( SourceFileName,
  2183. 0, // Export
  2184. &pContext
  2185. );
  2186. if (Error != ERROR_SUCCESS){
  2187. errorCase = ReportCopyError( CopyContext,
  2188. SourceFileName,
  2189. COPY_ERROR_ACTION_CREATE_FILE,
  2190. Error );
  2191. goto IMCEExit;
  2192. }
  2193. Error = ReadEncryptedFileRaw( (PFE_EXPORT_FUNC)IMReadRawCallback,
  2194. (PVOID) hDestFile, //app call back context
  2195. pContext
  2196. );
  2197. if (Error != ERROR_SUCCESS) {
  2198. errorCase = ReportCopyError( CopyContext,
  2199. SourceFileName,
  2200. COPY_ERROR_ACTION_CREATE_FILE,
  2201. Error );
  2202. goto IMCEExit;
  2203. }
  2204. IMCEExit:
  2205. if (hDestFile != INVALID_HANDLE_VALUE){
  2206. CloseHandle(hDestFile);
  2207. }
  2208. if (pContext){
  2209. CloseEncryptedFileRaw(pContext);
  2210. }
  2211. if (errorCase == STATUS_RETRY) {
  2212. goto retryCopyEncrypt;
  2213. }
  2214. if (errorCase == ERROR_SUCCESS) {
  2215. Error = ERROR_SUCCESS;
  2216. }
  2217. return Error;
  2218. }
  2219. #endif
  2220. NTSTATUS
  2221. SetPrivs(
  2222. IN HANDLE TokenHandle,
  2223. IN LPTSTR lpszPriv
  2224. )
  2225. /*++
  2226. Routine Description:
  2227. This routine enables the given privilege in the given token.
  2228. Arguments:
  2229. Return Value:
  2230. FALSE - Failure.
  2231. TRUE - Success.
  2232. --*/
  2233. {
  2234. LUID SetPrivilegeValue;
  2235. TOKEN_PRIVILEGES TokenPrivileges;
  2236. //
  2237. // First, find out the value of the privilege
  2238. //
  2239. if (!LookupPrivilegeValue(NULL, lpszPriv, &SetPrivilegeValue)) {
  2240. return GetLastError();
  2241. }
  2242. //
  2243. // Set up the privilege set we will need
  2244. //
  2245. TokenPrivileges.PrivilegeCount = 1;
  2246. TokenPrivileges.Privileges[0].Luid = SetPrivilegeValue;
  2247. TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  2248. if (!AdjustTokenPrivileges( TokenHandle,
  2249. FALSE,
  2250. &TokenPrivileges,
  2251. sizeof(TOKEN_PRIVILEGES),
  2252. NULL,
  2253. NULL)) {
  2254. return GetLastError();
  2255. }
  2256. return ERROR_SUCCESS;
  2257. }
  2258. NTSTATUS
  2259. GetTokenHandle(
  2260. IN OUT PHANDLE TokenHandle
  2261. )
  2262. /*++
  2263. Routine Description:
  2264. This routine opens the current process object and returns a
  2265. handle to its token.
  2266. Arguments:
  2267. Return Value:
  2268. NTSTATUS
  2269. --*/
  2270. {
  2271. HANDLE ProcessHandle;
  2272. NTSTATUS Result;
  2273. ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION,
  2274. FALSE,
  2275. GetCurrentProcessId());
  2276. if (ProcessHandle == NULL) {
  2277. return GetLastError();
  2278. }
  2279. Result = OpenProcessToken(ProcessHandle,
  2280. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  2281. TokenHandle);
  2282. CloseHandle(ProcessHandle);
  2283. if (Result) {
  2284. Result = ERROR_SUCCESS;
  2285. } else {
  2286. Result = GetLastError();
  2287. }
  2288. return Result;
  2289. }
  2290. NTSTATUS
  2291. CanHandleReparsePoint (
  2292. PIMIRROR_THREAD_CONTEXT ThreadContext,
  2293. PWCHAR SourceFileName,
  2294. DWORD FileAttributes
  2295. )
  2296. //
  2297. // This routine checks the type of reparse point a file is. If it is a
  2298. // reparse point we can handle (e.g. a structured storage document) then
  2299. // return success. Otherwise we return the appropriate error.
  2300. //
  2301. {
  2302. return(ERROR_REPARSE_ATTRIBUTE_CONFLICT);
  2303. }