"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/drive.c" between
rufus-3.12.tar.gz and rufus-3.13.tar.gz

About: Rufus is a utility that helps format and create bootable USB flash drives, such as USB keys/pendrives, memory sticks, etc (for Linux and Windows).

drive.c  (rufus-3.12):drive.c  (rufus-3.13)
skipping to change at line 76 skipping to change at line 76
#endif #endif
PF_TYPE_DECL(NTAPI, NTSTATUS, NtQueryVolumeInformationFile, (HANDLE, PIO_STATUS_ BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS)); PF_TYPE_DECL(NTAPI, NTSTATUS, NtQueryVolumeInformationFile, (HANDLE, PIO_STATUS_ BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS));
/* /*
* Globals * Globals
*/ */
RUFUS_DRIVE_INFO SelectedDrive; RUFUS_DRIVE_INFO SelectedDrive;
extern BOOL installed_uefi_ntfs, write_as_esp; extern BOOL installed_uefi_ntfs, write_as_esp;
extern int nWindowsVersion, nWindowsBuildNumber; extern int nWindowsVersion, nWindowsBuildNumber;
uint64_t partition_offset[3]; uint64_t partition_offset[PI_MAX];
uint64_t persistence_size = 0; uint64_t persistence_size = 0;
/* /*
* The following methods get or set the AutoMount setting (which is different fr om AutoRun) * The following methods get or set the AutoMount setting (which is different fr om AutoRun)
* Rufus needs AutoMount to be set as the format process may fail for fixed driv es otherwise. * Rufus needs AutoMount to be set as the format process may fail for fixed driv es otherwise.
* See https://github.com/pbatard/rufus/issues/386. * See https://github.com/pbatard/rufus/issues/386.
* *
* Reverse engineering diskpart and mountvol indicates that the former uses the IVdsService * Reverse engineering diskpart and mountvol indicates that the former uses the IVdsService
* ClearFlags()/SetFlags() to set VDS_SVF_AUTO_MOUNT_OFF whereas mountvol on use s * ClearFlags()/SetFlags() to set VDS_SVF_AUTO_MOUNT_OFF whereas mountvol on use s
* IOCTL_MOUNTMGR_SET_AUTO_MOUNT on "\\\\.\\MountPointManager". * IOCTL_MOUNTMGR_SET_AUTO_MOUNT on "\\\\.\\MountPointManager".
* As the latter is MUCH simpler this is what we'll use too * As the latter is MUCH simpler this is what we'll use too
*/ */
BOOL SetAutoMount(BOOL enable) BOOL SetAutoMount(BOOL enable)
{ {
HANDLE hMountMgr; HANDLE hMountMgr;
DWORD size; DWORD size;
BOOL ret = FALSE; BOOL ret = FALSE;
hMountMgr = CreateFileA(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WR hMountMgr = CreateFileA(MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_READ|FILE
ITE, _SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRI if (hMountMgr == INVALID_HANDLE_VALUE)
BUTE_NORMAL, NULL);
if (hMountMgr == NULL)
return FALSE; return FALSE;
ret = DeviceIoControl(hMountMgr, IOCTL_MOUNTMGR_SET_AUTO_MOUNT, &enable, sizeof(enable), NULL, 0, &size, NULL); ret = DeviceIoControl(hMountMgr, IOCTL_MOUNTMGR_SET_AUTO_MOUNT, &enable, sizeof(enable), NULL, 0, &size, NULL);
CloseHandle(hMountMgr); CloseHandle(hMountMgr);
return ret; return ret;
} }
BOOL GetAutoMount(BOOL* enabled) BOOL GetAutoMount(BOOL* enabled)
{ {
HANDLE hMountMgr; HANDLE hMountMgr;
DWORD size; DWORD size;
BOOL ret = FALSE; BOOL ret = FALSE;
if (enabled == NULL) if (enabled == NULL)
return FALSE; return FALSE;
hMountMgr = CreateFileA(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WR hMountMgr = CreateFileA(MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_READ|FILE
ITE, _SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRI if (hMountMgr == INVALID_HANDLE_VALUE)
BUTE_NORMAL, NULL);
if (hMountMgr == NULL)
return FALSE; return FALSE;
ret = DeviceIoControl(hMountMgr, IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT, NULL, 0 , enabled, sizeof(*enabled), &size, NULL); ret = DeviceIoControl(hMountMgr, IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT, NULL, 0 , enabled, sizeof(*enabled), &size, NULL);
CloseHandle(hMountMgr); CloseHandle(hMountMgr);
return ret; return ret;
} }
/* /*
* Working with drive indexes quite risky (left unchecked,inadvertently passing 0 as * Working with drive indexes quite risky (left unchecked,inadvertently passing 0 as
* index would return a handle to C:, which we might then proceed to unknowingly * index would return a handle to C:, which we might then proceed to unknowingly
* clear the MBR of!), so we mitigate the risk by forcing our indexes to belong to * clear the MBR of!), so we mitigate the risk by forcing our indexes to belong to
skipping to change at line 169 skipping to change at line 167
// We keep FILE_SHARE_READ though, as this shouldn't hurt us any, and is // We keep FILE_SHARE_READ though, as this shouldn't hurt us any, and is
// required for enumeration. // required for enumeration.
hDrive = CreateFileA(Path, GENERIC_READ|(bWriteAccess?GENERIC_WRI TE:0), hDrive = CreateFileA(Path, GENERIC_READ|(bWriteAccess?GENERIC_WRI TE:0),
FILE_SHARE_READ|(bWriteShare?FILE_SHARE_WRITE:0), FILE_SHARE_READ|(bWriteShare?FILE_SHARE_WRITE:0),
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDrive != INVALID_HANDLE_VALUE) if (hDrive != INVALID_HANDLE_VALUE)
break; break;
if ((GetLastError() != ERROR_SHARING_VIOLATION) && (GetLastError( ) != ERROR_ACCESS_DENIED)) if ((GetLastError() != ERROR_SHARING_VIOLATION) && (GetLastError( ) != ERROR_ACCESS_DENIED))
break; break;
if (i == 0) { if (i == 0) {
uprintf("Waiting for access on %s [%s]...", Path, DevPath uprintf("Notice: Volume Device Path is %s", DevPath);
); uprintf("Waiting for access on %s...", Path);
} else if (!bWriteShare && (i > DRIVE_ACCESS_RETRIES/3)) { } else if (!bWriteShare && (i > DRIVE_ACCESS_RETRIES/3)) {
// If we can't seem to get a hold of the drive for some t ime, try to enable FILE_SHARE_WRITE... // If we can't seem to get a hold of the drive for some t ime, try to enable FILE_SHARE_WRITE...
uprintf("Warning: Could not obtain exclusive rights. Retr ying with write sharing enabled..."); uprintf("Warning: Could not obtain exclusive rights. Retr ying with write sharing enabled...");
bWriteShare = TRUE; bWriteShare = TRUE;
// Try to report the process that is locking the drive // Try to report the process that is locking the drive
// We also use bit 6 as a flag to indicate that SearchPro cess was called. // We also use bit 6 as a flag to indicate that SearchPro cess was called.
access_mask = SearchProcess(DevPath, SEARCH_PROCESS_TIMEO UT, TRUE, TRUE, FALSE) | 0x40; access_mask = SearchProcess(DevPath, SEARCH_PROCESS_TIMEO UT, TRUE, TRUE, FALSE) | 0x40;
} }
Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES); Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES);
} }
skipping to change at line 441 skipping to change at line 440
for (i = 0; (i < MAX_PARTITIONS) && (PartitionOffset != SelectedDrive.Par titionOffset[i]); i++); for (i = 0; (i < MAX_PARTITIONS) && (PartitionOffset != SelectedDrive.Par titionOffset[i]); i++);
if (i >= MAX_PARTITIONS) if (i >= MAX_PARTITIONS)
goto out; goto out;
static_sprintf(volume_name, "\\\\.\\PhysicalDrive%lu %I64u %I64u", DriveI ndex, static_sprintf(volume_name, "\\\\.\\PhysicalDrive%lu %I64u %I64u", DriveI ndex,
SelectedDrive.PartitionOffset[i], SelectedDrive.PartitionSize[i]) ; SelectedDrive.PartitionOffset[i], SelectedDrive.PartitionSize[i]) ;
ret = safe_strdup(volume_name); ret = safe_strdup(volume_name);
out: out:
return ret; return ret;
} }
static const char* VdsErrorString(HRESULT hr) {
SetLastError(hr);
return WindowsErrorString();
}
/* /*
* Call on VDS to refresh the drive layout * Call on VDS to refresh the drive layout
*/ */
BOOL RefreshLayout(DWORD DriveIndex) BOOL RefreshLayout(DWORD DriveIndex)
{ {
BOOL r = FALSE; HRESULT hr = S_FALSE;
HRESULT hr;
wchar_t wPhysicalName[24]; wchar_t wPhysicalName[24];
IVdsServiceLoader *pLoader; IVdsServiceLoader* pLoader = NULL;
IVdsService *pService; IVdsService* pService = NULL;
IEnumVdsObject *pEnum; IEnumVdsObject *pEnum;
CheckDriveIndex(DriveIndex); CheckDriveIndex(DriveIndex);
wnsprintf(wPhysicalName, ARRAYSIZE(wPhysicalName), L"\\\\?\\PhysicalDrive %lu", DriveIndex); wnsprintf(wPhysicalName, ARRAYSIZE(wPhysicalName), L"\\\\?\\PhysicalDrive %lu", DriveIndex);
// Initialize COM // Initialize COM
IGNORE_RETVAL(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); IGNORE_RETVAL(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
IGNORE_RETVAL(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVE L_CONNECT, IGNORE_RETVAL(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVE L_CONNECT,
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL)); RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL));
// Create a VDS Loader Instance // Create a VDS Loader Instance
hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCT X_REMOTE_SERVER, hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCT X_REMOTE_SERVER,
&IID_IVdsServiceLoader, (void **)&pLoader); &IID_IVdsServiceLoader, (void **)&pLoader);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); uprintf("Could not create VDS Loader Instance: %s", VdsErrorStrin
uprintf("Could not create VDS Loader Instance: %s", WindowsErrorS g(hr));
tring());
goto out; goto out;
} }
// Load the VDS Service // Load the VDS Service
hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService); hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService);
IVdsServiceLoader_Release(pLoader);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); uprintf("Could not load VDS Service: %s", VdsErrorString(hr));
uprintf("Could not load VDS Service: %s", WindowsErrorString());
goto out; goto out;
} }
// Wait for the Service to become ready if needed // Wait for the Service to become ready if needed
hr = IVdsService_WaitForServiceReady(pService); hr = IVdsService_WaitForServiceReady(pService);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); uprintf("VDS Service is not ready: %s", VdsErrorString(hr));
uprintf("VDS Service is not ready: %s", WindowsErrorString());
goto out; goto out;
} }
// Query the VDS Service Providers // Query the VDS Service Providers
hr = IVdsService_QueryProviders(pService, VDS_QUERY_SOFTWARE_PROVIDERS, & pEnum); hr = IVdsService_QueryProviders(pService, VDS_QUERY_SOFTWARE_PROVIDERS, & pEnum);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); uprintf("Could not query VDS Service Providers: %s", VdsErrorStri
uprintf("Could not query VDS Service Providers: %s", WindowsError ng(hr));
String());
goto out; goto out;
} }
// Remove mountpoints // Remove mountpoints
hr = IVdsService_CleanupObsoleteMountPoints(pService); hr = IVdsService_CleanupObsoleteMountPoints(pService);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); uprintf("Could not clean up VDS mountpoints: %s", VdsErrorString(
uprintf("Could not clean up VDS mountpoints: %s", WindowsErrorStr hr));
ing());
goto out; goto out;
} }
// Invoke layout refresh // Invoke layout refresh
hr = IVdsService_Refresh(pService); hr = IVdsService_Refresh(pService);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); uprintf("Could not refresh VDS layout: %s", VdsErrorString(hr));
uprintf("Could not refresh VDS layout: %s", WindowsErrorString())
;
goto out; goto out;
} }
// Force re-enum // Force re-enum
hr = IVdsService_Reenumerate(pService); hr = IVdsService_Reenumerate(pService);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); uprintf("Could not refresh VDS layout: %s", VdsErrorString(hr));
uprintf("Could not refresh VDS layout: %s", WindowsErrorString())
;
goto out; goto out;
} }
r = TRUE;
out: out:
return r; if (pService != NULL)
IVdsService_Release(pService);
if (pLoader != NULL)
IVdsServiceLoader_Release(pLoader);
VDS_SET_ERROR(hr);
return (hr == S_OK);
} }
/* /*
* Delete all the partitions from a disk, using VDS * Generic call to instantiate a VDS Disk Interface. Mostly copied from:
* Mostly copied from https://social.msdn.microsoft.com/Forums/vstudio/en-US/b90 * https://social.msdn.microsoft.com/Forums/vstudio/en-US/b90482ae-4e44-4b08-873
482ae-4e44-4b08-8731-81915030b32a/createpartition-using-vds-interface-throw-erro 1-81915030b32a/createpartition-using-vds-interface-throw-error-enointerface-dcom
r-enointerface-dcom?forum=vcgeneral ?forum=vcgeneral
* See also: https://docs.microsoft.com/en-us/windows/win32/vds/working-with-enu
meration-objects
*/ */
BOOL DeletePartitions(DWORD DriveIndex) static BOOL GetVdsDiskInterface(DWORD DriveIndex, const IID* InterfaceIID, void* * pInterfaceInstance, BOOL bSilent)
{ {
BOOL r = FALSE, bNeverFound = TRUE; HRESULT hr = S_FALSE;
HRESULT hr;
ULONG ulFetched; ULONG ulFetched;
wchar_t wPhysicalName[24]; wchar_t wPhysicalName[24];
IVdsServiceLoader *pLoader; IVdsServiceLoader* pLoader;
IVdsService *pService; IVdsService* pService;
IEnumVdsObject *pEnum; IEnumVdsObject* pEnum;
IUnknown *pUnk; IUnknown* pUnk;
*pInterfaceInstance = NULL;
CheckDriveIndex(DriveIndex); CheckDriveIndex(DriveIndex);
wnsprintf(wPhysicalName, ARRAYSIZE(wPhysicalName), L"\\\\?\\PhysicalDrive %lu", DriveIndex); wnsprintf(wPhysicalName, ARRAYSIZE(wPhysicalName), L"\\\\?\\PhysicalDrive %lu", DriveIndex);
// Initialize COM // Initialize COM
IGNORE_RETVAL(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); IGNORE_RETVAL(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
IGNORE_RETVAL(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVE L_CONNECT, IGNORE_RETVAL(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVE L_CONNECT,
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL)); RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL));
// Create a VDS Loader Instance // Create a VDS Loader Instance
hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCT X_REMOTE_SERVER, hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCT X_REMOTE_SERVER,
&IID_IVdsServiceLoader, (void **)&pLoader); &IID_IVdsServiceLoader, (void**)&pLoader);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("Could not create VDS Loader Instance: %s", VdsErrorStri
uprintf("Could not create VDS Loader Instance: %s", WindowsErrorS ng(hr));
tring());
goto out; goto out;
} }
// Load the VDS Service // Load the VDS Service
hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService); hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService);
IVdsServiceLoader_Release(pLoader); IVdsServiceLoader_Release(pLoader);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("Could not load VDS Service: %s", VdsErrorString(hr));
uprintf("Could not load VDS Service: %s", WindowsErrorString());
goto out; goto out;
} }
// Wait for the Service to become ready if needed // Wait for the Service to become ready if needed
hr = IVdsService_WaitForServiceReady(pService); hr = IVdsService_WaitForServiceReady(pService);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("VDS Service is not ready: %s", VdsErrorString(hr));
uprintf("VDS Service is not ready: %s", WindowsErrorString());
goto out; goto out;
} }
// Query the VDS Service Providers // Query the VDS Service Providers
hr = IVdsService_QueryProviders(pService, VDS_QUERY_SOFTWARE_PROVIDERS, & pEnum); hr = IVdsService_QueryProviders(pService, VDS_QUERY_SOFTWARE_PROVIDERS, & pEnum);
IVdsService_Release(pService);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("Could not query VDS Service Providers: %s", VdsErrorStr
uprintf("Could not query VDS Service Providers: %s", WindowsError ing(hr));
String());
goto out; goto out;
} }
while (IEnumVdsObject_Next(pEnum, 1, &pUnk, &ulFetched) == S_OK) { while (IEnumVdsObject_Next(pEnum, 1, &pUnk, &ulFetched) == S_OK) {
IVdsProvider *pProvider; IVdsProvider* pProvider;
IVdsSwProvider *pSwProvider; IVdsSwProvider* pSwProvider;
IEnumVdsObject *pEnumPack; IEnumVdsObject* pEnumPack;
IUnknown *pPackUnk; IUnknown* pPackUnk;
// Get VDS Provider // Get VDS Provider
hr = IUnknown_QueryInterface(pUnk, &IID_IVdsProvider, (void **)&p Provider); hr = IUnknown_QueryInterface(pUnk, &IID_IVdsProvider, (void**)&pP rovider);
IUnknown_Release(pUnk); IUnknown_Release(pUnk);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("Could not get VDS Provider: %s", VdsErrorString
uprintf("Could not get VDS Provider: %s", WindowsErrorStr (hr));
ing()); break;
goto out;
} }
// Get VDS Software Provider // Get VDS Software Provider
hr = IVdsSwProvider_QueryInterface(pProvider, &IID_IVdsSwProvider , (void **)&pSwProvider); hr = IVdsSwProvider_QueryInterface(pProvider, &IID_IVdsSwProvider , (void**)&pSwProvider);
IVdsProvider_Release(pProvider); IVdsProvider_Release(pProvider);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("Could not get VDS Software Provider: %s", VdsEr
uprintf("Could not get VDS Software Provider: %s", Window rorString(hr));
sErrorString()); break;
goto out;
} }
// Get VDS Software Provider Packs // Get VDS Software Provider Packs
hr = IVdsSwProvider_QueryPacks(pSwProvider, &pEnumPack); hr = IVdsSwProvider_QueryPacks(pSwProvider, &pEnumPack);
IVdsSwProvider_Release(pSwProvider); IVdsSwProvider_Release(pSwProvider);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("Could not get VDS Software Provider Packs: %s",
uprintf("Could not get VDS Software Provider Packs: %s", VdsErrorString(hr));
WindowsErrorString()); break;
goto out;
} }
// Enumerate Provider Packs // Enumerate Provider Packs
while (IEnumVdsObject_Next(pEnumPack, 1, &pPackUnk, &ulFetched) = = S_OK) { while (IEnumVdsObject_Next(pEnumPack, 1, &pPackUnk, &ulFetched) = = S_OK) {
IVdsPack *pPack; IVdsPack* pPack;
IEnumVdsObject *pEnumDisk; IEnumVdsObject* pEnumDisk;
IUnknown *pDiskUnk; IUnknown* pDiskUnk;
hr = IUnknown_QueryInterface(pPackUnk, &IID_IVdsPack, (vo id **)&pPack); hr = IUnknown_QueryInterface(pPackUnk, &IID_IVdsPack, (vo id**)&pPack);
IUnknown_Release(pPackUnk); IUnknown_Release(pPackUnk);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("Could not query VDS Software Provider P
uprintf("Could not query VDS Software Provider Pa ack: %s", VdsErrorString(hr));
ck: %s", WindowsErrorString()); break;
goto out;
} }
// Use the pack interface to access the disks // Use the pack interface to access the disks
hr = IVdsPack_QueryDisks(pPack, &pEnumDisk); hr = IVdsPack_QueryDisks(pPack, &pEnumDisk);
IVdsPack_Release(pPack);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("Could not query VDS disks: %s", VdsErro
uprintf("Could not query VDS disks: %s", WindowsE rString(hr));
rrorString()); break;
goto out;
} }
// List disks // List disks
while (IEnumVdsObject_Next(pEnumDisk, 1, &pDiskUnk, &ulFe tched) == S_OK) { while (IEnumVdsObject_Next(pEnumDisk, 1, &pDiskUnk, &ulFe tched) == S_OK) {
VDS_DISK_PROP diskprop; VDS_DISK_PROP prop;
VDS_PARTITION_PROP* prop_array; IVdsDisk* pDisk;
LONG i, prop_array_size;
IVdsDisk *pDisk;
IVdsAdvancedDisk *pAdvancedDisk;
// Get the disk interface. // Get the disk interface.
hr = IUnknown_QueryInterface(pDiskUnk, &IID_IVdsD hr = IUnknown_QueryInterface(pDiskUnk, &IID_IVdsD
isk, (void **)&pDisk); isk, (void**)&pDisk);
IUnknown_Release(pDiskUnk);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("Could not query VDS Disk Interf
uprintf("Could not query VDS Disk Interfa ace: %s", VdsErrorString(hr));
ce: %s", WindowsErrorString()); break;
goto out;
} }
// Get the disk properties // Get the disk properties
hr = IVdsDisk_GetProperties(pDisk, &diskprop); hr = IVdsDisk_GetProperties(pDisk, &prop);
if (hr != S_OK) { if ((hr != S_OK) && (hr != VDS_S_PROPERTIES_INCOM
VDS_SET_ERROR(hr); PLETE)) {
uprintf("Could not query VDS Disk Propert IVdsDisk_Release(pDisk);
ies: %s", WindowsErrorString()); suprintf("Could not query VDS Disk Proper
goto out; ties: %s", VdsErrorString(hr));
break;
} }
// Isolate the disk we want // Check if we are on the target disk
if (_wcsicmp(wPhysicalName, diskprop.pwszName) != hr = (HRESULT)_wcsicmp(wPhysicalName, prop.pwszNa
0) { me);
IVdsDisk_Release(pDisk); CoTaskMemFree(prop.pwszName);
if (hr != S_OK) {
hr = S_OK;
continue; continue;
} }
bNeverFound = FALSE;
// Instantiate the AdvanceDisk interface for our // Instantiate the requested VDS disk interface
disk. hr = IVdsDisk_QueryInterface(pDisk, InterfaceIID,
hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsAdva pInterfaceInstance);
ncedDisk, (void **)&pAdvancedDisk);
IVdsDisk_Release(pDisk); IVdsDisk_Release(pDisk);
if (hr != S_OK)
suprintf("Could not access the requested
Disk interface: %s", VdsErrorString(hr));
// With the interface found, we should be able to
return
break;
}
IEnumVdsObject_Release(pEnumDisk);
}
IEnumVdsObject_Release(pEnumPack);
}
IEnumVdsObject_Release(pEnum);
out:
VDS_SET_ERROR(hr);
return (hr == S_OK);
}
/*
* Delete one partition at offset PartitionOffset, or all partitions if the offs
et is 0.
*/
BOOL DeletePartition(DWORD DriveIndex, ULONGLONG PartitionOffset, BOOL bSilent)
{
HRESULT hr = S_FALSE;
VDS_PARTITION_PROP* prop_array;
LONG i, prop_array_size;
IVdsAdvancedDisk *pAdvancedDisk;
if (!GetVdsDiskInterface(DriveIndex, &IID_IVdsAdvancedDisk, (void**)&pAdv
ancedDisk, bSilent))
return FALSE;
if (pAdvancedDisk == NULL) {
suprintf("No partition to delete on disk");
return TRUE;
}
// Query the partition data, so we can get the start offset, which we nee
d for deletion
hr = IVdsAdvancedDisk_QueryPartitions(pAdvancedDisk, &prop_array, &prop_a
rray_size);
if (hr == S_OK) {
suprintf("Deleting partition%s:", (PartitionOffset == 0) ? "s" :
"");
// Now go through each partition
for (i = 0; i < prop_array_size; i++) {
if ((PartitionOffset != 0) && (prop_array[i].ullOffset !=
PartitionOffset))
continue;
suprintf("● Partition %d (offset: %lld, size: %s)", prop_
array[i].ulPartitionNumber,
prop_array[i].ullOffset, SizeToHumanReadable(prop
_array[i].ullSize, FALSE, FALSE));
hr = IVdsAdvancedDisk_DeletePartition(pAdvancedDisk, prop
_array[i].ullOffset, TRUE, TRUE);
if (hr != S_OK)
suprintf("Could not delete partition: %s", VdsErr
orString(hr));
}
} else {
suprintf("No partition to delete on disk");
hr = S_OK;
}
CoTaskMemFree(prop_array);
IVdsAdvancedDisk_Release(pAdvancedDisk);
VDS_SET_ERROR(hr);
return (hr == S_OK);
}
/*
* Count on Microsoft for *COMPLETELY CRIPPLING* an API when alledgedly upgradin
g it...
* As illustrated when you do so with diskpart (which uses VDS behind the scenes
), VDS
* simply *DOES NOT* list all the volumes that the system can see, especially co
mpared
* to what mountvol (which uses FindFirstVolume()/FindNextVolume()) and other AP
Is do.
* Also for reference, if you want to list volumes through WMI in PowerShell:
* Get-WmiObject win32_volume | Format-Table -Property DeviceID,Name,Label,Capac
ity
*/
BOOL ListVdsVolumes(BOOL bSilent)
{
HRESULT hr = S_FALSE;
ULONG ulFetched;
IVdsServiceLoader* pLoader;
IVdsService* pService;
IEnumVdsObject* pEnum;
IUnknown* pUnk;
// Initialize COM
IGNORE_RETVAL(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
IGNORE_RETVAL(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVE
L_CONNECT,
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL));
// Create a VDS Loader Instance
hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCT
X_REMOTE_SERVER,
&IID_IVdsServiceLoader, (void**)&pLoader);
if (hr != S_OK) {
suprintf("Could not create VDS Loader Instance: %s", VdsErrorStri
ng(hr));
goto out;
}
// Load the VDS Service
hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService);
IVdsServiceLoader_Release(pLoader);
if (hr != S_OK) {
suprintf("Could not load VDS Service: %s", VdsErrorString(hr));
goto out;
}
// Wait for the Service to become ready if needed
hr = IVdsService_WaitForServiceReady(pService);
if (hr != S_OK) {
suprintf("VDS Service is not ready: %s", VdsErrorString(hr));
goto out;
}
// Query the VDS Service Providers
hr = IVdsService_QueryProviders(pService, VDS_QUERY_SOFTWARE_PROVIDERS, &
pEnum);
IVdsService_Release(pService);
if (hr != S_OK) {
suprintf("Could not query VDS Service Providers: %s", VdsErrorStr
ing(hr));
goto out;
}
while (IEnumVdsObject_Next(pEnum, 1, &pUnk, &ulFetched) == S_OK) {
IVdsProvider* pProvider;
IVdsSwProvider* pSwProvider;
IEnumVdsObject* pEnumPack;
IUnknown* pPackUnk;
// Get VDS Provider
hr = IUnknown_QueryInterface(pUnk, &IID_IVdsProvider, (void**)&pP
rovider);
IUnknown_Release(pUnk);
if (hr != S_OK) {
suprintf("Could not get VDS Provider: %s", VdsErrorString
(hr));
break;
}
// Get VDS Software Provider
hr = IVdsSwProvider_QueryInterface(pProvider, &IID_IVdsSwProvider
, (void**)&pSwProvider);
IVdsProvider_Release(pProvider);
if (hr != S_OK) {
suprintf("Could not get VDS Software Provider: %s", VdsEr
rorString(hr));
break;
}
// Get VDS Software Provider Packs
hr = IVdsSwProvider_QueryPacks(pSwProvider, &pEnumPack);
IVdsSwProvider_Release(pSwProvider);
if (hr != S_OK) {
suprintf("Could not get VDS Software Provider Packs: %s",
VdsErrorString(hr));
break;
}
// Enumerate Provider Packs
while (IEnumVdsObject_Next(pEnumPack, 1, &pPackUnk, &ulFetched) =
= S_OK) {
IVdsPack* pPack;
IEnumVdsObject* pEnumVolume;
IUnknown* pVolumeUnk;
hr = IUnknown_QueryInterface(pPackUnk, &IID_IVdsPack, (vo
id**)&pPack);
IUnknown_Release(pPackUnk);
if (hr != S_OK) {
suprintf("Could not query VDS Software Provider P
ack: %s", VdsErrorString(hr));
break;
}
// Use the pack interface to access the disks
hr = IVdsPack_QueryVolumes(pPack, &pEnumVolume);
if (hr != S_OK) {
suprintf("Could not query VDS volumes: %s", VdsEr
rorString(hr));
break;
}
// List volumes
while (IEnumVdsObject_Next(pEnumVolume, 1, &pVolumeUnk, &
ulFetched) == S_OK) {
IVdsVolume* pVolume;
IVdsVolumeMF3* pVolumeMF3;
VDS_VOLUME_PROP prop;
LPWSTR* wszPathArray;
ULONG i, ulNumberOfPaths;
// Get the volume interface.
hr = IUnknown_QueryInterface(pVolumeUnk, &IID_IVd
sVolume, (void**)&pVolume);
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("Could not query VDS Volume Inte
uprintf("Could not access VDS Advanced Di rface: %s", VdsErrorString(hr));
sk interface: %s", WindowsErrorString()); break;
goto out;
} }
// Query the partition data, so we can get the st // Get the volume properties
art offset, which we need for deletion hr = IVdsVolume_GetProperties(pVolume, &prop);
hr = IVdsAdvancedDisk_QueryPartitions(pAdvancedDi if ((hr != S_OK) && (hr != VDS_S_PROPERTIES_INCOM
sk, &prop_array, &prop_array_size); PLETE)) {
if (hr == S_OK) { suprintf("Could not query VDS Volume Prop
uprintf("Deleting ALL partition(s) from d erties: %s", VdsErrorString(hr));
isk '%S':", diskprop.pwszName); break;
// Now go through each partition
for (i = 0; i < prop_array_size; i++) {
uprintf("● Partition %d (offset:
%lld, size: %s)", prop_array[i].ulPartitionNumber,
prop_array[i].ullOffset,
SizeToHumanReadable(prop_array[i].ullSize, FALSE, FALSE));
hr = IVdsAdvancedDisk_DeleteParti
tion(pAdvancedDisk, prop_array[i].ullOffset, TRUE, TRUE);
if (hr != S_OK) {
r = FALSE;
VDS_SET_ERROR(hr);
uprintf("Could not delete
partitions: %s", WindowsErrorString());
}
}
r = TRUE;
} else {
uprintf("No partition to delete on disk '
%S'", diskprop.pwszName);
r = TRUE;
} }
CoTaskMemFree(prop_array);
#if 0 uprintf("FOUND VOLUME: '%S'", prop.pwszName);
// Issue a Clean while we're at it CoTaskMemFree(prop.pwszName);
HRESULT hr2 = E_FAIL; IVdsVolume_Release(pVolume);
ULONG completed;
IVdsAsync* pAsync; // Get the volume MF3 interface.
hr = IVdsAdvancedDisk_Clean(pAdvancedDisk, TRUE, hr = IUnknown_QueryInterface(pVolumeUnk, &IID_IVd
FALSE, FALSE, &pAsync); sVolumeMF3, (void**)&pVolumeMF3);
while (SUCCEEDED(hr)) {
if (IS_ERROR(FormatStatus)) {
IVdsAsync_Cancel(pAsync);
break;
}
hr = IVdsAsync_QueryStatus(pAsync, &hr2,
&completed);
if (SUCCEEDED(hr)) {
hr = hr2;
if (hr == S_OK)
break;
if (hr == VDS_E_OPERATION_PENDING
)
hr = S_OK;
}
Sleep(500);
}
if (hr != S_OK) { if (hr != S_OK) {
VDS_SET_ERROR(hr); suprintf("Could not query VDS VolumeMF3 I
uprintf("Could not clean disk: %s", Windo nterface: %s", VdsErrorString(hr));
wsErrorString()); break;
} }
#endif
IVdsAdvancedDisk_Release(pAdvancedDisk); // Get the volume properties
goto out; hr = IVdsVolumeMF3_QueryVolumeGuidPathnames(pVolu
meMF3, &wszPathArray, &ulNumberOfPaths);
if ((hr != S_OK) && (hr != VDS_S_PROPERTIES_INCOM
PLETE)) {
suprintf("Could not query VDS VolumeMF3 G
UID PathNames: %s", VdsErrorString(hr));
break;
}
hr = S_OK;
for (i = 0; i < ulNumberOfPaths; i++)
uprintf(" VOL GUID: '%S'", wszPathArray[
i]);
CoTaskMemFree(wszPathArray);
IVdsVolume_Release(pVolumeMF3);
IUnknown_Release(pVolumeUnk);
} }
IEnumVdsObject_Release(pEnumVolume);
} }
IEnumVdsObject_Release(pEnumPack);
} }
IEnumVdsObject_Release(pEnum);
out: out:
if (bNeverFound) VDS_SET_ERROR(hr);
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERR return (hr == S_OK);
OR_PATH_NOT_FOUND;
return r;
} }
/* Wait for a logical drive to reappear - Used when a drive has just been repart itioned */ /* Wait for a logical drive to reappear - Used when a drive has just been repart itioned */
BOOL WaitForLogical(DWORD DriveIndex, uint64_t PartitionOffset) BOOL WaitForLogical(DWORD DriveIndex, uint64_t PartitionOffset)
{ {
uint64_t EndTime; uint64_t EndTime;
char* LogicalPath = NULL; char* LogicalPath = NULL;
// GetLogicalName() calls may be slow, so use the system time to // GetLogicalName() calls may be slow, so use the system time to
// make sure we don't spend more than DRIVE_ACCESS_TIMEOUT in wait. // make sure we don't spend more than DRIVE_ACCESS_TIMEOUT in wait.
skipping to change at line 937 skipping to change at line 1081
} }
// There's already a GetDriveType in the Windows API // There's already a GetDriveType in the Windows API
UINT GetDriveTypeFromIndex(DWORD DriveIndex) UINT GetDriveTypeFromIndex(DWORD DriveIndex)
{ {
UINT drive_type; UINT drive_type;
_GetDriveLettersAndType(DriveIndex, NULL, &drive_type); _GetDriveLettersAndType(DriveIndex, NULL, &drive_type);
return drive_type; return drive_type;
} }
// Removes all drive letters associated with the specific drive, and return
// either the first or last letter that was removed, according to bReturnLast.
char RemoveDriveLetters(DWORD DriveIndex, BOOL bReturnLast, BOOL bSilent)
{
int i, len;
char drive_letters[27] = { 0 }, drive_name[4] = "#:\\";
if (!GetDriveLetters(DriveIndex, drive_letters)) {
suprintf("Failed to get a drive letter");
return 0;
}
if (drive_letters[0] == 0) {
suprintf("No drive letter was assigned...");
return GetUnusedDriveLetter();
}
len = (int)strlen(drive_letters);
if (len == 0)
return 0;
// Unmount all mounted volumes that belong to this drive
for (i = 0; i < len; i++) {
// Check that the current image isn't located on a drive we are t
rying to dismount
if ((boot_type == BT_IMAGE) && (drive_letters[i] == (PathGetDrive
NumberU(image_path) + 'A'))) {
if ((PathGetDriveNumberU(image_path) + 'A') == drive_lett
ers[i]) {
suprintf("ABORTED: Cannot use an image that is lo
cated on the target drive!");
return 0;
}
}
drive_name[0] = drive_letters[i];
// DefineDosDevice() cannot have a trailing backslash...
drive_name[2] = 0;
DefineDosDeviceA(DDD_REMOVE_DEFINITION, drive_name, NULL);
// ... but DeleteVolumeMountPoint() requires one. Go figure...
drive_name[2] = '\\';
if (!DeleteVolumeMountPointA(drive_name))
suprintf("Failed to delete mountpoint %s: %s", drive_name
, WindowsErrorString());
}
return drive_letters[bReturnLast ? (len - 1) : 0];
}
/* /*
* Return the next unused drive letter from the system or NUL on error. * Return the next unused drive letter from the system or NUL on error.
*/ */
char GetUnusedDriveLetter(void) char GetUnusedDriveLetter(void)
{ {
DWORD size; DWORD size;
char drive_letter, *drive, drives[26*4 + 1]; /* "D:\", "E:\", etc., pl us one NUL */ char drive_letter, *drive, drives[26*4 + 1]; /* "D:\", "E:\", etc., pl us one NUL */
size = GetLogicalDriveStringsA(sizeof(drives), drives); size = GetLogicalDriveStringsA(sizeof(drives), drives);
if (size == 0) { if (size == 0) {
skipping to change at line 1049 skipping to change at line 1233
*label = VolumeLabel; *label = VolumeLabel;
} else if (GetVolumeInformationU(DrivePath, VolumeLabel, ARRAYSIZE(Volume Label), } else if (GetVolumeInformationU(DrivePath, VolumeLabel, ARRAYSIZE(Volume Label),
NULL, NULL, NULL, NULL, 0) && (VolumeLabel[0] != 0)) { NULL, NULL, NULL, NULL, 0) && (VolumeLabel[0] != 0)) {
*label = VolumeLabel; *label = VolumeLabel;
} else { } else {
// Might be an extfs label // Might be an extfs label
error = GetLastError(); error = GetLastError();
*label = (char*)GetExtFsLabel(DriveIndex, 0); *label = (char*)GetExtFsLabel(DriveIndex, 0);
if (*label == NULL) { if (*label == NULL) {
SetLastError(error); SetLastError(error);
duprintf("Failed to read label: %s", WindowsErrorString() if (error != ERROR_UNRECOGNIZED_VOLUME)
); duprintf("Failed to read label: %s", WindowsError
String());
*label = STR_NO_LABEL; *label = STR_NO_LABEL;
} }
} }
return TRUE; return TRUE;
} }
/* /*
* Return the drive size * Return the drive size
*/ */
uint64_t GetDriveSize(DWORD DriveIndex) uint64_t GetDriveSize(DWORD DriveIndex)
skipping to change at line 1115 skipping to change at line 1300
{ is_reactos_mbr, "ReactOS" }, { is_reactos_mbr, "ReactOS" },
{ is_kolibrios_mbr, "KolibriOS" }, { is_kolibrios_mbr, "KolibriOS" },
{ is_grub4dos_mbr, "Grub4DOS" }, { is_grub4dos_mbr, "Grub4DOS" },
{ is_grub2_mbr, "Grub 2.0" }, { is_grub2_mbr, "Grub 2.0" },
{ is_zero_mbr_not_including_disk_signature_or_copy_protect, "Zeroed" }, { is_zero_mbr_not_including_disk_signature_or_copy_protect, "Zeroed" },
}; };
// Returns TRUE if the drive seems bootable, FALSE otherwise // Returns TRUE if the drive seems bootable, FALSE otherwise
BOOL AnalyzeMBR(HANDLE hPhysicalDrive, const char* TargetName, BOOL bSilent) BOOL AnalyzeMBR(HANDLE hPhysicalDrive, const char* TargetName, BOOL bSilent)
{ {
const char* mbr_name = "Master Boot Record";
FAKE_FD fake_fd = { 0 }; FAKE_FD fake_fd = { 0 };
FILE* fp = (FILE*)&fake_fd; FILE* fp = (FILE*)&fake_fd;
int i; int i;
fake_fd._handle = (char*)hPhysicalDrive; fake_fd._handle = (char*)hPhysicalDrive;
set_bytes_per_sector(SelectedDrive.SectorSize); set_bytes_per_sector(SelectedDrive.SectorSize);
if (!is_br(fp)) { if (!is_br(fp)) {
suprintf("%s does not have an x86 %s", TargetName, mbr_name); suprintf("%s does not have a Boot Marker", TargetName);
return FALSE; return FALSE;
} }
for (i=0; i<ARRAYSIZE(known_mbr); i++) { for (i=0; i<ARRAYSIZE(known_mbr); i++) {
if (known_mbr[i].fn(fp)) { if (known_mbr[i].fn(fp)) {
suprintf("%s has a %s %s", TargetName, known_mbr[i].str, mbr_name); suprintf("%s has a %s Master Boot Record", TargetName, kn own_mbr[i].str);
return TRUE; return TRUE;
} }
} }
suprintf("%s has an unknown %s", TargetName, mbr_name); suprintf("%s has an unknown Master Boot Record", TargetName);
return TRUE; return TRUE;
} }
const struct {int (*fn)(FILE *fp); char* str;} known_pbr[] = { const struct {int (*fn)(FILE *fp); char* str;} known_pbr[] = {
{ entire_fat_16_br_matches, "FAT16 DOS" }, { entire_fat_16_br_matches, "FAT16 DOS" },
{ entire_fat_16_fd_br_matches, "FAT16 FreeDOS" }, { entire_fat_16_fd_br_matches, "FAT16 FreeDOS" },
{ entire_fat_16_ros_br_matches, "FAT16 ReactOS" }, { entire_fat_16_ros_br_matches, "FAT16 ReactOS" },
{ entire_fat_32_br_matches, "FAT32 DOS" }, { entire_fat_32_br_matches, "FAT32 DOS" },
{ entire_fat_32_nt_br_matches, "FAT32 NT" }, { entire_fat_32_nt_br_matches, "FAT32 NT" },
{ entire_fat_32_fd_br_matches, "FAT32 FreeDOS" }, { entire_fat_32_fd_br_matches, "FAT32 FreeDOS" },
skipping to change at line 1293 skipping to change at line 1477
if (found) if (found)
break; break;
} }
} }
if (j > MAX_ESP_TOGGLE) if (j > MAX_ESP_TOGGLE)
goto out; goto out;
DriveLayout->PartitionEntry[i].Gpt.PartitionType = PARTIT ION_GENERIC_ESP; DriveLayout->PartitionEntry[i].Gpt.PartitionType = PARTIT ION_GENERIC_ESP;
} }
} else { } else {
for (i = 0, j = 0; i < DriveLayout->PartitionCount; i++) { for (i = 0, j = 0; i < DriveLayout->PartitionCount; i++) {
if (DriveLayout->PartitionEntry[i].StartingOffset.QuadPar t == PartitionOffset) if (DriveLayout->PartitionEntry[i].StartingOffset.QuadPar t == PartitionOffset) {
DriveLayout->PartitionEntry[i].Gpt.PartitionType = PARTITION_GENERIC_ESP; DriveLayout->PartitionEntry[i].Gpt.PartitionType = PARTITION_GENERIC_ESP;
break;
}
} }
} }
if (i >= DriveLayout->PartitionCount) { if (i >= DriveLayout->PartitionCount) {
uprintf("No partition to toggle"); uprintf("No partition to toggle");
goto out; goto out;
} }
DriveLayout->PartitionEntry[i].RewritePartition = TRUE; // Just in case DriveLayout->PartitionEntry[i].RewritePartition = TRUE; // Just in case
r = DeviceIoControl(hPhysical, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)Dri veLayout, size, NULL, 0, &size, NULL); r = DeviceIoControl(hPhysical, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)Dri veLayout, size, NULL, 0, &size, NULL);
if (!r) { if (!r) {
skipping to change at line 1555 skipping to change at line 1741
return TRUE; return TRUE;
} }
/* /*
* Mount the volume identified by drive_guid to mountpoint drive_name. * Mount the volume identified by drive_guid to mountpoint drive_name.
* If volume_name is already mounted, but with a different letter than the * If volume_name is already mounted, but with a different letter than the
* one requested then drive_name is updated to use that letter. * one requested then drive_name is updated to use that letter.
*/ */
BOOL MountVolume(char* drive_name, char *volume_name) BOOL MountVolume(char* drive_name, char *volume_name)
{ {
char mounted_guid[52]; char mounted_guid[52], dos_name[] = "?:";
#if defined(WINDOWS_IS_NOT_BUGGY) #if defined(WINDOWS_IS_NOT_BUGGY)
char mounted_letter[27] = { 0 }; char mounted_letter[27] = { 0 };
DWORD size; DWORD size;
#endif #endif
if ((drive_name == NULL) || (volume_name == NULL) || (drive_name[0] == '? if ((drive_name == NULL) || (volume_name == NULL) || (drive_name[0] == '?
') || ')) {
(strncmp(volume_name, groot_name, groot_len) == 0)) SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
}
// If we are working with a "\\?\GLOBALROOT" device, SetVolumeMountPoint(
)
// is useless, so try with DefineDosDevice() instead.
if (_strnicmp(volume_name, groot_name, groot_len) == 0) {
dos_name[0] = drive_name[0];
// Microsoft will also have to explain why "In no case is a trail
ing backslash allowed" [1] in
// DefineDosDevice(), instead of just checking if the driver para
meter is "X:\" and remove the
// backslash from a copy of the parameter in the bloody API call.
*THIS* really tells a lot
// about the level of thought and foresight that actually goes in
to the Windows APIs...
// [1] https://docs.microsoft.com/en-us/windows/win32/api/fileapi
/nf-fileapi-definedosdevicew
if (!DefineDosDeviceA(DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYST
EM, dos_name, &volume_name[14])) {
uprintf("Could not mount %s as %C:", volume_name, drive_n
ame[0]);
return FALSE;
}
uprintf("%s was successfully mounted as %C:", volume_name, drive_
name[0]);
return TRUE;
}
// Great: Windows has a *MAJOR BUG* whereas, in some circumstances, GetVo lumePathNamesForVolumeName() // Great: Windows has a *MAJOR BUG* whereas, in some circumstances, GetVo lumePathNamesForVolumeName()
// can return the *WRONG* drive letter. And yes, we validated that this i s *NOT* an issue like stack // can return the *WRONG* drive letter. And yes, we validated that this i s *NOT* an issue like stack
// or buffer corruption and whatnot. It *IS* a Windows bug. So just drop the idea of updating the // or buffer corruption and whatnot. It *IS* a Windows bug. So just drop the idea of updating the
// drive letter if already mounted and use the passed target always. // drive letter if already mounted and use the passed target always.
#if defined(WINDOWS_IS_NOT_BUGGY) #if defined(WINDOWS_IS_NOT_BUGGY)
// Windows may already have the volume mounted but under a different lett er. // Windows may already have the volume mounted but under a different lett er.
// If that is the case, update drive_name to that letter. // If that is the case, update drive_name to that letter.
if ( (GetVolumePathNamesForVolumeNameA(volume_name, mounted_letter, sizeo f(mounted_letter), &size)) if ( (GetVolumePathNamesForVolumeNameA(volume_name, mounted_letter, sizeo f(mounted_letter), &size))
&& (size > 1) && (mounted_letter[0] != drive_name[0]) ) { && (size > 1) && (mounted_letter[0] != drive_name[0]) ) {
skipping to change at line 1590 skipping to change at line 1794
if (!SetVolumeMountPointA(drive_name, volume_name)) { if (!SetVolumeMountPointA(drive_name, volume_name)) {
if (GetLastError() == ERROR_DIR_NOT_EMPTY) { if (GetLastError() == ERROR_DIR_NOT_EMPTY) {
if (!GetVolumeNameForVolumeMountPointA(drive_name, mounte d_guid, sizeof(mounted_guid))) { if (!GetVolumeNameForVolumeMountPointA(drive_name, mounte d_guid, sizeof(mounted_guid))) {
uprintf("%s is already mounted, but volume GUID c ould not be checked: %s", uprintf("%s is already mounted, but volume GUID c ould not be checked: %s",
drive_name, WindowsErrorString()); drive_name, WindowsErrorString());
} else if (safe_strcmp(volume_name, mounted_guid) != 0) { } else if (safe_strcmp(volume_name, mounted_guid) != 0) {
uprintf("%s is mounted, but volume GUID doesn't m atch:\r\n expected %s, got %s", uprintf("%s is mounted, but volume GUID doesn't m atch:\r\n expected %s, got %s",
drive_name, volume_name, mounted_guid); drive_name, volume_name, mounted_guid);
} else { } else {
uprintf("%s is already mounted as %C:", volume_na me, drive_name[0]); duprintf("%s is already mounted as %C:", volume_n ame, drive_name[0]);
return TRUE; return TRUE;
} }
uprintf("Retrying after dismount..."); uprintf("Retrying after dismount...");
if (!DeleteVolumeMountPointA(drive_name)) if (!DeleteVolumeMountPointA(drive_name))
uprintf("Warning: Could not delete volume mountpo int '%s': %s", drive_name, WindowsErrorString()); uprintf("Warning: Could not delete volume mountpo int '%s': %s", drive_name, WindowsErrorString());
if (SetVolumeMountPointA(drive_name, volume_name)) if (SetVolumeMountPointA(drive_name, volume_name))
return TRUE; return TRUE;
if ((GetLastError() == ERROR_DIR_NOT_EMPTY) && if ((GetLastError() == ERROR_DIR_NOT_EMPTY) &&
GetVolumeNameForVolumeMountPointA(drive_name, mou nted_guid, sizeof(mounted_guid)) && GetVolumeNameForVolumeMountPointA(drive_name, mou nted_guid, sizeof(mounted_guid)) &&
(safe_strcmp(volume_name, mounted_guid) == 0)) { (safe_strcmp(volume_name, mounted_guid) == 0)) {
skipping to change at line 1666 skipping to change at line 1870
return FALSE; return FALSE;
} }
suprintf("Successfully unmounted '%s'", drive_name); suprintf("Successfully unmounted '%s'", drive_name);
return TRUE; return TRUE;
} }
/* /*
* Issue a complete remount of the volume. * Issue a complete remount of the volume.
* Note that drive_name *may* be altered when the volume gets remounted. * Note that drive_name *may* be altered when the volume gets remounted.
*/ */
BOOL RemountVolume(char* drive_name) BOOL RemountVolume(char* drive_name, BOOL bSilent)
{ {
char volume_name[51]; char volume_name[51];
// UDF requires a sync/flush, and it's also a good idea for other FS's // UDF requires a sync/flush, and it's also a good idea for other FS's
FlushDrive(drive_name[0]); FlushDrive(drive_name[0]);
if (GetVolumeNameForVolumeMountPointA(drive_name, volume_name, sizeof(vol ume_name))) { if (GetVolumeNameForVolumeMountPointA(drive_name, volume_name, sizeof(vol ume_name))) {
if (DeleteVolumeMountPointA(drive_name)) { if (MountVolume(drive_name, volume_name)) {
Sleep(200); suprintf("Successfully remounted %s as %C:", volume_name,
if (MountVolume(drive_name, volume_name)) { drive_name[0]);
uprintf("Successfully remounted %s as %C:", volum
e_name, drive_name[0]);
} else {
uprintf("Failed to remount %s as %C:", volume_nam
e, drive_name[0]);
// This will leave the drive inaccessible and mus
t be flagged as an error
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_
STORAGE)|APPERR(ERROR_CANT_REMOUNT_VOLUME);
return FALSE;
}
} else { } else {
uprintf("Could not remount %s as %C: %s", volume_name, dr suprintf("Could not remount %s as %C: %s", volume_name, d
ive_name[0], WindowsErrorString()); rive_name[0], WindowsErrorString());
// Try to continue regardless // This will leave the drive inaccessible and must be fla
gged as an error
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)
|APPERR(ERROR_CANT_REMOUNT_VOLUME);
return FALSE;
} }
} }
return TRUE; return TRUE;
} }
/* /*
* Zero the first 'size' bytes of a partition. This is needed because we haven't found a way to * Zero the first 'size' bytes of a partition. This is needed because we haven't found a way to
* properly reset Windows's cached view of a drive partitioning short of cycling the USB port * properly reset Windows's cached view of a drive partitioning short of cycling the USB port
* (especially IOCTL_DISK_UPDATE_PROPERTIES is *USELESS*), and therefore the OS will try to * (especially IOCTL_DISK_UPDATE_PROPERTIES is *USELESS*), and therefore the OS will try to
* read the file system data at an old location, even if the partition has just been deleted. * read the file system data at an old location, even if the partition has just been deleted.
* TODO: We should do something like this in DeletePartitions() too.
*/ */
static BOOL ClearPartition(HANDLE hDrive, LARGE_INTEGER offset, DWORD size) static BOOL ClearPartition(HANDLE hDrive, LARGE_INTEGER offset, DWORD size)
{ {
BOOL r = FALSE; BOOL r = FALSE;
uint8_t* buffer = calloc(size, 1); uint8_t* buffer = calloc(size, 1);
if (buffer == NULL) if (buffer == NULL)
return FALSE; return FALSE;
if (!SetFilePointerEx(hDrive, offset, NULL, FILE_BEGIN)) { if (!SetFilePointerEx(hDrive, offset, NULL, FILE_BEGIN)) {
skipping to change at line 1854 skipping to change at line 2051
} else if ((extra_partitions & XP_CASPER)) { } else if ((extra_partitions & XP_CASPER)) {
assert(persistence_size != 0); assert(persistence_size != 0);
extra_part_name = L"Linux Persistence"; extra_part_name = L"Linux Persistence";
extra_part_size_in_tracks = persistence_size / bytes_per_ track; extra_part_size_in_tracks = persistence_size / bytes_per_ track;
} else if (extra_partitions & XP_COMPAT) { } else if (extra_partitions & XP_COMPAT) {
extra_part_name = L"BIOS Compatibility"; extra_part_name = L"BIOS Compatibility";
extra_part_size_in_tracks = 1; // One track for the extr a partition extra_part_size_in_tracks = 1; // One track for the extr a partition
} else { } else {
assert(FALSE); assert(FALSE);
} }
// NB: Because we already subtracted the backup GPT size from the
main partition size and
// this extra partition is indexed on main size, it does not over
flow into the backup GPT.
main_part_size_in_sectors = ((main_part_size_in_sectors / Selecte dDrive.SectorsPerTrack) - main_part_size_in_sectors = ((main_part_size_in_sectors / Selecte dDrive.SectorsPerTrack) -
extra_part_size_in_tracks) * SelectedDrive.SectorsPerTrac k; extra_part_size_in_tracks) * SelectedDrive.SectorsPerTrac k;
} }
if (main_part_size_in_sectors <= 0) { if (main_part_size_in_sectors <= 0) {
uprintf("Error: Invalid %S size", main_part_name); uprintf("Error: Invalid %S size", main_part_name);
return FALSE; return FALSE;
} }
uprintf("● Creating %S (offset: %lld, size: %s)", main_part_name, DriveLa youtEx.PartitionEntry[pn].StartingOffset.QuadPart, uprintf("● Creating %S (offset: %lld, size: %s)", main_part_name, DriveLa youtEx.PartitionEntry[pn].StartingOffset.QuadPart,
SizeToHumanReadable(main_part_size_in_sectors * SelectedDrive.Sec torSize, TRUE, FALSE)); SizeToHumanReadable(main_part_size_in_sectors * SelectedDrive.Sec torSize, TRUE, FALSE));
// Zero the beginning of this partition to avoid conflicting leftovers // Zero the beginning of this partition to avoid conflicting leftovers
 End of changes. 74 change blocks. 
215 lines changed or deleted 453 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)