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:
parent
22fb8febc5
commit
23057f6124
6 changed files with 205 additions and 16 deletions
178
src/drive.c
178
src/drive.c
|
@ -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) {
|
||||
|
@ -930,7 +931,7 @@ char GetUnusedDriveLetter(void)
|
|||
}
|
||||
|
||||
for (drive_letter = 'C'; drive_letter <= 'Z'; drive_letter++) {
|
||||
for (drive = drives ;*drive; drive += safe_strlen(drive)+1) {
|
||||
for (drive = drives ; *drive; drive += safe_strlen(drive) + 1) {
|
||||
if (!isalpha(*drive))
|
||||
continue;
|
||||
if (drive_letter == (char)toupper((int)*drive))
|
||||
|
@ -941,7 +942,30 @@ char GetUnusedDriveLetter(void)
|
|||
}
|
||||
|
||||
out:
|
||||
return (drive_letter>'Z')?0:drive_letter;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
10
src/rufus.c
10
src/rufus.c
|
@ -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')) {
|
||||
|
|
|
@ -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);
|
||||
|
|
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.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"
|
||||
|
|
16
src/stdio.c
16
src/stdio.c
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue