mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[core] partial overhaul of the partitioning and formatting facilities
* Add VDS formatting support (through an Alt-V cheat mode) * Add partition index support * Improve(?) Windows To Go support by following Microsoft recommended partition order * Code refactoring & cleanup
This commit is contained in:
parent
4b38483a68
commit
1c39a80d72
11 changed files with 955 additions and 509 deletions
466
src/drive.c
466
src/drive.c
|
@ -45,6 +45,11 @@
|
|||
#include "fat32.h"
|
||||
#include "ntfs.h"
|
||||
|
||||
#define GLOBALROOT_NAME "\\\\?\\GLOBALROOT"
|
||||
const char* sfd_name = "Super Floppy Disk";
|
||||
const char* groot_name = GLOBALROOT_NAME;
|
||||
const size_t groot_len = sizeof(GLOBALROOT_NAME) - 1;
|
||||
|
||||
#if !defined(PARTITION_BASIC_DATA_GUID)
|
||||
const GUID PARTITION_BASIC_DATA_GUID =
|
||||
{ 0xebd0a0a2L, 0xb9e5, 0x4433, {0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7} };
|
||||
|
@ -70,6 +75,8 @@ const IID IID_IVdsSwProvider = { 0x9aa58360, 0xce33, 0x4f92, { 0xb6, 0x58, 0xed,
|
|||
const IID IID_IVdsPack = { 0x3b69d7f5, 0x9d94, 0x4648, { 0x91, 0xca, 0x79, 0x93, 0x9b, 0xa2, 0x63, 0xbf } };
|
||||
const IID IID_IVdsDisk = { 0x07e5c822, 0xf00c, 0x47a1, { 0x8f, 0xce, 0xb2, 0x44, 0xda, 0x56, 0xfd, 0x06 } };
|
||||
const IID IID_IVdsAdvancedDisk = { 0x6e6f6b40, 0x977c, 0x4069, { 0xbd, 0xdd, 0xac, 0x71, 0x00, 0x59, 0xf8, 0xc0 } };
|
||||
const IID IID_IVdsVolume = { 0x88306BB2, 0xE71F, 0x478C, { 0x86, 0xA2, 0x79, 0xDA, 0x20, 0x0A, 0x0F, 0x11} };
|
||||
const IID IID_IVdsVolumeMF3 = { 0x6788FAF9, 0x214E, 0x4B85, { 0xBA, 0x59, 0x26, 0x69, 0x53, 0x61, 0x6E, 0x09 } };
|
||||
#endif
|
||||
|
||||
PF_TYPE_DECL(NTAPI, NTSTATUS, NtQueryVolumeInformationFile, (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS));
|
||||
|
@ -79,8 +86,8 @@ PF_TYPE_DECL(NTAPI, NTSTATUS, NtQueryVolumeInformationFile, (HANDLE, PIO_STATUS_
|
|||
*/
|
||||
RUFUS_DRIVE_INFO SelectedDrive;
|
||||
BOOL installed_uefi_ntfs;
|
||||
DWORD partition_index[3];
|
||||
uint64_t persistence_size = 0;
|
||||
const char* sfd_name = "Super Floppy Disk";
|
||||
|
||||
/*
|
||||
* The following methods get or set the AutoMount setting (which is different from AutoRun)
|
||||
|
@ -153,7 +160,9 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
|
|||
goto out;
|
||||
|
||||
// Resolve a device path, so that we can look for that handle in case of access issues.
|
||||
if (QueryDosDeviceA(&Path[4], DevPath, sizeof(DevPath)) == 0)
|
||||
if (safe_strncmp(Path, groot_name, groot_len) == 0)
|
||||
static_strcpy(DevPath, &Path[groot_len]);
|
||||
else if (QueryDosDeviceA(&Path[4], DevPath, sizeof(DevPath)) == 0)
|
||||
strcpy(DevPath, "???");
|
||||
|
||||
for (i = 0; i < DRIVE_ACCESS_RETRIES; i++) {
|
||||
|
@ -237,14 +246,18 @@ out:
|
|||
* Return the path to access a partition on a specific disk, or NULL on error.
|
||||
* The string is allocated and must be freed (to ensure concurrent access)
|
||||
*/
|
||||
char* GetPartitionName(DWORD DriveIndex, DWORD PartitionNumber)
|
||||
char* GetPartitionName(DWORD DriveIndex, DWORD PartitionIndex)
|
||||
{
|
||||
BOOL success = FALSE;
|
||||
char partition_name[32];
|
||||
|
||||
CheckDriveIndex(DriveIndex);
|
||||
if (PartitionIndex >= MAX_PARTITIONS)
|
||||
goto out;
|
||||
if (PartitionIndex == 0)
|
||||
PartitionIndex = 1;
|
||||
|
||||
static_sprintf(partition_name, "\\Device\\Harddisk%lu\\Partition%lu", DriveIndex, PartitionNumber);
|
||||
static_sprintf(partition_name, "\\Device\\Harddisk%lu\\Partition%lu", DriveIndex, PartitionIndex);
|
||||
success = TRUE;
|
||||
out:
|
||||
return (success) ? safe_strdup(partition_name) : NULL;
|
||||
|
@ -263,25 +276,30 @@ HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, B
|
|||
}
|
||||
|
||||
/*
|
||||
* Return the first GUID volume name for the associated drive or NULL if not found
|
||||
* Return the GUID volume name for the disk and partition specified, or NULL if not found.
|
||||
* See http://msdn.microsoft.com/en-us/library/cc542456.aspx
|
||||
* The returned string is allocated and must be freed
|
||||
* PartitionIndex starts at 1 (for the first partition). If PartitionIndex is zero, then
|
||||
* the first partition found by this function (which *MAY NOT* be the actual first partition)
|
||||
* is returned. The returned string is allocated and must be freed.
|
||||
*/
|
||||
char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent)
|
||||
char* GetLogicalName(DWORD DriveIndex, DWORD PartitionIndex, BOOL bKeepTrailingBackslash, BOOL bSilent)
|
||||
{
|
||||
BOOL success = FALSE;
|
||||
char volume_name[MAX_PATH];
|
||||
static const char* ignore_device[] = { "\\Device\\CdRom", "\\Device\\Floppy" };
|
||||
static const char* volume_start = "\\\\?\\";
|
||||
char *ret = NULL, volume_name[MAX_PATH], path[MAX_PATH];
|
||||
HANDLE hDrive = INVALID_HANDLE_VALUE, hVolume = INVALID_HANDLE_VALUE;
|
||||
size_t len;
|
||||
char path[MAX_PATH];
|
||||
VOLUME_DISK_EXTENTS_REDEF DiskExtents;
|
||||
DWORD size;
|
||||
UINT drive_type;
|
||||
int i, j;
|
||||
static const char* ignore_device[] = { "\\Device\\CdRom", "\\Device\\Floppy" };
|
||||
static const char* volume_start = "\\\\?\\";
|
||||
StrArray found_name;
|
||||
uint64_t found_offset[MAX_PARTITIONS] = { 0 };
|
||||
uint32_t i, j, k;
|
||||
size_t len;
|
||||
|
||||
StrArrayCreate(&found_name, MAX_PARTITIONS);
|
||||
CheckDriveIndex(DriveIndex);
|
||||
if (PartitionIndex > MAX_PARTITIONS)
|
||||
goto out;
|
||||
|
||||
for (i = 0; hDrive == INVALID_HANDLE_VALUE; i++) {
|
||||
if (i == 0) {
|
||||
|
@ -295,7 +313,7 @@ char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent
|
|||
if (GetLastError() != ERROR_NO_MORE_FILES) {
|
||||
suprintf("Could not access next GUID volume: %s", WindowsErrorString());
|
||||
}
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,18 +355,68 @@ char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent
|
|||
continue;
|
||||
}
|
||||
safe_closehandle(hDrive);
|
||||
if ((DiskExtents.NumberOfDiskExtents >= 1) && (DiskExtents.Extents[0].DiskNumber == DriveIndex)) {
|
||||
if (DiskExtents.NumberOfDiskExtents == 0) {
|
||||
suprintf("Ignoring volume '%s' because it has no extents...", volume_name);
|
||||
continue;
|
||||
}
|
||||
if (DiskExtents.NumberOfDiskExtents != 1) {
|
||||
// If we have more than one extent for a volume, it means that someone
|
||||
// is using RAID-1 or something => Stay well away from such a volume!
|
||||
suprintf("Ignoring volume '%s' because it has more than one extent (RAID?)...", volume_name);
|
||||
continue;
|
||||
}
|
||||
if (DiskExtents.Extents[0].DiskNumber != DriveIndex)
|
||||
// Not on our disk
|
||||
continue;
|
||||
|
||||
if (found_name.Index == MAX_PARTITIONS) {
|
||||
uprintf("Error: Trying to process a disk with more than %d partitions!", MAX_PARTITIONS);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bKeepTrailingBackslash)
|
||||
volume_name[len-1] = '\\';
|
||||
success = TRUE;
|
||||
volume_name[len - 1] = '\\';
|
||||
found_offset[found_name.Index] = DiskExtents.Extents[0].StartingOffset.QuadPart;
|
||||
StrArrayAdd(&found_name, volume_name, TRUE);
|
||||
// uprintf("GOT %s @%lld", volume_name, DiskExtents.Extents[0].StartingOffset.QuadPart);
|
||||
}
|
||||
|
||||
if (found_name.Index == 0)
|
||||
goto out;
|
||||
|
||||
// Now process all the volumes we found, and find the one that matches our partition index
|
||||
if (PartitionIndex == 0) {
|
||||
i = 0;
|
||||
} else for (i = 0, k = 0; i < found_name.Index; i++) {
|
||||
for (j = 0; j < found_name.Index; j++) {
|
||||
if (found_offset[i] > found_offset[j])
|
||||
k++;
|
||||
}
|
||||
if (k == ((int)PartitionIndex) - 1)
|
||||
break;
|
||||
}
|
||||
if (i < found_name.Index) {
|
||||
ret = safe_strdup(found_name.String[i]);
|
||||
} else {
|
||||
// Some volumes, such as ESPs, are not listed by Windows, be it with VDS or other APIs.
|
||||
// For these, we return the "\\?\GLOBALROOT\Device\HarddiskVolume#" identifier that
|
||||
// matches our "Harddisk#Partition#", as reported by QueryDosDevice().
|
||||
static_sprintf(path, "Harddisk%luPartition%lu", DriveIndex, PartitionIndex);
|
||||
static_strcpy(volume_name, groot_name);
|
||||
if (!QueryDosDeviceA(path, &volume_name[groot_len], (DWORD)(MAX_PATH - groot_len)) || (strlen(volume_name) < 20)) {
|
||||
uprintf("Could not find the DOS volume name for '%s': %s", path, WindowsErrorString());
|
||||
} else {
|
||||
if (bKeepTrailingBackslash)
|
||||
static_strcat(volume_name, "\\");
|
||||
ret = safe_strdup(volume_name);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (hVolume != INVALID_HANDLE_VALUE)
|
||||
FindVolumeClose(hVolume);
|
||||
return (success)?safe_strdup(volume_name):NULL;
|
||||
StrArrayDestroy(&found_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -378,7 +446,8 @@ BOOL DeletePartitions(DWORD DriveIndex)
|
|||
hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
|
||||
&IID_IVdsServiceLoader, (void **)&pLoader);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not create VDS Loader Instance: hr=%X\n", hr);
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not create VDS Loader Instance: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -386,14 +455,16 @@ BOOL DeletePartitions(DWORD DriveIndex)
|
|||
hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService);
|
||||
IVdsServiceLoader_Release(pLoader);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not load VDS Service: 0x%08X", hr);
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not load VDS Service: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Query the VDS Service Providers
|
||||
hr = IVdsService_QueryProviders(pService, VDS_QUERY_SOFTWARE_PROVIDERS, &pEnum);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not query VDS Service Providers: 0x%08X", hr);
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not query VDS Service Providers: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -407,7 +478,8 @@ BOOL DeletePartitions(DWORD DriveIndex)
|
|||
hr = IUnknown_QueryInterface(pUnk, &IID_IVdsProvider, (void **)&pProvider);
|
||||
IUnknown_Release(pUnk);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not get VDS Provider: 0x%08X", hr);
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not get VDS Provider: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -415,7 +487,8 @@ BOOL DeletePartitions(DWORD DriveIndex)
|
|||
hr = IVdsSwProvider_QueryInterface(pProvider, &IID_IVdsSwProvider, (void **)&pSwProvider);
|
||||
IVdsProvider_Release(pProvider);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not get VDS Software Provider: 0x%08X", hr);
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not get VDS Software Provider: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -423,7 +496,8 @@ BOOL DeletePartitions(DWORD DriveIndex)
|
|||
hr = IVdsSwProvider_QueryPacks(pSwProvider, &pEnumPack);
|
||||
IVdsSwProvider_Release(pSwProvider);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not get VDS Software Provider Packs: 0x%08X", hr);
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not get VDS Software Provider Packs: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -436,14 +510,16 @@ BOOL DeletePartitions(DWORD DriveIndex)
|
|||
hr = IUnknown_QueryInterface(pPackUnk, &IID_IVdsPack, (void **)&pPack);
|
||||
IUnknown_Release(pPackUnk);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not query VDS Software Provider Pack: 0x%08X", hr);
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not query VDS Software Provider Pack: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Use the pack interface to access the disks
|
||||
hr = IVdsPack_QueryDisks(pPack, &pEnumDisk);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not query VDS disks: 0x%08X", hr);
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not query VDS disks: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -458,14 +534,16 @@ BOOL DeletePartitions(DWORD DriveIndex)
|
|||
// Get the disk interface.
|
||||
hr = IUnknown_QueryInterface(pDiskUnk, &IID_IVdsDisk, (void **)&pDisk);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not query VDS Disk Interface: 0x%08X", hr);
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not query VDS Disk Interface: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Get the disk properties
|
||||
hr = IVdsDisk_GetProperties(pDisk, &diskprop);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not query VDS Disk Properties: 0x%08X", hr);
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not query VDS Disk Properties: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -479,65 +557,58 @@ BOOL DeletePartitions(DWORD DriveIndex)
|
|||
hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsAdvancedDisk, (void **)&pAdvancedDisk);
|
||||
IVdsDisk_Release(pDisk);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not access VDS Advanced Disk interface: 0x%08X", hr);
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not access VDS Advanced Disk interface: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Query the partition data, so we can get the start offset, which we need for deletion
|
||||
hr = IVdsAdvancedDisk_QueryPartitions(pAdvancedDisk, &prop_array, &prop_array_size);
|
||||
if (hr != S_OK) {
|
||||
uprintf("No partition to delete on disk '%ws'", diskprop.pwszName);
|
||||
goto out;
|
||||
}
|
||||
|
||||
uprintf("Deleting ALL partitions from disk '%ws':", diskprop.pwszName);
|
||||
|
||||
if (hr == S_OK) {
|
||||
uprintf("Deleting ALL partition(s) from disk '%S':", diskprop.pwszName);
|
||||
// Now go through each partition
|
||||
r = (prop_array_size >= 1);
|
||||
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_DeletePartition(pAdvancedDisk, prop_array[i].ullOffset, TRUE, TRUE);
|
||||
if (hr != S_OK) {
|
||||
r = FALSE;
|
||||
uprintf("Could not delete partitions: 0x%08X", hr);
|
||||
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);
|
||||
|
||||
// NB: In the future, we could try something like this to format partitions:
|
||||
#if 0
|
||||
// Initiate formatting and wait for completion.
|
||||
LPWSTR pwszLabel[8] = L"TEST";
|
||||
ULONGLONG Offset = 1024 * 1024;
|
||||
BOOL QuickFormat = TRUE;
|
||||
BOOL EnableCompression = FALSE;
|
||||
IVdsAsync* pAsync;
|
||||
hr = IVdsAdvancedDisk_FormatPartition(pAdvancedDisk, Offset, FileSystemType,
|
||||
pwszLabel, 0, TRUE, QuickFormat, EnableCompression, &pAsync);
|
||||
if (hr != S_OK) {
|
||||
uprintf("Could not start formatting: 0x%08X", hr);
|
||||
goto out;
|
||||
}
|
||||
VDS_ASYNC_OUTPUT AsyncOut;
|
||||
ULONG ulPercentCompleted;
|
||||
// Issue a Clean while we're at it
|
||||
HRESULT hr2 = E_FAIL;
|
||||
do {
|
||||
hr = IVdsAsync_QueryStatus(pAsync, &hr2, &ulPercentCompleted);
|
||||
ULONG completed;
|
||||
IVdsAsync* pAsync;
|
||||
hr = IVdsAdvancedDisk_Clean(pAdvancedDisk, TRUE, FALSE, FALSE, &pAsync);
|
||||
while (SUCCEEDED(hr)) {
|
||||
if (IS_ERROR(FormatStatus)) {
|
||||
IVdsAsync_Cancel(pAsync);
|
||||
break;
|
||||
}
|
||||
hr = IVdsAsync_QueryStatus(pAsync, &hr2, &completed);
|
||||
if (SUCCEEDED(hr)) {
|
||||
printf("%ld%%", ulPercentCompleted);
|
||||
if ((hr2 != S_OK) && (hr2 != VDS_E_OPERATION_PENDING)) {
|
||||
uprintf("hr2: %X", hr2);
|
||||
hr = hr2;
|
||||
if (hr == S_OK)
|
||||
break;
|
||||
}
|
||||
if (hr2 == S_OK) {
|
||||
break;
|
||||
}
|
||||
if (hr == VDS_E_OPERATION_PENDING)
|
||||
hr = S_OK;
|
||||
}
|
||||
Sleep(500);
|
||||
} while (SUCCEEDED(hr));
|
||||
hr = IVdsAsync_Wait(pAsync, &hr2, &AsyncOut);
|
||||
IVdsAsync_Release(pAsync);
|
||||
}
|
||||
if (hr != S_OK) {
|
||||
VDS_SET_ERROR(hr);
|
||||
uprintf("Could not clean disk: %s", WindowsErrorString());
|
||||
}
|
||||
#endif
|
||||
IVdsAdvancedDisk_Release(pAdvancedDisk);
|
||||
goto out;
|
||||
|
@ -551,7 +622,7 @@ out:
|
|||
|
||||
|
||||
/* Wait for a logical drive to reappear - Used when a drive has just been repartitioned */
|
||||
BOOL WaitForLogical(DWORD DriveIndex)
|
||||
BOOL WaitForLogical(DWORD DriveIndex, DWORD PartitionIndex)
|
||||
{
|
||||
uint64_t EndTime;
|
||||
char* LogicalPath = NULL;
|
||||
|
@ -560,11 +631,13 @@ BOOL WaitForLogical(DWORD DriveIndex)
|
|||
// make sure we don't spend more than DRIVE_ACCESS_TIMEOUT in wait.
|
||||
EndTime = GetTickCount64() + DRIVE_ACCESS_TIMEOUT;
|
||||
do {
|
||||
LogicalPath = GetLogicalName(DriveIndex, FALSE, TRUE);
|
||||
if (LogicalPath != NULL) {
|
||||
LogicalPath = GetLogicalName(DriveIndex, PartitionIndex, FALSE, TRUE);
|
||||
// Need to filter out GlobalRoot devices as we don't want to wait on those
|
||||
if ((LogicalPath != NULL) && (strncmp(LogicalPath, groot_name, groot_len) != 0)) {
|
||||
free(LogicalPath);
|
||||
return TRUE;
|
||||
}
|
||||
free(LogicalPath);
|
||||
if (IS_ERROR(FormatStatus)) // User cancel
|
||||
return FALSE;
|
||||
Sleep(DRIVE_ACCESS_TIMEOUT/DRIVE_ACCESS_RETRIES);
|
||||
|
@ -574,14 +647,14 @@ BOOL WaitForLogical(DWORD DriveIndex)
|
|||
}
|
||||
|
||||
/*
|
||||
* Obtain a handle to the first logical volume on the disk identified by DriveIndex
|
||||
* Obtain a handle to the volume identified by DriveIndex + PartitionIndex
|
||||
* Returns INVALID_HANDLE_VALUE on error or NULL if no logical path exists (typical
|
||||
* of unpartitioned drives)
|
||||
*/
|
||||
HANDLE GetLogicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare)
|
||||
HANDLE GetLogicalHandle(DWORD DriveIndex, DWORD PartitionIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare)
|
||||
{
|
||||
HANDLE hLogical = INVALID_HANDLE_VALUE;
|
||||
char* LogicalPath = GetLogicalName(DriveIndex, FALSE, FALSE);
|
||||
char* LogicalPath = GetLogicalName(DriveIndex, PartitionIndex, FALSE, FALSE);
|
||||
|
||||
if (LogicalPath == NULL) {
|
||||
uprintf("No logical drive found (unpartitioned?)");
|
||||
|
@ -956,7 +1029,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
|
|||
SelectedDrive.nPartitions = 0;
|
||||
// Populate the filesystem data
|
||||
FileSystemName[0] = 0;
|
||||
volume_name = GetLogicalName(DriveIndex, TRUE, FALSE);
|
||||
volume_name = GetLogicalName(DriveIndex, 0, TRUE, FALSE);
|
||||
if ((volume_name == NULL) || (!GetVolumeInformationA(volume_name, NULL, 0, NULL, NULL, NULL, FileSystemName, FileSystemNameSize))) {
|
||||
suprintf("No volume information for drive 0x%02x", DriveIndex);
|
||||
}
|
||||
|
@ -1142,49 +1215,50 @@ BOOL UnmountVolume(HANDLE hDrive)
|
|||
|
||||
/*
|
||||
* Mount the volume identified by drive_guid to mountpoint drive_name.
|
||||
* If drive_guid is already mounted, but with a different letter than the
|
||||
* one requested, drive_name is updated to use that letter.
|
||||
* If volume_name is already mounted, but with a different letter than the
|
||||
* one requested then drive_name is updated to use that letter.
|
||||
*/
|
||||
BOOL MountVolume(char* drive_name, char *drive_guid)
|
||||
BOOL MountVolume(char* drive_name, char *volume_name)
|
||||
{
|
||||
char mounted_guid[52];
|
||||
char mounted_letter[27] = { 0 };
|
||||
DWORD size;
|
||||
|
||||
if (drive_name[0] == '?')
|
||||
if ((drive_name == NULL) || (volume_name == NULL) || (drive_name[0] == '?') ||
|
||||
(strncmp(volume_name, groot_name, groot_len) == 0))
|
||||
return FALSE;
|
||||
|
||||
// Windows may already have the volume mounted but under a different letter.
|
||||
// If that is the case, update drive_name to that letter.
|
||||
if ( (GetVolumePathNamesForVolumeNameA(drive_guid, mounted_letter, sizeof(mounted_letter), &size))
|
||||
if ( (GetVolumePathNamesForVolumeNameA(volume_name, mounted_letter, sizeof(mounted_letter), &size))
|
||||
&& (size > 1) && (mounted_letter[0] != drive_name[0]) ) {
|
||||
uprintf("%s is already mounted as %C: instead of %C: - Will now use this target instead...",
|
||||
drive_guid, mounted_letter[0], drive_name[0]);
|
||||
volume_name, mounted_letter[0], drive_name[0]);
|
||||
drive_name[0] = mounted_letter[0];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!SetVolumeMountPointA(drive_name, drive_guid)) {
|
||||
if (!SetVolumeMountPointA(drive_name, volume_name)) {
|
||||
if (GetLastError() == ERROR_DIR_NOT_EMPTY) {
|
||||
if (!GetVolumeNameForVolumeMountPointA(drive_name, mounted_guid, sizeof(mounted_guid))) {
|
||||
uprintf("%s is already mounted, but volume GUID could not be checked: %s",
|
||||
drive_name, WindowsErrorString());
|
||||
} else if (safe_strcmp(drive_guid, mounted_guid) != 0) {
|
||||
} else if (safe_strcmp(volume_name, mounted_guid) != 0) {
|
||||
uprintf("%s is mounted, but volume GUID doesn't match:\r\n expected %s, got %s",
|
||||
drive_name, drive_guid, mounted_guid);
|
||||
drive_name, volume_name, mounted_guid);
|
||||
} else {
|
||||
uprintf("%s is already mounted as %C:", drive_guid, drive_name[0]);
|
||||
uprintf("%s is already mounted as %C:", volume_name, drive_name[0]);
|
||||
return TRUE;
|
||||
}
|
||||
uprintf("Retrying after dismount...");
|
||||
if (!DeleteVolumeMountPointA(drive_name))
|
||||
uprintf("Warning: Could not delete volume mountpoint: %s", WindowsErrorString());
|
||||
if (SetVolumeMountPointA(drive_name, drive_guid))
|
||||
if (SetVolumeMountPointA(drive_name, volume_name))
|
||||
return TRUE;
|
||||
if ((GetLastError() == ERROR_DIR_NOT_EMPTY) &&
|
||||
GetVolumeNameForVolumeMountPointA(drive_name, mounted_guid, sizeof(mounted_guid)) &&
|
||||
(safe_strcmp(drive_guid, mounted_guid) == 0)) {
|
||||
uprintf("%s was remounted as %C: (second time lucky!)", drive_guid, drive_name[0]);
|
||||
(safe_strcmp(volume_name, mounted_guid) == 0)) {
|
||||
uprintf("%s was remounted as %C: (second time lucky!)", volume_name, drive_name[0]);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -1194,85 +1268,39 @@ BOOL MountVolume(char* drive_name, char *drive_guid)
|
|||
}
|
||||
|
||||
/*
|
||||
* Mount partition #part_nr, residing on the same disk as drive_name to an available
|
||||
* drive letter. Returns the newly allocated drive string.
|
||||
* We need to do this because, for instance, EFI System partitions are not assigned
|
||||
* Volume GUIDs by the OS, and we need to have a letter assigned, for when we invoke
|
||||
* bcdtool for Windows To Go. All in all, the process looks like this:
|
||||
* 1. F: = \Device\HarddiskVolume9 (SINGLE LOOKUP)
|
||||
* 2. Harddisk5Partition1 = \Device\HarddiskVolume9 (FULL LOOKUP)
|
||||
* 3. Harddisk5Partition2 = \Device\HarddiskVolume10 (SINGLE LOOKUP)
|
||||
* 4. DefineDosDevice(letter, \Device\HarddiskVolume10)
|
||||
* Alternate version of MountVolume required for ESP's, since Windows (including VDS) does
|
||||
* *NOT* provide any means of mounting these volume but through DefineDosDevice(). Also
|
||||
* note the bcdboot is very finicky about what it may or may not handle, even if the
|
||||
* mount was successful (e.g. '\Device\HarddiskVolume###' vs 'Device\HarddiskVolume###').
|
||||
* Returned string is static (no concurrency) and should not be freed.
|
||||
*/
|
||||
char* AltMountVolume(const char* drive_name, uint8_t part_nr)
|
||||
char* AltMountVolume(DWORD DriveIndex, DWORD PartitionIndex)
|
||||
{
|
||||
char* ret = NULL, *volume_name = NULL;
|
||||
static char mounted_drive[] = "?:";
|
||||
const DWORD bufsize = 65536;
|
||||
char *buffer = NULL, *p, target[2][MAX_PATH], *ret = NULL;
|
||||
size_t i;
|
||||
|
||||
mounted_drive[0] = GetUnusedDriveLetter();
|
||||
if (mounted_drive[0] == 0) {
|
||||
uprintf("Could not find an unused drive letter");
|
||||
goto out;
|
||||
}
|
||||
|
||||
target[0][0] = 0;
|
||||
// Convert our drive letter to something like "\Device\HarddiskVolume9"
|
||||
if (!QueryDosDeviceA(drive_name, target[0], MAX_PATH) || (strlen(target[0]) == 0)) {
|
||||
uprintf("Could not get the DOS volume name for '%s': %s", drive_name, WindowsErrorString());
|
||||
volume_name = GetLogicalName(DriveIndex, PartitionIndex, FALSE, TRUE);
|
||||
if ((volume_name == NULL) || (strncmp(volume_name, groot_name, groot_len) != 0)) {
|
||||
uprintf("Unexpected volume name: '%s'", volume_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Now parse the whole DOS device list to find the 'Harddisk#Partition#' that matches the above
|
||||
// TODO: realloc if someone ever manages to burst through 64K of DOS devices
|
||||
buffer = malloc(bufsize);
|
||||
if (buffer == NULL)
|
||||
goto out;
|
||||
|
||||
buffer[0] = 0;
|
||||
if (!QueryDosDeviceA(NULL, buffer, bufsize)) {
|
||||
uprintf("Could not get the DOS device list: %s", WindowsErrorString());
|
||||
// bcdboot sure won't like it if you forget the starting '\'
|
||||
if (!DefineDosDeviceA(DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM, mounted_drive, &volume_name[14])) {
|
||||
uprintf("Could not mount '%s' to '%s': %s", &volume_name[14], mounted_drive, WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = buffer;
|
||||
while (strlen(p) != 0) {
|
||||
if ((strncmp("Harddisk", p, 8) == 0) && (strstr(&p[9], "Partition") != NULL)) {
|
||||
target[1][0] = 0;
|
||||
if (QueryDosDeviceA(p, target[1], MAX_PATH) && (strlen(target[1]) != 0))
|
||||
if ((strcmp(target[1], target[0]) == 0) && (p[1] != ':'))
|
||||
break;
|
||||
}
|
||||
p += strlen(p) + 1;
|
||||
}
|
||||
|
||||
i = strlen(p);
|
||||
if (i == 0) {
|
||||
uprintf("Could not find partition mapping for %s", target[0]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
while ((--i > 0) && (isdigit(p[i])));
|
||||
p[++i] = '0' + part_nr;
|
||||
p[++i] = 0;
|
||||
|
||||
target[0][0] = 0;
|
||||
if (!QueryDosDeviceA(p, target[0], MAX_PATH) || (strlen(target[0]) == 0)) {
|
||||
uprintf("Could not find the DOS volume name for partition '%s': %s", p, WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!DefineDosDeviceA(DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM, mounted_drive, target[0])) {
|
||||
uprintf("Could not mount '%s' to '%s': %s", target[0], mounted_drive, WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
uprintf("Successfully mounted '%s' (USB partition %d) as '%s'", target[0], part_nr, mounted_drive);
|
||||
uprintf("Successfully mounted '%s' (Partition %d) as '%s'", &volume_name[14], PartitionIndex, mounted_drive);
|
||||
ret = mounted_drive;
|
||||
|
||||
out:
|
||||
safe_free(buffer);
|
||||
free(volume_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1297,23 +1325,23 @@ BOOL AltUnmountVolume(const char* drive_name)
|
|||
*/
|
||||
BOOL RemountVolume(char* drive_name)
|
||||
{
|
||||
char drive_guid[51];
|
||||
char volume_name[51];
|
||||
|
||||
// UDF requires a sync/flush, and it's also a good idea for other FS's
|
||||
FlushDrive(drive_name[0]);
|
||||
if (GetVolumeNameForVolumeMountPointA(drive_name, drive_guid, sizeof(drive_guid))) {
|
||||
if (GetVolumeNameForVolumeMountPointA(drive_name, volume_name, sizeof(volume_name))) {
|
||||
if (DeleteVolumeMountPointA(drive_name)) {
|
||||
Sleep(200);
|
||||
if (MountVolume(drive_name, drive_guid)) {
|
||||
uprintf("Successfully remounted %s as %C:", drive_guid, drive_name[0]);
|
||||
if (MountVolume(drive_name, volume_name)) {
|
||||
uprintf("Successfully remounted %s as %C:", volume_name, drive_name[0]);
|
||||
} else {
|
||||
uprintf("Failed to remount %s as %C:", drive_guid, drive_name[0]);
|
||||
uprintf("Failed to remount %s as %C:", volume_name, drive_name[0]);
|
||||
// This will leave the drive inaccessible and must be flagged as an error
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_REMOUNT_VOLUME);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
uprintf("Could not remount %s as %C: %s", drive_guid, drive_name[0], WindowsErrorString());
|
||||
uprintf("Could not remount %s as %C: %s", volume_name, drive_name[0], WindowsErrorString());
|
||||
// Try to continue regardless
|
||||
}
|
||||
}
|
||||
|
@ -1328,7 +1356,7 @@ typedef struct _DRIVE_LAYOUT_INFORMATION_EX4 {
|
|||
DRIVE_LAYOUT_INFORMATION_MBR Mbr;
|
||||
DRIVE_LAYOUT_INFORMATION_GPT Gpt;
|
||||
} Type;
|
||||
PARTITION_INFORMATION_EX PartitionEntry[4];
|
||||
PARTITION_INFORMATION_EX PartitionEntry[MAX_PARTITIONS];
|
||||
} DRIVE_LAYOUT_INFORMATION_EX4,*PDRIVE_LAYOUT_INFORMATION_EX4;
|
||||
|
||||
/*
|
||||
|
@ -1341,13 +1369,14 @@ typedef struct _DRIVE_LAYOUT_INFORMATION_EX4 {
|
|||
BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, uint8_t extra_partitions)
|
||||
{
|
||||
const char* PartitionTypeName[] = { "MBR", "GPT", "SFD" };
|
||||
const wchar_t* extra_part_name;
|
||||
unsigned char* buffer;
|
||||
size_t uefi_ntfs_size = 0;
|
||||
CREATE_DISK CreateDisk = {PARTITION_STYLE_RAW, {{0}}};
|
||||
DRIVE_LAYOUT_INFORMATION_EX4 DriveLayoutEx = {0};
|
||||
BOOL r;
|
||||
DWORD i, size, bufsize, pn = 0;
|
||||
LONGLONG main_part_size_in_sectors, extra_part_size_in_tracks = 0, ms_efi_size;
|
||||
LONGLONG main_part_size_in_sectors, extra_part_size_in_tracks = 0, ms_esp_size;
|
||||
const LONGLONG bytes_per_track = ((LONGLONG)SelectedDrive.SectorsPerTrack) * SelectedDrive.SectorSize;
|
||||
|
||||
PrintInfoDebug(0, MSG_238, PartitionTypeName[partition_style]);
|
||||
|
@ -1361,6 +1390,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
|||
if (uefi_ntfs_size == 0)
|
||||
return FALSE;
|
||||
}
|
||||
memset(partition_index, 0, sizeof(partition_index));
|
||||
|
||||
// Compute the start offset of our first partition
|
||||
if ((partition_style == PARTITION_STYLE_GPT) || (!IsChecked(IDC_OLD_BIOS_FIXES))) {
|
||||
|
@ -1371,14 +1401,43 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
|||
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = bytes_per_track;
|
||||
}
|
||||
|
||||
// If required, set the ESP (which Microsoft wants to be the first)
|
||||
if (extra_partitions & XP_ESP) {
|
||||
uprintf("● Creating EFI System Partition");
|
||||
// The size of the ESP depends on the minimum size we're able to format in FAT32, which
|
||||
// in turn depends on the cluster size used, which in turn depends on the disk sector size.
|
||||
// Plus some people are complaining that the *OFFICIAL MINIMUM SIZE* as documented by Microsoft at
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/configure-uefigpt-based-hard-drive-partitions
|
||||
// is too small. See: https://github.com/pbatard/rufus/issues/979
|
||||
if (SelectedDrive.SectorSize <= 4096)
|
||||
ms_esp_size = 300 * MB;
|
||||
else
|
||||
ms_esp_size = 1200 * MB; // That'll teach you to have a nonstandard disk!
|
||||
extra_part_size_in_tracks = (ms_esp_size + bytes_per_track - 1) / bytes_per_track;
|
||||
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = extra_part_size_in_tracks * bytes_per_track;
|
||||
|
||||
if (partition_style == PARTITION_STYLE_GPT) {
|
||||
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_SYSTEM_GUID;
|
||||
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId));
|
||||
// coverity[strcpy_overrun]
|
||||
wcscpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, L"EFI System Partition");
|
||||
} else {
|
||||
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0xef;
|
||||
}
|
||||
pn++;
|
||||
partition_index[PI_ESP] = pn;
|
||||
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn - 1].StartingOffset.QuadPart +
|
||||
DriveLayoutEx.PartitionEntry[pn - 1].PartitionLength.QuadPart;
|
||||
}
|
||||
|
||||
// If required, set the MSR partition (GPT only - must be created before the data part)
|
||||
if ((partition_style == PARTITION_STYLE_GPT) && (extra_partitions & XP_MSR)) {
|
||||
uprintf("Adding MSR partition");
|
||||
uprintf("● Creating MSR Partition");
|
||||
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = 128*MB;
|
||||
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_MSFT_RESERVED_GUID;
|
||||
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId));
|
||||
// coverity[strcpy_overrun]
|
||||
wcscpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, L"Microsoft reserved partition");
|
||||
wcscpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, L"Microsoft Reserved Partition");
|
||||
|
||||
// We must zero the beginning of this partition, else we get FAT leftovers and stuff
|
||||
if (SetFilePointerEx(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, NULL, FILE_BEGIN)) {
|
||||
|
@ -1390,49 +1449,45 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
|||
free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
pn++;
|
||||
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn-1].StartingOffset.QuadPart +
|
||||
DriveLayoutEx.PartitionEntry[pn-1].PartitionLength.QuadPart;
|
||||
}
|
||||
// Clear the extra partitions we processed
|
||||
extra_partitions &= ~(XP_ESP|XP_MSR);
|
||||
|
||||
// Set our main data partition
|
||||
main_part_size_in_sectors = (SelectedDrive.DiskSize - DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart) /
|
||||
// Need 33 sectors at the end for secondary GPT
|
||||
SelectedDrive.SectorSize - ((partition_style == PARTITION_STYLE_GPT)?33:0);
|
||||
if (main_part_size_in_sectors <= 0)
|
||||
return FALSE;
|
||||
|
||||
if (!extra_partitions) {
|
||||
uprintf("● Creating Main Data Partition: %lld tracks (%s)", main_part_size_in_sectors / SelectedDrive.SectorsPerTrack,
|
||||
SizeToHumanReadable(main_part_size_in_sectors * SelectedDrive.SectorSize, TRUE, FALSE));
|
||||
} else {
|
||||
// Adjust the size according to extra partitions (which we always align to a track)
|
||||
if (extra_partitions) {
|
||||
uprintf("Adding %s partition", (extra_partitions & XP_CASPER) ? "casper-rw": "extra");
|
||||
if (extra_partitions & XP_EFI) {
|
||||
// The size of the EFI partition depends on the minimum size we're able to format in FAT32, which
|
||||
// in turn depends on the cluster size used, which in turn depends on the disk sector size.
|
||||
// Plus some people are complaining that the *OFFICIAL MINIMUM SIZE* as documented by Microsoft at
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/configure-uefigpt-based-hard-drive-partitions
|
||||
// is too small. See: https://github.com/pbatard/rufus/issues/979
|
||||
if (SelectedDrive.SectorSize <= 4096)
|
||||
ms_efi_size = 300*MB;
|
||||
else
|
||||
ms_efi_size = 1200*MB; // That'll teach you to have a nonstandard disk!
|
||||
extra_part_size_in_tracks = (ms_efi_size + bytes_per_track - 1) / bytes_per_track;
|
||||
} else if (extra_partitions & XP_UEFI_NTFS) {
|
||||
if (extra_partitions & XP_UEFI_NTFS) {
|
||||
extra_part_name = L"UEFI:NTFS";
|
||||
extra_part_size_in_tracks = (max(MIN_EXTRA_PART_SIZE, uefi_ntfs_size) + bytes_per_track - 1) / bytes_per_track;
|
||||
} else if (extra_partitions & XP_COMPAT) {
|
||||
extra_part_size_in_tracks = 1; // One track for the extra partition
|
||||
} else if ((extra_partitions & XP_CASPER)) {
|
||||
assert(persistence_size != 0);
|
||||
extra_part_name = L"Linux Persistence";
|
||||
extra_part_size_in_tracks = persistence_size / bytes_per_track;
|
||||
} else if (extra_partitions & XP_COMPAT) {
|
||||
extra_part_name = L"BIOS Compatibility";
|
||||
extra_part_size_in_tracks = 1; // One track for the extra partition
|
||||
}
|
||||
uprintf("Reserved %" PRIi64" tracks (%s) for %s partition", extra_part_size_in_tracks,
|
||||
SizeToHumanReadable(extra_part_size_in_tracks * bytes_per_track, TRUE, FALSE),
|
||||
(extra_partitions & XP_CASPER) ? "casper-rw" : "extra");
|
||||
main_part_size_in_sectors = ((main_part_size_in_sectors / SelectedDrive.SectorsPerTrack) -
|
||||
extra_part_size_in_tracks) * SelectedDrive.SectorsPerTrack;
|
||||
if (main_part_size_in_sectors <= 0)
|
||||
uprintf("● Creating Main Data Partition: %lld tracks (%s)", main_part_size_in_sectors / SelectedDrive.SectorsPerTrack,
|
||||
SizeToHumanReadable(main_part_size_in_sectors * SelectedDrive.SectorSize, TRUE, FALSE));
|
||||
uprintf("● Creating %S Partition: %lld tracks (%s)", extra_part_name, extra_part_size_in_tracks,
|
||||
SizeToHumanReadable(extra_part_size_in_tracks * bytes_per_track, TRUE, FALSE));
|
||||
}
|
||||
if (main_part_size_in_sectors <= 0) {
|
||||
uprintf("Error: Invalid Main Partition size!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = main_part_size_in_sectors * SelectedDrive.SectorSize;
|
||||
if (partition_style == PARTITION_STYLE_MBR) {
|
||||
DriveLayoutEx.PartitionEntry[pn].Mbr.BootIndicator = (boot_type != BT_NON_BOOTABLE);
|
||||
|
@ -1446,6 +1501,11 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
|||
case FS_REFS:
|
||||
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x07;
|
||||
break;
|
||||
case FS_EXT2:
|
||||
case FS_EXT3:
|
||||
case FS_EXT4:
|
||||
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x83;
|
||||
break;
|
||||
case FS_FAT32:
|
||||
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x0c; // FAT32 LBA
|
||||
break;
|
||||
|
@ -1456,61 +1516,49 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
|||
} else {
|
||||
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_BASIC_DATA_GUID;
|
||||
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId));
|
||||
wcscpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, L"Microsoft Basic Data");
|
||||
wcscpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, L"Basic Data");
|
||||
}
|
||||
pn++;
|
||||
partition_index[PI_MAIN] = pn;
|
||||
|
||||
// Set the optional extra partition
|
||||
if (extra_partitions) {
|
||||
// Don't forget to set our peristent partition index!
|
||||
if (extra_partitions & XP_CASPER)
|
||||
partition_index[PI_CASPER] = pn + 1;
|
||||
// Should end on a track boundary
|
||||
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn-1].StartingOffset.QuadPart +
|
||||
DriveLayoutEx.PartitionEntry[pn-1].PartitionLength.QuadPart;
|
||||
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = (extra_partitions & XP_UEFI_NTFS)?uefi_ntfs_size:
|
||||
extra_part_size_in_tracks * bytes_per_track;
|
||||
if (partition_style == PARTITION_STYLE_GPT) {
|
||||
const wchar_t* name = L"Basic Data";
|
||||
const GUID* guid = &PARTITION_BASIC_DATA_GUID;
|
||||
if (extra_partitions & XP_EFI) {
|
||||
guid = &PARTITION_SYSTEM_GUID;
|
||||
name = L"EFI system partition";
|
||||
} else if (extra_partitions & XP_CASPER) {
|
||||
// TODO: We may also want to use PARTITION_LINUX_HOME_GUID as fallback
|
||||
// to automout as /home in case casper-rw fails.
|
||||
name = L"casper-rw"; // Just in case
|
||||
} else if (extra_partitions & XP_UEFI_NTFS) {
|
||||
name = L"UEFI:NTFS";
|
||||
} else {
|
||||
assert(FALSE);
|
||||
}
|
||||
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = *guid;
|
||||
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_BASIC_DATA_GUID;
|
||||
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId));
|
||||
wcscpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, name);
|
||||
wcscpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, extra_part_name);
|
||||
} else {
|
||||
BYTE type = 0;
|
||||
if (extra_partitions & XP_UEFI_NTFS) {
|
||||
type = 0xef;
|
||||
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0xef;
|
||||
} else if (extra_partitions & XP_CASPER) {
|
||||
type = 0x83;
|
||||
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x83;
|
||||
} else if (extra_partitions & XP_COMPAT) {
|
||||
type = RUFUS_EXTRA_PARTITION_TYPE;
|
||||
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = RUFUS_EXTRA_PARTITION_TYPE;
|
||||
// Set the one track compatibility partition to be all hidden sectors
|
||||
DriveLayoutEx.PartitionEntry[pn].Mbr.HiddenSectors = SelectedDrive.SectorsPerTrack;
|
||||
} else {
|
||||
assert(FALSE);
|
||||
}
|
||||
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = type;
|
||||
}
|
||||
|
||||
// We need to write the UEFI:NTFS partition before we refresh the disk
|
||||
if (extra_partitions & XP_UEFI_NTFS) {
|
||||
uprintf("Writing UEFI:NTFS partition...");
|
||||
uprintf("Writing %S data...", extra_part_name);
|
||||
if (!SetFilePointerEx(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, NULL, FILE_BEGIN)) {
|
||||
uprintf("Unable to set position");
|
||||
uprintf("Could not set position");
|
||||
return FALSE;
|
||||
}
|
||||
buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_NTFS), _RT_RCDATA, "uefi-ntfs.img", &bufsize, FALSE);
|
||||
if (buffer == NULL) {
|
||||
uprintf("Could not access uefi-ntfs.img");
|
||||
uprintf("Could not access source image");
|
||||
return FALSE;
|
||||
}
|
||||
if(!WriteFileWithRetry(hDrive, buffer, bufsize, &size, WRITE_RETRIES)) {
|
||||
|
@ -1524,7 +1572,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
|||
|
||||
// Initialize the remaining partition data
|
||||
for (i = 0; i < pn; i++) {
|
||||
DriveLayoutEx.PartitionEntry[i].PartitionNumber = i+1;
|
||||
DriveLayoutEx.PartitionEntry[i].PartitionNumber = i + 1;
|
||||
DriveLayoutEx.PartitionEntry[i].PartitionStyle = partition_style;
|
||||
DriveLayoutEx.PartitionEntry[i].RewritePartition = TRUE;
|
||||
}
|
||||
|
@ -1552,14 +1600,14 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
|||
|
||||
CreateDisk.PartitionStyle = PARTITION_STYLE_GPT;
|
||||
IGNORE_RETVAL(CoCreateGuid(&CreateDisk.Gpt.DiskId));
|
||||
CreateDisk.Gpt.MaxPartitionCount = MAX_GPT_PARTITIONS;
|
||||
CreateDisk.Gpt.MaxPartitionCount = MAX_PARTITIONS;
|
||||
|
||||
DriveLayoutEx.PartitionStyle = PARTITION_STYLE_GPT;
|
||||
DriveLayoutEx.PartitionCount = pn;
|
||||
// At the very least, a GPT disk has 34 reserved sectors at the beginning and 33 at the end.
|
||||
DriveLayoutEx.Type.Gpt.StartingUsableOffset.QuadPart = 34 * SelectedDrive.SectorSize;
|
||||
DriveLayoutEx.Type.Gpt.UsableLength.QuadPart = SelectedDrive.DiskSize - (34+33) * SelectedDrive.SectorSize;
|
||||
DriveLayoutEx.Type.Gpt.MaxPartitionCount = MAX_GPT_PARTITIONS;
|
||||
DriveLayoutEx.Type.Gpt.MaxPartitionCount = MAX_PARTITIONS;
|
||||
DriveLayoutEx.Type.Gpt.DiskId = CreateDisk.Gpt.DiskId;
|
||||
break;
|
||||
}
|
||||
|
|
122
src/drive.h
122
src/drive.h
|
@ -33,13 +33,27 @@
|
|||
CTL_CODE(MOUNTMGRCONTROLTYPE, 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
|
||||
|
||||
#define XP_MSR 0x01
|
||||
#define XP_EFI 0x02
|
||||
#define XP_ESP 0x02
|
||||
#define XP_UEFI_NTFS 0x04
|
||||
#define XP_COMPAT 0x08
|
||||
#define XP_CASPER 0x10
|
||||
|
||||
#define PI_MAIN 0
|
||||
#define PI_ESP 1
|
||||
#define PI_CASPER 2
|
||||
|
||||
// The following should match VDS_FSOF_FLAGS as much as possible
|
||||
#define FP_FORCE 0x00000001
|
||||
#define FP_QUICK 0x00000002
|
||||
#define FP_COMPRESSION 0x00000004
|
||||
#define FP_DUPLICATE_METADATA 0x00000008
|
||||
#define FP_LARGE_FAT32 0x00010000
|
||||
#define FP_NO_BOOT 0x00020000
|
||||
|
||||
#define FILE_FLOPPY_DISKETTE 0x00000004
|
||||
|
||||
#define VDS_SET_ERROR(hr) do { if (hr == S_FALSE) hr = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE; FormatStatus = hr; SetLastError(hr); } while(0)
|
||||
|
||||
#if !defined(__MINGW32__)
|
||||
typedef enum _FSINFOCLASS {
|
||||
FileFsVolumeInformation = 1,
|
||||
|
@ -87,6 +101,25 @@ typedef interface IVdsDisk IVdsDisk;
|
|||
typedef interface IVdsAdvancedDisk IVdsAdvancedDisk;
|
||||
typedef interface IVdsAdviseSink IVdsAdviseSink;
|
||||
typedef interface IVdsAsync IVdsAsync;
|
||||
typedef interface IVdsVolume IVdsVolume;
|
||||
typedef interface IVdsVolumeMF3 IVdsVolumeMF3;
|
||||
|
||||
extern const IID CLSID_VdsLoader;
|
||||
extern const IID IID_IVdsServiceLoader;
|
||||
extern const IID IID_IVdsProvider;
|
||||
extern const IID IID_IVdsSwProvider;
|
||||
extern const IID IID_IVdsPack;
|
||||
extern const IID IID_IVdsDisk;
|
||||
extern const IID IID_IVdsAdvancedDisk;
|
||||
extern const IID IID_IVdsVolume;
|
||||
extern const IID IID_IVdsVolumeMF3;
|
||||
|
||||
#ifndef VDS_S_PROPERTIES_INCOMPLETE
|
||||
#define VDS_S_PROPERTIES_INCOMPLETE ((HRESULT)0x00042715L)
|
||||
#endif
|
||||
#ifndef VDS_E_OPERATION_PENDING
|
||||
#define VDS_E_OPERATION_PENDING ((HRESULT)0x80042409L)
|
||||
#endif
|
||||
|
||||
typedef struct IVdsServiceLoaderVtbl {
|
||||
HRESULT(STDMETHODCALLTYPE *QueryInterface)(__RPC__in IVdsServiceLoader *This, __RPC__in REFIID riid, _COM_Outptr_ void **ppvObject);
|
||||
|
@ -212,21 +245,77 @@ interface IVdsAdvancedDisk {
|
|||
CONST_VTBL struct IVdsAdvancedDiskVtbl *lpVtbl;
|
||||
};
|
||||
|
||||
#define IVdsServiceLoader_LoadService(This,pwszMachineName,ppService) (This)->lpVtbl->LoadService(This,pwszMachineName,ppService)
|
||||
typedef struct IVdsVolumeVtbl {
|
||||
HRESULT (STDMETHODCALLTYPE *QueryInterface)(__RPC__in IVdsVolume *This, __RPC__in REFIID riid, _COM_Outptr_ void **ppvObject);
|
||||
ULONG (STDMETHODCALLTYPE *AddRef)(__RPC__in IVdsVolume *This);
|
||||
ULONG (STDMETHODCALLTYPE *Release)(__RPC__in IVdsVolume *This);
|
||||
HRESULT (STDMETHODCALLTYPE *GetProperties)(__RPC__in IVdsVolume *This, __RPC__out VDS_VOLUME_PROP *pVolumeProperties);
|
||||
HRESULT (STDMETHODCALLTYPE *GetPack)(__RPC__in IVdsVolume *This, __RPC__deref_out_opt IVdsPack **ppPack);
|
||||
HRESULT (STDMETHODCALLTYPE *QueryPlexes)(__RPC__in IVdsVolume *This, __RPC__deref_out_opt IEnumVdsObject **ppEnum);
|
||||
HRESULT (STDMETHODCALLTYPE *Extend)(__RPC__in IVdsVolume *This, __RPC__in_ecount_full_opt(lNumberOfDisks) VDS_INPUT_DISK *pInputDiskArray, LONG lNumberOfDisks, __RPC__deref_out_opt IVdsAsync **ppAsync);
|
||||
HRESULT (STDMETHODCALLTYPE *Shrink)(__RPC__in IVdsVolume *This, ULONGLONG ullNumberOfBytesToRemove, __RPC__deref_out_opt IVdsAsync **ppAsync);
|
||||
HRESULT (STDMETHODCALLTYPE *AddPlex)(__RPC__in IVdsVolume *This, VDS_OBJECT_ID VolumeId,__RPC__deref_out_opt IVdsAsync **ppAsync);
|
||||
HRESULT (STDMETHODCALLTYPE *BreakPlex)(__RPC__in IVdsVolume *This, VDS_OBJECT_ID plexId, __RPC__deref_out_opt IVdsAsync **ppAsync);
|
||||
HRESULT (STDMETHODCALLTYPE *RemovePlex)(__RPC__in IVdsVolume *This, VDS_OBJECT_ID plexId, __RPC__deref_out_opt IVdsAsync **ppAsync);
|
||||
HRESULT (STDMETHODCALLTYPE *Delete)(__RPC__in IVdsVolume *This, BOOL bForce);
|
||||
HRESULT (STDMETHODCALLTYPE *SetFlags)(__RPC__in IVdsVolume *This, ULONG ulFlags, BOOL bRevertOnClose);
|
||||
HRESULT (STDMETHODCALLTYPE *ClearFlags)(__RPC__in IVdsVolume *This, ULONG ulFlags);
|
||||
} IVdsVolumeVtbl;
|
||||
interface IVdsVolume {
|
||||
CONST_VTBL struct IVdsVolumeVtbl *lpVtbl;
|
||||
};
|
||||
|
||||
typedef struct IVdsVolumeMF3Vtbl {
|
||||
HRESULT (STDMETHODCALLTYPE *QueryInterface)(__RPC__in IVdsVolumeMF3 *This, __RPC__in REFIID riid, _COM_Outptr_ void **ppvObject);
|
||||
ULONG (STDMETHODCALLTYPE *AddRef)(__RPC__in IVdsVolumeMF3 *This);
|
||||
ULONG (STDMETHODCALLTYPE *Release)(__RPC__in IVdsVolumeMF3 *This);
|
||||
HRESULT (STDMETHODCALLTYPE *QueryVolumeGuidPathnames)(__RPC__in IVdsVolumeMF3 *This, __RPC__deref_out_ecount_full_opt_string(*pulNumberOfPaths) LPWSTR **pwszPathArray, __RPC__out ULONG *pulNumberOfPaths);
|
||||
HRESULT (STDMETHODCALLTYPE *FormatEx2)(__RPC__in IVdsVolumeMF3 *This, __RPC__in_opt_string LPWSTR pwszFileSystemTypeName, USHORT usFileSystemRevision, ULONG ulDesiredUnitAllocationSize, __RPC__in_opt_string LPWSTR pwszLabel, DWORD Options, __RPC__deref_out_opt IVdsAsync **ppAsync);
|
||||
HRESULT (STDMETHODCALLTYPE *OfflineVolume)(__RPC__in IVdsVolumeMF3 *This);
|
||||
} IVdsVolumeMF3Vtbl;
|
||||
interface IVdsVolumeMF3 {
|
||||
CONST_VTBL struct IVdsVolumeMF3Vtbl *lpVtbl;
|
||||
};
|
||||
|
||||
typedef struct IVdsAsyncVtbl {
|
||||
HRESULT (STDMETHODCALLTYPE *QueryInterface)(__RPC__in IVdsAsync *This, __RPC__in REFIID riid, _COM_Outptr_ void **ppvObject);
|
||||
ULONG (STDMETHODCALLTYPE *AddRef)(__RPC__in IVdsAsync *This);
|
||||
ULONG (STDMETHODCALLTYPE *Release)(__RPC__in IVdsAsync *This);
|
||||
HRESULT (STDMETHODCALLTYPE *Cancel)(__RPC__in IVdsAsync *This);
|
||||
HRESULT (STDMETHODCALLTYPE *Wait)(__RPC__in IVdsAsync *This, __RPC__out HRESULT *pHrResult, __RPC__out VDS_ASYNC_OUTPUT *pAsyncOut);
|
||||
HRESULT (STDMETHODCALLTYPE *QueryStatus)(__RPC__in IVdsAsync *This, __RPC__out HRESULT *pHrResult, __RPC__out ULONG *pulPercentCompleted);
|
||||
} IVdsAsyncVtbl;
|
||||
interface IVdsAsync {
|
||||
CONST_VTBL struct IVdsAsyncVtbl *lpVtbl;
|
||||
};
|
||||
|
||||
#define IVdsServiceLoader_LoadService(This, pwszMachineName, ppService) (This)->lpVtbl->LoadService(This, pwszMachineName, ppService)
|
||||
#define IVdsServiceLoader_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IVdsService_QueryProviders(This,masks,ppEnum) (This)->lpVtbl->QueryProviders(This,masks,ppEnum)
|
||||
#define IVdsSwProvider_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
|
||||
#define IVdsService_QueryProviders(This, masks, ppEnum) (This)->lpVtbl->QueryProviders(This, masks, ppEnum)
|
||||
#define IVdsSwProvider_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
|
||||
#define IVdsProvider_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IVdsSwProvider_QueryPacks(This,ppEnum) (This)->lpVtbl->QueryPacks(This,ppEnum)
|
||||
#define IVdsSwProvider_QueryPacks(This, ppEnum) (This)->lpVtbl->QueryPacks(This, ppEnum)
|
||||
#define IVdsSwProvider_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IVdsPack_QueryDisks(This,ppEnum) (This)->lpVtbl->QueryDisks(This,ppEnum)
|
||||
#define IVdsDisk_GetProperties(This,pDiskProperties) (This)->lpVtbl->GetProperties(This,pDiskProperties)
|
||||
#define IVdsPack_QueryDisks(This, ppEnum) (This)->lpVtbl->QueryDisks(This, ppEnum)
|
||||
#define IVdsDisk_GetProperties(This, pDiskProperties) (This)->lpVtbl->GetProperties(This, pDiskProperties)
|
||||
#define IVdsDisk_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IVdsDisk_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
|
||||
#define IVdsAdvancedDisk_QueryPartitions(This,ppPartitionPropArray,plNumberOfPartitions) (This)->lpVtbl->QueryPartitions(This,ppPartitionPropArray,plNumberOfPartitions)
|
||||
#define IVdsAdvancedDisk_DeletePartition(This,ullOffset,bForce,bForceProtected) (This)->lpVtbl->DeletePartition(This,ullOffset,bForce,bForceProtected)
|
||||
#define IVdsDisk_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
|
||||
#define IVdsAdvancedDisk_QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions) (This)->lpVtbl->QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions)
|
||||
#define IVdsAdvancedDisk_DeletePartition(This, ullOffset, bForce, bForceProtected) (This)->lpVtbl->DeletePartition(This, ullOffset, bForce, bForceProtected)
|
||||
#define IVdsAdvancedDisk_Clean(This, bForce, bForceOEM, bFullClean, ppAsync) (This)->lpVtbl->Clean(This, bForce, bForceOEM, bFullClean, ppAsync)
|
||||
#define IVdsAdvancedDisk_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IEnumVdsObject_Next(This,celt,ppObjectArray,pcFetched) (This)->lpVtbl->Next(This,celt,ppObjectArray,pcFetched)
|
||||
#define IEnumVdsObject_Next(This, celt, ppObjectArray, pcFetched) (This)->lpVtbl->Next(This, celt, ppObjectArray, pcFetched)
|
||||
#define IVdsPack_QueryVolumes(This, ppEnum) (This)->lpVtbl->QueryVolumes(This, ppEnum)
|
||||
#define IVdsVolume_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
|
||||
#define IVdsVolume_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IVdsVolumeMF3_QueryVolumeGuidPathnames(This, pwszPathArray, pulNumberOfPaths) (This)->lpVtbl->QueryVolumeGuidPathnames(This,pwszPathArray,pulNumberOfPaths)
|
||||
#define IVdsVolumeMF3_FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync) (This)->lpVtbl->FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync)
|
||||
#define IVdsVolumeMF3_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IVdsVolume_GetProperties(This, pVolumeProperties) (This)->lpVtbl->GetProperties(This,pVolumeProperties)
|
||||
#define IVdsAsync_Cancel(This) (This)->lpVtbl->Cancel(This)
|
||||
#define IVdsAsync_QueryStatus(This,pHrResult,pulPercentCompleted) (This)->lpVtbl->QueryStatus(This,pHrResult,pulPercentCompleted)
|
||||
#define IVdsAsync_Wait(This,pHrResult,pAsyncOut) (This)->lpVtbl->Wait(This,pHrResult,pAsyncOut)
|
||||
#define IVdsAsync_Release(This) (This)->lpVtbl->Release(This)
|
||||
#endif
|
||||
|
||||
static __inline BOOL UnlockDrive(HANDLE hDrive) {
|
||||
|
@ -256,16 +345,17 @@ typedef struct {
|
|||
} RUFUS_DRIVE_INFO;
|
||||
extern RUFUS_DRIVE_INFO SelectedDrive;
|
||||
extern uint64_t persistence_size;
|
||||
extern DWORD partition_index[3];
|
||||
|
||||
BOOL SetAutoMount(BOOL enable);
|
||||
BOOL GetAutoMount(BOOL* enabled);
|
||||
char* GetPhysicalName(DWORD DriveIndex);
|
||||
char* GetPartitionName(DWORD DriveIndex, DWORD PartitionNumber);
|
||||
char* GetPartitionName(DWORD DriveIndex, DWORD PartitionIndex);
|
||||
BOOL DeletePartitions(DWORD DriveIndex);
|
||||
HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare);
|
||||
char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent);
|
||||
BOOL WaitForLogical(DWORD DriveIndex);
|
||||
HANDLE GetLogicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare);
|
||||
char* GetLogicalName(DWORD DriveIndex, DWORD PartitionIndex, BOOL bKeepTrailingBackslash, BOOL bSilent);
|
||||
BOOL WaitForLogical(DWORD DriveIndex, DWORD PartitionIndex);
|
||||
HANDLE GetLogicalHandle(DWORD DriveIndex, DWORD PartitionIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare);
|
||||
int GetDriveNumber(HANDLE hDrive, char* path);
|
||||
BOOL GetDriveLetters(DWORD DriveIndex, char* drive_letters);
|
||||
UINT GetDriveTypeFromIndex(DWORD DriveIndex);
|
||||
|
@ -279,7 +369,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
|
|||
BOOL UnmountVolume(HANDLE hDrive);
|
||||
BOOL MountVolume(char* drive_name, char *drive_guid);
|
||||
BOOL AltUnmountVolume(const char* drive_name);
|
||||
char* AltMountVolume(const char* drive_name, uint8_t part_nr);
|
||||
char* AltMountVolume(DWORD DriveIndex, DWORD PartitionIndex);
|
||||
BOOL RemountVolume(char* drive_name);
|
||||
BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, uint8_t extra_partitions);
|
||||
BOOL InitializeDisk(HANDLE hDrive);
|
||||
|
|
760
src/format.c
760
src/format.c
File diff suppressed because it is too large
Load diff
|
@ -85,6 +85,10 @@ static __inline char* wchar_to_utf8(const wchar_t* wstr)
|
|||
int size = 0;
|
||||
char* str = NULL;
|
||||
|
||||
// Convert the empty string too
|
||||
if (wstr[0] == 0)
|
||||
return calloc(1, 1);
|
||||
|
||||
// Find out the size we need to allocate for our converted string
|
||||
size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
|
||||
if (size <= 1) // An empty string would be size 1
|
||||
|
@ -113,6 +117,10 @@ static __inline wchar_t* utf8_to_wchar(const char* str)
|
|||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
// Convert the empty string too
|
||||
if (str[0] == 0)
|
||||
return calloc(1, sizeof(wchar_t));
|
||||
|
||||
// Find out the size we need to allocate for our converted string
|
||||
size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
||||
if (size <= 1) // An empty string would be size 1
|
||||
|
|
30
src/rufus.c
30
src/rufus.c
|
@ -51,7 +51,6 @@
|
|||
#include "../res/grub2/grub2_version.h"
|
||||
|
||||
static const char* cmdline_hogger = "rufus.com";
|
||||
static const char* FileSystemLabel[FS_MAX] = { "FAT", "FAT32", "NTFS", "UDF", "exFAT", "ReFS" };
|
||||
static const char* ep_reg = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer";
|
||||
static const char* vs_reg = "Software\\Microsoft\\VisualStudio";
|
||||
static BOOL existing_key = FALSE; // For LGP set/restore
|
||||
|
@ -84,6 +83,7 @@ extern long grub2_len;
|
|||
extern char* szStatusMessage;
|
||||
extern const char* old_c32_name[NB_OLD_C32];
|
||||
extern const char* cert_name[3];
|
||||
extern const char* FileSystemLabel[FS_MAX];
|
||||
|
||||
/*
|
||||
* Globals
|
||||
|
@ -108,7 +108,7 @@ BOOL enable_HDDs = FALSE, enable_ntfs_compression = FALSE, no_confirmation_on_ca
|
|||
BOOL advanced_mode_device, advanced_mode_format, allow_dual_uefi_bios, detect_fakes, enable_vmdk, force_large_fat32, usb_debug;
|
||||
BOOL use_fake_units, preserve_timestamps = FALSE, fast_zeroing = FALSE, app_changed_size = FALSE;
|
||||
BOOL zero_drive = FALSE, list_non_usb_removable_drives = FALSE, enable_file_indexing, large_drive = FALSE;
|
||||
BOOL write_as_image = FALSE, installed_uefi_ntfs = FALSE, enable_fido = FALSE;
|
||||
BOOL write_as_image = FALSE, installed_uefi_ntfs = FALSE, enable_fido = FALSE, use_vds = FALSE;
|
||||
float fScale = 1.0f;
|
||||
int dialog_showing = 0, selection_default = BT_IMAGE, windows_to_go_selection = 0, persistence_unit_selection = -1;
|
||||
int default_fs, fs_type, boot_type, partition_type, target_type; // file system, boot type, partition type, target type
|
||||
|
@ -121,7 +121,7 @@ char msgbox[1024], msgbox_title[32], *ini_file = NULL, *image_path = NULL, *shor
|
|||
char image_option_txt[128], *fido_url = NULL;
|
||||
StrArray DriveID, DriveLabel, DriveHub, BlockingProcess, ImageList;
|
||||
// Number of steps for each FS for FCC_STRUCTURE_PROGRESS
|
||||
const int nb_steps[FS_MAX] = { 5, 5, 12, 1, 10 };
|
||||
const int nb_steps[FS_MAX] = { 5, 5, 12, 1, 10, 1, 1, 1, 1 };
|
||||
const char* flash_type[BADLOCKS_PATTERN_TYPES] = { "SLC", "MLC", "TLC" };
|
||||
|
||||
// TODO: Remember to update copyright year in stdlg's AboutCallback() WM_INITDIALOG,
|
||||
|
@ -1859,10 +1859,6 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#ifdef RUFUS_TEST
|
||||
extern BOOL FormatExtFs(const char* label, uint32_t version);
|
||||
#endif
|
||||
/*
|
||||
* Main dialog callback
|
||||
*/
|
||||
|
@ -1898,7 +1894,15 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
case WM_COMMAND:
|
||||
#ifdef RUFUS_TEST
|
||||
if (LOWORD(wParam) == IDC_TEST) {
|
||||
FormatExtFs("casper-rw", 3);
|
||||
// uprintf(" IID_IVdsVolume: %s", GuidToString(&IID_IVdsVolume));
|
||||
// uprintf(" IID_IVdsVolumeMF3: %s", GuidToString(&IID_IVdsVolumeMF3));
|
||||
nDeviceIndex = ComboBox_GetCurSel(hDeviceList);
|
||||
// AltMountVolume2("G:", 3);
|
||||
AltMountVolume((DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex), 3);
|
||||
// AltUnmountVolume("P:");
|
||||
// uprintf("%s", GetLogicalName((DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex), 0, FALSE, FALSE));
|
||||
// uprintf("%s", GetLogicalName((DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex), 1, FALSE, FALSE));
|
||||
// uprintf("%s", GetLogicalName((DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex), 2, FALSE, FALSE));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -3026,6 +3030,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
advanced_mode_format = ReadSettingBool(SETTING_ADVANCED_MODE_FORMAT);
|
||||
preserve_timestamps = ReadSettingBool(SETTING_PRESERVE_TIMESTAMPS);
|
||||
use_fake_units = !ReadSettingBool(SETTING_USE_PROPER_SIZE_UNITS);
|
||||
use_vds = ReadSettingBool(SETTING_USE_VDS);
|
||||
usb_debug = ReadSettingBool(SETTING_ENABLE_USB_DEBUG);
|
||||
detect_fakes = !ReadSettingBool(SETTING_DISABLE_FAKE_DRIVES_CHECK);
|
||||
allow_dual_uefi_bios = ReadSettingBool(SETTING_ENABLE_WIN_DUAL_EFI_BIOS);
|
||||
|
@ -3198,7 +3203,7 @@ relaunch:
|
|||
|
||||
// Do our own event processing and process "magic" commands
|
||||
while(GetMessage(&msg, NULL, 0, 0)) {
|
||||
// ** ***** **** ** ***** ****
|
||||
// ** ***** **** ** **********
|
||||
// .,ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
|
||||
// Ctrl-A => Select the log data
|
||||
|
@ -3357,6 +3362,13 @@ relaunch:
|
|||
GetDevices(0);
|
||||
continue;
|
||||
}
|
||||
// Alt-V => Use VDS facilities for formatting
|
||||
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'V')) {
|
||||
use_vds = !use_vds;
|
||||
WriteSettingBool(SETTING_USE_VDS, use_vds);
|
||||
PrintStatusTimeout("VDS", use_vds);
|
||||
continue;
|
||||
}
|
||||
// Alt-W => Enable VMWare disk detection
|
||||
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'W')) {
|
||||
enable_vmdk = !enable_vmdk;
|
||||
|
|
15
src/rufus.h
15
src/rufus.h
|
@ -22,13 +22,16 @@
|
|||
#if defined(_MSC_VER)
|
||||
// Disable some VS Code Analysis warnings
|
||||
#pragma warning(disable: 4996) // Ignore deprecated
|
||||
#pragma warning(disable: 28159) // I'll keep using GetVersionEx(), thank you very much!
|
||||
#pragma warning(disable: 6258) // I know what I'm using TerminateThread for
|
||||
#pragma warning(disable: 26451) // Stop bugging me with casts already!
|
||||
#pragma warning(disable: 28159) // I'll keep using GetVersionEx(), thank you very much...
|
||||
#endif
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Features not ready for prime time and that may *DESTROY* your data - USE AT YOUR OWN RISKS! */
|
||||
/*
|
||||
* Features not ready for prime time and that may *DESTROY* your data - USE AT YOUR OWN RISKS!
|
||||
*/
|
||||
//#define RUFUS_TEST
|
||||
|
||||
#define APPLICATION_NAME "Rufus"
|
||||
|
@ -67,7 +70,7 @@
|
|||
#define MAX_LOG_SIZE 0x7FFFFFFE
|
||||
#define MAX_REFRESH 25 // How long we should wait to refresh UI elements (in ms)
|
||||
#define MAX_GUID_STRING_LENGTH 40
|
||||
#define MAX_GPT_PARTITIONS 128
|
||||
#define MAX_PARTITIONS 16 // Maximum number of partitions we handle
|
||||
#define MAX_SECTORS_TO_CLEAR 128 // nb sectors to zap when clearing the MBR/GPT (must be >34)
|
||||
#define MAX_WININST 4 // Max number of install[.wim|.esd] we can handle on an image
|
||||
#define MBR_UEFI_MARKER 0x49464555 // 'U', 'E', 'F', 'I', as a 32 bit little endian longword
|
||||
|
@ -80,7 +83,6 @@
|
|||
#define CHECK_DRIVE_TIMEOUT 2000
|
||||
#define MARQUEE_TIMER_REFRESH 10 // Time between progress bar marquee refreshes, in ms
|
||||
#define FS_DEFAULT FS_FAT32
|
||||
#define CASPER_PARTITION_DEFAULT 2
|
||||
#define SINGLE_CLUSTERSIZE_DEFAULT 0x00000100
|
||||
#define BADLOCKS_PATTERN_TYPES 3
|
||||
#define BADBLOCK_PATTERN_COUNT 4
|
||||
|
@ -118,7 +120,7 @@
|
|||
#endif
|
||||
#define IsChecked(CheckBox_ID) (IsDlgButtonChecked(hMainDialog, CheckBox_ID) == BST_CHECKED)
|
||||
#define MB_IS_RTL (right_to_left_mode?MB_RTLREADING|MB_RIGHT:0)
|
||||
#define CHECK_FOR_USER_CANCEL if (IS_ERROR(FormatStatus)) goto out
|
||||
#define CHECK_FOR_USER_CANCEL if (IS_ERROR(FormatStatus) && (SCODE_CODE(FormatStatus) == ERROR_CANCELLED)) goto out
|
||||
// Bit masks used for the display of additional image options in the UI
|
||||
#define IMOP_WINTOGO 0x01
|
||||
#define IMOP_PERSISTENCE 0x02
|
||||
|
@ -243,6 +245,9 @@ enum fs_type {
|
|||
FS_UDF,
|
||||
FS_EXFAT,
|
||||
FS_REFS,
|
||||
FS_EXT2,
|
||||
FS_EXT3,
|
||||
FS_EXT4,
|
||||
FS_MAX
|
||||
};
|
||||
|
||||
|
|
10
src/rufus.rc
10
src/rufus.rc
|
@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
|||
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
EXSTYLE WS_EX_ACCEPTFILES
|
||||
CAPTION "Rufus 3.6.1527"
|
||||
CAPTION "Rufus 3.6.1528"
|
||||
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
||||
BEGIN
|
||||
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
||||
|
@ -394,8 +394,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,6,1527,0
|
||||
PRODUCTVERSION 3,6,1527,0
|
||||
FILEVERSION 3,6,1528,0
|
||||
PRODUCTVERSION 3,6,1528,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -413,13 +413,13 @@ BEGIN
|
|||
VALUE "Comments", "https://akeo.ie"
|
||||
VALUE "CompanyName", "Akeo Consulting"
|
||||
VALUE "FileDescription", "Rufus"
|
||||
VALUE "FileVersion", "3.6.1527"
|
||||
VALUE "FileVersion", "3.6.1528"
|
||||
VALUE "InternalName", "Rufus"
|
||||
VALUE "LegalCopyright", "© 2011-2019 Pete Batard (GPL v3)"
|
||||
VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html"
|
||||
VALUE "OriginalFilename", "rufus-3.6.exe"
|
||||
VALUE "ProductName", "Rufus"
|
||||
VALUE "ProductVersion", "3.6.1527"
|
||||
VALUE "ProductVersion", "3.6.1528"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
@ -43,8 +43,10 @@ extern char* ini_file;
|
|||
#define SETTING_LAST_UPDATE "LastUpdateCheck"
|
||||
#define SETTING_LOCALE "Locale"
|
||||
#define SETTING_UPDATE_INTERVAL "UpdateCheckInterval"
|
||||
#define SETTING_USE_EXTFS_VERSION "UseExtFsVersion"
|
||||
#define SETTING_USE_EXT_VERSION "UseExtVersion"
|
||||
#define SETTING_USE_PROPER_SIZE_UNITS "UseProperSizeUnits"
|
||||
#define SETTING_USE_UDF_VERSION "UseUdfVersion"
|
||||
#define SETTING_USE_VDS "UseVds"
|
||||
#define SETTING_PRESERVE_TIMESTAMPS "PreserveTimestamps"
|
||||
#define SETTING_VERBOSE_UPDATES "VerboseUpdateCheck"
|
||||
|
||||
|
|
|
@ -272,7 +272,7 @@ const char* _StrError(DWORD error_code)
|
|||
return lmprintf(MSG_050);
|
||||
}
|
||||
if (SCODE_FACILITY(error_code) != FACILITY_STORAGE) {
|
||||
uprintf("StrError: non storage - %08X (%X)\n", error_code, SCODE_FACILITY(error_code));
|
||||
// uprintf("StrError: non storage - %08X (%X)\n", error_code, SCODE_FACILITY(error_code));
|
||||
SetLastError(error_code);
|
||||
return WindowsErrorString();
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int file_system)
|
|||
* weird reason.the Syslinux install process *MUST* have FILE_SHARE_WRITE
|
||||
* on the volume, or else creating 'ldlinux.sys' will fail...
|
||||
*/
|
||||
d_handle = GetLogicalHandle(drive_index, FALSE, TRUE, TRUE);
|
||||
d_handle = GetLogicalHandle(drive_index, 0, FALSE, TRUE, TRUE);
|
||||
if ((d_handle == INVALID_HANDLE_VALUE) || (d_handle == NULL)) {
|
||||
uprintf("Could open volume for Syslinux installation");
|
||||
goto out;
|
||||
|
|
15
src/ui.c
15
src/ui.c
|
@ -43,7 +43,7 @@
|
|||
|
||||
UINT_PTR UM_LANGUAGE_MENU_MAX = UM_LANGUAGE_MENU;
|
||||
HIMAGELIST hUpImageList, hDownImageList;
|
||||
extern BOOL enable_fido;
|
||||
extern BOOL enable_fido, use_vds;
|
||||
int advanced_device_section_height, advanced_format_section_height;
|
||||
// (empty) check box width, (empty) drop down width, button height (for and without dropdown match)
|
||||
int cbw, ddw, ddbh = 0, bh = 0;
|
||||
|
@ -1168,20 +1168,21 @@ void InitProgress(BOOL bOnlyFormat)
|
|||
nb_slots[OP_ZERO_MBR] = 1;
|
||||
nb_slots[OP_PARTITION] = 1;
|
||||
nb_slots[OP_FIX_MBR] = 1;
|
||||
nb_slots[OP_CREATE_FS] =
|
||||
nb_slots[OP_CREATE_FS] = (use_vds) ? 2 :
|
||||
nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))];
|
||||
// So, yeah, if you're doing slow format, or using Large FAT32, and have persistence, you'll see
|
||||
// the progress bar revert during format on account that we reuse the same operation for both
|
||||
// partitions. Maybe one day I'll be bothered to handle two separate OP_FORMAT ops...
|
||||
if ((!IsChecked(IDC_QUICK_FORMAT)) || (persistence_size != 0)
|
||||
|| ((fs_type == FS_FAT32) && ((SelectedDrive.DiskSize >= LARGE_FAT32_SIZE) || (force_large_fat32)))) {
|
||||
if ((!IsChecked(IDC_QUICK_FORMAT)) || (persistence_size != 0) ||
|
||||
((fs_type == FS_FAT32) && ((SelectedDrive.DiskSize >= LARGE_FAT32_SIZE) || (force_large_fat32)))) {
|
||||
nb_slots[OP_FORMAT] = -1;
|
||||
nb_slots[OP_CREATE_FS] = 0;
|
||||
}
|
||||
nb_slots[OP_FINALIZE] = ((selection_default == BT_IMAGE) && (fs_type == FS_NTFS)) ? 3 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i<OP_MAX; i++) {
|
||||
for (i = 0; i < OP_MAX; i++) {
|
||||
if (nb_slots[i] > 0) {
|
||||
slots_discrete += nb_slots[i] * 1.0f;
|
||||
}
|
||||
|
@ -1190,7 +1191,7 @@ void InitProgress(BOOL bOnlyFormat)
|
|||
}
|
||||
}
|
||||
|
||||
for (i = 0; i<OP_MAX; i++) {
|
||||
for (i = 0; i < OP_MAX; i++) {
|
||||
if (nb_slots[i] == 0) {
|
||||
slot_end[i + 1] = last_end;
|
||||
} else if (nb_slots[i] > 0) {
|
||||
|
@ -1203,7 +1204,7 @@ void InitProgress(BOOL bOnlyFormat)
|
|||
|
||||
// If there's no analog, adjust our discrete ends to fill the whole bar
|
||||
if (slots_analog == 0.0f) {
|
||||
for (i = 0; i<OP_MAX; i++) {
|
||||
for (i = 0; i < OP_MAX; i++) {
|
||||
slot_end[i + 1] *= 100.0f / slots_discrete;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue