1
1
Fork 0
mirror of https://github.com/pbatard/rufus.git synced 2024-08-14 23:57:05 +00:00

[misc] refactor partition creation

This commit is contained in:
Pete Batard 2024-02-08 14:17:03 +00:00
parent 164d4b0ab0
commit 0f23c47184
No known key found for this signature in database
GPG key ID: 38E0CF5E69EDD671
6 changed files with 229 additions and 247 deletions

View file

@ -74,7 +74,7 @@ PF_TYPE_DECL(NTAPI, NTSTATUS, NtQueryVolumeInformationFile, (HANDLE, PIO_STATUS_
RUFUS_DRIVE_INFO SelectedDrive; RUFUS_DRIVE_INFO SelectedDrive;
extern BOOL write_as_esp; extern BOOL write_as_esp;
extern windows_version_t WindowsVersion; extern windows_version_t WindowsVersion;
uint64_t partition_offset[PI_MAX]; int partition_index[PI_MAX];
uint64_t persistence_size = 0; uint64_t persistence_size = 0;
/* /*
@ -392,7 +392,7 @@ char* AltGetLogicalName(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bKeepTr
if (PartitionOffset == 0) { if (PartitionOffset == 0) {
i = 0; i = 0;
} else if (matching_drive) { } else if (matching_drive) {
for (i = 0; (i < MAX_PARTITIONS) && (PartitionOffset != SelectedDrive.PartitionOffset[i]); i++); for (i = 0; (i < MAX_PARTITIONS) && (PartitionOffset != SelectedDrive.Partition[i].Offset); i++);
if (i >= MAX_PARTITIONS) { if (i >= MAX_PARTITIONS) {
suprintf("Error: Could not find a partition at offset %lld on this disk", PartitionOffset); suprintf("Error: Could not find a partition at offset %lld on this disk", PartitionOffset);
goto out; goto out;
@ -428,11 +428,11 @@ char* GetExtPartitionName(DWORD DriveIndex, uint64_t PartitionOffset)
if (DriveIndex != SelectedDrive.DeviceNumber) if (DriveIndex != SelectedDrive.DeviceNumber)
goto out; goto out;
CheckDriveIndex(DriveIndex); CheckDriveIndex(DriveIndex);
for (i = 0; (i < MAX_PARTITIONS) && (PartitionOffset != SelectedDrive.PartitionOffset[i]); i++); for (i = 0; (i < MAX_PARTITIONS) && (PartitionOffset != SelectedDrive.Partition[i].Offset); i++);
if (i >= MAX_PARTITIONS) if (i >= MAX_PARTITIONS)
goto out; goto out;
static_sprintf(volume_name, "\\\\.\\PhysicalDrive%lu %I64u %I64u", DriveIndex, static_sprintf(volume_name, "\\\\.\\PhysicalDrive%lu %I64u %I64u", DriveIndex,
SelectedDrive.PartitionOffset[i], SelectedDrive.PartitionSize[i]); SelectedDrive.Partition[i].Offset, SelectedDrive.Partition[i].Size);
ret = safe_strdup(volume_name); ret = safe_strdup(volume_name);
out: out:
return ret; return ret;
@ -1868,8 +1868,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
return FALSE; return FALSE;
SelectedDrive.nPartitions = 0; SelectedDrive.nPartitions = 0;
memset(SelectedDrive.PartitionOffset, 0, sizeof(SelectedDrive.PartitionOffset)); memset(SelectedDrive.Partition, 0, sizeof(SelectedDrive.Partition));
memset(SelectedDrive.PartitionSize, 0, sizeof(SelectedDrive.PartitionSize));
// Populate the filesystem data // Populate the filesystem data
FileSystemName[0] = 0; FileSystemName[0] = 0;
volume_name = GetLogicalName(DriveIndex, 0, TRUE, FALSE); volume_name = GetLogicalName(DriveIndex, 0, TRUE, FALSE);
@ -1961,8 +1960,8 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
} }
} }
if (i < MAX_PARTITIONS) { if (i < MAX_PARTITIONS) {
SelectedDrive.PartitionOffset[i] = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart; SelectedDrive.Partition[i].Offset = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart;
SelectedDrive.PartitionSize[i] = DriveLayout->PartitionEntry[i].PartitionLength.QuadPart; SelectedDrive.Partition[i].Size = DriveLayout->PartitionEntry[i].PartitionLength.QuadPart;
} }
suprintf(" Type: %s (0x%02x)\r\n Detected File System: %s\r\n" suprintf(" Type: %s (0x%02x)\r\n Detected File System: %s\r\n"
" Size: %s (%lld bytes)\r\n Start Sector: %lld, Boot: %s", " Size: %s (%lld bytes)\r\n Start Sector: %lld, Boot: %s",
@ -1992,12 +1991,13 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
DriveLayout->Gpt.MaxPartitionCount, DriveLayout->Gpt.StartingUsableOffset.QuadPart, DriveLayout->Gpt.UsableLength.QuadPart); DriveLayout->Gpt.MaxPartitionCount, DriveLayout->Gpt.StartingUsableOffset.QuadPart, DriveLayout->Gpt.UsableLength.QuadPart);
for (i = 0; i < DriveLayout->PartitionCount; i++) { for (i = 0; i < DriveLayout->PartitionCount; i++) {
if (i < MAX_PARTITIONS) { if (i < MAX_PARTITIONS) {
SelectedDrive.PartitionOffset[i] = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart; SelectedDrive.Partition[i].Offset = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart;
SelectedDrive.PartitionSize[i] = DriveLayout->PartitionEntry[i].PartitionLength.QuadPart; SelectedDrive.Partition[i].Size = DriveLayout->PartitionEntry[i].PartitionLength.QuadPart;
wcscpy(SelectedDrive.Partition[i].Name, DriveLayout->PartitionEntry[i].Gpt.Name);
} }
SelectedDrive.nPartitions++; SelectedDrive.nPartitions++;
isUefiNtfs = (wcscmp(DriveLayout->PartitionEntry[i].Gpt.Name, L"UEFI:NTFS") == 0); isUefiNtfs = (wcscmp(DriveLayout->PartitionEntry[i].Gpt.Name, L"UEFI:NTFS") == 0);
suprintf("Partition %d%s:\r\n Type: %s", i+1, isUefiNtfs ? " (UEFI:NTFS)" : "", suprintf("Partition %d%s:\r\n Type: %s", i + 1, isUefiNtfs ? " (UEFI:NTFS)" : "",
GetGPTPartitionType(&DriveLayout->PartitionEntry[i].Gpt.PartitionType)); GetGPTPartitionType(&DriveLayout->PartitionEntry[i].Gpt.PartitionType));
if (DriveLayout->PartitionEntry[i].Gpt.Name[0] != 0) if (DriveLayout->PartitionEntry[i].Gpt.Name[0] != 0)
suprintf(" Name: '%S'", DriveLayout->PartitionEntry[i].Gpt.Name); suprintf(" Name: '%S'", DriveLayout->PartitionEntry[i].Gpt.Name);
@ -2232,15 +2232,17 @@ BOOL RemountVolume(char* drive_name, BOOL bSilent)
* (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.
*/ */
static BOOL ClearPartition(HANDLE hDrive, LARGE_INTEGER offset, DWORD size) static BOOL ClearPartition(HANDLE hDrive, uint64_t offset, DWORD size)
{ {
BOOL r = FALSE; BOOL r = FALSE;
uint8_t* buffer = calloc(size, 1); uint8_t* buffer = calloc(size, 1);
LARGE_INTEGER li_offset;
if (buffer == NULL) if (buffer == NULL)
return FALSE; return FALSE;
if (!SetFilePointerEx(hDrive, offset, NULL, FILE_BEGIN)) { li_offset.QuadPart = offset;
if (!SetFilePointerEx(hDrive, li_offset, NULL, FILE_BEGIN)) {
free(buffer); free(buffer);
return FALSE; return FALSE;
} }
@ -2260,17 +2262,14 @@ static BOOL ClearPartition(HANDLE hDrive, LARGE_INTEGER offset, DWORD size)
BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, uint8_t extra_partitions) 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 char* PartitionTypeName[] = { "MBR", "GPT", "SFD" };
const wchar_t *extra_part_name = L"", *main_part_name = write_as_esp ? L"EFI System Partition" : L"Main Data Partition";
const LONGLONG main_part_size = write_as_esp ? MAX_ISO_TO_ESP_SIZE * MB : SelectedDrive.DiskSize;
const LONGLONG bytes_per_track = ((LONGLONG)SelectedDrive.SectorsPerTrack) * SelectedDrive.SectorSize; const LONGLONG bytes_per_track = ((LONGLONG)SelectedDrive.SectorsPerTrack) * SelectedDrive.SectorSize;
const DWORD size_to_clear = MAX_SECTORS_TO_CLEAR * SelectedDrive.SectorSize; const DWORD size_to_clear = MAX_SECTORS_TO_CLEAR * SelectedDrive.SectorSize;
uint8_t* buffer; uint8_t* buffer;
uint64_t last_offset = SelectedDrive.DiskSize;
size_t uefi_ntfs_size = 0; size_t uefi_ntfs_size = 0;
DWORD pi = 0, mi, i, size, bufsize;
CREATE_DISK CreateDisk = { PARTITION_STYLE_RAW, { { 0 } } }; CREATE_DISK CreateDisk = { PARTITION_STYLE_RAW, { { 0 } } };
DRIVE_LAYOUT_INFORMATION_EX4 DriveLayoutEx = { 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;
// Go for a 260 MB sized ESP by default to keep everyone happy, including 4K sector users: // Go for a 260 MB sized ESP by default to keep everyone happy, including 4K sector users:
// https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/configure-uefigpt-based-hard-drive-partitions // https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/configure-uefigpt-based-hard-drive-partitions
// and folks using MacOS: https://github.com/pbatard/rufus/issues/979 // and folks using MacOS: https://github.com/pbatard/rufus/issues/979
@ -2288,17 +2287,19 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
if (extra_partitions & XP_UEFI_NTFS) { if (extra_partitions & XP_UEFI_NTFS) {
uefi_ntfs_size = GetResourceSize(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_NTFS), _RT_RCDATA, "uefi-ntfs.img"); uefi_ntfs_size = GetResourceSize(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_NTFS), _RT_RCDATA, "uefi-ntfs.img");
if (uefi_ntfs_size == 0) if (uefi_ntfs_size == 0) {
uprintf("Could not access embedded 'uefi-ntfs.img'");
return FALSE; return FALSE;
}
} }
memset(partition_offset, 0, sizeof(partition_offset));
memset(SelectedDrive.PartitionOffset, 0, sizeof(SelectedDrive.PartitionOffset));
memset(SelectedDrive.PartitionSize, 0, sizeof(SelectedDrive.PartitionSize));
// Compute the start offset of our first partition memset(partition_index, 0, sizeof(partition_index));
memset(SelectedDrive.Partition, 0, sizeof(SelectedDrive.Partition));
// Compute the starting offset of the first partition
if ((partition_style == PARTITION_STYLE_GPT) || (!IsChecked(IDC_OLD_BIOS_FIXES))) { if ((partition_style == PARTITION_STYLE_GPT) || (!IsChecked(IDC_OLD_BIOS_FIXES))) {
// Go with the MS 1 MB wastage at the beginning... // Go with the MS 1 MB wastage at the beginning...
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = MB; SelectedDrive.Partition[pi].Offset = 1 * MB;
} else { } else {
// Some folks appear to think that 'Fixes for old BIOSes' is some kind of magic // Some folks appear to think that 'Fixes for old BIOSes' is some kind of magic
// wand and are adamant to try to apply them when creating *MODERN* VHD drives. // wand and are adamant to try to apply them when creating *MODERN* VHD drives.
@ -2308,11 +2309,10 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
// CHS sizes that IBM imparted upon us. Long story short, we now align to a // CHS sizes that IBM imparted upon us. Long story short, we now align to a
// cylinder size that is itself aligned to the cluster size. // cylinder size that is itself aligned to the cluster size.
// If this actually breaks old systems, please send your complaints to IBM. // If this actually breaks old systems, please send your complaints to IBM.
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = SelectedDrive.Partition[pi].Offset = HI_ALIGN_X_TO_Y(bytes_per_track, ClusterSize);
((bytes_per_track + (ClusterSize - 1)) / ClusterSize) * ClusterSize;
// GRUB2 no longer fits in the usual 31½ KB that the above computation provides // GRUB2 no longer fits in the usual 31½ KB that the above computation provides
// so just unconditionally double that size and get on with it. // so just unconditionally double that size and get on with it.
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart *= 2; SelectedDrive.Partition[pi].Offset *= 2;
} }
// Having the ESP up front may help (and is the Microsoft recommended way) but this // Having the ESP up front may help (and is the Microsoft recommended way) but this
@ -2321,22 +2321,16 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
if (((SelectedDrive.MediaType == FixedMedia) || (WindowsVersion.BuildNumber > 15000)) && if (((SelectedDrive.MediaType == FixedMedia) || (WindowsVersion.BuildNumber > 15000)) &&
(extra_partitions & XP_ESP)) { (extra_partitions & XP_ESP)) {
assert(partition_style == PARTITION_STYLE_GPT); assert(partition_style == PARTITION_STYLE_GPT);
extra_part_name = L"EFI System Partition"; partition_index[PI_ESP] = pi;
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = esp_size; wcscpy(SelectedDrive.Partition[pi].Name, L"EFI System Partition");
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_GENERIC_ESP; SelectedDrive.Partition[pi].Size = esp_size;
uprintf("● Creating %S (offset: %lld, size: %s)", extra_part_name, DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart, SelectedDrive.Partition[pi + 1].Offset = SelectedDrive.Partition[pi].Offset + SelectedDrive.Partition[pi].Size;
SizeToHumanReadable(DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart, TRUE, FALSE)); // Align next partition to track and cluster
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId)); SelectedDrive.Partition[pi + 1].Offset = HI_ALIGN_X_TO_Y(SelectedDrive.Partition[pi + 1].Offset, bytes_per_track);
wcsncpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, extra_part_name, ARRAYSIZE(DriveLayoutEx.PartitionEntry[pn].Gpt.Name)); if (ClusterSize % SelectedDrive.SectorSize == 0)
// Zero the first sectors from this partition to avoid file system caching issues SelectedDrive.Partition[pi + 1].Offset = LO_ALIGN_X_TO_Y(SelectedDrive.Partition[pi + 1].Offset, ClusterSize);
if (!ClearPartition(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, size_to_clear)) assert(SelectedDrive.Partition[pi + 1].Offset >= SelectedDrive.Partition[pi].Offset + SelectedDrive.Partition[pi].Size);
uprintf("Could not zero %S: %s", extra_part_name, WindowsErrorString()); pi++;
SelectedDrive.PartitionOffset[pn] = DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart;
SelectedDrive.PartitionSize[pn] = DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart;
partition_offset[PI_ESP] = SelectedDrive.PartitionOffset[pn];
pn++;
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn - 1].StartingOffset.QuadPart +
DriveLayoutEx.PartitionEntry[pn - 1].PartitionLength.QuadPart;
// Clear the extra partition we processed // Clear the extra partition we processed
extra_partitions &= ~(XP_ESP); extra_partitions &= ~(XP_ESP);
} }
@ -2344,192 +2338,165 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
// If required, set the MSR partition (GPT only - must be created before the data part) // If required, set the MSR partition (GPT only - must be created before the data part)
if (extra_partitions & XP_MSR) { if (extra_partitions & XP_MSR) {
assert(partition_style == PARTITION_STYLE_GPT); assert(partition_style == PARTITION_STYLE_GPT);
extra_part_name = L"Microsoft Reserved Partition"; wcscpy(SelectedDrive.Partition[pi].Name, L"Microsoft Reserved Partition");
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = 128*MB; SelectedDrive.Partition[pi].Size = 128 * MB;
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_MICROSOFT_RESERVED; SelectedDrive.Partition[pi + 1].Offset = SelectedDrive.Partition[pi].Offset + SelectedDrive.Partition[pi].Size;
uprintf("● Creating %S (offset: %lld, size: %s)", extra_part_name, DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart, SelectedDrive.Partition[pi + 1].Offset = HI_ALIGN_X_TO_Y(SelectedDrive.Partition[pi + 1].Offset, bytes_per_track);
SizeToHumanReadable(DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart, TRUE, FALSE)); if (ClusterSize % SelectedDrive.SectorSize == 0)
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId)); SelectedDrive.Partition[pi + 1].Offset = LO_ALIGN_X_TO_Y(SelectedDrive.Partition[pi + 1].Offset, ClusterSize);
wcsncpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, extra_part_name, ARRAYSIZE(DriveLayoutEx.PartitionEntry[pn].Gpt.Name)); assert(SelectedDrive.Partition[pi + 1].Offset >= SelectedDrive.Partition[pi].Offset + SelectedDrive.Partition[pi].Size);
// Zero the first sectors from this partition to avoid file system caching issues pi++;
if (!ClearPartition(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, size_to_clear))
uprintf("Could not zero %S: %s", extra_part_name, WindowsErrorString());
SelectedDrive.PartitionOffset[pn] = DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart;
SelectedDrive.PartitionSize[pn] = DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart;
pn++;
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn-1].StartingOffset.QuadPart +
DriveLayoutEx.PartitionEntry[pn-1].PartitionLength.QuadPart;
// Clear the extra partition we processed
extra_partitions &= ~(XP_MSR); extra_partitions &= ~(XP_MSR);
} }
// Set our main data partition // Reserve an entry for the main partition
if (write_as_esp) { partition_index[PI_MAIN] = pi++;
// Align ESP to 64 MB while leaving at least 32 MB free space // Shorthand for the main index.
esp_size = max(esp_size, ((((LONGLONG)img_report.projected_size / MB) + 96) / 64) * 64 * MB); mi = partition_index[PI_MAIN];
main_part_size_in_sectors = (esp_size - DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart) / wcscpy(SelectedDrive.Partition[mi].Name, write_as_esp ? L"EFI System Partition" : L"Main Data Partition");
SelectedDrive.SectorSize;
} else {
main_part_size_in_sectors = (main_part_size - DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart) /
// Need 33 sectors at the end for secondary GPT
SelectedDrive.SectorSize - ((partition_style == PARTITION_STYLE_GPT) ? 33 : 0);
}
if (extra_partitions) { if (extra_partitions) {
// Adjust the size according to extra partitions (which we always align to a track) // Adjust the size according to extra partitions (which we always align to a track)
if (extra_partitions & XP_ESP) { // TODO: Should we align these to cluster as well?
extra_part_name = L"EFI System"; if (extra_partitions & XP_PERSISTENCE) {
extra_part_size_in_tracks = (esp_size + bytes_per_track - 1) / bytes_per_track;
} else 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_CASPER)) {
assert(persistence_size != 0); assert(persistence_size != 0);
extra_part_name = L"Linux Persistence"; partition_index[PI_CASPER] = pi;
extra_part_size_in_tracks = persistence_size / bytes_per_track; wcscpy(SelectedDrive.Partition[pi].Name, L"Linux Persistence");
} else if (extra_partitions & XP_COMPAT) { SelectedDrive.Partition[pi++].Size = HI_ALIGN_X_TO_Y(persistence_size, bytes_per_track);
extra_part_name = L"BIOS Compatibility";
extra_part_size_in_tracks = 1; // One track for the extra partition
} else {
assert(FALSE);
} }
// NB: Because we already subtracted the backup GPT size from the main partition size and if (extra_partitions & XP_ESP) {
// this extra partition is indexed on main size, it does not overflow into the backup GPT. partition_index[PI_ESP] = pi;
main_part_size_in_sectors = ((main_part_size_in_sectors / SelectedDrive.SectorsPerTrack) - wcscpy(SelectedDrive.Partition[pi].Name, L"EFI System Partition");
extra_part_size_in_tracks) * SelectedDrive.SectorsPerTrack; SelectedDrive.Partition[pi++].Size = HI_ALIGN_X_TO_Y(esp_size, bytes_per_track);
} else if (extra_partitions & XP_UEFI_NTFS) {
partition_index[PI_UEFI_NTFS] = pi;
wcscpy(SelectedDrive.Partition[pi].Name, L"UEFI:NTFS");
SelectedDrive.Partition[pi++].Size = HI_ALIGN_X_TO_Y(uefi_ntfs_size, bytes_per_track);
} else if (extra_partitions & XP_COMPAT) {
wcscpy(SelectedDrive.Partition[pi].Name, L"BIOS Compatibility");
SelectedDrive.Partition[pi++].Size = bytes_per_track; // One track for the extra partition
}
assert(pi <= MAX_PARTITIONS);
} }
// Compute the offsets of the extra partitions (which we always align to a track)
last_offset = SelectedDrive.DiskSize;
if (partition_style == PARTITION_STYLE_GPT)
last_offset -= 33 * SelectedDrive.SectorSize;
for (i = pi - 1; i > mi; i--) {
assert(SelectedDrive.Partition[i].Size < last_offset);
SelectedDrive.Partition[i].Offset = LO_ALIGN_X_TO_Y(last_offset - SelectedDrive.Partition[i].Size, bytes_per_track);
last_offset = SelectedDrive.Partition[i].Offset;
}
// With the above, Compute the main partition size (which we align to a track)
assert(last_offset > SelectedDrive.Partition[mi].Offset);
SelectedDrive.Partition[mi].Size = LO_ALIGN_X_TO_Y(last_offset - SelectedDrive.Partition[mi].Offset, bytes_per_track);
// Try to make sure that the main partition size is a multiple of the cluster size // Try to make sure that the main partition size is a multiple of the cluster size
// This can be especially important when trying to capture an NTFS partition as FFU, as, when // This can be especially important when trying to capture an NTFS partition as FFU, as, when
// the NTFS partition is aligned to cluster size, the FFU capture parses the NTFS allocated // the NTFS partition is aligned to cluster size, the FFU capture parses the NTFS allocated
// map to only record clusters that are in use, whereas, if not aligned, the FFU capture uses // map to only record clusters that are in use, whereas, if not aligned, the FFU capture uses
// a full sector by sector scan of the NTFS partition and records any non-zero garbage, which // a full sector by sector scan of the NTFS partition and records any non-zero garbage, which
// may include garbage leftover data from a previous reformat... // may include garbage leftover data from a previous reformat...
if (ClusterSize % SelectedDrive.SectorSize == 0) { if (ClusterSize % SelectedDrive.SectorSize == 0)
main_part_size_in_sectors = (((main_part_size_in_sectors * SelectedDrive.SectorSize) / SelectedDrive.Partition[mi].Size = LO_ALIGN_X_TO_Y(SelectedDrive.Partition[mi].Size, ClusterSize);
ClusterSize) * ClusterSize) / SelectedDrive.SectorSize; if (SelectedDrive.Partition[mi].Size <= 0) {
} uprintf("Error: Invalid %S size", SelectedDrive.Partition[mi].Name);
if (main_part_size_in_sectors <= 0) {
uprintf("Error: Invalid %S size", main_part_name);
return FALSE; return FALSE;
} }
uprintf("● Creating %S (offset: %lld, size: %s)", main_part_name, DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart,
SizeToHumanReadable(main_part_size_in_sectors * SelectedDrive.SectorSize, TRUE, FALSE));
// Zero the beginning of this partition to avoid conflicting leftovers
if (!ClearPartition(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, size_to_clear))
uprintf("Could not zero %S: %s", main_part_name, WindowsErrorString());
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = main_part_size_in_sectors * SelectedDrive.SectorSize; // Build the DriveLayoutEx table
if (partition_style == PARTITION_STYLE_MBR) { for (i = 0; i < pi; i++) {
DriveLayoutEx.PartitionEntry[pn].Mbr.BootIndicator = (boot_type != BT_NON_BOOTABLE); uprintf("● Creating %S%s (offset: %lld, size: %s)", SelectedDrive.Partition[i].Name,
switch (file_system) { (wcsstr(SelectedDrive.Partition[i].Name, L"Partition") == NULL) ? " Partition" : "",
case FS_FAT16: SelectedDrive.Partition[i].Offset,
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x0e; // FAT16 LBA SizeToHumanReadable(SelectedDrive.Partition[i].Size, TRUE, FALSE));
break; // Zero the first sectors of the partition to avoid file system caching issues
case FS_NTFS: if (!ClearPartition(hDrive, SelectedDrive.Partition[i].Offset,
case FS_EXFAT: (DWORD)MIN(size_to_clear, SelectedDrive.Partition[i].Size)))
case FS_UDF: uprintf("Could not zero %S: %s", SelectedDrive.Partition[i].Name, WindowsErrorString());
case FS_REFS: DriveLayoutEx.PartitionEntry[i].PartitionStyle = partition_style;
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x07; DriveLayoutEx.PartitionEntry[i].StartingOffset.QuadPart = SelectedDrive.Partition[i].Offset;
break; DriveLayoutEx.PartitionEntry[i].PartitionLength.QuadPart = SelectedDrive.Partition[i].Size;
case FS_EXT2: DriveLayoutEx.PartitionEntry[i].PartitionNumber = i + 1;
case FS_EXT3: DriveLayoutEx.PartitionEntry[i].RewritePartition = TRUE;
case FS_EXT4: if (partition_style == PARTITION_STYLE_MBR) {
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x83; if (i == mi) {
break; DriveLayoutEx.PartitionEntry[i].Mbr.BootIndicator = (boot_type != BT_NON_BOOTABLE);
case FS_FAT32: switch (file_system) {
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x0c; // FAT32 LBA case FS_FAT16:
break; DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0x0e; // FAT16 LBA
default: break;
uprintf("Unsupported file system"); case FS_NTFS:
return FALSE; case FS_EXFAT:
} case FS_UDF:
} else { case FS_REFS:
if (write_as_esp) DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0x07;
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_GENERIC_ESP; break;
else if (IS_EXT(file_system)) case FS_EXT2:
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_LINUX_DATA; case FS_EXT3:
else case FS_EXT4:
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_MICROSOFT_DATA; DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0x83;
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId)); break;
wcsncpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, main_part_name, ARRAYSIZE(DriveLayoutEx.PartitionEntry[pn].Gpt.Name)); case FS_FAT32:
} DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0x0c; // FAT32 LBA
SelectedDrive.PartitionOffset[pn] = DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart; break;
SelectedDrive.PartitionSize[pn] = DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart; default:
partition_offset[PI_MAIN] = SelectedDrive.PartitionOffset[pn]; uprintf("Unsupported file system");
pn++; return FALSE;
}
// Set the optional extra partition }
if (extra_partitions) { // May override the the type of main partition if write_as_esp is active
// Should end on a track boundary if ((wcscmp(SelectedDrive.Partition[i].Name, L"EFI System Partition") == 0) ||
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn-1].StartingOffset.QuadPart + (wcscmp(SelectedDrive.Partition[i].Name, L"UEFI:NTFS") == 0))
DriveLayoutEx.PartitionEntry[pn-1].PartitionLength.QuadPart; DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0xef;
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = (extra_partitions & XP_UEFI_NTFS) ? uefi_ntfs_size : else if (wcscmp(SelectedDrive.Partition[i].Name, L"Linux Persistence") == 0)
extra_part_size_in_tracks * bytes_per_track; DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0x83;
uprintf("● Creating %S Partition (offset: %lld, size: %s)", extra_part_name, DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart, else if (wcscmp(SelectedDrive.Partition[i].Name, L"BIOS Compatibility") == 0)
SizeToHumanReadable(DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart, TRUE, FALSE)); DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = RUFUS_EXTRA_PARTITION_TYPE;
SelectedDrive.PartitionOffset[pn] = DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart; } else {
SelectedDrive.PartitionSize[pn] = DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart; assert(partition_style == PARTITION_STYLE_GPT);
if (extra_partitions & XP_CASPER) if (wcscmp(SelectedDrive.Partition[i].Name, L"UEFI:NTFS") == 0) {
partition_offset[PI_CASPER] = SelectedDrive.PartitionOffset[pn]; DriveLayoutEx.PartitionEntry[i].Gpt.PartitionType = PARTITION_GENERIC_ESP;
else if (extra_partitions & XP_ESP)
partition_offset[PI_ESP] = SelectedDrive.PartitionOffset[pn];
if (partition_style == PARTITION_STYLE_GPT) {
if (extra_partitions & XP_ESP)
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_GENERIC_ESP;
else if (extra_partitions & XP_CASPER)
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_LINUX_DATA;
else
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_MICROSOFT_DATA;
if (extra_partitions & XP_UEFI_NTFS) {
// Prevent a drive letter from being assigned to the UEFI:NTFS partition // Prevent a drive letter from being assigned to the UEFI:NTFS partition
DriveLayoutEx.PartitionEntry[pn].Gpt.Attributes = GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER; DriveLayoutEx.PartitionEntry[i].Gpt.Attributes = GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER;
#if !defined(_DEBUG) #if !defined(_DEBUG)
// Also make the partition read-only for release versions // Also make the partition read-only for release versions
DriveLayoutEx.PartitionEntry[pn].Gpt.Attributes += GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY; DriveLayoutEx.PartitionEntry[i].Gpt.Attributes += GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY;
#endif #endif
} } else if (wcscmp(SelectedDrive.Partition[i].Name, L"EFI System Partition") == 0)
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId)); DriveLayoutEx.PartitionEntry[i].Gpt.PartitionType = PARTITION_GENERIC_ESP;
wcsncpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, (extra_partitions & XP_ESP) ? L"EFI System Partition" : extra_part_name, else if (wcscmp(SelectedDrive.Partition[i].Name, L"Linux Persistence") == 0)
ARRAYSIZE(DriveLayoutEx.PartitionEntry[pn].Gpt.Name)); DriveLayoutEx.PartitionEntry[i].Gpt.PartitionType = PARTITION_LINUX_DATA;
} else { else if (wcscmp(SelectedDrive.Partition[i].Name, L"Microsoft Reserved Partition") == 0)
if (extra_partitions & (XP_UEFI_NTFS | XP_ESP)) { DriveLayoutEx.PartitionEntry[i].Gpt.PartitionType = PARTITION_MICROSOFT_RESERVED;
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0xef; else
} else if (extra_partitions & XP_CASPER) { DriveLayoutEx.PartitionEntry[i].Gpt.PartitionType = PARTITION_MICROSOFT_DATA;
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x83; IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[i].Gpt.PartitionId));
} else if (extra_partitions & XP_COMPAT) { wcscpy(DriveLayoutEx.PartitionEntry[i].Gpt.Name, SelectedDrive.Partition[i].Name);
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);
}
} }
// We need to write the UEFI:NTFS partition before we refresh the disk
if (extra_partitions & XP_UEFI_NTFS) {
uprintf("Writing %S data...", extra_part_name);
if (!SetFilePointerEx(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, NULL, FILE_BEGIN)) {
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 source image");
return FALSE;
}
if(!WriteFileWithRetry(hDrive, buffer, bufsize, &size, WRITE_RETRIES)) {
uprintf("Write error: %s", WindowsErrorString());
return FALSE;
}
}
pn++;
} }
// Initialize the remaining partition data // We need to write the UEFI:NTFS partition before we refresh the disk
for (i = 0; i < pn; i++) { if (extra_partitions & XP_UEFI_NTFS) {
DriveLayoutEx.PartitionEntry[i].PartitionNumber = i + 1; LARGE_INTEGER li;
DriveLayoutEx.PartitionEntry[i].PartitionStyle = partition_style; uprintf("Writing UEFI:NTFS data...", SelectedDrive.Partition[partition_index[PI_UEFI_NTFS]].Name);
DriveLayoutEx.PartitionEntry[i].RewritePartition = TRUE; li.QuadPart = SelectedDrive.Partition[partition_index[PI_UEFI_NTFS]].Offset;
if (!SetFilePointerEx(hDrive, li, NULL, FILE_BEGIN)) {
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 source image");
return FALSE;
}
if(!WriteFileWithRetry(hDrive, buffer, bufsize, &size, WRITE_RETRIES)) {
uprintf(" Write error: %s", WindowsErrorString());
return FALSE;
}
} }
switch (partition_style) { switch (partition_style) {
@ -2558,7 +2525,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
CreateDisk.Gpt.MaxPartitionCount = MAX_PARTITIONS; CreateDisk.Gpt.MaxPartitionCount = MAX_PARTITIONS;
DriveLayoutEx.PartitionStyle = PARTITION_STYLE_GPT; DriveLayoutEx.PartitionStyle = PARTITION_STYLE_GPT;
DriveLayoutEx.PartitionCount = pn; DriveLayoutEx.PartitionCount = pi;
// At the very least, a GPT disk has 34 reserved sectors at the beginning and 33 at the end. // 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.StartingUsableOffset.QuadPart = 34 * SelectedDrive.SectorSize;
DriveLayoutEx.Type.Gpt.UsableLength.QuadPart = SelectedDrive.DiskSize - (34+33) * SelectedDrive.SectorSize; DriveLayoutEx.Type.Gpt.UsableLength.QuadPart = SelectedDrive.DiskSize - (34+33) * SelectedDrive.SectorSize;
@ -2569,8 +2536,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
// If you don't call IOCTL_DISK_CREATE_DISK, the IOCTL_DISK_SET_DRIVE_LAYOUT_EX call will fail // If you don't call IOCTL_DISK_CREATE_DISK, the IOCTL_DISK_SET_DRIVE_LAYOUT_EX call will fail
size = sizeof(CreateDisk); size = sizeof(CreateDisk);
r = DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK, (BYTE*)&CreateDisk, size, NULL, 0, &size, NULL); if (!DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK, (BYTE*)&CreateDisk, size, NULL, 0, &size, NULL)) {
if (!r) {
uprintf("Could not reset disk: %s", WindowsErrorString()); uprintf("Could not reset disk: %s", WindowsErrorString());
return FALSE; return FALSE;
} }
@ -2578,9 +2544,9 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
// "The goggles, they do nothing!" // "The goggles, they do nothing!"
RefreshDriveLayout(hDrive); RefreshDriveLayout(hDrive);
size = sizeof(DriveLayoutEx) - ((partition_style == PARTITION_STYLE_GPT)?((4-pn)*sizeof(PARTITION_INFORMATION_EX)):0); size = sizeof(DriveLayoutEx) - ((partition_style == PARTITION_STYLE_GPT) ?
r = DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL); ((4 - pi) * sizeof(PARTITION_INFORMATION_EX)) : 0);
if (!r) { if (!DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL)) {
uprintf("Could not set drive layout: %s", WindowsErrorString()); uprintf("Could not set drive layout: %s", WindowsErrorString());
return FALSE; return FALSE;
} }

View file

@ -36,12 +36,13 @@
#define XP_ESP 0x02 #define XP_ESP 0x02
#define XP_UEFI_NTFS 0x04 #define XP_UEFI_NTFS 0x04
#define XP_COMPAT 0x08 #define XP_COMPAT 0x08
#define XP_CASPER 0x10 #define XP_PERSISTENCE 0x10
#define PI_MAIN 0 #define PI_MAIN 0
#define PI_ESP 1 #define PI_ESP 1
#define PI_CASPER 2 #define PI_CASPER 2
#define PI_MAX 3 #define PI_UEFI_NTFS 3
#define PI_MAX 4
// The following should match VDS_FSOF_FLAGS as much as possible // The following should match VDS_FSOF_FLAGS as much as possible
#define FP_FORCE 0x00000001 #define FP_FORCE 0x00000001
@ -362,8 +363,11 @@ typedef struct {
MEDIA_TYPE MediaType; MEDIA_TYPE MediaType;
int PartitionStyle; int PartitionStyle;
int nPartitions; // number of partitions we actually care about int nPartitions; // number of partitions we actually care about
uint64_t PartitionOffset[MAX_PARTITIONS]; struct {
uint64_t PartitionSize[MAX_PARTITIONS]; wchar_t Name[36];
uint64_t Offset;
uint64_t Size;
} Partition[MAX_PARTITIONS];
int FSType; int FSType;
char proposed_label[16]; char proposed_label[16];
BOOL has_protective_mbr; BOOL has_protective_mbr;
@ -374,7 +378,7 @@ typedef struct {
} ClusterSize[FS_MAX]; } ClusterSize[FS_MAX];
} RUFUS_DRIVE_INFO; } RUFUS_DRIVE_INFO;
extern RUFUS_DRIVE_INFO SelectedDrive; extern RUFUS_DRIVE_INFO SelectedDrive;
extern uint64_t partition_offset[PI_MAX]; extern int partition_index[PI_MAX];
BOOL SetAutoMount(BOOL enable); BOOL SetAutoMount(BOOL enable);
BOOL GetAutoMount(BOOL* enabled); BOOL GetAutoMount(BOOL* enabled);

View file

@ -972,7 +972,7 @@ static BOOL WriteSBR(HANDLE hPhysicalDrive)
} }
// Ensure that we have sufficient space for the SBR // Ensure that we have sufficient space for the SBR
max_size = (DWORD)SelectedDrive.PartitionOffset[0]; max_size = (DWORD)SelectedDrive.Partition[0].Offset;
if (br_size + size > max_size) { if (br_size + size > max_size) {
uprintf(" SBR size is too large - You may need to uncheck 'Add fixes for old BIOSes'."); uprintf(" SBR size is too large - You may need to uncheck 'Add fixes for old BIOSes'.");
if (sub_type == BT_MAX) if (sub_type == BT_MAX)
@ -1456,23 +1456,32 @@ DWORD WINAPI FormatThread(void* param)
large_drive = (SelectedDrive.DiskSize > (1*TB)); large_drive = (SelectedDrive.DiskSize > (1*TB));
if (large_drive) if (large_drive)
uprintf("Notice: Large drive detected (may produce short writes)"); uprintf("Notice: Large drive detected (may produce short writes)");
// Find out if we need to add any extra partitions // Find out if we need to add any extra partitions
extra_partitions = 0;
if ((boot_type == BT_IMAGE) && !write_as_image && HAS_PERSISTENCE(img_report) && persistence_size)
extra_partitions |= XP_PERSISTENCE;
// According to Microsoft, every GPT disk (we RUN Windows from) must have an MSR due to not having hidden sectors
// https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-and-gpt-faq#disks-that-require-an-msr
if ((windows_to_go) && (target_type == TT_UEFI) && (partition_type == PARTITION_STYLE_GPT)) if ((windows_to_go) && (target_type == TT_UEFI) && (partition_type == PARTITION_STYLE_GPT))
// According to Microsoft, every GPT disk (we RUN Windows from) must have an MSR due to not having hidden sectors extra_partitions |= XP_ESP | XP_MSR;
// https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-and-gpt-faq#disks-that-require-an-msr // If we have a bootable image with UEFI bootloaders and the target file system is NTFS or exFAT
extra_partitions = XP_ESP | XP_MSR; // or the UEFI:NTFS option is selected, we add the UEFI:NTFS partition...
else if ( ((fs_type == FS_NTFS) || (fs_type == FS_EXFAT)) && else if (((boot_type == BT_IMAGE) && IS_EFI_BOOTABLE(img_report)) && ((fs_type == FS_NTFS) || (fs_type == FS_EXFAT)) ||
((boot_type == BT_UEFI_NTFS) || ((boot_type == BT_IMAGE) && IS_EFI_BOOTABLE(img_report) && (boot_type == BT_UEFI_NTFS)) {
((target_type == TT_UEFI) || (windows_to_go) || (allow_dual_uefi_bios) || extra_partitions |= XP_UEFI_NTFS;
(img_report.has_4GB_file) || (img_report.needs_ntfs)))) ) // ...but only if we're not dealing with a Windows image in installer mode with target
extra_partitions = XP_UEFI_NTFS; // system set to BIOS and without dual BIOS+UEFI boot enabled.
else if ((boot_type == BT_IMAGE) && !write_as_image && HAS_PERSISTENCE(img_report) && persistence_size) if ((boot_type == BT_IMAGE) && HAS_BOOTMGR_BIOS(img_report) && (!windows_to_go) &&
extra_partitions = XP_CASPER; (target_type == TT_BIOS) && (!allow_dual_uefi_bios))
else if (IsChecked(IDC_OLD_BIOS_FIXES)) extra_partitions &= ~XP_UEFI_NTFS;
extra_partitions = XP_COMPAT; }
if (IsChecked(IDC_OLD_BIOS_FIXES))
extra_partitions |= XP_COMPAT;
// On pre 1703 platforms (and even on later ones), anything with ext2/ext3 doesn't sit // On pre 1703 platforms (and even on later ones), anything with ext2/ext3 doesn't sit
// too well with Windows. Same with ESPs. Relaxing our locking rules seems to help... // too well with Windows. Same with ESPs. Relaxing our locking rules seems to help...
if ((extra_partitions & (XP_ESP | XP_CASPER)) || IS_EXT(fs_type)) if ((extra_partitions & (XP_ESP | XP_PERSISTENCE)) || IS_EXT(fs_type))
actual_lock_drive = FALSE; actual_lock_drive = FALSE;
// Windows 11 is a lot more proactive in locking ESPs and MSRs than previous versions // Windows 11 is a lot more proactive in locking ESPs and MSRs than previous versions
// were, meaning that we also can't lock the drive without incurring errors... // were, meaning that we also can't lock the drive without incurring errors...
@ -1710,13 +1719,13 @@ DWORD WINAPI FormatThread(void* param)
Sleep(200); Sleep(200);
if (write_as_esp || write_as_ext) { if (write_as_esp || write_as_ext) {
// Can't format ESPs or ext2/ext3 partitions unless we mount them ourselves // Can't format ESPs or ext2/ext3 partitions unless we mount them ourselves
volume_name = AltMountVolume(DriveIndex, partition_offset[PI_MAIN], FALSE); volume_name = AltMountVolume(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset, FALSE);
if (volume_name == NULL) { if (volume_name == NULL) {
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_ASSIGN_LETTER); FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_ASSIGN_LETTER);
goto out; goto out;
} }
} else { } else {
if (!WaitForLogical(DriveIndex, partition_offset[PI_MAIN])) { if (!WaitForLogical(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset)) {
uprintf("Logical drive was not found - aborting"); uprintf("Logical drive was not found - aborting");
if (!IS_ERROR(FormatStatus)) if (!IS_ERROR(FormatStatus))
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_TIMEOUT; FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_TIMEOUT;
@ -1727,12 +1736,12 @@ DWORD WINAPI FormatThread(void* param)
// Format Casper partition if required. Do it before we format anything with // Format Casper partition if required. Do it before we format anything with
// a file system that Windows will recognize, to avoid concurrent access. // a file system that Windows will recognize, to avoid concurrent access.
if (extra_partitions & XP_CASPER) { if (extra_partitions & XP_PERSISTENCE) {
uint32_t ext_version = ReadSetting32(SETTING_USE_EXT_VERSION); uint32_t ext_version = ReadSetting32(SETTING_USE_EXT_VERSION);
if ((ext_version < 2) || (ext_version > 4)) if ((ext_version < 2) || (ext_version > 4))
ext_version = 3; ext_version = 3;
uprintf("Using %s-like method to enable persistence", img_report.uses_casper ? "Ubuntu" : "Debian"); uprintf("Using %s-like method to enable persistence", img_report.uses_casper ? "Ubuntu" : "Debian");
if (!FormatPartition(DriveIndex, partition_offset[PI_CASPER], 0, FS_EXT2 + (ext_version - 2), if (!FormatPartition(DriveIndex, SelectedDrive.Partition[partition_index[PI_CASPER]].Offset, 0, FS_EXT2 + (ext_version - 2),
img_report.uses_casper ? "casper-rw" : "persistence", img_report.uses_casper ? "casper-rw" : "persistence",
(img_report.uses_casper ? 0 : FP_CREATE_PERSISTENCE_CONF) | (img_report.uses_casper ? 0 : FP_CREATE_PERSISTENCE_CONF) |
(IsChecked(IDC_QUICK_FORMAT) ? FP_QUICK : 0))) { (IsChecked(IDC_QUICK_FORMAT) ? FP_QUICK : 0))) {
@ -1757,7 +1766,7 @@ DWORD WINAPI FormatThread(void* param)
if (write_as_esp) if (write_as_esp)
Flags |= FP_LARGE_FAT32; Flags |= FP_LARGE_FAT32;
ret = FormatPartition(DriveIndex, partition_offset[PI_MAIN], ClusterSize, fs_type, label, Flags); ret = FormatPartition(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset, ClusterSize, fs_type, label, Flags);
if (!ret) { if (!ret) {
// Error will be set by FormatPartition() in FormatStatus // Error will be set by FormatPartition() in FormatStatus
uprintf("Format error: %s", StrError(FormatStatus, TRUE)); uprintf("Format error: %s", StrError(FormatStatus, TRUE));
@ -1790,7 +1799,7 @@ DWORD WINAPI FormatThread(void* param)
// Try to continue // Try to continue
CHECK_FOR_USER_CANCEL; CHECK_FOR_USER_CANCEL;
volume_name = GetLogicalName(DriveIndex, partition_offset[PI_MAIN], TRUE, TRUE); volume_name = GetLogicalName(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset, TRUE, TRUE);
if (volume_name == NULL) { if (volume_name == NULL) {
uprintf("Could not get volume name"); uprintf("Could not get volume name");
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NO_VOLUME_ID; FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NO_VOLUME_ID;
@ -1848,7 +1857,7 @@ DWORD WINAPI FormatThread(void* param)
} else { } else {
// We still have a lock, which we need to modify the volume boot record // We still have a lock, which we need to modify the volume boot record
// => no need to reacquire the lock... // => no need to reacquire the lock...
hLogicalVolume = GetLogicalHandle(DriveIndex, partition_offset[PI_MAIN], FALSE, TRUE, FALSE); hLogicalVolume = GetLogicalHandle(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset, FALSE, TRUE, FALSE);
if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL)) { if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL)) {
uprintf("Could not re-mount volume for partition boot record access"); uprintf("Could not re-mount volume for partition boot record access");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
@ -1999,7 +2008,7 @@ out:
} }
} }
if (IS_ERROR(FormatStatus)) { if (IS_ERROR(FormatStatus)) {
volume_name = GetLogicalName(DriveIndex, partition_offset[PI_MAIN], TRUE, TRUE); volume_name = GetLogicalName(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset, TRUE, TRUE);
if (volume_name != NULL) { if (volume_name != NULL) {
if (MountVolume(drive_name, volume_name)) if (MountVolume(drive_name, volume_name))
uprintf("Re-mounted volume as %c: after error", toupper(drive_name[0])); uprintf("Re-mounted volume as %c: after error", toupper(drive_name[0]));

View file

@ -1,7 +1,7 @@
/* /*
* Rufus: The Reliable USB Formatting Utility * Rufus: The Reliable USB Formatting Utility
* Constants and defines missing from various toolchains * Constants and defines missing from various toolchains
* Copyright © 2016-2022 Pete Batard <pete@akeo.ie> * Copyright © 2016-2024 Pete Batard <pete@akeo.ie>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -31,6 +31,9 @@
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif #endif
#define LO_ALIGN_X_TO_Y(x, y) (((x) / (y)) * (y))
#define HI_ALIGN_X_TO_Y(x, y) ((((x) + (y) - 1) / (y)) * (y))
#if defined(__GNUC__) #if defined(__GNUC__)
#define ALIGNED(m) __attribute__ ((__aligned__(m))) #define ALIGNED(m) __attribute__ ((__aligned__(m)))
#elif defined(_MSC_VER) #elif defined(_MSC_VER)

View file

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 232, 326 IDD_DIALOG DIALOGEX 12, 12, 232, 326
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 4.5.2109" CAPTION "Rufus 4.5.2110"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0 FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@ -392,8 +392,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,5,2109,0 FILEVERSION 4,5,2110,0
PRODUCTVERSION 4,5,2109,0 PRODUCTVERSION 4,5,2110,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -411,13 +411,13 @@ BEGIN
VALUE "Comments", "https://rufus.ie" VALUE "Comments", "https://rufus.ie"
VALUE "CompanyName", "Akeo Consulting" VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus" VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "4.5.2109" VALUE "FileVersion", "4.5.2110"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2024 Pete Batard (GPL v3)" VALUE "LegalCopyright", "© 2011-2024 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
VALUE "OriginalFilename", "rufus-4.5.exe" VALUE "OriginalFilename", "rufus-4.5.exe"
VALUE "ProductName", "Rufus" VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "4.5.2109" VALUE "ProductVersion", "4.5.2110"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -1,7 +1,7 @@
/* /*
* Rufus: The Reliable USB Formatting Utility * Rufus: The Reliable USB Formatting Utility
* Windows User Experience * Windows User Experience
* Copyright © 2022-2023 Pete Batard <pete@akeo.ie> * Copyright © 2022-2024 Pete Batard <pete@akeo.ie>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -690,14 +690,14 @@ BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp)
// VDS cannot list ESP volumes (talk about allegedly improving on the old disk and volume APIs, only to // VDS cannot list ESP volumes (talk about allegedly improving on the old disk and volume APIs, only to
// completely neuter it) and IVdsDiskPartitionMF::FormatPartitionEx(), which is what you are supposed to // completely neuter it) and IVdsDiskPartitionMF::FormatPartitionEx(), which is what you are supposed to
// use for ESPs, explicitly states: "This method cannot be used to format removable media." // use for ESPs, explicitly states: "This method cannot be used to format removable media."
if (!FormatPartition(DriveIndex, partition_offset[PI_ESP], cluster_size, FS_FAT32, "", if (!FormatPartition(DriveIndex, SelectedDrive.Partition[partition_index[PI_ESP]].Offset, cluster_size, FS_FAT32, "",
FP_QUICK | FP_FORCE | FP_LARGE_FAT32 | FP_NO_BOOT)) { FP_QUICK | FP_FORCE | FP_LARGE_FAT32 | FP_NO_BOOT)) {
uprintf("Could not format EFI System Partition"); uprintf("Could not format EFI System Partition");
return FALSE; return FALSE;
} }
Sleep(200); Sleep(200);
// Need to have the ESP mounted to invoke bcdboot // Need to have the ESP mounted to invoke bcdboot
ms_efi = AltMountVolume(DriveIndex, partition_offset[PI_ESP], FALSE); ms_efi = AltMountVolume(DriveIndex, SelectedDrive.Partition[partition_index[PI_ESP]].Offset, FALSE);
if (ms_efi == NULL) { if (ms_efi == NULL) {
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_ASSIGN_LETTER); FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_ASSIGN_LETTER);
return FALSE; return FALSE;