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.

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