From 8ec570570f36161f241ee0f30d0626e143819855 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 24 Mar 2022 17:24:39 +0000 Subject: [PATCH] [core] reassign a letter for drives written in DD mode that don't have an ESP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * This should help with the CoreELEC usage case described in #1842 * Also add MBR handling for ESP ↔ FAT cheat mode (Alt-P) * Also set rufus-next to 3.19 --- configure | 20 +++--- configure.ac | 2 +- src/drive.c | 175 ++++++++++++++++++++++++++++++++++-------------- src/drive.h | 1 + src/format.c | 39 +++++------ src/mbr_types.h | 2 +- src/rufus.rc | 12 ++-- 7 files changed, 162 insertions(+), 89 deletions(-) diff --git a/configure b/configure index 3ea2c16d..ba858bb7 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for rufus 3.18. +# Generated by GNU Autoconf 2.71 for rufus 3.19. # # Report bugs to . # @@ -611,8 +611,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='rufus' PACKAGE_TARNAME='rufus' -PACKAGE_VERSION='3.18' -PACKAGE_STRING='rufus 3.18' +PACKAGE_VERSION='3.19' +PACKAGE_STRING='rufus 3.19' PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues' PACKAGE_URL='https://rufus.ie' @@ -1268,7 +1268,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures rufus 3.18 to adapt to many kinds of systems. +\`configure' configures rufus 3.19 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1335,7 +1335,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of rufus 3.18:";; + short | recursive ) echo "Configuration of rufus 3.19:";; esac cat <<\_ACEOF @@ -1427,7 +1427,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -rufus configure 3.18 +rufus configure 3.19 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -1503,7 +1503,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by rufus $as_me 3.18, which was +It was created by rufus $as_me 3.19, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -2767,7 +2767,7 @@ fi # Define the identity of the package. PACKAGE='rufus' - VERSION='3.18' + VERSION='3.19' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -5205,7 +5205,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by rufus $as_me 3.18, which was +This file was extended by rufus $as_me 3.19, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -5261,7 +5261,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -rufus config.status 3.18 +rufus config.status 3.19 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 298d635b..32f061de 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([rufus], [3.18], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie]) +AC_INIT([rufus], [3.19], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie]) AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies]) AC_CONFIG_SRCDIR([src/rufus.c]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/src/drive.c b/src/drive.c index 4e01f0f6..778c67d7 100644 --- a/src/drive.c +++ b/src/drive.c @@ -1487,6 +1487,43 @@ BOOL AnalyzePBR(HANDLE hLogicalVolume) return TRUE; } +/* + * This call returns the offset of the first ESP partition found + * on the relevant drive, or 0ULL if no ESP was found. + */ +uint64_t GetEspOffset(DWORD DriveIndex) +{ + uint64_t ret = 0ULL; + BOOL r; + HANDLE hPhysical; + DWORD size, i; + BYTE layout[4096] = { 0 }; + PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)(void*)layout; + + hPhysical = GetPhysicalHandle(DriveIndex, FALSE, TRUE, TRUE); + if (hPhysical == INVALID_HANDLE_VALUE) + return FALSE; + + r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, + NULL, 0, layout, sizeof(layout), &size, NULL); + if (!r || size <= 0) { + uprintf("Could not get layout for drive 0x%02x: %s", DriveIndex, WindowsErrorString()); + goto out; + } + + for (i = 0; i < DriveLayout->PartitionCount; i++) { + if (((DriveLayout->PartitionStyle == PARTITION_STYLE_MBR) && (DriveLayout->PartitionEntry[i].Mbr.PartitionType == 0xef)) || + ((DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) && CompareGUID(&DriveLayout->PartitionEntry[i].Gpt.PartitionType, &PARTITION_GENERIC_ESP))) { + ret = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart; + break; + } + } + +out: + safe_closehandle(hPhysical); + return ret; +} + static BOOL StoreEspInfo(GUID* guid) { uint8_t j; @@ -1531,12 +1568,23 @@ static BOOL ClearEspInfo(uint8_t index) BOOL ToggleEsp(DWORD DriveIndex, uint64_t PartitionOffset) { char *volume_name, mount_point[] = DEFAULT_ESP_MOUNT_POINT; - BOOL r, ret = FALSE, found = FALSE; + int i, j, esp_index = -1; + BOOL r, ret = FALSE, delete_data = FALSE; HANDLE hPhysical; - DWORD size, i, j, esp_index = 0; - BYTE layout[4096] = { 0 }; - GUID* guid; + DWORD dl_size, size, offset; + BYTE layout[4096] = { 0 }, buf[512]; + GUID *guid = NULL, *stored_guid = NULL, mbr_guid; PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)(void*)layout; + typedef struct { + const uint8_t mbr_type; + const uint8_t magic[8]; + } fat_mbr_type; + const fat_mbr_type fat_mbr_types[] = { + { 0x0b, { 'F', 'A', 'T', ' ', ' ', ' ', ' ', ' ' } }, + { 0x01, { 'F', 'A', 'T', '1', '2', ' ', ' ', ' ' } }, + { 0x0e, { 'F', 'A', 'T', '1', '6', ' ', ' ', ' ' } }, + { 0x0c, { 'F', 'A', 'T', '3', '2', ' ', ' ', ' ' } }, + }; if ((PartitionOffset == 0) && (nWindowsVersion < WINDOWS_10)) { uprintf("ESP toggling is only available for Windows 10 or later"); @@ -1547,86 +1595,113 @@ BOOL ToggleEsp(DWORD DriveIndex, uint64_t PartitionOffset) if (hPhysical == INVALID_HANDLE_VALUE) return FALSE; - r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, - NULL, 0, layout, sizeof(layout), &size, NULL); - if (!r || size <= 0) { + r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, layout, sizeof(layout), &dl_size, NULL); + if (!r || dl_size <= 0) { uprintf("Could not get layout for drive 0x%02x: %s", DriveIndex, WindowsErrorString()); goto out; } - // TODO: Handle MBR - if (DriveLayout->PartitionStyle != PARTITION_STYLE_GPT) { - uprintf("ESP toggling is only available for GPT drives"); - goto out; - } if (PartitionOffset == 0) { // See if the current drive contains an ESP - for (i = 0, j = 0; i < DriveLayout->PartitionCount; i++) { - if (CompareGUID(&DriveLayout->PartitionEntry[i].Gpt.PartitionType, &PARTITION_GENERIC_ESP)) { + for (i = 0; i < (int)DriveLayout->PartitionCount; i++) { + if (((DriveLayout->PartitionStyle == PARTITION_STYLE_MBR) && (DriveLayout->PartitionEntry[i].Mbr.PartitionType == 0xef)) || + ((DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) && CompareGUID(&DriveLayout->PartitionEntry[i].Gpt.PartitionType, &PARTITION_GENERIC_ESP))) { esp_index = i; - j++; + break; } } - if (j > 1) { - uprintf("ESP toggling is not available for drives with more than one ESP"); - goto out; - } - if (j == 1) { + if (esp_index >= 0) { // ESP -> Basic Data - i = esp_index; - uprintf("ESP name: '%S'", DriveLayout->PartitionEntry[i].Gpt.Name); - if (!StoreEspInfo(&DriveLayout->PartitionEntry[i].Gpt.PartitionId)) { + if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) { + uprintf("ESP name: '%S'", DriveLayout->PartitionEntry[esp_index].Gpt.Name); + guid = &DriveLayout->PartitionEntry[esp_index].Gpt.PartitionId; + } else { + // For MBR we create a GUID from the disk signature and the offset + mbr_guid.Data1 = DriveLayout->Mbr.Signature; + mbr_guid.Data2 = 0; mbr_guid.Data3 = 0; + *((uint64_t*)&mbr_guid.Data4) = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart; + guid = &mbr_guid; + } + if (!StoreEspInfo(guid)) { uprintf("ESP toggling data could not be stored"); goto out; } - DriveLayout->PartitionEntry[i].Gpt.PartitionType = PARTITION_MICROSOFT_DATA; - } else { - // Basic Data -> ESP - for (j = 1; j <= MAX_ESP_TOGGLE; j++) { - guid = GetEspGuid((uint8_t)j); - if (guid != NULL) { - for (i = 0; i < DriveLayout->PartitionCount; i++) { - if (CompareGUID(guid, &DriveLayout->PartitionEntry[i].Gpt.PartitionId)) { - found = TRUE; - break; + if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) { + DriveLayout->PartitionEntry[esp_index].Gpt.PartitionType = PARTITION_MICROSOFT_DATA; + } else if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR) { + // Default to FAT32 (non LBA) if we can't determine anything better + DriveLayout->PartitionEntry[esp_index].Mbr.PartitionType = 0x0b; + // Now detect if we're dealing with FAT12/16/32 + if (SetFilePointerEx(hPhysical, DriveLayout->PartitionEntry[esp_index].StartingOffset, NULL, FILE_BEGIN) && + ReadFile(hPhysical, buf, 512, &size, NULL) && size == 512) { + for (offset = 0x36; offset <= 0x52; offset += 0x1c) { + for (i = 0; i < ARRAYSIZE(fat_mbr_types); i++) { + if (memcmp(&buf[offset], fat_mbr_types[i].magic, 8) == 0) { + DriveLayout->PartitionEntry[esp_index].Mbr.PartitionType = fat_mbr_types[i].mbr_type; + break; + } + } + } + } + } + } else { + // Basic Data -> ESP + for (i = 1; i <= MAX_ESP_TOGGLE && esp_index < 0; i++) { + stored_guid = GetEspGuid((uint8_t)i); + if (stored_guid != NULL) { + for (j = 0; j < (int)DriveLayout->PartitionCount && esp_index < 0; j++) { + if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) { + guid = &DriveLayout->PartitionEntry[j].Gpt.PartitionId; + } else if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR) { + mbr_guid.Data1 = DriveLayout->Mbr.Signature; + mbr_guid.Data2 = 0; mbr_guid.Data3 = 0; + *((uint64_t*)&mbr_guid.Data4) = DriveLayout->PartitionEntry[j].StartingOffset.QuadPart; + guid = &mbr_guid; + } + if (CompareGUID(stored_guid, guid)) { + esp_index = j; + delete_data = TRUE; + if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) + DriveLayout->PartitionEntry[esp_index].Gpt.PartitionType = PARTITION_GENERIC_ESP; + else if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR) + DriveLayout->PartitionEntry[esp_index].Mbr.PartitionType = 0xef; } } - if (found) - break; } } - if (j > MAX_ESP_TOGGLE) - goto out; - DriveLayout->PartitionEntry[i].Gpt.PartitionType = PARTITION_GENERIC_ESP; } } else { - for (i = 0, j = 0; i < DriveLayout->PartitionCount; i++) { + for (i = 0; i < (int)DriveLayout->PartitionCount; i++) { if (DriveLayout->PartitionEntry[i].StartingOffset.QuadPart == PartitionOffset) { - DriveLayout->PartitionEntry[i].Gpt.PartitionType = PARTITION_GENERIC_ESP; + esp_index = i; + if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) + DriveLayout->PartitionEntry[esp_index].Gpt.PartitionType = PARTITION_GENERIC_ESP; + else if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR) + DriveLayout->PartitionEntry[esp_index].Mbr.PartitionType = 0xef; break; } } } - if (i >= DriveLayout->PartitionCount) { + if (esp_index < 0) { uprintf("No partition to toggle"); goto out; } - DriveLayout->PartitionEntry[i].RewritePartition = TRUE; // Just in case - r = DeviceIoControl(hPhysical, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)DriveLayout, size, NULL, 0, &size, NULL); + DriveLayout->PartitionEntry[esp_index].RewritePartition = TRUE; // Just in case + r = DeviceIoControl(hPhysical, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)DriveLayout, dl_size, NULL, 0, &dl_size, NULL); if (!r) { uprintf("Could not set drive layout: %s", WindowsErrorString()); goto out; } RefreshDriveLayout(hPhysical); if (PartitionOffset == 0) { - if (CompareGUID(&DriveLayout->PartitionEntry[i].Gpt.PartitionType, &PARTITION_GENERIC_ESP)) { + if (delete_data) { // We successfully reverted ESP from Basic Data -> Delete stored ESP info ClearEspInfo((uint8_t)j); } else if (!IsDriveLetterInUse(*mount_point)) { // We successfully switched ESP to Basic Data -> Try to mount it - volume_name = GetLogicalName(DriveIndex, DriveLayout->PartitionEntry[i].StartingOffset.QuadPart, TRUE, FALSE); + volume_name = GetLogicalName(DriveIndex, DriveLayout->PartitionEntry[esp_index].StartingOffset.QuadPart, TRUE, FALSE); IGNORE_RETVAL(MountVolume(mount_point, volume_name)); free(volume_name); } @@ -1652,11 +1727,11 @@ const char* GetFsName(HANDLE hPhysical, LARGE_INTEGER StartingOffset) { "NTFS", { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ' } }, { "ReFS", { 'R', 'e', 'F', 'S', 0, 0, 0, 0 } } }; - const win_fs_type fat_fs_types[] = { - { "FAT", { 'F', 'A', 'T', ' ', ' ', ' ', ' ', ' ' } }, - { "FAT12", { 'F', 'A', 'T', '1', '2', ' ', ' ', ' ' } }, - { "FAT16", { 'F', 'A', 'T', '1', '6', ' ', ' ', ' ' } }, - { "FAT32", { 'F', 'A', 'T', '3', '2', ' ', ' ', ' ' } }, + const win_fs_type fat_fs_types[] = { + { "FAT", { 'F', 'A', 'T', ' ', ' ', ' ', ' ', ' ' } }, + { "FAT12", { 'F', 'A', 'T', '1', '2', ' ', ' ', ' ' } }, + { "FAT16", { 'F', 'A', 'T', '1', '6', ' ', ' ', ' ' } }, + { "FAT32", { 'F', 'A', 'T', '3', '2', ' ', ' ', ' ' } }, }; const uint32_t ext_feature[3][3] = { // feature_compat diff --git a/src/drive.h b/src/drive.h index 6506da75..1a6be225 100644 --- a/src/drive.h +++ b/src/drive.h @@ -418,4 +418,5 @@ BOOL CyclePort(int index); int CycleDevice(int index); BOOL RefreshLayout(DWORD DriveIndex); BOOL GetOpticalMedia(IMG_SAVE* img_save); +uint64_t GetEspOffset(DWORD DriveIndex); BOOL ToggleEsp(DWORD DriveIndex, uint64_t PartitionOffset); diff --git a/src/format.c b/src/format.c index a3fcc63b..fde30967 100644 --- a/src/format.c +++ b/src/format.c @@ -2064,23 +2064,6 @@ DWORD WINAPI FormatThread(void* param) // Write an image file if ((boot_type == BT_IMAGE) && write_as_image) { WriteDrive(hPhysicalDrive, FALSE); - - // Trying to mount accessible partitions after writing an image leads to the - // creation of the infamous 'System Volume Information' folder on ESPs, which - // in turn leads to checksum errors for Ubuntu's boot/grub/efi.img (that maps - // to the Ubuntu ESP). So we only call the code below for Ventoy's vtsi images. - if (img_report.compression_type == BLED_COMPRESSION_VTSI) { - // If the image contains a partition we might be able to access, try to re-mount it - safe_unlockclose(hPhysicalDrive); - safe_unlockclose(hLogicalVolume); - Sleep(200); - WaitForLogical(DriveIndex, 0); - if (GetDrivePartitionData(SelectedDrive.DeviceNumber, fs_name, sizeof(fs_name), TRUE)) { - volume_name = GetLogicalName(DriveIndex, 0, TRUE, TRUE); - if ((volume_name != NULL) && (MountVolume(drive_name, volume_name))) - uprintf("Remounted %s as %c:", volume_name, toupper(drive_name[0])); - } - } goto out; } @@ -2403,13 +2386,27 @@ out: AltUnmountVolume(volume_name, TRUE); else safe_free(volume_name); - if ((boot_type == BT_IMAGE) && write_as_image) { - PrintInfo(0, MSG_320, lmprintf(MSG_307)); - VdsRescan(VDS_RESCAN_REFRESH, 0, TRUE); - } safe_free(buffer); safe_unlockclose(hLogicalVolume); safe_unlockclose(hPhysicalDrive); // This can take a while + if ((boot_type == BT_IMAGE) && write_as_image) { + PrintInfo(0, MSG_320, lmprintf(MSG_307)); + Sleep(200); + VdsRescan(VDS_RESCAN_REFRESH, 0, TRUE); + // Trying to mount accessible partitions after writing an image leads to the + // creation of the infamous 'System Volume Information' folder on ESPs, which + // in turn leads to checksum errors for Ubuntu's boot/grub/efi.img (that maps + // to the Ubuntu ESP). So we only call the code below if there are no ESPs or + // if we're running a Ventoy image. + if ((GetEspOffset(DriveIndex) == 0) || (img_report.compression_type == BLED_COMPRESSION_VTSI)) { + WaitForLogical(DriveIndex, 0); + if (GetDrivePartitionData(SelectedDrive.DeviceNumber, fs_name, sizeof(fs_name), TRUE)) { + volume_name = GetLogicalName(DriveIndex, 0, TRUE, TRUE); + if ((volume_name != NULL) && (MountVolume(drive_name, volume_name))) + uprintf("Remounted %s as %c:", volume_name, toupper(drive_name[0])); + } + } + } if (IS_ERROR(FormatStatus)) { volume_name = GetLogicalName(DriveIndex, partition_offset[PI_MAIN], TRUE, TRUE); if (volume_name != NULL) { diff --git a/src/mbr_types.h b/src/mbr_types.h index 652a0ef4..caa43738 100644 --- a/src/mbr_types.h +++ b/src/mbr_types.h @@ -165,7 +165,7 @@ mbr_type_t mbr_type[] = { { 0xec, "SkyFS" }, { 0xed, "GPT Hybrid MBR" }, { 0xee, "GPT Protective MBR" }, - { 0xef, "EFI FAT" }, + { 0xef, "EFI System Partition" }, { 0xf0, "PA-RISC Boot" }, { 0xf1, "SpeedStor" }, { 0xf2, "DOS secondary" }, diff --git a/src/rufus.rc b/src/rufus.rc index 5c66e470..a87ec5fb 100644 --- a/src/rufus.rc +++ b/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.18.1877" +CAPTION "Rufus 3.19.1878" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -395,8 +395,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,18,1877,0 - PRODUCTVERSION 3,18,1877,0 + FILEVERSION 3,19,1878,0 + PRODUCTVERSION 3,19,1878,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -414,13 +414,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.18.1877" + VALUE "FileVersion", "3.19.1878" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2022 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" - VALUE "OriginalFilename", "rufus-3.18.exe" + VALUE "OriginalFilename", "rufus-3.19.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.18.1877" + VALUE "ProductVersion", "3.19.1878" END END BLOCK "VarFileInfo"