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.
389 lines
9.9 KiB
389 lines
9.9 KiB
|
|
// 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 );
|
|
}
|
|
}
|