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

[core] add a cheat mode (Alt-P) to toggle GPT ESP to Basic Data

* Windows 10 or later *ONLY*
* Also don't report a GPT partition name if it's empty
This commit is contained in:
Pete Batard 2020-06-06 16:34:17 +01:00
parent 22fb8febc5
commit 23057f6124
No known key found for this signature in database
GPG key ID: 38E0CF5E69EDD671
6 changed files with 205 additions and 16 deletions

View file

@ -34,6 +34,7 @@
#include "rufus.h"
#include "missing.h"
#include "resource.h"
#include "settings.h"
#include "msapi_utf8.h"
#include "localization.h"
@ -917,7 +918,7 @@ UINT GetDriveTypeFromIndex(DWORD DriveIndex)
char GetUnusedDriveLetter(void)
{
DWORD size;
char drive_letter = 'Z'+1, *drive, drives[26*4 + 1]; /* "D:\", "E:\", etc., plus one NUL */
char drive_letter, *drive, drives[26*4 + 1]; /* "D:\", "E:\", etc., plus one NUL */
size = GetLogicalDriveStringsA(sizeof(drives), drives);
if (size == 0) {
@ -944,6 +945,29 @@ out:
return (drive_letter > 'Z') ? 0 : drive_letter;
}
BOOL IsDriveLetterInUse(const char drive_letter)
{
DWORD size;
char *drive, drives[26 * 4 + 1];
size = GetLogicalDriveStringsA(sizeof(drives), drives);
if (size == 0) {
uprintf("GetLogicalDriveStrings failed: %s", WindowsErrorString());
return TRUE;
}
if (size > sizeof(drives)) {
uprintf("GetLogicalDriveStrings: Buffer too small (required %d vs. %d)", size, sizeof(drives));
return TRUE;
}
for (drive = drives; *drive; drive += safe_strlen(drive) + 1) {
if (drive_letter == (char)toupper((int)*drive))
return TRUE;
}
return FALSE;
}
/*
* Return the drive letter and volume label
* If the drive doesn't have a volume assigned, space is returned for the letter
@ -1130,6 +1154,142 @@ BOOL AnalyzePBR(HANDLE hLogicalVolume)
return TRUE;
}
static BOOL StoreEspInfo(GUID* guid)
{
uint8_t j;
char key_name[2][16], *str;
// Look for an empty slot and use that if available
for (j = 1; j <= MAX_ESP_TOGGLE; j++) {
static_sprintf(key_name[0], "ToggleEsp%02u", j);
str = ReadSettingStr(key_name[0]);
if ((str == NULL) || (str[0] == 0))
return WriteSettingStr(key_name[0], GuidToString(guid));
}
// All slots are used => Move every key down and add to last slot
// NB: No, we don't care that the slot we remove may not be the oldest.
for (j = 1; j < MAX_ESP_TOGGLE; j++) {
static_sprintf(key_name[0], "ToggleEsp%02u", j);
static_sprintf(key_name[1], "ToggleEsp%02u", j + 1);
WriteSettingStr(key_name[0], ReadSettingStr(key_name[1]));
}
return WriteSettingStr(key_name[1], GuidToString(guid));
}
static GUID* GetEspGuid(uint8_t index)
{
char key_name[16];
static_sprintf(key_name, "ToggleEsp%02u", index);
return StringToGuid(ReadSettingStr(key_name));
}
static BOOL ClearEspInfo(uint8_t index)
{
char key_name[16];
static_sprintf(key_name, "ToggleEsp%02u", index);
return WriteSettingStr(key_name, "");
}
/*
* This calls changes the type of a GPT ESP back and forth to Basic Data.
* Needed because Windows 10 doesn't mount ESPs by default, and also
* doesn't let usermode apps (such as File Explorer) access mounted ESPs.
*/
BOOL ToggleEsp(DWORD DriveIndex)
{
char *volume_name, mount_point[] = DEFAULT_ESP_MOUNT_POINT;
BOOL r, ret = FALSE, found = FALSE;
HANDLE hPhysical;
DWORD size, i, j, esp_index = 0;
BYTE layout[4096] = { 0 };
GUID* guid;
PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)(void*)layout;
if (nWindowsVersion < WINDOWS_10) {
uprintf("ESP toggling is only available for Windows 10 or later");
return FALSE;
}
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;
}
if (DriveLayout->PartitionStyle != PARTITION_STYLE_GPT) {
uprintf("ESP toggling is only available for GPT drives");
goto out;
}
// 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)) {
esp_index = i;
j++;
}
}
if (j > 1) {
uprintf("ESP toggling is not available for drives with more than one ESP");
goto out;
}
if (j == 1) {
// ESP -> Basic Data
i = esp_index;
uprintf("ESP name: '%S'", DriveLayout->PartitionEntry[i].Gpt.Name);
if (!StoreEspInfo(&DriveLayout->PartitionEntry[i].Gpt.PartitionId)) {
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)) {
uprintf("BD name: '%S'", DriveLayout->PartitionEntry[i].Gpt.Name);
found = TRUE;
break;
}
}
if (found)
break;
}
}
if (j > MAX_ESP_TOGGLE)
goto out;
DriveLayout->PartitionEntry[i].Gpt.PartitionType = PARTITION_GENERIC_ESP;
}
DriveLayout->PartitionEntry[i].RewritePartition = TRUE; // Just in case
r = DeviceIoControl(hPhysical, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)DriveLayout, size, NULL, 0, &size, NULL);
if (!r) {
uprintf("Could not set drive layout: %s", WindowsErrorString());
return FALSE;
}
RefreshDriveLayout(hPhysical);
if (CompareGUID(&DriveLayout->PartitionEntry[i].Gpt.PartitionType, &PARTITION_GENERIC_ESP)) {
// We successfully reverted ESP from Basic Data -> Delete stored ESP info
ClearEspInfo((uint8_t)j);
} else if (!IsDriveLetterInUse(*mount_point)) {
// We succesfully switched ESP to Basic Data -> Try to mount it
volume_name = GetLogicalName(DriveIndex, DriveLayout->PartitionEntry[i].StartingOffset.QuadPart, TRUE, FALSE);
MountVolume(mount_point, volume_name);
free(volume_name);
}
ret = TRUE;
out:
safe_closehandle(hPhysical);
return ret;
}
/*
* Fill the drive properties (size, FS, etc)
* Returns TRUE if the drive has a partition that can be mounted in Windows, FALSE otherwise
@ -1162,14 +1322,14 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
hPhysical = GetPhysicalHandle(DriveIndex, FALSE, FALSE, TRUE);
if (hPhysical == INVALID_HANDLE_VALUE)
return 0;
return FALSE;
r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
NULL, 0, geometry, sizeof(geometry), &size, NULL);
if (!r || size <= 0) {
suprintf("Could not get geometry for drive 0x%02x: %s", DriveIndex, WindowsErrorString());
safe_closehandle(hPhysical);
return 0;
return FALSE;
}
SelectedDrive.DiskSize = DiskGeometry->DiskSize.QuadPart;
SelectedDrive.SectorSize = DiskGeometry->Geometry.BytesPerSector;
@ -1192,7 +1352,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
if (!r || size <= 0) {
suprintf("Could not get layout for drive 0x%02x: %s", DriveIndex, WindowsErrorString());
safe_closehandle(hPhysical);
return 0;
return FALSE;
}
#if defined(__GNUC__)
@ -1282,8 +1442,10 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
}
SelectedDrive.nPartitions++;
isUefiNtfs = (wcscmp(DriveLayout->PartitionEntry[i].Gpt.Name, L"UEFI:NTFS") == 0);
suprintf("Partition %d%s:\r\n Type: %s\r\n Name: '%S'", i+1, isUefiNtfs ? " (UEFI:NTFS)" : "",
GetGPTPartitionType(&DriveLayout->PartitionEntry[i].Gpt.PartitionType), DriveLayout->PartitionEntry[i].Gpt.Name);
suprintf("Partition %d%s:\r\n Type: %s", i+1, isUefiNtfs ? " (UEFI:NTFS)" : "",
GetGPTPartitionType(&DriveLayout->PartitionEntry[i].Gpt.PartitionType));
if (DriveLayout->PartitionEntry[i].Gpt.Name[0] != 0)
suprintf(" Name: '%S'", DriveLayout->PartitionEntry[i].Gpt.Name);
suprintf(" ID: %s\r\n Size: %s (%" PRIi64 " bytes)\r\n Start Sector: %" PRIi64 ", Attributes: 0x%016" PRIX64,
GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionId),
SizeToHumanReadable(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE),

View file

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Drive access function calls
* Copyright © 2011-2019 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2020 Pete Batard <pete@akeo.ie>
*
* 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
@ -377,6 +377,7 @@ int GetDriveNumber(HANDLE hDrive, char* path);
BOOL GetDriveLetters(DWORD DriveIndex, char* drive_letters);
UINT GetDriveTypeFromIndex(DWORD DriveIndex);
char GetUnusedDriveLetter(void);
BOOL IsDriveLetterInUse(const char drive_letter);
BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label);
uint64_t GetDriveSize(DWORD DriveIndex);
BOOL IsMediaPresent(DWORD DriveIndex);
@ -399,3 +400,4 @@ BOOL CyclePort(int index);
int CycleDevice(int index);
BOOL RefreshLayout(DWORD DriveIndex);
BOOL GetOpticalMedia(IMG_SAVE* img_save);
BOOL ToggleEsp(DWORD DriveIndex);

View file

@ -3286,7 +3286,7 @@ relaunch:
while(GetMessage(&msg, NULL, 0, 0)) {
static BOOL ctrl_without_focus = FALSE;
BOOL no_focus = (msg.message == WM_SYSKEYDOWN) && !(msg.lParam & 0x20000000);
// ** ****** **** ** **********
// ** ****** **** *************
// .,ABCDEFGHIJKLMNOPQRSTUVWXYZ
// Sigh... The things one need to do to detect standalone use of the 'Alt' key.
@ -3452,6 +3452,14 @@ relaunch:
SaveISO();
continue;
}
// Alt-P => Toggle GPT ESP to and from Basic Data type (Windows 10 or later)
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'P')) {
int index = ComboBox_GetCurSel(hDeviceList);
DWORD DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, index);
if (ToggleEsp(DeviceNum))
CyclePort(index);
continue;
}
// Alt-Q => Enable file indexing (for file systems that support it)
// For multiple reasons, file indexing is disabled by default
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'Q')) {

View file

@ -71,6 +71,7 @@
#define MAX_REFRESH 25 // How long we should wait to refresh UI elements (in ms)
#define MAX_GUID_STRING_LENGTH 40
#define MAX_PARTITIONS 16 // Maximum number of partitions we handle
#define MAX_ESP_TOGGLE 8 // Maximum number of entries we record to toggle GPT ESP back and forth
#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
@ -111,6 +112,7 @@
#define WPPRECORDER_MORE_INFO_URL "https://github.com/pbatard/rufus/wiki/FAQ#BSODs_with_Windows_To_Go_drives_created_from_Windows_10_1809_ISOs"
#define SEVENZIP_URL "https://www.7-zip.org"
#define FILES_DIR "rufus_files"
#define DEFAULT_ESP_MOUNT_POINT "S:\\"
#define IS_POWER_OF_2(x) ((x != 0) && (((x) & ((x) - 1)) == 0))
#define IGNORE_RETVAL(expr) do { (void)(expr); } while(0)
#ifndef ARRAYSIZE
@ -485,6 +487,7 @@ extern void UpdateProgressWithInfo(int op, int msg, uint64_t processed, uint64_t
#define UpdateProgressWithInfoInit(hProgressDialog, bNoAltMode) UpdateProgressWithInfo(OP_INIT, (int)bNoAltMode, (uint64_t)(uintptr_t)hProgressDialog, 0);
extern const char* StrError(DWORD error_code, BOOL use_default_locale);
extern char* GuidToString(const GUID* guid);
extern GUID* StringToGuid(const char* str);
extern char* SizeToHumanReadable(uint64_t size, BOOL copy_to_log, BOOL fake_units);
extern char* TimestampToHumanReadable(uint64_t ts);
extern HWND MyCreateDialog(HINSTANCE hInstance, int Dialog_ID, HWND hWndParent, DLGPROC lpDialogFunc);

View file

@ -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.11.1667"
CAPTION "Rufus 3.11.1668"
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,11,1667,0
PRODUCTVERSION 3,11,1667,0
FILEVERSION 3,11,1668,0
PRODUCTVERSION 3,11,1668,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.11.1667"
VALUE "FileVersion", "3.11.1668"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2020 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
VALUE "OriginalFilename", "rufus-3.11.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "3.11.1667"
VALUE "ProductVersion", "3.11.1668"
END
END
BLOCK "VarFileInfo"

View file

@ -674,12 +674,26 @@ char* GuidToString(const GUID* guid)
if (guid == NULL) return NULL;
sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
(unsigned int)guid->Data1, guid->Data2, guid->Data3,
(uint32_t)guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
return guid_string;
}
GUID* StringToGuid(const char* str)
{
static GUID guid;
if (str == NULL) return NULL;
if (sscanf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
(uint32_t*)&guid.Data1, (uint32_t*)&guid.Data2, (uint32_t*)&guid.Data3,
(uint32_t*)&guid.Data4[0], (uint32_t*)&guid.Data4[1], (uint32_t*)&guid.Data4[2],
(uint32_t*)&guid.Data4[3], (uint32_t*)&guid.Data4[4], (uint32_t*)&guid.Data4[5],
(uint32_t*)&guid.Data4[6], (uint32_t*)&guid.Data4[7]) != 11)
return NULL;
return &guid;
}
// Find upper power of 2
static __inline uint16_t upo2(uint16_t v)
{