|
|
/******************************************************************************
Copyright (c) 2000 Microsoft Corporation
Module Name: ntfs.cpp
Abstract: This file contains the common utility functions for NTFS file operations, e.g. CopyNTFSFile to copy a file overriding ACL and EFS.
Revision History: Seong Kook Khang (SKKhang) 08/16/00 created
******************************************************************************/ #include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <winioctl.h>
#include "srdefs.h"
#include "utils.h"
#include <dbgtrace.h>
#include <stdio.h>
#include <objbase.h>
#include <ntlsa.h>
#include <accctrl.h>
#include <aclapi.h>
#include <malloc.h>
#include <regstr.h>
#include <shlwapi.h>
#include <commctrl.h>
#include <shellapi.h>
#include <srapi.h>
#define TRACEID 9875
BOOL IsFileEncrypted(const WCHAR * cszDst);
/////////////////////////////////////////////////////////////////////////////
//
// ClearFileAttribute
//
// Check the attribute of file and clear it if necessary.
//
/////////////////////////////////////////////////////////////////////////////
DWORD ClearFileAttribute( LPCWSTR cszFile, DWORD dwMask ) { TraceFunctEnter("ClearFileAttribute"); DWORD dwRet = ERROR_SUCCESS; DWORD dwErr; LPCWSTR cszErr; DWORD dwAttr;
// Check if file exists, ignore if not exist
dwAttr = ::GetFileAttributes( cszFile ); if ( dwAttr == 0xFFFFFFFF ) goto Exit;
// If file exist, clear the given flags
if ( ( dwAttr & dwMask ) != 0 ) { // This will always succeed even if the file is ACL protected or
// encrypted, so don't worry about it...
if ( !::SetFileAttributes( cszFile, dwAttr & ~dwMask ) ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::SetFileAttributes failed - %ls", cszErr); ErrorTrace(0, "Src='%ls'", cszFile); goto Exit; } }
Exit: TraceFunctLeave(); return( dwRet ); }
/////////////////////////////////////////////////////////////////////////////
//
// TakeOwnership
//
/////////////////////////////////////////////////////////////////////////////
DWORD TakeOwnership( LPCWSTR cszPath ) { TraceFunctEnter("TakeOwnership"); DWORD dwRet; LPCWSTR cszErr; HANDLE hTokenProcess = NULL; TOKEN_USER *pUser = NULL; DWORD dwSize;
if ( !::OpenProcessToken( ::GetCurrentProcess(), TOKEN_QUERY, &hTokenProcess ) ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::OpenProcessToken failed - %ls", cszErr); goto Exit; } if ( !::GetTokenInformation( hTokenProcess, TokenUser, NULL, 0, &dwSize ) ) { dwRet = ::GetLastError(); if ( dwRet != ERROR_INSUFFICIENT_BUFFER ) { cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::GetTokenInformation(query) failed - %ls", cszErr); goto Exit; } else dwRet = ERROR_SUCCESS; } pUser = (TOKEN_USER*) new BYTE[dwSize]; if ( pUser == NULL ) { FatalTrace(0, "Insufficient memory..."); dwRet = ERROR_NOT_ENOUGH_MEMORY; goto Exit; } if ( !::GetTokenInformation( hTokenProcess, TokenUser, pUser, dwSize, &dwSize ) ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::GetTokenInformation(get) failed - %ls", cszErr); goto Exit; } dwRet = ::SetNamedSecurityInfo( (LPWSTR)cszPath, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, pUser->User.Sid, NULL, NULL, NULL ); if ( dwRet != ERROR_SUCCESS ) { cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::SetNamedSecurityInfo failed - %ls", cszErr); goto Exit; }
Exit: if ( pUser != NULL ) delete [] (BYTE*)pUser; if ( hTokenProcess != NULL ) ::CloseHandle( hTokenProcess );
TraceFunctLeave(); return( dwRet ); }
/////////////////////////////////////////////////////////////////////////////
//
// Copy File Routines
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CopyACLProtectedFile
BYTE s_pBuf[4096];
DWORD CopyACLProtectedFile( LPCWSTR cszSrc, LPCWSTR cszDst ) { TraceFunctEnter("CopyACLProtectedFile"); DWORD dwRet = ERROR_SUCCESS; LPCWSTR cszErr; HANDLE hfSrc = INVALID_HANDLE_VALUE; HANDLE hfDst = INVALID_HANDLE_VALUE; LPVOID lpCtxRead = NULL; LPVOID lpCtxWrite = NULL; DWORD dwRead; DWORD dwCopied; DWORD dwWritten;
hfSrc = ::CreateFile( cszSrc, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); if ( hfSrc == INVALID_HANDLE_VALUE ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::CreateFile() failed - %ls", cszErr); ErrorTrace(0, "cszSrc='%ls'", cszSrc); goto Exit; } hfDst = ::CreateFile( cszDst, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL ); if ( hfDst == INVALID_HANDLE_VALUE ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::CreateFile() failed - %ls", cszErr); ErrorTrace(0, "cszDst='%ls'", cszDst); goto Exit; }
for ( ;; ) { if ( !::BackupRead( hfSrc, s_pBuf, sizeof(s_pBuf), &dwRead, FALSE, FALSE, &lpCtxRead ) ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::BackupRead() failed - %ls", cszErr); goto Exit; } if ( dwRead == 0 ) break;
for ( dwCopied = 0; dwCopied < dwRead; dwCopied += dwWritten ) { if ( !::BackupWrite( hfDst, s_pBuf+dwCopied, dwRead-dwCopied, &dwWritten, FALSE, FALSE, &lpCtxWrite ) ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::BackupWrite() failed - %ls", cszErr); goto Exit; } } }
Exit: if ( lpCtxWrite != NULL ) if ( !::BackupWrite( hfDst, NULL, 0, NULL, TRUE, FALSE, &lpCtxWrite ) ) { cszErr = ::GetSysErrStr(); ErrorTrace(0, "::BackupWrite(TRUE) failed - %ls", cszErr); // Ignore the error
} if ( lpCtxRead != NULL ) if ( !::BackupRead( hfSrc, NULL, 0, NULL, TRUE, FALSE, &lpCtxRead ) ) { cszErr = ::GetSysErrStr(); ErrorTrace(0, "::BackupRead(TRUE) failed - %ls", cszErr); // Ignore the error
} if ( hfDst != INVALID_HANDLE_VALUE ) ::CloseHandle( hfDst ); if ( hfSrc != INVALID_HANDLE_VALUE ) ::CloseHandle( hfSrc );
TraceFunctLeave(); return( dwRet ); }
/////////////////////////////////////////////////////////////////////////////
// CopyEncryptedFile
DWORD WINAPI FEExportFunc( PBYTE pbData, PVOID param, ULONG ulLen ) { TraceFunctEnter("FEExportFunc"); DWORD dwRet = ERROR_SUCCESS; LPCWSTR cszErr; HANDLE hfTmp = (HANDLE)param; DWORD dwRes;
if ( !::WriteFile( hfTmp, pbData, ulLen, &dwRes, NULL ) ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::WriteFile failed - %ls", cszErr); goto Exit; }
Exit: TraceFunctLeave(); return( dwRet ); }
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI FEImportFunc( PBYTE pbData, PVOID param, PULONG pulLen ) { TraceFunctEnter("FEImportFunc"); DWORD dwRet = ERROR_SUCCESS; LPCWSTR cszErr; HANDLE hfTmp = (HANDLE)param; DWORD dwRes;
if ( !::ReadFile( hfTmp, pbData, *pulLen, &dwRes, NULL ) ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::ReadFile failed - %ls", cszErr); goto Exit; }
*pulLen = dwRes;
Exit: TraceFunctLeave(); return( dwRet ); }
void GetVolumeName(const WCHAR * pszFileName, WCHAR * pszVolumeName) {
WCHAR * pszPastVolumeName;
pszPastVolumeName = ReturnPastVolumeName(pszFileName); // now copy everything upto the volume name into the buffer
wcsncpy(pszVolumeName, pszFileName, pszPastVolumeName - pszFileName); pszVolumeName[pszPastVolumeName - pszFileName]=L'\0'; }
/////////////////////////////////////////////////////////////////////////////
LPCWSTR s_cszEncTmpDir = L"encrypt.tmp"; LPCWSTR s_cszEncTmpExtension = L"ExistingMoved";
// this file moves the file to a temp file. This is done to prevent MoveFile
// from failing if the destination file already exists.
// Returns true if the file existed and was moved
BOOL MoveExistingFile(const WCHAR * pszFile, WCHAR * pszTempFile) // this is the file to use as the
// template file for the move
// destination
{ TraceFunctEnter("MoveExistingFile"); BOOL fReturn=FALSE; DWORD dwError; if (DoesFileExist(pszFile)) { WCHAR szNewFileName[MAX_PATH]; // create new file name
wsprintf(szNewFileName, L"%s.%s", pszTempFile, s_cszEncTmpExtension); // Delete existing file (if it exists)
DeleteFile(szNewFileName); // Now do the move
if (MoveFile(pszFile, szNewFileName)) { fReturn=TRUE; } else { dwError = GetLastError(); DebugTrace(0, "Failed to move file ec=%d %s %s",dwError, pszFile, szNewFileName); } } TraceFunctLeave(); return fReturn; }
BOOL MoveExistingFileBack(const WCHAR * pszFile, WCHAR * pszTempFile) // this is the file to use as
// the template file for the move
// destination
{ TraceFunctEnter("MoveExistingFileBack"); BOOL fReturn=FALSE; DWORD dwError; WCHAR szNewFileName[MAX_PATH]; // create new file name
wsprintf(szNewFileName, L"%s.%s", pszTempFile, s_cszEncTmpExtension); if (DoesFileExist(szNewFileName)) { // Now do the move
if (MoveFile(szNewFileName, pszFile)) { fReturn=TRUE; } else { dwError = GetLastError(); DebugTrace(0, "Failed to move file ec=%d %s %s",dwError, szNewFileName, pszFile); } } TraceFunctLeave(); return fReturn; }
void DeleteMovedFile( WCHAR * pszTempFile) // this is the file to use as
// the template file for the move
// destination (the file to delete)
{ TraceFunctEnter("DeleteMovedFile");
WCHAR szNewFileName[MAX_PATH]; // create new file name
wsprintf(szNewFileName, L"%s.%s", pszTempFile, s_cszEncTmpExtension); DeleteFile(szNewFileName); TraceFunctLeave(); return; }
DWORD SRCreateSubdirectory ( LPCWSTR cszDst, LPSECURITY_ATTRIBUTES pSecAttr ) { TraceFunctEnter("SRCreateSubdirectory");
WCHAR szDrv[MAX_PATH]; WCHAR szTmpPath[MAX_PATH]; DWORD dwRet = ERROR_SUCCESS; DWORD dwAttr = ::GetFileAttributes( cszDst );
if ( dwAttr != 0xFFFFFFFF ) { dwRet = ERROR_ALREADY_EXISTS; goto Exit; }
// Prepare temporary directory (must be non-encrypted), create if necessary
GetVolumeName(cszDst, szDrv );
::MakeRestorePath( szTmpPath, szDrv, s_cszEncTmpDir ); if ( ::GetFileAttributes( szTmpPath ) == 0xFFFFFFFF ) { if ( !::CreateDirectory( szTmpPath, NULL ) ) { ErrorTrace(0, "::CreateDirectory(tmp-in-DS) failed - %d", GetLastError());
::PathCombine( szTmpPath, szDrv, s_cszEncTmpDir ); if ( ::GetFileAttributes( szTmpPath ) == 0xFFFFFFFF ) { if ( !::CreateDirectory( szTmpPath, NULL ) ) { ErrorTrace(0, "::CreateDirectory(tmp-in-root) failed -%d", GetLastError());
// use the root directory as last restort
::lstrcpy( szTmpPath, szDrv ); } } } }
lstrcat (szTmpPath, L"\\"); // create the subdirectory to be renamed
lstrcat (szTmpPath, s_cszEncTmpDir);
if ( !::CreateDirectory( szTmpPath, pSecAttr) ) { dwRet = GetLastError(); ErrorTrace(0, "::CreateDirectory failed - %d", dwRet); goto Exit; }
// now rename szTmpPath into the destination
if ( !::MoveFile( szTmpPath, cszDst ) ) { dwRet = ::GetLastError(); ErrorTrace(0, "::MoveFile failed - %d", dwRet); ErrorTrace(0, " szTmp ='%ls'", szTmpPath); ErrorTrace(0, " cszDst='%ls'", cszDst);
RemoveDirectory (szTmpPath); // clean up
goto Exit; }
Exit: TraceFunctLeave(); return dwRet; }
//
// NOTE (10/05/00 skkhang)
// Somehow, OpenEncryptedFileRaw(write) fails if directory is encrypted (and
// probably context is SYSTEM, which is true for restoration.)
// To work around this problem, the encrypted file in data store will be
// copied to a non-encrypted directory (temporary one in data store), and
// then moved into the real target location.
//
DWORD CopyEncryptedFile( LPCWSTR cszSrc, LPCWSTR cszDst ) { TraceFunctEnter("CopyEncryptedFile"); DWORD dwRet = ERROR_SUCCESS; LPCWSTR cszErr; DWORD dwAttr; WCHAR szDrv[MAX_PATH]; WCHAR szTmpPath[MAX_PATH]=L""; WCHAR szTmp[MAX_PATH]=L""; WCHAR szEnc[MAX_PATH]=L""; HANDLE hfTmp = INVALID_HANDLE_VALUE; LPVOID lpContext = NULL; // BOOL fMovedDestination;
dwAttr = ::GetFileAttributes( cszDst ); if ( dwAttr != 0xFFFFFFFF ) { // If dest file already exist, it may protected by ACL and
// causes OpenEncryptedFileRaw to fail. Just delete the dest
// file, even though it'll create two log entries.
if (ERROR_SUCCESS == ::ClearFileAttribute( cszDst, FILE_ATTRIBUTE_READONLY ) ) { if ( !::DeleteFile( cszDst ) ) { cszErr = ::GetSysErrStr(); ErrorTrace(0, "::DeleteFile failed - %ls", cszErr); } } // Ignore any error, OpenEncryptedFileRaw might succeed.
}
// Prepare temporary directory (must be non-encrypted), create if necessary
/*
// strip filename
lstrcpy(szTmpPath, cszDst); LPWSTR pszFileName = wcsrchr(szTmpPath, L'\\'); if (pszFileName) *(++pszFileName) = L'\0';
trace(0, "szTmpPath = %S", szTmpPath); */ GetVolumeName(cszDst, szDrv );
::MakeRestorePath( szTmpPath, szDrv, s_cszEncTmpDir ); if ( ::GetFileAttributes( szTmpPath ) == 0xFFFFFFFF ) { if ( !::CreateDirectory( szTmpPath, NULL ) ) { cszErr = ::GetSysErrStr(); ErrorTrace(0, "::CreateDirectory(tmp-in-DS) failed - %ls", cszErr);
::PathCombine( szTmpPath, szDrv, s_cszEncTmpDir ); if ( ::GetFileAttributes( szTmpPath ) == 0xFFFFFFFF ) { if ( !::CreateDirectory( szTmpPath, NULL ) ) { cszErr = ::GetSysErrStr(); ErrorTrace(0, "::CreateDirectory(tmp-in-root) failed -%ls", cszErr);
// Use root directory, as a last resort...
::lstrcpy( szTmpPath, szDrv ); } } } }
// Prepare temporary file to store the raw data.
// "cef" means Copy Encrypted File.
if ( ::GetTempFileName( szTmpPath, L"cef", 0, szTmp ) == 0 ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::GetTempFileName failed - %ls", cszErr); goto Exit; } hfTmp = ::CreateFile( szTmp, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL ); if ( hfTmp == INVALID_HANDLE_VALUE ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::CreateFile failed - %ls", cszErr); ErrorTrace(0, "szTmp='%ls'", szTmp); goto Exit; } DebugTrace(0, "szTmp='%ls'", szTmp);
// Prepare temporary encrypted file.
// "ief" means Intermediate Encrypted File.
if ( ::GetTempFileName( szTmpPath, L"ief", 0, szEnc ) == 0 ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::GetTempFileName failed - %ls", cszErr); goto Exit; } DebugTrace(0, "szEnc='%ls'", szEnc);
// now check to see if the temp file is encrypted. If it is not,
// then just use CopyFile to copy the temp file.
if (IsFileEncrypted(cszSrc)) { // Read encrypted raw data from the source file.
dwRet = ::OpenEncryptedFileRaw( cszSrc, 0, &lpContext ); if ( dwRet != ERROR_SUCCESS ) { cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::OpenEncryptedFileRaw(read) failed - %ls", cszErr); ErrorTrace(0, "szSrc='%ls'", cszSrc); goto Exit; } dwRet = ::ReadEncryptedFileRaw( FEExportFunc, hfTmp, lpContext ); if ( dwRet != ERROR_SUCCESS ) { cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::ReadEncryptedFileRaw() failed - %ls", cszErr); goto Exit; } ::CloseEncryptedFileRaw( lpContext ); lpContext = NULL; // Rewind the temporary file.
if ( ::SetFilePointer( hfTmp, 0, NULL, FILE_BEGIN ) == INVALID_SET_FILE_POINTER ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::SetFilePointer failed - %ls", cszErr); goto Exit; } // Write encrypted raw data to the destination file.
dwRet = ::OpenEncryptedFileRaw( szEnc, CREATE_FOR_IMPORT, &lpContext ); if ( dwRet != ERROR_SUCCESS ) { cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::OpenEncryptedFileRaw(write) failed - %ls",cszErr); ErrorTrace(0, "szEnc='%ls'", szEnc); goto Exit; } dwRet = ::WriteEncryptedFileRaw( FEImportFunc, hfTmp, lpContext ); if ( dwRet != ERROR_SUCCESS ) { cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::WriteEncryptedFileRaw() failed - %ls", cszErr); goto Exit; } ::CloseEncryptedFileRaw( lpContext ); lpContext = NULL; } else { // the temp file is not an encrypted file. Just copy this
// file in the temp location.
dwRet = SRCopyFile(cszSrc, szEnc); if ( dwRet != ERROR_SUCCESS ) { cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::SRCopyFile() failed - %ls", cszErr); goto Exit; } }
/*
// before moving the file to the destination, move the
// destination file if it already exists to another location.
fMovedDestination = MoveExistingFile(cszDst, szEnc); // this is the file
// to use as the template
// file for the move
// destination
*/
// Rename intermediate file into the real target file.
if ( !::MoveFile( szEnc, cszDst ) ) { dwRet = ::GetLastError(); cszErr = ::GetSysErrStr(dwRet); ErrorTrace(0, "::MoveFile failed - %ls", cszErr); ErrorTrace(0, " szEnc ='%ls'", szEnc); ErrorTrace(0, " cszDst='%ls'", cszDst); /*
if (TRUE==fMovedDestination) { MoveExistingFileBack(cszDst, szEnc); // this is the file to use as the
// template file for the move
} */ goto Exit; }
Exit: /*
if (TRUE==fMovedDestination) { DeleteMovedFile(szEnc); // this is the file to use as the template
// file for the delete
} */ if ( lpContext != NULL ) ::CloseEncryptedFileRaw( lpContext ); if ( hfTmp != INVALID_HANDLE_VALUE ) ::CloseHandle( hfTmp );
DeleteFile(szEnc); RemoveDirectory(szTmpPath); TraceFunctLeave(); return( dwRet ); }
DWORD CopyFileTimes( LPCWSTR cszSrc, LPCWSTR cszDst ) { TraceFunctEnter("CopyFileTimes"); DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR; FILETIME CreationTime, LastWriteTime, LastAccessTime; HANDLE hSrcFile=INVALID_HANDLE_VALUE, hDestFile=INVALID_HANDLE_VALUE; // open the source file
// paulmcd: 1/2001: only need to get FILE_READ_ATTRIBUTES in order
// to call GetFileTimes, only do this as the file might be EFS
// and we can't get GENERIC_READ .
//
hSrcFile=CreateFile(cszSrc, // file name
FILE_READ_ATTRIBUTES, // access mode
FILE_SHARE_DELETE| FILE_SHARE_READ| FILE_SHARE_WRITE, // share mode
NULL, // SD
OPEN_EXISTING, // how to create
FILE_FLAG_BACKUP_SEMANTICS, // file attributes
NULL); // handle to template file
if (INVALID_HANDLE_VALUE == hSrcFile) { dwErr = GetLastError(); if (ERROR_SUCCESS != dwErr) { dwReturn = dwErr; } ErrorTrace(0, "CreateFile of src failed ec=%d", dwErr); LogDSFileTrace(0,L"File was ", cszSrc); goto cleanup; } // open the destination file
// paulmcd: 1/2001: only need to get FILE_WRITE_ATTRIBUTES in order
// to call SetFileTimes, only do this as the file might be EFS
// and we can't get GENERIC_READ .
//
hDestFile=CreateFile(cszDst, // file name
FILE_WRITE_ATTRIBUTES, // access mode
FILE_SHARE_DELETE| FILE_SHARE_READ| FILE_SHARE_WRITE, // share mode
NULL, // SD
OPEN_EXISTING, // how to create
FILE_FLAG_BACKUP_SEMANTICS, // file attributes
NULL); // handle to template file
if (INVALID_HANDLE_VALUE == hDestFile) { dwErr = GetLastError(); if (ERROR_SUCCESS != dwErr) { dwReturn = dwErr; } ErrorTrace(0, "CreateFile of dst failed ec=%d", dwErr); LogDSFileTrace(0,L"File was ", cszDst); goto cleanup; }
// Call getfiletimes on the source file
if (FALSE == GetFileTime(hSrcFile,// handle to file
&CreationTime, // creation time
&LastAccessTime, // last access time
&LastWriteTime)) // last write time
{ dwErr = GetLastError(); if (ERROR_SUCCESS != dwErr) { dwReturn = dwErr; } ErrorTrace(0, "GetFileTime of src failed ec=%d", dwErr); LogDSFileTrace(0,L"File was ", cszSrc); goto cleanup; }
// call SetFileTimes on the destination file
if (FALSE == SetFileTime(hDestFile,// handle to file
&CreationTime, // creation time
&LastAccessTime, // last access time
&LastWriteTime)) // last write time
{ dwErr = GetLastError(); if (ERROR_SUCCESS != dwErr) { dwReturn = dwErr; } ErrorTrace(0, "SetFileTime of dest file failed ec=%d", dwErr); LogDSFileTrace(0,L"File was ", cszDst); goto cleanup; } dwReturn = ERROR_SUCCESS; cleanup: if (INVALID_HANDLE_VALUE != hDestFile) { _VERIFY(CloseHandle(hDestFile)); } if (INVALID_HANDLE_VALUE != hSrcFile) { _VERIFY(CloseHandle(hSrcFile)); } TraceFunctLeave(); return dwReturn; }
BOOL IsFileEncrypted(const WCHAR * cszDst) { TraceFunctEnter("IsFileEncrypted"); BOOL fReturn=FALSE; DWORD dwAttr, dwError; dwAttr = ::GetFileAttributes( cszDst ); if ( dwAttr == 0xFFFFFFFF ) { dwError=GetLastError(); DebugTrace(0, "! GetFileAttributes ec=%d", dwError); goto cleanup; } if (dwAttr & FILE_ATTRIBUTE_ENCRYPTED ) { DebugTrace(0, " File is encrypted %S", cszDst); fReturn = TRUE; }
cleanup: TraceFunctLeave(); return fReturn; }
// this function checks to see if the parent directory under the
// specified file name is encrypted
BOOL IsParentDirectoryEncrypted(const WCHAR * pszFileName) { TraceFunctEnter("IsParentDirectoryEncrypted");
WCHAR * pszParentDir = new WCHAR[SR_MAX_FILENAME_LENGTH]; BOOL fReturn = FALSE; DWORD dwError;
if (!pszParentDir) { ErrorTrace(0, "Cannot allocate memory"); goto cleanup; }
lstrcpy(pszParentDir, pszFileName); // get the parent directory
RemoveTrailingFilename(pszParentDir, L'\\');
if (TRUE == IsFileEncrypted(pszParentDir)) { fReturn = TRUE; } else { fReturn = FALSE; }
cleanup:
if (pszParentDir) delete [] pszParentDir; TraceFunctLeave(); return fReturn; }
/////////////////////////////////////////////////////////////////////////////
// SRCopyFile
DWORD SRCopyFile( LPCWSTR cszSrc, LPCWSTR cszDst ) { TraceFunctEnter("SRCopyFile"); DWORD dwRet = ERROR_SUCCESS; DWORD dwErr; LPCWSTR cszErr; DWORD dwAttr, dwAttrDest; BOOL fDestinationEncrypted;
DebugTrace(TRACEID, "Source %S", cszSrc); DebugTrace(TRACEID, "Dest %S", cszDst); dwAttr = ::GetFileAttributes( cszSrc ); if ( dwAttr == 0xFFFFFFFF ) { ErrorTrace(0, "Source file does not exist...???"); ErrorTrace(0, "Src='%ls'", cszSrc); dwRet = ERROR_FILE_NOT_FOUND; goto Exit; }
fDestinationEncrypted = FALSE; if (IsFileEncrypted(cszDst) || IsParentDirectoryEncrypted(cszDst)) { fDestinationEncrypted =TRUE; }
// Check Encrypted File.
if ( (dwAttr & FILE_ATTRIBUTE_ENCRYPTED ) || (TRUE == fDestinationEncrypted) ) { // Assuming Encryption APIs would override ACL settings and
// file attributes...
dwRet = ::CopyEncryptedFile( cszSrc, cszDst ); goto Exit; }
// Check attribute of destination file and clear it if necessary.
dwRet = ::ClearFileAttribute( cszDst, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM ); if ( dwRet != ERROR_SUCCESS ) goto Exit;
// Try Normal Copy.
if ( ::CopyFile( cszSrc, cszDst, FALSE ) ) goto Exit; dwRet = GetLastError(); cszErr = ::GetSysErrStr(); DebugTrace(0, "::CopyFile failed - %ls", cszErr);
// Now Try to Override ACL. - however - do not do this in case of
// disk full
if (ERROR_DISK_FULL != dwRet) { dwRet = ::CopyACLProtectedFile( cszSrc, cszDst ); }
Exit: if (ERROR_SUCCESS == dwRet) { //
// CopyFileTimes may fail for read-only files
// so ignore error here
//
CopyFileTimes(cszSrc, cszDst );
} TraceFunctLeave(); return( dwRet ); }
DWORD SetShortFileName(const WCHAR * pszFile, const WCHAR * pszShortName) { TraceFunctEnter("SetShortFileName"); HANDLE hFile=INVALID_HANDLE_VALUE;// access mode
DWORD dwRet=ERROR_INTERNAL_ERROR;
if (NULL == pszShortName) { goto cleanup; }
// first open the file
// paulmcd: 1/2001, you need DELETE|FILE_WRITE_ATTRIBUTES access
// in order to call SetFileShortName, don't ask for more as the
// file might be EFS and we might not be able to get read/write .
//
hFile = ::CreateFile( pszFile, FILE_WRITE_ATTRIBUTES|DELETE,// access mode
FILE_SHARE_READ| FILE_SHARE_WRITE,// share mode
NULL, // security attributes
OPEN_EXISTING, // how to create
FILE_FLAG_BACKUP_SEMANTICS, // to override ACLs
NULL );// handle to template file
if ( hFile == INVALID_HANDLE_VALUE ) { dwRet = ::GetLastError(); ErrorTrace(0, "::CreateFile() failed - %d", dwRet); ErrorTrace(0, "File was=%S", pszFile); goto cleanup; } // now set the short file name
if (FALSE==SetFileShortName(hFile, pszShortName)) { dwRet = ::GetLastError(); ErrorTrace(0, "!SetFileShortName (it is a FAT drive?) %d %S", dwRet, pszShortName); ErrorTrace(0, "File was=%S", pszFile); goto cleanup; }
dwRet = ERROR_SUCCESS; cleanup: // close the file
if ( hFile != INVALID_HANDLE_VALUE ) { _VERIFY(TRUE==CloseHandle(hFile)); }
TraceFunctLeave(); return dwRet; }
// end of file
|