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.

937 lines
28 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ntfs.cpp
  5. Abstract:
  6. This file contains the common utility functions for NTFS file operations,
  7. e.g. CopyNTFSFile to copy a file overriding ACL and EFS.
  8. Revision History:
  9. Seong Kook Khang (SKKhang) 08/16/00
  10. created
  11. ******************************************************************************/
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <winioctl.h>
  17. #include "srdefs.h"
  18. #include "utils.h"
  19. #include <dbgtrace.h>
  20. #include <stdio.h>
  21. #include <objbase.h>
  22. #include <ntlsa.h>
  23. #include <accctrl.h>
  24. #include <aclapi.h>
  25. #include <malloc.h>
  26. #include <regstr.h>
  27. #include <shlwapi.h>
  28. #include <commctrl.h>
  29. #include <shellapi.h>
  30. #include <srapi.h>
  31. #define TRACEID 9875
  32. BOOL IsFileEncrypted(const WCHAR * cszDst);
  33. /////////////////////////////////////////////////////////////////////////////
  34. //
  35. // ClearFileAttribute
  36. //
  37. // Check the attribute of file and clear it if necessary.
  38. //
  39. /////////////////////////////////////////////////////////////////////////////
  40. DWORD
  41. ClearFileAttribute( LPCWSTR cszFile, DWORD dwMask )
  42. {
  43. TraceFunctEnter("ClearFileAttribute");
  44. DWORD dwRet = ERROR_SUCCESS;
  45. DWORD dwErr;
  46. LPCWSTR cszErr;
  47. DWORD dwAttr;
  48. // Check if file exists, ignore if not exist
  49. dwAttr = ::GetFileAttributes( cszFile );
  50. if ( dwAttr == 0xFFFFFFFF )
  51. goto Exit;
  52. // If file exist, clear the given flags
  53. if ( ( dwAttr & dwMask ) != 0 )
  54. {
  55. // This will always succeed even if the file is ACL protected or
  56. // encrypted, so don't worry about it...
  57. if ( !::SetFileAttributes( cszFile, dwAttr & ~dwMask ) )
  58. {
  59. dwRet = ::GetLastError();
  60. cszErr = ::GetSysErrStr(dwRet);
  61. ErrorTrace(0, "::SetFileAttributes failed - %ls", cszErr);
  62. ErrorTrace(0, "Src='%ls'", cszFile);
  63. goto Exit;
  64. }
  65. }
  66. Exit:
  67. TraceFunctLeave();
  68. return( dwRet );
  69. }
  70. /////////////////////////////////////////////////////////////////////////////
  71. //
  72. // Copy File Routines
  73. //
  74. /////////////////////////////////////////////////////////////////////////////
  75. /////////////////////////////////////////////////////////////////////////////
  76. // CopyACLProtectedFile
  77. BYTE s_pBuf[4096];
  78. DWORD
  79. CopyACLProtectedFile( LPCWSTR cszSrc, LPCWSTR cszDst )
  80. {
  81. TraceFunctEnter("CopyACLProtectedFile");
  82. DWORD dwRet = ERROR_SUCCESS;
  83. LPCWSTR cszErr;
  84. HANDLE hfSrc = INVALID_HANDLE_VALUE;
  85. HANDLE hfDst = INVALID_HANDLE_VALUE;
  86. LPVOID lpCtxRead = NULL;
  87. LPVOID lpCtxWrite = NULL;
  88. DWORD dwRead;
  89. DWORD dwCopied;
  90. DWORD dwWritten;
  91. hfSrc = ::CreateFile( cszSrc, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
  92. if ( hfSrc == INVALID_HANDLE_VALUE )
  93. {
  94. dwRet = ::GetLastError();
  95. cszErr = ::GetSysErrStr(dwRet);
  96. ErrorTrace(0, "::CreateFile() failed - %ls", cszErr);
  97. ErrorTrace(0, "cszSrc='%ls'", cszSrc);
  98. goto Exit;
  99. }
  100. hfDst = ::CreateFile( cszDst, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL );
  101. if ( hfDst == INVALID_HANDLE_VALUE )
  102. {
  103. dwRet = ::GetLastError();
  104. cszErr = ::GetSysErrStr(dwRet);
  105. ErrorTrace(0, "::CreateFile() failed - %ls", cszErr);
  106. ErrorTrace(0, "cszDst='%ls'", cszDst);
  107. goto Exit;
  108. }
  109. for ( ;; )
  110. {
  111. if ( !::BackupRead( hfSrc, s_pBuf, sizeof(s_pBuf), &dwRead, FALSE, FALSE, &lpCtxRead ) )
  112. {
  113. dwRet = ::GetLastError();
  114. cszErr = ::GetSysErrStr(dwRet);
  115. ErrorTrace(0, "::BackupRead() failed - %ls", cszErr);
  116. goto Exit;
  117. }
  118. if ( dwRead == 0 )
  119. break;
  120. for ( dwCopied = 0; dwCopied < dwRead; dwCopied += dwWritten )
  121. {
  122. if ( !::BackupWrite( hfDst, s_pBuf+dwCopied, dwRead-dwCopied, &dwWritten, FALSE, FALSE, &lpCtxWrite ) )
  123. {
  124. dwRet = ::GetLastError();
  125. cszErr = ::GetSysErrStr(dwRet);
  126. ErrorTrace(0, "::BackupWrite() failed - %ls", cszErr);
  127. goto Exit;
  128. }
  129. }
  130. }
  131. Exit:
  132. if ( lpCtxWrite != NULL )
  133. if ( !::BackupWrite( hfDst, NULL, 0, NULL, TRUE, FALSE, &lpCtxWrite ) )
  134. {
  135. cszErr = ::GetSysErrStr();
  136. ErrorTrace(0, "::BackupWrite(TRUE) failed - %ls", cszErr);
  137. // Ignore the error
  138. }
  139. if ( lpCtxRead != NULL )
  140. if ( !::BackupRead( hfSrc, NULL, 0, NULL, TRUE, FALSE, &lpCtxRead ) )
  141. {
  142. cszErr = ::GetSysErrStr();
  143. ErrorTrace(0, "::BackupRead(TRUE) failed - %ls", cszErr);
  144. // Ignore the error
  145. }
  146. if ( hfDst != INVALID_HANDLE_VALUE )
  147. ::CloseHandle( hfDst );
  148. if ( hfSrc != INVALID_HANDLE_VALUE )
  149. ::CloseHandle( hfSrc );
  150. TraceFunctLeave();
  151. return( dwRet );
  152. }
  153. /////////////////////////////////////////////////////////////////////////////
  154. // CopyEncryptedFile
  155. DWORD WINAPI
  156. FEExportFunc( PBYTE pbData, PVOID param, ULONG ulLen )
  157. {
  158. TraceFunctEnter("FEExportFunc");
  159. DWORD dwRet = ERROR_SUCCESS;
  160. LPCWSTR cszErr;
  161. HANDLE hfTmp = (HANDLE)param;
  162. DWORD dwRes;
  163. if ( !::WriteFile( hfTmp, pbData, ulLen, &dwRes, NULL ) )
  164. {
  165. dwRet = ::GetLastError();
  166. cszErr = ::GetSysErrStr(dwRet);
  167. ErrorTrace(0, "::WriteFile failed - %ls", cszErr);
  168. goto Exit;
  169. }
  170. Exit:
  171. TraceFunctLeave();
  172. return( dwRet );
  173. }
  174. /////////////////////////////////////////////////////////////////////////////
  175. DWORD WINAPI
  176. FEImportFunc( PBYTE pbData, PVOID param, PULONG pulLen )
  177. {
  178. TraceFunctEnter("FEImportFunc");
  179. DWORD dwRet = ERROR_SUCCESS;
  180. LPCWSTR cszErr;
  181. HANDLE hfTmp = (HANDLE)param;
  182. DWORD dwRes;
  183. if ( !::ReadFile( hfTmp, pbData, *pulLen, &dwRes, NULL ) )
  184. {
  185. dwRet = ::GetLastError();
  186. cszErr = ::GetSysErrStr(dwRet);
  187. ErrorTrace(0, "::ReadFile failed - %ls", cszErr);
  188. goto Exit;
  189. }
  190. *pulLen = dwRes;
  191. Exit:
  192. TraceFunctLeave();
  193. return( dwRet );
  194. }
  195. void GetVolumeName(const WCHAR * pszFileName,
  196. WCHAR * pszVolumeName)
  197. {
  198. WCHAR * pszPastVolumeName;
  199. pszPastVolumeName = ReturnPastVolumeName(pszFileName);
  200. // now copy everything upto the volume name into the buffer
  201. wcsncpy(pszVolumeName, pszFileName, pszPastVolumeName - pszFileName);
  202. pszVolumeName[pszPastVolumeName - pszFileName]=L'\0';
  203. }
  204. /////////////////////////////////////////////////////////////////////////////
  205. LPCWSTR s_cszEncTmpDir = L"encrypt.tmp";
  206. LPCWSTR s_cszEncTmpExtension = L"ExistingMoved";
  207. // this file moves the file to a temp file. This is done to prevent MoveFile
  208. // from failing if the destination file already exists.
  209. // Returns true if the file existed and was moved
  210. BOOL MoveExistingFile(const WCHAR * pszFile,
  211. WCHAR * pszTempFile) // this is the file to use as the
  212. // template file for the move
  213. // destination
  214. {
  215. TraceFunctEnter("MoveExistingFile");
  216. BOOL fReturn=FALSE;
  217. DWORD dwError;
  218. if (DoesFileExist(pszFile))
  219. {
  220. WCHAR szNewFileName[MAX_PATH];
  221. // create new file name
  222. wsprintf(szNewFileName, L"%s.%s", pszTempFile, s_cszEncTmpExtension);
  223. // Delete existing file (if it exists)
  224. DeleteFile(szNewFileName);
  225. // Now do the move
  226. if (MoveFile(pszFile, szNewFileName))
  227. {
  228. fReturn=TRUE;
  229. }
  230. else
  231. {
  232. dwError = GetLastError();
  233. DebugTrace(0, "Failed to move file ec=%d %s %s",dwError,
  234. pszFile, szNewFileName);
  235. }
  236. }
  237. TraceFunctLeave();
  238. return fReturn;
  239. }
  240. BOOL MoveExistingFileBack(const WCHAR * pszFile,
  241. WCHAR * pszTempFile) // this is the file to use as
  242. // the template file for the move
  243. // destination
  244. {
  245. TraceFunctEnter("MoveExistingFileBack");
  246. BOOL fReturn=FALSE;
  247. DWORD dwError;
  248. WCHAR szNewFileName[MAX_PATH];
  249. // create new file name
  250. wsprintf(szNewFileName, L"%s.%s", pszTempFile, s_cszEncTmpExtension);
  251. if (DoesFileExist(szNewFileName))
  252. {
  253. // Now do the move
  254. if (MoveFile(szNewFileName, pszFile))
  255. {
  256. fReturn=TRUE;
  257. }
  258. else
  259. {
  260. dwError = GetLastError();
  261. DebugTrace(0, "Failed to move file ec=%d %s %s",dwError,
  262. szNewFileName, pszFile);
  263. }
  264. }
  265. TraceFunctLeave();
  266. return fReturn;
  267. }
  268. void DeleteMovedFile( WCHAR * pszTempFile) // this is the file to use as
  269. // the template file for the move
  270. // destination (the file to delete)
  271. {
  272. TraceFunctEnter("DeleteMovedFile");
  273. WCHAR szNewFileName[MAX_PATH];
  274. // create new file name
  275. wsprintf(szNewFileName, L"%s.%s", pszTempFile, s_cszEncTmpExtension);
  276. DeleteFile(szNewFileName);
  277. TraceFunctLeave();
  278. return;
  279. }
  280. DWORD SRCreateSubdirectory ( LPCWSTR cszDst, LPSECURITY_ATTRIBUTES pSecAttr )
  281. {
  282. TraceFunctEnter("SRCreateSubdirectory");
  283. WCHAR szDrv[MAX_PATH];
  284. WCHAR szTmpPath[MAX_PATH];
  285. DWORD dwRet = ERROR_SUCCESS;
  286. DWORD dwAttr = ::GetFileAttributes( cszDst );
  287. if ( dwAttr != 0xFFFFFFFF )
  288. {
  289. dwRet = ERROR_ALREADY_EXISTS;
  290. goto Exit;
  291. }
  292. // Prepare temporary directory (must be non-encrypted), create if necessary
  293. GetVolumeName(cszDst, szDrv );
  294. ::MakeRestorePath( szTmpPath, szDrv, s_cszEncTmpDir );
  295. if ( ::GetFileAttributes( szTmpPath ) == 0xFFFFFFFF )
  296. {
  297. if ( !::CreateDirectory( szTmpPath, NULL ) )
  298. {
  299. ErrorTrace(0, "::CreateDirectory(tmp-in-DS) failed - %d",
  300. GetLastError());
  301. ::PathCombine( szTmpPath, szDrv, s_cszEncTmpDir );
  302. if ( ::GetFileAttributes( szTmpPath ) == 0xFFFFFFFF )
  303. {
  304. if ( !::CreateDirectory( szTmpPath, NULL ) )
  305. {
  306. ErrorTrace(0, "::CreateDirectory(tmp-in-root) failed -%d",
  307. GetLastError());
  308. // use the root directory as last restort
  309. ::lstrcpy( szTmpPath, szDrv );
  310. }
  311. }
  312. }
  313. }
  314. lstrcat (szTmpPath, L"\\"); // create the subdirectory to be renamed
  315. lstrcat (szTmpPath, s_cszEncTmpDir);
  316. if ( !::CreateDirectory( szTmpPath, pSecAttr) )
  317. {
  318. dwRet = GetLastError();
  319. ErrorTrace(0, "::CreateDirectory failed - %d", dwRet);
  320. goto Exit;
  321. }
  322. // now rename szTmpPath into the destination
  323. if ( !::MoveFile( szTmpPath, cszDst ) )
  324. {
  325. dwRet = ::GetLastError();
  326. ErrorTrace(0, "::MoveFile failed - %d", dwRet);
  327. ErrorTrace(0, " szTmp ='%ls'", szTmpPath);
  328. ErrorTrace(0, " cszDst='%ls'", cszDst);
  329. RemoveDirectory (szTmpPath); // clean up
  330. goto Exit;
  331. }
  332. Exit:
  333. TraceFunctLeave();
  334. return dwRet;
  335. }
  336. //
  337. // NOTE (10/05/00 skkhang)
  338. // Somehow, OpenEncryptedFileRaw(write) fails if directory is encrypted (and
  339. // probably context is SYSTEM, which is true for restoration.)
  340. // To work around this problem, the encrypted file in data store will be
  341. // copied to a non-encrypted directory (temporary one in data store), and
  342. // then moved into the real target location.
  343. //
  344. DWORD
  345. CopyEncryptedFile( LPCWSTR cszSrc, LPCWSTR cszDst )
  346. {
  347. TraceFunctEnter("CopyEncryptedFile");
  348. DWORD dwRet = ERROR_SUCCESS;
  349. LPCWSTR cszErr;
  350. DWORD dwAttr;
  351. WCHAR szDrv[MAX_PATH];
  352. WCHAR szTmpPath[MAX_PATH]=L"";
  353. WCHAR szTmp[MAX_PATH]=L"";
  354. WCHAR szEnc[MAX_PATH]=L"";
  355. HANDLE hfTmp = INVALID_HANDLE_VALUE;
  356. LPVOID lpContext = NULL;
  357. // BOOL fMovedDestination;
  358. dwAttr = ::GetFileAttributes( cszDst );
  359. if ( dwAttr != 0xFFFFFFFF )
  360. {
  361. // If dest file already exist, it may protected by ACL and
  362. // causes OpenEncryptedFileRaw to fail. Just delete the dest
  363. // file, even though it'll create two log entries.
  364. if (ERROR_SUCCESS == ::ClearFileAttribute( cszDst, FILE_ATTRIBUTE_READONLY ) )
  365. {
  366. if ( !::DeleteFile( cszDst ) )
  367. {
  368. cszErr = ::GetSysErrStr();
  369. ErrorTrace(0, "::DeleteFile failed - %ls", cszErr);
  370. }
  371. }
  372. // Ignore any error, OpenEncryptedFileRaw might succeed.
  373. }
  374. // Prepare temporary directory (must be non-encrypted), create if necessary
  375. /*
  376. // strip filename
  377. lstrcpy(szTmpPath, cszDst);
  378. LPWSTR pszFileName = wcsrchr(szTmpPath, L'\\');
  379. if (pszFileName)
  380. *(++pszFileName) = L'\0';
  381. trace(0, "szTmpPath = %S", szTmpPath);
  382. */
  383. GetVolumeName(cszDst, szDrv );
  384. ::MakeRestorePath( szTmpPath, szDrv, s_cszEncTmpDir );
  385. if ( ::GetFileAttributes( szTmpPath ) == 0xFFFFFFFF )
  386. {
  387. if ( !::CreateDirectory( szTmpPath, NULL ) )
  388. {
  389. cszErr = ::GetSysErrStr();
  390. ErrorTrace(0, "::CreateDirectory(tmp-in-DS) failed - %ls", cszErr);
  391. ::PathCombine( szTmpPath, szDrv, s_cszEncTmpDir );
  392. if ( ::GetFileAttributes( szTmpPath ) == 0xFFFFFFFF )
  393. {
  394. if ( !::CreateDirectory( szTmpPath, NULL ) )
  395. {
  396. cszErr = ::GetSysErrStr();
  397. ErrorTrace(0, "::CreateDirectory(tmp-in-root) failed -%ls",
  398. cszErr);
  399. // Use root directory, as a last resort...
  400. ::lstrcpy( szTmpPath, szDrv );
  401. }
  402. }
  403. }
  404. }
  405. // Prepare temporary file to store the raw data.
  406. // "cef" means Copy Encrypted File.
  407. if ( ::GetTempFileName( szTmpPath, L"cef", 0, szTmp ) == 0 )
  408. {
  409. dwRet = ::GetLastError();
  410. cszErr = ::GetSysErrStr(dwRet);
  411. ErrorTrace(0, "::GetTempFileName failed - %ls", cszErr);
  412. goto Exit;
  413. }
  414. hfTmp = ::CreateFile( szTmp, GENERIC_READ|GENERIC_WRITE, 0, NULL,
  415. CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL );
  416. if ( hfTmp == INVALID_HANDLE_VALUE )
  417. {
  418. dwRet = ::GetLastError();
  419. cszErr = ::GetSysErrStr(dwRet);
  420. ErrorTrace(0, "::CreateFile failed - %ls", cszErr);
  421. ErrorTrace(0, "szTmp='%ls'", szTmp);
  422. goto Exit;
  423. }
  424. DebugTrace(0, "szTmp='%ls'", szTmp);
  425. // Prepare temporary encrypted file.
  426. // "ief" means Intermediate Encrypted File.
  427. if ( ::GetTempFileName( szTmpPath, L"ief", 0, szEnc ) == 0 )
  428. {
  429. dwRet = ::GetLastError();
  430. cszErr = ::GetSysErrStr(dwRet);
  431. ErrorTrace(0, "::GetTempFileName failed - %ls", cszErr);
  432. goto Exit;
  433. }
  434. DebugTrace(0, "szEnc='%ls'", szEnc);
  435. // now check to see if the temp file is encrypted. If it is not,
  436. // then just use CopyFile to copy the temp file.
  437. if (IsFileEncrypted(cszSrc))
  438. {
  439. // Read encrypted raw data from the source file.
  440. dwRet = ::OpenEncryptedFileRaw( cszSrc, 0, &lpContext );
  441. if ( dwRet != ERROR_SUCCESS )
  442. {
  443. cszErr = ::GetSysErrStr(dwRet);
  444. ErrorTrace(0, "::OpenEncryptedFileRaw(read) failed - %ls", cszErr);
  445. ErrorTrace(0, "szSrc='%ls'", cszSrc);
  446. goto Exit;
  447. }
  448. dwRet = ::ReadEncryptedFileRaw( FEExportFunc, hfTmp, lpContext );
  449. if ( dwRet != ERROR_SUCCESS )
  450. {
  451. cszErr = ::GetSysErrStr(dwRet);
  452. ErrorTrace(0, "::ReadEncryptedFileRaw() failed - %ls", cszErr);
  453. goto Exit;
  454. }
  455. ::CloseEncryptedFileRaw( lpContext );
  456. lpContext = NULL;
  457. // Rewind the temporary file.
  458. if ( ::SetFilePointer( hfTmp, 0, NULL, FILE_BEGIN ) == INVALID_SET_FILE_POINTER )
  459. {
  460. dwRet = ::GetLastError();
  461. cszErr = ::GetSysErrStr(dwRet);
  462. ErrorTrace(0, "::SetFilePointer failed - %ls", cszErr);
  463. goto Exit;
  464. }
  465. // Write encrypted raw data to the destination file.
  466. dwRet = ::OpenEncryptedFileRaw( szEnc, CREATE_FOR_IMPORT, &lpContext );
  467. if ( dwRet != ERROR_SUCCESS )
  468. {
  469. cszErr = ::GetSysErrStr(dwRet);
  470. ErrorTrace(0, "::OpenEncryptedFileRaw(write) failed - %ls",cszErr);
  471. ErrorTrace(0, "szEnc='%ls'", szEnc);
  472. goto Exit;
  473. }
  474. dwRet = ::WriteEncryptedFileRaw( FEImportFunc, hfTmp, lpContext );
  475. if ( dwRet != ERROR_SUCCESS )
  476. {
  477. cszErr = ::GetSysErrStr(dwRet);
  478. ErrorTrace(0, "::WriteEncryptedFileRaw() failed - %ls", cszErr);
  479. goto Exit;
  480. }
  481. ::CloseEncryptedFileRaw( lpContext );
  482. lpContext = NULL;
  483. }
  484. else
  485. {
  486. // the temp file is not an encrypted file. Just copy this
  487. // file in the temp location.
  488. dwRet = SRCopyFile(cszSrc, szEnc);
  489. if ( dwRet != ERROR_SUCCESS )
  490. {
  491. cszErr = ::GetSysErrStr(dwRet);
  492. ErrorTrace(0, "::SRCopyFile() failed - %ls", cszErr);
  493. goto Exit;
  494. }
  495. }
  496. /*
  497. // before moving the file to the destination, move the
  498. // destination file if it already exists to another location.
  499. fMovedDestination = MoveExistingFile(cszDst,
  500. szEnc); // this is the file
  501. // to use as the template
  502. // file for the move
  503. // destination
  504. */
  505. // Rename intermediate file into the real target file.
  506. if ( !::MoveFile( szEnc, cszDst ) )
  507. {
  508. dwRet = ::GetLastError();
  509. cszErr = ::GetSysErrStr(dwRet);
  510. ErrorTrace(0, "::MoveFile failed - %ls", cszErr);
  511. ErrorTrace(0, " szEnc ='%ls'", szEnc);
  512. ErrorTrace(0, " cszDst='%ls'", cszDst);
  513. /*
  514. if (TRUE==fMovedDestination)
  515. {
  516. MoveExistingFileBack(cszDst,
  517. szEnc); // this is the file to use as the
  518. // template file for the move
  519. }
  520. */
  521. goto Exit;
  522. }
  523. Exit:
  524. /*
  525. if (TRUE==fMovedDestination)
  526. {
  527. DeleteMovedFile(szEnc); // this is the file to use as the template
  528. // file for the delete
  529. }
  530. */
  531. if ( lpContext != NULL )
  532. ::CloseEncryptedFileRaw( lpContext );
  533. if ( hfTmp != INVALID_HANDLE_VALUE )
  534. ::CloseHandle( hfTmp );
  535. DeleteFile(szEnc);
  536. RemoveDirectory(szTmpPath);
  537. TraceFunctLeave();
  538. return( dwRet );
  539. }
  540. DWORD CopyFileTimes( LPCWSTR cszSrc, LPCWSTR cszDst )
  541. {
  542. TraceFunctEnter("CopyFileTimes");
  543. DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
  544. FILETIME CreationTime, LastWriteTime, LastAccessTime;
  545. HANDLE hSrcFile=INVALID_HANDLE_VALUE, hDestFile=INVALID_HANDLE_VALUE;
  546. // open the source file
  547. // paulmcd: 1/2001: only need to get FILE_READ_ATTRIBUTES in order
  548. // to call GetFileTimes, only do this as the file might be EFS
  549. // and we can't get GENERIC_READ .
  550. //
  551. hSrcFile=CreateFile(cszSrc, // file name
  552. FILE_READ_ATTRIBUTES, // access mode
  553. FILE_SHARE_DELETE| FILE_SHARE_READ| FILE_SHARE_WRITE,
  554. // share mode
  555. NULL, // SD
  556. OPEN_EXISTING, // how to create
  557. FILE_FLAG_BACKUP_SEMANTICS, // file attributes
  558. NULL); // handle to template file
  559. if (INVALID_HANDLE_VALUE == hSrcFile)
  560. {
  561. dwErr = GetLastError();
  562. if (ERROR_SUCCESS != dwErr)
  563. {
  564. dwReturn = dwErr;
  565. }
  566. ErrorTrace(0, "CreateFile of src failed ec=%d", dwErr);
  567. LogDSFileTrace(0,L"File was ", cszSrc);
  568. goto cleanup;
  569. }
  570. // open the destination file
  571. // paulmcd: 1/2001: only need to get FILE_WRITE_ATTRIBUTES in order
  572. // to call SetFileTimes, only do this as the file might be EFS
  573. // and we can't get GENERIC_READ .
  574. //
  575. hDestFile=CreateFile(cszDst, // file name
  576. FILE_WRITE_ATTRIBUTES, // access mode
  577. FILE_SHARE_DELETE| FILE_SHARE_READ| FILE_SHARE_WRITE,
  578. // share mode
  579. NULL, // SD
  580. OPEN_EXISTING, // how to create
  581. FILE_FLAG_BACKUP_SEMANTICS, // file attributes
  582. NULL); // handle to template file
  583. if (INVALID_HANDLE_VALUE == hDestFile)
  584. {
  585. dwErr = GetLastError();
  586. if (ERROR_SUCCESS != dwErr)
  587. {
  588. dwReturn = dwErr;
  589. }
  590. ErrorTrace(0, "CreateFile of dst failed ec=%d", dwErr);
  591. LogDSFileTrace(0,L"File was ", cszDst);
  592. goto cleanup;
  593. }
  594. // Call getfiletimes on the source file
  595. if (FALSE == GetFileTime(hSrcFile,// handle to file
  596. &CreationTime, // creation time
  597. &LastAccessTime, // last access time
  598. &LastWriteTime)) // last write time
  599. {
  600. dwErr = GetLastError();
  601. if (ERROR_SUCCESS != dwErr)
  602. {
  603. dwReturn = dwErr;
  604. }
  605. ErrorTrace(0, "GetFileTime of src failed ec=%d", dwErr);
  606. LogDSFileTrace(0,L"File was ", cszSrc);
  607. goto cleanup;
  608. }
  609. // call SetFileTimes on the destination file
  610. if (FALSE == SetFileTime(hDestFile,// handle to file
  611. &CreationTime, // creation time
  612. &LastAccessTime, // last access time
  613. &LastWriteTime)) // last write time
  614. {
  615. dwErr = GetLastError();
  616. if (ERROR_SUCCESS != dwErr)
  617. {
  618. dwReturn = dwErr;
  619. }
  620. ErrorTrace(0, "SetFileTime of dest file failed ec=%d", dwErr);
  621. LogDSFileTrace(0,L"File was ", cszDst);
  622. goto cleanup;
  623. }
  624. dwReturn = ERROR_SUCCESS;
  625. cleanup:
  626. if (INVALID_HANDLE_VALUE != hDestFile)
  627. {
  628. _VERIFY(CloseHandle(hDestFile));
  629. }
  630. if (INVALID_HANDLE_VALUE != hSrcFile)
  631. {
  632. _VERIFY(CloseHandle(hSrcFile));
  633. }
  634. TraceFunctLeave();
  635. return dwReturn;
  636. }
  637. BOOL IsFileEncrypted(const WCHAR * cszDst)
  638. {
  639. TraceFunctEnter("IsFileEncrypted");
  640. BOOL fReturn=FALSE;
  641. DWORD dwAttr, dwError;
  642. dwAttr = ::GetFileAttributes( cszDst );
  643. if ( dwAttr == 0xFFFFFFFF )
  644. {
  645. dwError=GetLastError();
  646. DebugTrace(0, "! GetFileAttributes ec=%d", dwError);
  647. goto cleanup;
  648. }
  649. if (dwAttr & FILE_ATTRIBUTE_ENCRYPTED )
  650. {
  651. DebugTrace(0, " File is encrypted %S", cszDst);
  652. fReturn = TRUE;
  653. }
  654. cleanup:
  655. TraceFunctLeave();
  656. return fReturn;
  657. }
  658. // this function checks to see if the parent directory under the
  659. // specified file name is encrypted
  660. BOOL IsParentDirectoryEncrypted(const WCHAR * pszFileName)
  661. {
  662. TraceFunctEnter("IsParentDirectoryEncrypted");
  663. WCHAR * pszParentDir = new WCHAR[SR_MAX_FILENAME_LENGTH];
  664. BOOL fReturn = FALSE;
  665. DWORD dwError;
  666. if (!pszParentDir)
  667. {
  668. ErrorTrace(0, "Cannot allocate memory");
  669. goto cleanup;
  670. }
  671. lstrcpy(pszParentDir, pszFileName);
  672. // get the parent directory
  673. RemoveTrailingFilename(pszParentDir, L'\\');
  674. if (TRUE == IsFileEncrypted(pszParentDir))
  675. {
  676. fReturn = TRUE;
  677. }
  678. else
  679. {
  680. fReturn = FALSE;
  681. }
  682. cleanup:
  683. if (pszParentDir)
  684. delete [] pszParentDir;
  685. TraceFunctLeave();
  686. return fReturn;
  687. }
  688. /////////////////////////////////////////////////////////////////////////////
  689. // SRCopyFile
  690. DWORD
  691. SRCopyFile( LPCWSTR cszSrc, LPCWSTR cszDst )
  692. {
  693. TraceFunctEnter("SRCopyFile");
  694. DWORD dwRet = ERROR_SUCCESS;
  695. DWORD dwErr;
  696. LPCWSTR cszErr;
  697. DWORD dwAttr, dwAttrDest;
  698. BOOL fDestinationEncrypted;
  699. DebugTrace(TRACEID, "Source %S", cszSrc);
  700. DebugTrace(TRACEID, "Dest %S", cszDst);
  701. dwAttr = ::GetFileAttributes( cszSrc );
  702. if ( dwAttr == 0xFFFFFFFF )
  703. {
  704. ErrorTrace(0, "Source file does not exist...???");
  705. ErrorTrace(0, "Src='%ls'", cszSrc);
  706. dwRet = ERROR_FILE_NOT_FOUND;
  707. goto Exit;
  708. }
  709. fDestinationEncrypted = FALSE;
  710. if (IsFileEncrypted(cszDst) || IsParentDirectoryEncrypted(cszDst))
  711. {
  712. fDestinationEncrypted =TRUE;
  713. }
  714. // Check Encrypted File.
  715. if ( (dwAttr & FILE_ATTRIBUTE_ENCRYPTED ) ||
  716. (TRUE == fDestinationEncrypted) )
  717. {
  718. // Assuming Encryption APIs would override ACL settings and
  719. // file attributes...
  720. dwRet = ::CopyEncryptedFile( cszSrc, cszDst );
  721. goto Exit;
  722. }
  723. // Check attribute of destination file and clear it if necessary.
  724. dwRet = ::ClearFileAttribute( cszDst, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM );
  725. if ( dwRet != ERROR_SUCCESS )
  726. goto Exit;
  727. // Try Normal Copy.
  728. if ( ::CopyFile( cszSrc, cszDst, FALSE ) )
  729. goto Exit;
  730. dwRet = GetLastError();
  731. cszErr = ::GetSysErrStr();
  732. DebugTrace(0, "::CopyFile failed - %ls", cszErr);
  733. // Now Try to Override ACL. - however - do not do this in case of
  734. // disk full
  735. if (ERROR_DISK_FULL != dwRet)
  736. {
  737. dwRet = ::CopyACLProtectedFile( cszSrc, cszDst );
  738. }
  739. Exit:
  740. if (ERROR_SUCCESS == dwRet)
  741. {
  742. //
  743. // CopyFileTimes may fail for read-only files
  744. // so ignore error here
  745. //
  746. CopyFileTimes(cszSrc, cszDst );
  747. }
  748. TraceFunctLeave();
  749. return( dwRet );
  750. }
  751. DWORD SetShortFileName(const WCHAR * pszFile,
  752. const WCHAR * pszShortName)
  753. {
  754. TraceFunctEnter("SetShortFileName");
  755. HANDLE hFile=INVALID_HANDLE_VALUE;// access mode
  756. DWORD dwRet=ERROR_INTERNAL_ERROR;
  757. if (NULL == pszShortName)
  758. {
  759. goto cleanup;
  760. }
  761. // first open the file
  762. // paulmcd: 1/2001, you need DELETE|FILE_WRITE_ATTRIBUTES access
  763. // in order to call SetFileShortName, don't ask for more as the
  764. // file might be EFS and we might not be able to get read/write .
  765. //
  766. hFile = ::CreateFile( pszFile,
  767. FILE_WRITE_ATTRIBUTES|DELETE,// access mode
  768. FILE_SHARE_READ| FILE_SHARE_WRITE,// share mode
  769. NULL, // security attributes
  770. OPEN_EXISTING, // how to create
  771. FILE_FLAG_BACKUP_SEMANTICS, // to override ACLs
  772. NULL );// handle to template file
  773. if ( hFile == INVALID_HANDLE_VALUE )
  774. {
  775. dwRet = ::GetLastError();
  776. ErrorTrace(0, "::CreateFile() failed - %d", dwRet);
  777. ErrorTrace(0, "File was=%S", pszFile);
  778. goto cleanup;
  779. }
  780. // now set the short file name
  781. if (FALSE==SetFileShortName(hFile,
  782. pszShortName))
  783. {
  784. dwRet = ::GetLastError();
  785. ErrorTrace(0, "!SetFileShortName (it is a FAT drive?) %d %S",
  786. dwRet, pszShortName);
  787. ErrorTrace(0, "File was=%S", pszFile);
  788. goto cleanup;
  789. }
  790. dwRet = ERROR_SUCCESS;
  791. cleanup:
  792. // close the file
  793. if ( hFile != INVALID_HANDLE_VALUE )
  794. {
  795. _VERIFY(TRUE==CloseHandle(hFile));
  796. }
  797. TraceFunctLeave();
  798. return dwRet;
  799. }
  800. // end of file