// Copyright (c) 1996-1999 Microsoft Corporation //+------------------------------------------------------------------------- // // Microsoft Windows // // File: fileops.hxx // // Contents: Definitions for OBJID and file operations // // Classes: // // Functions: // // // // History: 18-Nov-96 BillMo Created. // // Notes: // // Codework: // //-------------------------------------------------------------------------- unsigned ConvertToNtPath(const TCHAR *ptszVolumePath, WCHAR *pwszNtPath, ULONG cwcBuf); //+---------------------------------------------------------------------------- // // CVolumeDeviceName // // This represents a "volume device name", as defined by the mount manager. // Volume device names are of the form (but without the trailing whack). E.g.: // // "\\?\Volume{856d50da-d07e-11d2-9e72-806d6172696f}" // //+---------------------------------------------------------------------------- class CVolumeDeviceName { public: // Create a volume device name from a zero-relative // drive letter index. CVolumeDeviceName( LONG iVol ) { _stprintf( _tszPath, TEXT("\\\\.\\%c:"), iVol+TEXT('A') ); } // Return the volume name.. operator const TCHAR*() const { return( _tszPath ); } // Validate a zero-relative drive letter index. static BOOL IsValid( LONG iVol ) { if( 0 <= iVol && NUM_VOLUMES > iVol ) return( TRUE ); else return( FALSE ); } private: TCHAR _tszPath[ MAX_PATH ]; }; // // IsLocalObjectVolume // // Returns true of the volume supports object IDs (NTFS5). // BOOL IsLocalObjectVolume( const TCHAR *ptszVolumeName ); inline BOOL IsLocalObjectVolume( LONG iVol ) { if( !CVolumeDeviceName::IsValid(iVol) ) return( STATUS_OBJECT_PATH_NOT_FOUND ); TCHAR tszVolumeName[ MAX_PATH+1 ]; _tcscpy( tszVolumeName, CVolumeDeviceName(iVol) ); _tcscat( tszVolumeName, TEXT("\\") ); return( IsLocalObjectVolume( tszVolumeName )); } // // IsSystemVolumeInformation // // Returns true if the path is somewhere under "\System Volume Information" // BOOL IsSystemVolumeInformation( const TCHAR *ptszPath ); HRESULT MapLocalPathToUNC( RPC_BINDING_HANDLE IDL_handle, const TCHAR *ptszLocalPath, TCHAR *ptszUNC, ULONG cbMaxUnc ); NTSTATUS OpenFileById( const TCHAR *ptszVolumeDeviceName, const CObjId &oid, ACCESS_MASK AccessMask, ULONG ShareAccess, ULONG AdditionalCreateOptions, HANDLE *ph); inline NTSTATUS OpenFileById( LONG iVol, const CObjId &oid, ACCESS_MASK AccessMask, ULONG ShareAccess, ULONG AdditionalCreateOptions, HANDLE *ph) { if( !CVolumeDeviceName::IsValid(iVol) ) return( STATUS_OBJECT_PATH_NOT_FOUND ); return( OpenFileById( CVolumeDeviceName(iVol), oid, AccessMask, ShareAccess, AdditionalCreateOptions, ph )); } NTSTATUS OpenVolume( const TCHAR *ptszVolumeDeviceName, HANDLE * ph ); inline NTSTATUS OpenVolume( LONG iVol, HANDLE * phVolume ) { if( !CVolumeDeviceName::IsValid(iVol) ) return( STATUS_OBJECT_PATH_NOT_FOUND ); return( OpenVolume( CVolumeDeviceName(iVol), phVolume )); } NTSTATUS CheckVolumeWriteProtection( const TCHAR *ptszVolumeDeviceName, BOOL *pfWriteProtected ); #define CCH_MAX_VOLUME_NAME 50 // \\?\Volume{96765fc3-9c72-11d1-b93d-000000000000}\ LONG MapVolumeDeviceNameToIndex( TCHAR *ptszVolumeDeviceName ); NTSTATUS SetVolId( const TCHAR *ptszVolumeDeviceName, const CVolumeId &volid ); inline NTSTATUS SetVolId( LONG iVol, const CVolumeId &volid ) { if( !CVolumeDeviceName::IsValid(iVol) ) return( STATUS_OBJECT_PATH_NOT_FOUND ); return( SetVolId( CVolumeDeviceName(iVol), volid )); } NTSTATUS TrkCreateFile( const WCHAR *pwszCompleteDosPath, ACCESS_MASK AccessMask, ULONG Attributes, ULONG ShareAccess, ULONG CreationDisposition, // e.g. FILE_OPEN, FILE_OPEN_IF, etc ULONG CreateOptions, // e.g. FILE_WRITE_THROUGH, FILE_OPEN_FOR_BACKUP_INTENT LPSECURITY_ATTRIBUTES lpSecurityAttributes, HANDLE *ph); NTSTATUS FindLocalPath( IN const TCHAR *ptszVolumeDeviceName, IN const CObjId &objid, OUT CDomainRelativeObjId *pdroidBirth, OUT TCHAR *ptszLocalPath ); inline NTSTATUS FindLocalPath( IN ULONG iVol, IN const CObjId &objid, OUT CDomainRelativeObjId *pdroidBirth, OUT TCHAR *ptszLocalPath ) { if( !CVolumeDeviceName::IsValid(iVol) ) return( STATUS_OBJECT_PATH_NOT_FOUND ); return( FindLocalPath( CVolumeDeviceName(iVol), objid, pdroidBirth, ptszLocalPath )); } NTSTATUS GetDroids( HANDLE hFile, CDomainRelativeObjId *pdroidCurrent, CDomainRelativeObjId *pdroidBirth, RGO_ENUM rgoEnum ); NTSTATUS GetDroids( const TCHAR *ptszFile, CDomainRelativeObjId *pdroidCurrent, CDomainRelativeObjId *pdroidBirth, RGO_ENUM rgoEnum ); NTSTATUS SetObjId( const HANDLE hFile, CObjId objid, const CDomainRelativeObjId &droidBirth ); NTSTATUS SetObjId( const TCHAR *ptszFile, CObjId objid, const CDomainRelativeObjId &droidBirth ); NTSTATUS MakeObjIdReborn(HANDLE hFile); NTSTATUS MakeObjIdReborn(const TCHAR *ptszVolumeDeviceName, const CObjId &objid); inline NTSTATUS MakeObjIdReborn(LONG iVol, const CObjId &objid) { if( !CVolumeDeviceName::IsValid(iVol) ) return( STATUS_OBJECT_PATH_NOT_FOUND ); return( MakeObjIdReborn( CVolumeDeviceName(iVol), objid )); } NTSTATUS SetBirthId( HANDLE hFile, const CDomainRelativeObjId &droidBirth ); NTSTATUS SetBirthId( const TCHAR *ptszFile, const CDomainRelativeObjId &droidBirth ); NTSTATUS GetBirthId( IN HANDLE hFile, OUT CDomainRelativeObjId *pdroidBirth ); // This routine is inline because it doesn't get used in the production code, // only in tests. inline NTSTATUS DelObjId(HANDLE hFile) { // ----------------- // Delete the Object ID // ----------------- // Send the FSCTL IO_STATUS_BLOCK IoStatus; return NtFsControlFile( hFile, NULL, NULL, NULL, &IoStatus, FSCTL_DELETE_OBJECT_ID, NULL, // in buffer 0, // in buffer size NULL, // Out buffer 0); // Out buffer size } // This routine is inline because it doesn't get used in the production code, // only in tests. inline NTSTATUS DelObjId(const TCHAR *ptszVolumeDeviceName, const CObjId &objid) { // -------------- // Initialization // -------------- NTSTATUS status = STATUS_SUCCESS; HANDLE hFile = NULL; // ------------- // Open the file // ------------- EnableRestorePrivilege(); status = OpenFileById(ptszVolumeDeviceName, objid, SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_FOR_BACKUP_INTENT, // for FSCTL_DELETE_OBJECT_ID &hFile); if( !NT_SUCCESS(status) ) { hFile = NULL; TrkLog(( TRKDBG_ERROR, TEXT("Couldn't del objid, failed open (%08x)"), status )); goto Exit; } status = DelObjId( hFile ); if( !NT_SUCCESS(status) && STATUS_OBJECT_NAME_NOT_FOUND != status ) { TrkLog(( TRKDBG_ERROR, TEXT("Couldn't delete file Object ID, failed delete (%08x)"), status )); goto Exit; } // ---- // Exit // ---- Exit: if( NULL != hFile ) NtClose( hFile ); return( status ); } inline NTSTATUS DelObjId(LONG iVol, const CObjId &objid) { if( !CVolumeDeviceName::IsValid(iVol) ) return( STATUS_OBJECT_PATH_NOT_FOUND ); return( DelObjId( CVolumeDeviceName(iVol), objid )); } //+---------------------------------------------------------------------------- // // InterlockedCloseHandle // // This routine provides a thread-safe way to close a handle for code // that isn't thread-safe. This is used by CloseVolumeHandles, since // that routine can't take a lock. // //+---------------------------------------------------------------------------- inline void InterlockedCloseHandle( HANDLE *ph, void* EmptyValue = NULL, BOOL fCancelIo = FALSE ) { HANDLE h1 = NULL; HANDLE h2 = NULL; // Get the current value. h1 = *ph; // If the handle hasn't changed between the previous line and the // following call, set it to null. h2 = InterlockedCompareExchangePointer( (void**)ph, (void*)EmptyValue, h1 ); // If *ph was unchanged as of the previous // call, we've got a local copy of it now, and we can safely close it. if( h1 == h2 && EmptyValue != h1 ) { // *ph is already NULL if( fCancelIo ) { TrkLog(( TRKDBG_MISC, TEXT("Canceling handle x%x"), h1 )); CancelIo( h1 ); } TrkLog(( TRKDBG_MISC, TEXT("Closing handle x%x"), h1 )); NtClose( h1 ); } }