|
|
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-2004 Microsoft Corporation
//
// Module Name: volutil.cpp
//
// Description:
// Utility functions for handling volumes
//
// Author: Jim Benton (jbenton) 30-Apr-2002
//
//////////////////////////////////////////////////////////////////////////////
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <map>
#include "vs_assert.hxx"
#include <atlbase.h>
#include <winioctl.h>
#include <ntddvol.h> // IOCTL_VOLUME_IS_OFFLINE
#include <mountmgr.h> // MOUNTDEV_NAME
#include <lm.h> // NetShareDel
#include "vs_inc.hxx"
#include <strsafe.h>
#include "schema.h"
#include "volutil.h"
#define SYMBOLIC_LINK_LENGTH 28 // \DosDevices\X:
#define GLOBALROOT_SIZE 14 // \\?\GLOBALROOT
const WCHAR SETUP_KEY[] = L"SYSTEM\\Setup"; const WCHAR SETUP_SYSTEMPARTITION[] = L"SystemPartition";
BOOL GetVolumeDrive ( IN WCHAR* pwszVolumePath, IN DWORD cchDriveName, OUT WCHAR* pwszDriveNameBuf ) { CVssAutoPWSZ awszMountPoints; WCHAR* pwszCurrentMountPoint = NULL; BOOL fFound = FALSE; CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"VolumeMountPointExists"); // Get the length of the multi-string array
DWORD cchVolumesBufferLen = 0; BOOL bResult = GetVolumePathNamesForVolumeName( pwszVolumePath, NULL, 0, &cchVolumesBufferLen); if (!bResult && (GetLastError() != ERROR_MORE_DATA)) ft.TranslateGenericError(VSSDBG_VSSADMIN, HRESULT_FROM_WIN32(GetLastError()), L"GetVolumePathNamesForVolumeName(%s, 0, 0, %p)", pwszVolumePath, &cchVolumesBufferLen);
// Allocate the array
awszMountPoints.Allocate(cchVolumesBufferLen);
// Get the mount points
// Note: this API was introduced in WinXP so it will need to be replaced if backported
bResult = GetVolumePathNamesForVolumeName( pwszVolumePath, awszMountPoints, cchVolumesBufferLen, NULL); if (!bResult) ft.Throw(VSSDBG_VSSADMIN, HRESULT_FROM_WIN32(GetLastError()), L"GetVolumePathNamesForVolumeName(%s, %p, %lu, 0)", pwszVolumePath, awszMountPoints, cchVolumesBufferLen);
// If the volume has mount points
pwszCurrentMountPoint = awszMountPoints; if ( pwszCurrentMountPoint[0] ) { while(!fFound) { // End of iteration?
LONG lCurrentMountPointLength = (LONG) ::wcslen(pwszCurrentMountPoint); if (lCurrentMountPointLength == 0) break;
// Only a root directory should have a trailing backslash character
if (lCurrentMountPointLength == 3 && pwszCurrentMountPoint[1] == L':' && pwszCurrentMountPoint[2] == L'\\') { ft.hr = StringCchCopy(pwszDriveNameBuf, cchDriveName, pwszCurrentMountPoint); if (ft.HrFailed()) ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"StringCChCopy failed %#x", ft.hr); fFound = TRUE; }
// Go to the next one. Skip the zero character.
pwszCurrentMountPoint += lCurrentMountPointLength + 1; } }
return fFound; }
BOOL VolumeSupportsQuotas( IN WCHAR* pwszVolume ) { BOOL fSupportsQuotas = FALSE; DWORD dwDontCare = 0; DWORD dwFileSystemFlags = 0; _ASSERTE(pwszVolume != NULL);
if (GetVolumeInformation( pwszVolume, NULL, 0, &dwDontCare, &dwDontCare, &dwFileSystemFlags, NULL, 0)) { if (dwFileSystemFlags & FILE_VOLUME_QUOTAS) fSupportsQuotas = TRUE; }
return fSupportsQuotas; }
// Filter volumes where:
// - the supporting device is disconnected
// - the supporting device is a floppy
// - the volume is not found
// All other volumes are assumed valid
BOOL VolumeIsValid( IN WCHAR* pwszVolume ) { bool fValid = true; HANDLE hVol = INVALID_HANDLE_VALUE; DWORD cch = 0; DWORD dwRet = 0; CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"VolumeIsValid");
_ASSERTE(pwszVolume != NULL);
cch = wcslen(pwszVolume); pwszVolume[cch - 1] = 0; hVol = CreateFile(pwszVolume, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); pwszVolume[cch - 1] = '\\';
dwRet = GetLastError(); if (hVol == INVALID_HANDLE_VALUE && dwRet != ERROR_NOT_READY) { if (dwRet == ERROR_FILE_NOT_FOUND || dwRet == ERROR_DEVICE_NOT_CONNECTED) { fValid = false; } else { ft.Trace(VSSDBG_VSSADMIN, L"Unable to open volume %lS, %#x", pwszVolume, dwRet); } } if (hVol != INVALID_HANDLE_VALUE) CloseHandle(hVol);
// Filter floppy drives
if (fValid) { fValid = !VolumeIsFloppy(pwszVolume); }
return fValid; }
DWORD VolumeIsDirty( IN WCHAR* pwszVolume, OUT BOOL* pfDirty ) { HANDLE hVol = INVALID_HANDLE_VALUE; DWORD dwRet = 0; DWORD cBytes = 0; DWORD dwResult = 0; WCHAR wszDeviceName[MAX_PATH+GLOBALROOT_SIZE]; CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"VolumeIsDirty"); _ASSERTE(pwszVolume != NULL); _ASSERTE(pfDirty != NULL);
*pfDirty = FALSE;
do { dwRet = GetDeviceName(pwszVolume, wszDeviceName); if (dwRet != ERROR_SUCCESS) { ft.hr = HRESULT_FROM_WIN32(dwRet); ft.Trace(VSSDBG_VSSADMIN, L"Unable to get volume device name %lS", pwszVolume); break; }
hVol = CreateFile(wszDeviceName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
if (hVol != INVALID_HANDLE_VALUE) { if (DeviceIoControl(hVol, FSCTL_IS_VOLUME_DIRTY, NULL, 0, &dwResult, sizeof(dwResult), &cBytes, NULL)) { *pfDirty = dwResult & VOLUME_IS_DIRTY; } else { dwRet = GetLastError(); ft.Trace(VSSDBG_VSSADMIN, L"DeviceIoControl failed for device %lS, %#x", wszDeviceName, dwRet); break; } CloseHandle(hVol); } else { dwRet = GetLastError(); ft.Trace(VSSDBG_VSSADMIN, L"Unable to open volume %lS, %#x", pwszVolume, dwRet); break; } } while(false);
return dwRet; }
BOOL VolumeIsMountable( IN WCHAR* pwszVolume ) { CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"VolumeIsMountable"); DWORD cch = 0; HANDLE hVol = INVALID_HANDLE_VALUE; BOOL bIsOffline = FALSE; DWORD bytes = 0;
cch = wcslen(pwszVolume); pwszVolume[cch - 1] = 0; hVol = CreateFile(pwszVolume, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); pwszVolume[cch - 1] = '\\'; if (hVol != INVALID_HANDLE_VALUE) { bIsOffline = DeviceIoControl(hVol, IOCTL_VOLUME_IS_OFFLINE, NULL, 0, NULL, 0, &bytes, NULL); CloseHandle(hVol); } else { ft.Trace(VSSDBG_VSSADMIN, L"Unable to open volume %lS, %#x", pwszVolume, GetLastError()); }
return !bIsOffline; }
BOOL VolumeHasMountPoints( IN WCHAR* pwszVolume ) { CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"VolumeHasMountPoints"); DWORD dwVolumesBufferLen = 0; BOOL bResult = GetVolumePathNamesForVolumeName( pwszVolume, NULL, 0, &dwVolumesBufferLen); if (!bResult && (GetLastError() != ERROR_MORE_DATA)) ft.Throw(VSSDBG_VSSADMIN, HRESULT_FROM_WIN32(GetLastError()), L"GetVolumePathNamesForVolumeName(%s, 0, 0, %p)", pwszVolume, &dwVolumesBufferLen);
// More than three characters are needed to store just one mount point (multi-string buffer)
// dwVolumesBufferLen == 1 typically for an un-mounted volume.
return dwVolumesBufferLen > 3; }
BOOL VolumeIsFloppy( WCHAR* pwszVolume ) { HANDLE hDevice = INVALID_HANDLE_VALUE; WCHAR wszDeviceName[MAX_PATH+GLOBALROOT_SIZE]; NTSTATUS Status = ERROR_SUCCESS; IO_STATUS_BLOCK IoStatusBlock; FILE_FS_DEVICE_INFORMATION DeviceInfo; BOOL fIsFloppy = FALSE;
DWORD dwRet = GetDeviceName(pwszVolume, wszDeviceName);
if (dwRet == ERROR_SUCCESS) { hDevice = CreateFile(wszDeviceName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ |FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
if (hDevice != INVALID_HANDLE_VALUE) { Status = NtQueryVolumeInformationFile( hDevice, &IoStatusBlock, &DeviceInfo, sizeof(DeviceInfo), FileFsDeviceInformation);
if (NT_SUCCESS(Status)) { if (DeviceInfo.DeviceType == FILE_DEVICE_DISK && DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE) { fIsFloppy = TRUE ; } } } } if (hDevice != INVALID_HANDLE_VALUE) CloseHandle(hDevice);
return fIsFloppy; }
BOOL VolumeIsReady( IN WCHAR* pwszVolume ) { BOOL bIsReady = FALSE; DWORD dwDontCare; CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"VolumeIsReady");
if (GetVolumeInformation( pwszVolume, NULL, 0, &dwDontCare, &dwDontCare, &dwDontCare, NULL, 0)) { bIsReady = TRUE; } else if (GetLastError() != ERROR_NOT_READY) ft.Trace(VSSDBG_VSSADMIN, L"GetVolumeInformation failed for volume %lS, %#x", pwszVolume, GetLastError()); return bIsReady; }
BOOL VolumeIsSystem( IN WCHAR* pwszVolume ) { CRegKey cRegKeySetup; DWORD dwRet = 0; WCHAR wszRegDevice[MAX_PATH]; WCHAR wszVolDevice[MAX_PATH+GLOBALROOT_SIZE]; CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"VolumeIsSystem");
dwRet = cRegKeySetup.Open( HKEY_LOCAL_MACHINE, SETUP_KEY, KEY_READ); if (dwRet != ERROR_SUCCESS) { ft.hr = HRESULT_FROM_WIN32(dwRet); ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Reg key open failed, %#x", dwRet); }
DWORD dwLen = MAX_PATH; dwRet = cRegKeySetup.QueryValue(wszRegDevice, SETUP_SYSTEMPARTITION, &dwLen); if (dwRet != ERROR_SUCCESS) { ft.hr = HRESULT_FROM_WIN32(dwRet); ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Reg key query failed, %#x", dwRet); }
dwRet = GetDeviceName(pwszVolume, wszVolDevice); if (dwRet != ERROR_SUCCESS) { ft.hr = HRESULT_FROM_WIN32(dwRet); ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get volume device name, %lS, %#x", pwszVolume, dwRet); }
if (_wcsicmp(wszVolDevice+GLOBALROOT_SIZE, wszRegDevice) == 0) return TRUE; return FALSE; }
BOOL VolumeHoldsPagefile( IN WCHAR* pwszVolume ) { CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"VolumeHoldsPagefile");
//
// Retrieve page files.
//
BYTE* pbBuffer; DWORD dwBufferSize; PSYSTEM_PAGEFILE_INFORMATION pPageFileInfo = NULL; NTSTATUS status; BOOL fFound = FALSE;
try { for (dwBufferSize=512; ; dwBufferSize += 512) { // Allocate buffer at 512 bytes increment. Previous allocation is
// freed automatically.
pbBuffer = (BYTE *) new BYTE[dwBufferSize]; if ( pbBuffer==NULL ) return E_OUTOFMEMORY;
status = NtQuerySystemInformation( SystemPageFileInformation, pbBuffer, dwBufferSize, NULL ); if ( status==STATUS_INFO_LENGTH_MISMATCH ) // buffer not big enough.
{ delete [] pbBuffer; continue; }
pPageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION) pbBuffer; if (!NT_SUCCESS(status)) { ft.hr = HRESULT_FROM_NT(status); ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"NtQuerySystemInformation failed, %#x", status); } else break; }
//
// Walk through each of the page file volumes. Usually the return
// looks like "\??\C:\pagefile.sys." If a pagefile is added\extended
// \moved, the return will look like
// "\Device\HarddiskVolume2\pagefile.sys."
//
WCHAR *p; WCHAR wszDrive[3] = L"?:"; WCHAR buffer2[MAX_PATH], *pbuffer2 = buffer2; WCHAR wszVolDevice[MAX_PATH+GLOBALROOT_SIZE], *pwszVolDevice = wszVolDevice; DWORD dwRet;
dwRet = GetDeviceName(pwszVolume, wszVolDevice); if (dwRet != ERROR_SUCCESS) { ft.hr = HRESULT_FROM_WIN32(dwRet); ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get volume device name, %lS, %#x", pwszVolume, dwRet); }
for ( ; ; ) { if ( pPageFileInfo==NULL || pPageFileInfo->TotalSize==0 ) // We get 0 on WinPE.
break;
if ( pPageFileInfo->PageFileName.Length==0) break;
p = wcschr(pPageFileInfo->PageFileName.Buffer, L':'); if (p != NULL) { //
// Convert drive letter to volume name.
//
_ASSERTE(p>pPageFileInfo->PageFileName.Buffer); _ASSERTE(towupper(*(p-1))>=L'A'); _ASSERTE(towupper(*(p-1))<=L'Z');
wszDrive[0] = towupper(*(p-1)); dwRet = QueryDosDevice(wszDrive, buffer2, MAX_PATH); if (dwRet == 0) { ft.hr = HRESULT_FROM_NT(dwRet); ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"QueryDosDevice failed, %#x", dwRet); } } else { _ASSERTE(_wcsnicmp(pPageFileInfo->PageFileName.Buffer, L"\\Device", 7)==0 );
p = wcsstr(pPageFileInfo->PageFileName.Buffer,L"\\pagefile.sys"); _ASSERTE( p!=NULL ); if (p == NULL) { ft.hr = E_UNEXPECTED; ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unexpected pagefile name format, %lS", pPageFileInfo->PageFileName.Buffer); } *p = L'\0'; ft.hr = StringCchCopy(buffer2, MAX_PATH, pPageFileInfo->PageFileName.Buffer); if (ft.HrFailed()) { ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"StringCchCopy failed, %#x", ft.hr); } }
if (_wcsicmp(wszVolDevice+GLOBALROOT_SIZE, buffer2) == 0) { fFound = TRUE; break; }
//
// Next page file volume.
//
if (pPageFileInfo->NextEntryOffset == 0) break;
pPageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR)pPageFileInfo + pPageFileInfo->NextEntryOffset);
} } catch (...) { delete [] pbBuffer; throw; }
delete [] pbBuffer;
return fFound; }
DWORD GetDeviceName( IN WCHAR* pwszVolume, OUT WCHAR wszDeviceName[MAX_PATH+GLOBALROOT_SIZE] ) /*++
Description:
Get the device name of the given device. E.g. \Device\HarddiskVolume### Arguments:
pwszVolume - volume GUID name.
wszDeviceName - a buffer to receive device name. The buffer size must be MAX_PATH+GLOBALROOT_SIZE (including "\\?\GLOBALROOT").
Return Value:
Win32 errors
--*/ { DWORD dwRet; BOOL bRet; WCHAR wszMountDevName[MAX_PATH+sizeof(MOUNTDEV_NAME)]; // Based on GetVolumeNameForRoot (in volmount.c), MAX_PATH seems to
// be big enough as out buffer for IOCTL_MOUNTDEV_QUERY_DEVICE_NAME.
// But we assume the size of device name could be as big as MAX_PATH-1,
// so we allocate the buffer size to include MOUNTDEV_NAME size.
PMOUNTDEV_NAME pMountDevName; DWORD dwBytesReturned; HANDLE hVol = INVALID_HANDLE_VALUE; CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"GetDeviceName"); DWORD cch = 0;
_ASSERTE(pwszVolume != NULL);
wszDeviceName[0] = L'\0'; //
// query the volume's device object name
//
cch = wcslen(pwszVolume); pwszVolume[cch - 1] = 0; hVol = CreateFile(pwszVolume, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); pwszVolume[cch - 1] = '\\';
if (hVol != INVALID_HANDLE_VALUE) { bRet = DeviceIoControl( hVol, // handle to device
IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, // input data buffer
0, // size of input data buffer
wszMountDevName, // output data buffer
sizeof(wszMountDevName), // size of output data buffer
&dwBytesReturned, NULL // overlapped information
);
dwRet = GetLastError(); CloseHandle(hVol); if ( bRet==FALSE ) { ft.Trace(VSSDBG_VSSADMIN, L"GetDeviceName: DeviceIoControl() failed: %X", dwRet); return dwRet; }
pMountDevName = (PMOUNTDEV_NAME) wszMountDevName; if (pMountDevName->NameLength == 0) { // TODO: Is this possible? UNKNOWN?
_ASSERTE( 0 ); } else { //
// copy name
//
ft.hr = StringCchPrintf(wszDeviceName, MAX_PATH+GLOBALROOT_SIZE, L"\\\\?\\GLOBALROOT" ); if (ft.HrFailed()) ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"StringCchPrintf failed: %#x", ft.hr);
CopyMemory(wszDeviceName+GLOBALROOT_SIZE, pMountDevName->Name, pMountDevName->NameLength ); // appending terminating NULL
wszDeviceName[pMountDevName->NameLength/2 + GLOBALROOT_SIZE] = L'\0'; } }
return ERROR_SUCCESS; }
// VolumeMountPointExists is currently written specifically to verify the existence of a mountpoint
// as defined by the WMI Win32_MountPoint Directory reference string. This string names the directory
// such that the trailing backslash appears only on root directories. This is a basic assumption
// made by this function. It is not general purpose. The calling code should be changed to append
// the trailing backslash so that this function can be generalized. Mount points are enumerated
// by GetVolumePathNamesForVolumeName API with trailing backslashes.
BOOL VolumeMountPointExists( IN WCHAR* pwszVolume, IN WCHAR* pwszDirectory ) { CVssAutoPWSZ awszMountPoints; WCHAR* pwszCurrentMountPoint = NULL; BOOL fFound = FALSE; CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"VolumeMountPointExists"); // Get the length of the multi-string array
DWORD cchVolumesBufferLen = 0; BOOL bResult = GetVolumePathNamesForVolumeName( pwszVolume, NULL, 0, &cchVolumesBufferLen); if (!bResult && (GetLastError() != ERROR_MORE_DATA)) ft.TranslateGenericError(VSSDBG_VSSADMIN, HRESULT_FROM_WIN32(GetLastError()), L"GetVolumePathNamesForVolumeName(%s, 0, 0, %p)", pwszVolume, &cchVolumesBufferLen);
// Allocate the array
awszMountPoints.Allocate(cchVolumesBufferLen);
// Get the mount points
// Note: this API was introduced in WinXP so it will need to be replaced if backported
bResult = GetVolumePathNamesForVolumeName( pwszVolume, awszMountPoints, cchVolumesBufferLen, NULL); if (!bResult) ft.Throw(VSSDBG_VSSADMIN, HRESULT_FROM_WIN32(GetLastError()), L"GetVolumePathNamesForVolumeName(%s, %p, %lu, 0)", pwszVolume, awszMountPoints, cchVolumesBufferLen);
// If the volume has mount points
pwszCurrentMountPoint = awszMountPoints; if ( pwszCurrentMountPoint[0] ) { while(true) { // End of iteration?
LONG lCurrentMountPointLength = (LONG) ::wcslen(pwszCurrentMountPoint); if (lCurrentMountPointLength == 0) break;
// Only a root directory should have a trailing backslash character
if (lCurrentMountPointLength > 2 && pwszCurrentMountPoint[lCurrentMountPointLength-1] == L'\\' && pwszCurrentMountPoint[lCurrentMountPointLength-2] != L':') { pwszCurrentMountPoint[lCurrentMountPointLength-1] = L'\0'; }
if (_wcsicmp(pwszDirectory, pwszCurrentMountPoint) == 0) { fFound = TRUE; break; }
// Go to the next one. Skip the zero character.
pwszCurrentMountPoint += lCurrentMountPointLength + 1; } }
return fFound; }
void DeleteVolumeDriveLetter( IN WCHAR* pwszVolume, IN WCHAR* pwszDrivePath ) { BOOL fVolumeLocked = FALSE; HANDLE hVolume = INVALID_HANDLE_VALUE; DWORD dwRet = 0; CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"DeleteVolumeDriveLetter");
_ASSERTE(pwszVolume != NULL); _ASSERTE(pwszDrivePath != NULL); // Try to lock the volume
DWORD cch = wcslen(pwszVolume); pwszVolume[cch - 1] = 0; hVolume = CreateFile( pwszVolume, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL ); pwszVolume[cch - 1] = '\\';
if (hVolume == INVALID_HANDLE_VALUE) { dwRet = GetLastError(); ft.hr = HRESULT_FROM_WIN32(dwRet); ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CreateFile(OPEN_EXISTING) failed for %lS, %#x", pwszVolume, dwRet); }
dwRet = LockVolume(hVolume); if (dwRet == ERROR_SUCCESS) { fVolumeLocked = TRUE; ft.Trace(VSSDBG_VSSADMIN, L"volume %lS locked", pwszVolume); } else { ft.Trace(VSSDBG_VSSADMIN, L"Unable to lock volume %lS, %#x", pwszVolume, dwRet); }
try { if (fVolumeLocked) { // If volume is locked delete the mount point
if (!DeleteVolumeMountPoint(pwszDrivePath)) { dwRet = GetLastError(); ft.hr = HRESULT_FROM_WIN32(dwRet); ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"DeleteVolumeMountPoint failed %#x, drivepath<%lS>", dwRet, pwszDrivePath); } } else { // Otherwise, remove the entry from the volume mgr database only
// The volume will still be accessible through the drive letter until reboot
ft.hr = DeleteDriveLetterFromDB(pwszDrivePath); if (ft.HrFailed()) ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"DeleteDriveLetterFromDB failed %#x, drivepath<%lS>", ft.hr, pwszDrivePath); } } catch (...) { CloseHandle(hVolume); throw; }
CloseHandle(hVolume); }
HRESULT DeleteDriveLetterFromDB( IN WCHAR* pwszDriveLetter) { CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"DeleteDriveLetterFromDB");
MOUNTMGR_MOUNT_POINT *InputMountPoint=NULL; MOUNTMGR_MOUNT_POINTS *OutputMountPoints=NULL; ULONG ulInputSize = 0; HANDLE hMountMgr = INVALID_HANDLE_VALUE; DWORD dwBytesReturned = 0; DWORD dwRet = 0; BOOL bRet = FALSE;
_ASSERTE(pwszDriveLetter != NULL); //
// Prepare IOCTL_MOUNTMGR_QUERY_POINTS input
//
ulInputSize = sizeof(MOUNTMGR_MOUNT_POINT) + SYMBOLIC_LINK_LENGTH; InputMountPoint = (MOUNTMGR_MOUNT_POINT *) new BYTE[ulInputSize]; if ( InputMountPoint==NULL ) { ft.hr = E_OUTOFMEMORY; return ft.hr; }
ZeroMemory(InputMountPoint, ulInputSize); InputMountPoint->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); InputMountPoint->SymbolicLinkNameLength = SYMBOLIC_LINK_LENGTH; InputMountPoint->UniqueIdOffset = 0; InputMountPoint->UniqueIdLength = 0; InputMountPoint->DeviceNameOffset = 0; InputMountPoint->DeviceNameLength = 0;
//
// Fill device name.
//
WCHAR wszBuffer[SYMBOLIC_LINK_LENGTH/2+1]; LPWSTR pwszBuffer;
pwszBuffer = (LPWSTR)((PCHAR)InputMountPoint + InputMountPoint->SymbolicLinkNameOffset); pwszDriveLetter[0] = towupper(pwszDriveLetter[0]); ft.hr = StringCchPrintf(wszBuffer, SYMBOLIC_LINK_LENGTH/2+1, L"\\DosDevices\\%c:", pwszDriveLetter[0] ); if (ft.HrFailed()) { ft.Trace(VSSDBG_VSSADMIN, L"StringCchPrintf failed %#x", ft.hr); goto _bailout; } memcpy(pwszBuffer, wszBuffer, SYMBOLIC_LINK_LENGTH);
//
// Allocate space for output
//
OutputMountPoints = (MOUNTMGR_MOUNT_POINTS *) new WCHAR[4096]; if ( OutputMountPoints==NULL ) { ft.hr = E_OUTOFMEMORY; goto _bailout; }
//
// Open mount manager
//
hMountMgr = CreateFile( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hMountMgr==INVALID_HANDLE_VALUE ) { dwRet = GetLastError(); ft.hr = HRESULT_FROM_WIN32(dwRet); ft.Trace(VSSDBG_VSSADMIN, L"DeleteDriveLetterFromDB CreateFile failed %#x", dwRet); goto _bailout; }
//
// Issue IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY.
//
bRet = DeviceIoControl( hMountMgr, IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY, InputMountPoint, ulInputSize, OutputMountPoints, 4096 * sizeof(WCHAR), &dwBytesReturned, NULL );
dwRet = GetLastError(); // Save error code.
CloseHandle(hMountMgr); hMountMgr = NULL;
if ( bRet==FALSE ) { ft.hr = HRESULT_FROM_WIN32(dwRet); ft.Trace(VSSDBG_VSSADMIN, L"DeleteDriveLetterFromDB DeviceIoControl failed %#x", dwRet); goto _bailout; }
delete [] InputMountPoint; delete [] OutputMountPoints; return S_OK;
_bailout:
delete [] InputMountPoint; delete [] OutputMountPoints; return ft.hr; }
DWORD LockVolume( IN HANDLE hVolume ) { DWORD dwBytes = 0; BOOL fRet = FALSE; int nCount = 0; while ( fRet==FALSE ) { fRet = DeviceIoControl( hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwBytes, NULL ); if (fRet == FALSE) { DWORD dwRet = GetLastError();
if (dwRet != ERROR_ACCESS_DENIED || nCount>=60) { return dwRet; }
nCount++; Sleep( 500 ); // Wait for half second up to 60 times (30s).
} }
return ERROR_SUCCESS; }
// Returns TRUE if the drive letter is available
BOOL IsDriveLetterAvailable ( IN WCHAR* pwszDriveLetter ) { int iLen = 0; BOOL fFound = FALSE; DWORD cchBufLen = 0; CVssAutoPWSZ awszDriveStrings; CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"IsDriveLetterAvailable");
_ASSERTE(pwszDriveLetter != NULL); // How much space needed for drive strings?
cchBufLen = GetLogicalDriveStrings(0, NULL); if (cchBufLen == 0) { ft.hr = HRESULT_FROM_WIN32(GetLastError()); ft.Trace(VSSDBG_VSSADMIN, L"GetLogicalDriveStrings failed %#x", GetLastError()); } else { // Allocate space for the drive strings
awszDriveStrings.Allocate(cchBufLen);
// Get the drive strings
if (GetLogicalDriveStrings(cchBufLen, awszDriveStrings) == 0) { ft.hr = HRESULT_FROM_WIN32(GetLastError()); ft.Trace(VSSDBG_VSSADMIN, L"GetLogicalDriveStrings failed %#x", GetLastError()); } else { WCHAR* pwcTempDriveString = awszDriveStrings; WCHAR wcDriveLetter = towupper(pwszDriveLetter[0]);
// Look for the drive letter in the list of system drive letters
while (!fFound) { iLen = lstrlen(pwcTempDriveString); if (iLen == 0) break;
pwcTempDriveString[0] = towupper(pwcTempDriveString[0]);
if (pwcTempDriveString[0] == wcDriveLetter) { fFound = TRUE; break; } pwcTempDriveString = &pwcTempDriveString [iLen + 1]; } } }
return !fFound; }
BOOL IsDriveLetterSticky( IN WCHAR* pwszDriveLetter ) { BOOL fFound = FALSE; WCHAR wszTempVolumeName [MAX_PATH+1]; CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"IsDriveLetterSticky"); WCHAR wszDrivePath[g_cchDriveName]; _ASSERTE(pwszDriveLetter != NULL);
wszDrivePath[0] = towupper(pwszDriveLetter[0]); wszDrivePath[1] = L':'; wszDrivePath[2] = L'\\'; wszDrivePath[3] = L'\0'; if (GetVolumeNameForVolumeMountPoint( wszDrivePath, wszTempVolumeName, MAX_PATH)) { WCHAR wszCurrentDrivePath[g_cchDriveName]; if (GetVolumeDrive(wszTempVolumeName, g_cchDriveName, wszCurrentDrivePath)) { wszCurrentDrivePath[0] = towupper(wszCurrentDrivePath[0]); if (wszDrivePath[0] == wszCurrentDrivePath[0]) fFound = TRUE; } } return fFound; }
BOOL IsBootDrive( IN WCHAR* pwszDriveLetter ) { WCHAR wszSystemDirectory[MAX_PATH+1]; CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"IsBootDrive");
_ASSERTE(pwszDriveLetter != NULL);
WCHAR wcDrive = towupper(pwszDriveLetter[0]); if (!GetSystemDirectory(wszSystemDirectory, MAX_PATH+1)) { DWORD dwErr = GetLastError(); ft.hr = HRESULT_FROM_WIN32(dwErr); ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"GetSystemDirectory failed %#x", dwErr); } wszSystemDirectory[0] = towupper(wszSystemDirectory[0]); if (wcDrive == wszSystemDirectory[0]) return TRUE; return FALSE; }
BOOL DeleteNetworkShare( IN WCHAR* pwszDriveRoot ) { NET_API_STATUS status; WCHAR wszShareName[3];
wszShareName[0] = pwszDriveRoot[0]; wszShareName[1] = L'$'; wszShareName[2] = L'\0'; status = NetShareDel(NULL, wszShareName, 0); if ( status!=NERR_Success ) return FALSE; else return TRUE; }
|