mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[togo] Add Windows To Go support - part 2
* Enable the creation of MSR and MS EFI partition in GPT mode * Closes #432
This commit is contained in:
parent
ec761dfb41
commit
ed9fae7c81
5 changed files with 205 additions and 51 deletions
155
src/drive.c
155
src/drive.c
|
@ -45,6 +45,10 @@ const GUID PARTITION_BASIC_DATA_GUID =
|
||||||
const GUID PARTITION_MSFT_RESERVED_GUID =
|
const GUID PARTITION_MSFT_RESERVED_GUID =
|
||||||
{ 0xe3c9e316L, 0x0b5c, 0x4db8, {0x81, 0x7d, 0xf9, 0x2d, 0xf0, 0x02, 0x15, 0xae} };
|
{ 0xe3c9e316L, 0x0b5c, 0x4db8, {0x81, 0x7d, 0xf9, 0x2d, 0xf0, 0x02, 0x15, 0xae} };
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(PARTITION_SYSTEM_GUID)
|
||||||
|
const GUID PARTITION_SYSTEM_GUID =
|
||||||
|
{ 0xc12a7328L, 0xf81f, 0x11d2, {0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} };
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Globals
|
* Globals
|
||||||
|
@ -102,7 +106,7 @@ BOOL GetAutoMount(BOOL* enabled)
|
||||||
*/
|
*/
|
||||||
#define CheckDriveIndex(DriveIndex) do { \
|
#define CheckDriveIndex(DriveIndex) do { \
|
||||||
if ((DriveIndex < DRIVE_INDEX_MIN) || (DriveIndex > DRIVE_INDEX_MAX)) { \
|
if ((DriveIndex < DRIVE_INDEX_MIN) || (DriveIndex > DRIVE_INDEX_MAX)) { \
|
||||||
uprintf("WARNING: Bad index value. Please check the code!\n"); \
|
uprintf("ERROR: Bad index value. Please check the code!\n"); \
|
||||||
goto out; \
|
goto out; \
|
||||||
} \
|
} \
|
||||||
DriveIndex -= DRIVE_INDEX_MIN; } while (0)
|
DriveIndex -= DRIVE_INDEX_MIN; } while (0)
|
||||||
|
@ -403,7 +407,7 @@ static BOOL _GetDriveLettersAndType(DWORD DriveIndex, char* drive_letters, UINT*
|
||||||
hDrive = CreateFileA(logical_drive, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
|
hDrive = CreateFileA(logical_drive, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
if (hDrive == INVALID_HANDLE_VALUE) {
|
if (hDrive == INVALID_HANDLE_VALUE) {
|
||||||
uprintf("Warning: could not open drive %c: %s\n", drive[0], WindowsErrorString());
|
// uprintf("Warning: could not open drive %c: %s\n", drive[0], WindowsErrorString());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -684,7 +688,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (DiskGeometry->Geometry.BytesPerSector < 512) {
|
if (DiskGeometry->Geometry.BytesPerSector < 512) {
|
||||||
suprintf("WARNING: Drive 0x%02x reports a sector size of %d - Correcting to 512 bytes.\n",
|
suprintf("Warning: Drive 0x%02x reports a sector size of %d - Correcting to 512 bytes.\n",
|
||||||
DriveIndex, DiskGeometry->Geometry.BytesPerSector);
|
DriveIndex, DiskGeometry->Geometry.BytesPerSector);
|
||||||
DiskGeometry->Geometry.BytesPerSector = 512;
|
DiskGeometry->Geometry.BytesPerSector = 512;
|
||||||
}
|
}
|
||||||
|
@ -863,6 +867,102 @@ BOOL MountVolume(char* drive_name, char *drive_guid)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mount partition #part_nr, residing on the same disk as drive_name to an available
|
||||||
|
* drive letter. Returns the newly allocated drive string.
|
||||||
|
* We need to do this because, for instance, EFI System partitions are not assigned
|
||||||
|
* Volume GUIDs by the OS, and we need to have a letter assigned, for when we invoke
|
||||||
|
* bcdtool for Windows To Go. All in all, the process looks like this:
|
||||||
|
* 1. F: = \Device\HarddiskVolume9 (SINGLE LOOKUP)
|
||||||
|
* 2. Harddisk5Partition1 = \Device\HarddiskVolume9 (FULL LOOKUP)
|
||||||
|
* 3. Harddisk5Partition2 = \Device\HarddiskVolume10 (SINGLE LOOKUP)
|
||||||
|
* 4. DefineDosDevice(letter, \Device\HarddiskVolume10)
|
||||||
|
*/
|
||||||
|
char* AltMountVolume(const char* drive_name, uint8_t part_nr)
|
||||||
|
{
|
||||||
|
static char mounted_drive[] = "?:";
|
||||||
|
const size_t bufsize = 65536;
|
||||||
|
char *buffer = NULL, *p, target[2][MAX_PATH], *ret = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
mounted_drive[0] = GetUnusedDriveLetter();
|
||||||
|
if (mounted_drive[0] == 0) {
|
||||||
|
uprintf("Could not find an unused drive letter");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
target[0][0] = 0;
|
||||||
|
// Convert our drive letter to something like "\Device\HarddiskVolume9"
|
||||||
|
if (!QueryDosDeviceA(drive_name, target[0], MAX_PATH) && (strlen(target[0]) == 0)) {
|
||||||
|
uprintf("Could not get the DOS device name for '%s': %s", drive_name, WindowsErrorString());
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now parse the whole DOS device list to find the 'Harddisk#Partition#' that matches the above
|
||||||
|
// TODO: realloc if someone ever manages to burst through 64K of DOS devices
|
||||||
|
buffer = malloc(bufsize);
|
||||||
|
if (buffer == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
buffer[0] = 0;
|
||||||
|
if (!QueryDosDeviceA(NULL, buffer, bufsize)) {
|
||||||
|
uprintf("Could not get the DOS device list: %s", WindowsErrorString());
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = buffer;
|
||||||
|
while (strlen(p) != 0) {
|
||||||
|
if ((strncmp("Harddisk", p, 8) == 0) && (strstr(&p[9], "Partition") != NULL)) {
|
||||||
|
target[1][0] = 0;
|
||||||
|
if (QueryDosDeviceA(p, target[1], MAX_PATH) && (strlen(target[1]) != 0))
|
||||||
|
if ((strcmp(target[1], target[0]) == 0) && (p[1] != ':'))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p += strlen(p) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = strlen(p);
|
||||||
|
if (i == 0) {
|
||||||
|
uprintf("Could not find partition mapping for %s", target[0]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((--i > 0) && (isdigit(p[i])));
|
||||||
|
p[++i] = '0' + part_nr;
|
||||||
|
p[++i] = 0;
|
||||||
|
|
||||||
|
target[0][0] = 0;
|
||||||
|
if (!QueryDosDeviceA(p, target[0], MAX_PATH) && (strlen(target[0]) == 0)) {
|
||||||
|
uprintf("Could not get DOS device name for partition '%s': %s", drive_name, WindowsErrorString());
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DefineDosDeviceA(DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM, mounted_drive, target[0])) {
|
||||||
|
uprintf("Could not mount '%s' to '%s': %s", target[0], mounted_drive, WindowsErrorString());
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
uprintf("Successfully mounted '%s' (USB partition %d) as '%s'", target[0], part_nr, mounted_drive);
|
||||||
|
ret = mounted_drive;
|
||||||
|
|
||||||
|
out:
|
||||||
|
safe_free(buffer);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unmount a volume that was mounted by AltmountVolume()
|
||||||
|
*/
|
||||||
|
BOOL AltUnmountVolume(const char* drive_name)
|
||||||
|
{
|
||||||
|
if (!DefineDosDeviceA(DDD_REMOVE_DEFINITION | DDD_NO_BROADCAST_SYSTEM, drive_name, NULL)) {
|
||||||
|
uprintf("Could not unmount '%s': %s", drive_name, WindowsErrorString());
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
uprintf("Successfully unmounted '%s'", drive_name);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Issue a complete remount of the volume
|
* Issue a complete remount of the volume
|
||||||
*/
|
*/
|
||||||
|
@ -909,7 +1009,7 @@ typedef struct _DRIVE_LAYOUT_INFORMATION_EX4 {
|
||||||
* copy it got from the last IOCTL, and ignores your changes until you replug the drive
|
* copy it got from the last IOCTL, and ignores your changes until you replug the drive
|
||||||
* or issue an IOCTL_DISK_UPDATE_PROPERTIES.
|
* or issue an IOCTL_DISK_UPDATE_PROPERTIES.
|
||||||
*/
|
*/
|
||||||
BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, BOOL add_uefi_togo)
|
BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, uint8_t extra_partitions)
|
||||||
{
|
{
|
||||||
const char* PartitionTypeName[2] = { "MBR", "GPT" };
|
const char* PartitionTypeName[2] = { "MBR", "GPT" };
|
||||||
unsigned char* buffer;
|
unsigned char* buffer;
|
||||||
|
@ -917,12 +1017,11 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
||||||
DRIVE_LAYOUT_INFORMATION_EX4 DriveLayoutEx = {0};
|
DRIVE_LAYOUT_INFORMATION_EX4 DriveLayoutEx = {0};
|
||||||
BOOL r;
|
BOOL r;
|
||||||
DWORD i, size, bufsize, pn = 0;
|
DWORD i, size, bufsize, pn = 0;
|
||||||
LONGLONG size_in_sectors, extra_part_size_in_tracks = 0;
|
LONGLONG main_part_size_in_sectors, extra_part_size_in_tracks = 0;
|
||||||
BOOL add_msr = FALSE; //TRUE;
|
|
||||||
|
|
||||||
PrintInfoDebug(0, MSG_238, PartitionTypeName[partition_style]);
|
PrintInfoDebug(0, MSG_238, PartitionTypeName[partition_style]);
|
||||||
|
|
||||||
if (uefi_togo_size == 0)
|
if ((extra_partitions & XP_UEFI_TOGO) && (uefi_togo_size == 0))
|
||||||
uefi_togo_size = GetResourceSize(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_TOGO), _RT_RCDATA, "uefi-togo.img");
|
uefi_togo_size = GetResourceSize(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_TOGO), _RT_RCDATA, "uefi-togo.img");
|
||||||
|
|
||||||
// Compute the start offset of our first partition
|
// Compute the start offset of our first partition
|
||||||
|
@ -936,7 +1035,7 @@ 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 ((partition_style == PARTITION_STYLE_GPT) && (add_msr)) {
|
if ((partition_style == PARTITION_STYLE_GPT) && (extra_partitions & XP_MSR)) {
|
||||||
uprintf("Adding MSR partition");
|
uprintf("Adding MSR partition");
|
||||||
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = 128*1024*1024;
|
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = 128*1024*1024;
|
||||||
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_MSFT_RESERVED_GUID;
|
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_MSFT_RESERVED_GUID;
|
||||||
|
@ -948,24 +1047,27 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set our main data partition
|
// Set our main data partition
|
||||||
size_in_sectors = (SelectedDrive.DiskSize - DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart) /
|
main_part_size_in_sectors = (SelectedDrive.DiskSize - DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart) /
|
||||||
// Need 33 sectors at the end for secondary GPT
|
// Need 33 sectors at the end for secondary GPT
|
||||||
SelectedDrive.Geometry.BytesPerSector - ((partition_style == PARTITION_STYLE_GPT)?33:0);
|
SelectedDrive.Geometry.BytesPerSector - ((partition_style == PARTITION_STYLE_GPT)?33:0);
|
||||||
// Adjust the size according to extra partitions
|
// Adjust the size according to extra partitions
|
||||||
if ((add_uefi_togo) || ((partition_style == PARTITION_STYLE_MBR) && (IsChecked(IDC_EXTRA_PARTITION)))) {
|
if (extra_partitions) {
|
||||||
if (add_uefi_togo) {
|
if (extra_partitions & (XP_UEFI_TOGO | XP_EFI)) {
|
||||||
extra_part_size_in_tracks = (MIN_EXTRA_PART_SIZE + SelectedDrive.Geometry.SectorsPerTrack - 1) /
|
// TODO: this will explode to 800MB instead of 100MB on 4K sectors...
|
||||||
SelectedDrive.Geometry.SectorsPerTrack;
|
extra_part_size_in_tracks = ((MIN_EXTRA_PART_SIZE*((extra_partitions & XP_EFI)?100:1))
|
||||||
|
+ SelectedDrive.Geometry.SectorsPerTrack - 1) / SelectedDrive.Geometry.SectorsPerTrack;
|
||||||
} else {
|
} else {
|
||||||
extra_part_size_in_tracks = 1; // One track for the extra part in non togo mode
|
extra_part_size_in_tracks = 1; // One track for the extra partition
|
||||||
}
|
}
|
||||||
uprintf("Reserving %d tracks for extra partition", extra_part_size_in_tracks);
|
uprintf("Reserving %lld tracks (%s) for extra partition", extra_part_size_in_tracks,
|
||||||
size_in_sectors = ((size_in_sectors / SelectedDrive.Geometry.SectorsPerTrack) - extra_part_size_in_tracks) *
|
SizeToHumanReadable(extra_part_size_in_tracks * SelectedDrive.Geometry.SectorsPerTrack *
|
||||||
SelectedDrive.Geometry.SectorsPerTrack;
|
SelectedDrive.Geometry.BytesPerSector, TRUE, FALSE));
|
||||||
if (size_in_sectors <= 0)
|
main_part_size_in_sectors = ((main_part_size_in_sectors / SelectedDrive.Geometry.SectorsPerTrack) -
|
||||||
|
extra_part_size_in_tracks) * SelectedDrive.Geometry.SectorsPerTrack;
|
||||||
|
if (main_part_size_in_sectors <= 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = size_in_sectors * SelectedDrive.Geometry.BytesPerSector;
|
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = main_part_size_in_sectors * SelectedDrive.Geometry.BytesPerSector;
|
||||||
if (partition_style == PARTITION_STYLE_MBR) {
|
if (partition_style == PARTITION_STYLE_MBR) {
|
||||||
DriveLayoutEx.PartitionEntry[pn].Mbr.BootIndicator = IsChecked(IDC_BOOT);
|
DriveLayoutEx.PartitionEntry[pn].Mbr.BootIndicator = IsChecked(IDC_BOOT);
|
||||||
DriveLayoutEx.PartitionEntry[pn].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack;
|
DriveLayoutEx.PartitionEntry[pn].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack;
|
||||||
|
@ -994,24 +1096,23 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
|
||||||
pn++;
|
pn++;
|
||||||
|
|
||||||
// Set the optional extra partition
|
// Set the optional extra partition
|
||||||
if (IsChecked(IDC_EXTRA_PARTITION) || (add_uefi_togo)) {
|
if (extra_partitions) {
|
||||||
// Should end on a track boundary
|
// Should end on a track boundary
|
||||||
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn-1].StartingOffset.QuadPart +
|
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn-1].StartingOffset.QuadPart +
|
||||||
DriveLayoutEx.PartitionEntry[pn-1].PartitionLength.QuadPart;
|
DriveLayoutEx.PartitionEntry[pn-1].PartitionLength.QuadPart;
|
||||||
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = (add_uefi_togo)?uefi_togo_size:
|
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = (extra_partitions & XP_UEFI_TOGO)?uefi_togo_size:
|
||||||
extra_part_size_in_tracks * SelectedDrive.Geometry.SectorsPerTrack * SelectedDrive.Geometry.BytesPerSector;
|
extra_part_size_in_tracks * SelectedDrive.Geometry.SectorsPerTrack * SelectedDrive.Geometry.BytesPerSector;
|
||||||
if (partition_style == PARTITION_STYLE_GPT) {
|
if (partition_style == PARTITION_STYLE_GPT) {
|
||||||
if (add_uefi_togo) // already set to UNUSED GUID (000...000) otherwise
|
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_SYSTEM_GUID;
|
||||||
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_BASIC_DATA_GUID;
|
|
||||||
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId));
|
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId));
|
||||||
wcscpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, (add_uefi_togo)?L"UEFI:TOGO":L"Rufus Extra Partition");
|
wcscpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, (extra_partitions & XP_UEFI_TOGO)?L"UEFI:TOGO":L"EFI system partition");
|
||||||
} else {
|
} else {
|
||||||
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = (add_uefi_togo)?0x01:RUFUS_EXTRA_PARTITION_TYPE;
|
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = (extra_partitions & XP_UEFI_TOGO)?0x01:RUFUS_EXTRA_PARTITION_TYPE;
|
||||||
DriveLayoutEx.PartitionEntry[pn].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack;
|
DriveLayoutEx.PartitionEntry[pn].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to write the TOGO partition before we refresh the disk
|
// We need to write the TOGO partition before we refresh the disk
|
||||||
if (add_uefi_togo) {
|
if (extra_partitions & XP_UEFI_TOGO) {
|
||||||
uprintf("Writing UEFI:TOGO partition...");
|
uprintf("Writing UEFI:TOGO partition...");
|
||||||
if (!SetFilePointerEx(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, NULL, FILE_BEGIN)) {
|
if (!SetFilePointerEx(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, NULL, FILE_BEGIN)) {
|
||||||
uprintf("Unable to set position");
|
uprintf("Unable to set position");
|
||||||
|
|
|
@ -30,6 +30,10 @@
|
||||||
#define IOCTL_MOUNTMGR_SET_AUTO_MOUNT \
|
#define IOCTL_MOUNTMGR_SET_AUTO_MOUNT \
|
||||||
CTL_CODE(MOUNTMGRCONTROLTYPE, 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
|
CTL_CODE(MOUNTMGRCONTROLTYPE, 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
|
||||||
|
|
||||||
|
#define XP_MSR 0x01
|
||||||
|
#define XP_EFI 0x02
|
||||||
|
#define XP_UEFI_TOGO 0x04
|
||||||
|
|
||||||
/* We need a redef of these MS structure */
|
/* We need a redef of these MS structure */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
DWORD DeviceType;
|
DWORD DeviceType;
|
||||||
|
@ -62,8 +66,10 @@ BOOL AnalyzePBR(HANDLE hLogicalVolume);
|
||||||
BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize, BOOL bSilent);
|
BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize, BOOL bSilent);
|
||||||
BOOL UnmountVolume(HANDLE hDrive);
|
BOOL UnmountVolume(HANDLE hDrive);
|
||||||
BOOL MountVolume(char* drive_name, char *drive_guid);
|
BOOL MountVolume(char* drive_name, char *drive_guid);
|
||||||
|
BOOL AltUnmountVolume(const char* drive_name);
|
||||||
|
char* AltMountVolume(const char* drive_name, uint8_t part_nr);
|
||||||
BOOL RemountVolume(char* drive_name);
|
BOOL RemountVolume(char* drive_name);
|
||||||
BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, BOOL add_uefi_togo);
|
BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, uint8_t extra_partitions);
|
||||||
BOOL DeletePartitions(HANDLE hDrive);
|
BOOL DeletePartitions(HANDLE hDrive);
|
||||||
BOOL RefreshDriveLayout(HANDLE hDrive);
|
BOOL RefreshDriveLayout(HANDLE hDrive);
|
||||||
const char* GetPartitionType(BYTE Type);
|
const char* GetPartitionType(BYTE Type);
|
||||||
|
|
73
src/format.c
73
src/format.c
|
@ -1226,15 +1226,24 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://technet.microsoft.com/en-ie/library/jj721578.aspx
|
// http://technet.microsoft.com/en-ie/library/jj721578.aspx
|
||||||
static BOOL SetupWinToGo(const char* drive_name)
|
BOOL SetupWinToGo(const char* drive_name, BOOL use_ms_efi)
|
||||||
{
|
{
|
||||||
char san_policy_path[] = "?:\\san_policy.xml", unattend_path[] = "?:\\Windows\\System32\\sysprep\\unattend.xml";
|
char san_policy_path[] = "?:\\san_policy.xml", unattend_path[] = "?:\\Windows\\System32\\sysprep\\unattend.xml";
|
||||||
char *mounted_iso, image[128], cmd[128];
|
char *mounted_iso, *ms_efi, image[128], cmd[128];
|
||||||
|
wchar_t wVolumeName[] = L"?:";
|
||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
DWORD bufsize;
|
DWORD bufsize;
|
||||||
FILE* fd;
|
FILE* fd;
|
||||||
|
PF_DECL(FormatEx);
|
||||||
|
PF_INIT(FormatEx, Fmifs);
|
||||||
|
|
||||||
uprintf("Windows To Go mode selected");
|
uprintf("Windows To Go mode selected");
|
||||||
|
if ((use_ms_efi) && (SelectedDrive.Geometry.MediaType != FixedMedia)) {
|
||||||
|
// Arthur's Theme: "♫ I know it's stupid... but it's true. ♫"
|
||||||
|
uprintf("Cannot set 'Windows To Go' for a GPT target unless it is a fixed drive");
|
||||||
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_SUPPORTED;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
// First, we need to access the install.wim image, that resides on the ISO
|
// First, we need to access the install.wim image, that resides on the ISO
|
||||||
mounted_iso = MountISO(image_path);
|
mounted_iso = MountISO(image_path);
|
||||||
|
@ -1256,15 +1265,46 @@ static BOOL SetupWinToGo(const char* drive_name)
|
||||||
}
|
}
|
||||||
UnMountISO();
|
UnMountISO();
|
||||||
|
|
||||||
uprintf("Setting up boot for Windows To Go...");
|
if (use_ms_efi) {
|
||||||
static_sprintf(cmd, "%C:\\Windows\\System32\\bcdboot.exe %C:\\Windows /f ALL /s %C:",
|
uprintf("Setting up MS EFI system partition");
|
||||||
drive_name[0], drive_name[0], drive_name[0]);
|
if (pfFormatEx == NULL)
|
||||||
|
return FALSE;
|
||||||
|
ms_efi = AltMountVolume(drive_name, 3); // MSR, main, EFI
|
||||||
|
if (ms_efi == NULL) {
|
||||||
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
fs_index = 0;
|
||||||
|
task_number = 0;
|
||||||
|
wVolumeName[0] = ms_efi[0];
|
||||||
|
// Boy do you *NOT* want to specify a label here, and spend
|
||||||
|
// HOURS figuring out why your EFI partition cannot boot...
|
||||||
|
pfFormatEx(wVolumeName, SelectedDrive.Geometry.MediaType, L"FAT32", L"",
|
||||||
|
TRUE, 1024, FormatExCallback);
|
||||||
|
if (IS_ERROR(FormatStatus)) {
|
||||||
|
uprintf("Failed to format EFI partition");
|
||||||
|
AltUnmountVolume(ms_efi);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Don't use ALL but adjust to what we effectively support
|
||||||
|
static_sprintf(cmd, "%s\\Windows\\System32\\bcdboot.exe %s\\Windows /f ALL /s %s",
|
||||||
|
drive_name, drive_name, (use_ms_efi)?ms_efi:drive_name);
|
||||||
|
uprintf("Enabling boot: '%s'", cmd);
|
||||||
if (RunCommand(cmd, NULL, TRUE) != 0) {
|
if (RunCommand(cmd, NULL, TRUE) != 0) {
|
||||||
// Fatal, as the UFD is unlikely to boot then
|
// Fatal, as the UFD is unlikely to boot then
|
||||||
uprintf("Command '%s' failed to run", cmd);
|
uprintf("Command '%s' failed to run", cmd);
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);
|
||||||
|
if (use_ms_efi)
|
||||||
|
AltUnmountVolume(ms_efi);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_ms_efi) {
|
||||||
|
Sleep(200);
|
||||||
|
AltUnmountVolume(ms_efi);
|
||||||
|
}
|
||||||
UpdateProgress(OP_DOS, 99.0f);
|
UpdateProgress(OP_DOS, 99.0f);
|
||||||
|
|
||||||
// The following are non fatal if they fail
|
// The following are non fatal if they fail
|
||||||
|
@ -1279,7 +1319,7 @@ static BOOL SetupWinToGo(const char* drive_name)
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
} else {
|
} else {
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
static_sprintf(cmd, "dism /Image:%C:\\ /Apply-Unattend:%s", drive_name[0], san_policy_path);
|
static_sprintf(cmd, "dism /Image:%s\\ /Apply-Unattend:%s", drive_name, san_policy_path);
|
||||||
if (RunCommand(cmd, NULL, TRUE) != 0)
|
if (RunCommand(cmd, NULL, TRUE) != 0)
|
||||||
uprintf("Command '%s' failed to run");
|
uprintf("Command '%s' failed to run");
|
||||||
}
|
}
|
||||||
|
@ -1367,7 +1407,7 @@ void update_progress(const uint64_t processed_bytes)
|
||||||
DWORD WINAPI FormatThread(void* param)
|
DWORD WINAPI FormatThread(void* param)
|
||||||
{
|
{
|
||||||
int i, r, pt, bt, fs, dt;
|
int i, r, pt, bt, fs, dt;
|
||||||
BOOL s, ret, use_large_fat32, add_uefi_togo;
|
BOOL s, ret, use_large_fat32, windows_to_go;
|
||||||
const DWORD SectorSize = SelectedDrive.Geometry.BytesPerSector;
|
const DWORD SectorSize = SelectedDrive.Geometry.BytesPerSector;
|
||||||
DWORD rSize, wSize, BufSize, DriveIndex = (DWORD)(uintptr_t)param;
|
DWORD rSize, wSize, BufSize, DriveIndex = (DWORD)(uintptr_t)param;
|
||||||
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
|
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
|
||||||
|
@ -1377,7 +1417,7 @@ DWORD WINAPI FormatThread(void* param)
|
||||||
FILE* log_fd;
|
FILE* log_fd;
|
||||||
LARGE_INTEGER li;
|
LARGE_INTEGER li;
|
||||||
uint64_t wb;
|
uint64_t wb;
|
||||||
uint8_t *buffer = NULL, *aligned_buffer;
|
uint8_t *buffer = NULL, *aligned_buffer, extra_partitions = 0;
|
||||||
char *bb_msg, *guid_volume = NULL;
|
char *bb_msg, *guid_volume = NULL;
|
||||||
char drive_name[] = "?:\\";
|
char drive_name[] = "?:\\";
|
||||||
char drive_letters[27];
|
char drive_letters[27];
|
||||||
|
@ -1397,7 +1437,14 @@ DWORD WINAPI FormatThread(void* param)
|
||||||
pt = GETPARTTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
|
pt = GETPARTTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
|
||||||
bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
|
bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
|
||||||
use_large_fat32 = (fs == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32));
|
use_large_fat32 = (fs == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32));
|
||||||
add_uefi_togo = (fs == FS_NTFS) && (dt == DT_ISO) && (iso_report.has_efi) && (bt == BT_UEFI);
|
windows_to_go = HAS_TOGO(iso_report) && (Button_GetCheck(GetDlgItem(hMainDialog, IDC_WINDOWS_TO_GO)) == BST_CHECKED);
|
||||||
|
// Find out if we need to add any extra partitions
|
||||||
|
if ((windows_to_go) && (bt == BT_UEFI) && (pt == PARTITION_STYLE_GPT))
|
||||||
|
// According to Microsoft, every GPT disk (we RUN Windows from) must have an MSR due to not having hidden sectors
|
||||||
|
// http://msdn.microsoft.com/en-us/library/windows/hardware/dn640535.aspx#gpt_faq_what_disk_require_msr
|
||||||
|
extra_partitions = XP_MSR | XP_EFI;
|
||||||
|
else if ((fs == FS_NTFS) && (dt == DT_ISO) && (iso_report.has_efi) && ((bt == BT_UEFI) || (windows_to_go)))
|
||||||
|
extra_partitions = XP_UEFI_TOGO;
|
||||||
|
|
||||||
PrintInfoDebug(0, MSG_225);
|
PrintInfoDebug(0, MSG_225);
|
||||||
hPhysicalDrive = GetPhysicalHandle(DriveIndex, TRUE, TRUE);
|
hPhysicalDrive = GetPhysicalHandle(DriveIndex, TRUE, TRUE);
|
||||||
|
@ -1636,7 +1683,7 @@ DWORD WINAPI FormatThread(void* param)
|
||||||
UpdateProgress(OP_ZERO_MBR, -1.0f);
|
UpdateProgress(OP_ZERO_MBR, -1.0f);
|
||||||
CHECK_FOR_USER_CANCEL;
|
CHECK_FOR_USER_CANCEL;
|
||||||
|
|
||||||
if (!CreatePartition(hPhysicalDrive, pt, fs, (pt==PARTITION_STYLE_MBR) && (bt==BT_UEFI), add_uefi_togo)) {
|
if (!CreatePartition(hPhysicalDrive, pt, fs, (pt==PARTITION_STYLE_MBR) && (bt==BT_UEFI), extra_partitions)) {
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE;
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1765,8 +1812,8 @@ DWORD WINAPI FormatThread(void* param)
|
||||||
if (image_path != NULL) {
|
if (image_path != NULL) {
|
||||||
UpdateProgress(OP_DOS, 0.0f);
|
UpdateProgress(OP_DOS, 0.0f);
|
||||||
PrintInfoDebug(0, MSG_231);
|
PrintInfoDebug(0, MSG_231);
|
||||||
drive_name[2] = 0;
|
drive_name[2] = 0; // Ensure our drive is something like 'D:'
|
||||||
if (HAS_TOGO(iso_report) && (Button_GetCheck(GetDlgItem(hMainDialog, IDC_WINDOWS_TO_GO)) == BST_CHECKED)) {
|
if (windows_to_go) {
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
if (fs != FS_NTFS) {
|
if (fs != FS_NTFS) {
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INCOMPATIBLE_FS);
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INCOMPATIBLE_FS);
|
||||||
|
@ -1776,7 +1823,7 @@ DWORD WINAPI FormatThread(void* param)
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_SUPPORTED;
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_SUPPORTED;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!SetupWinToGo(drive_name)) {
|
if (!SetupWinToGo(drive_name, (extra_partitions & XP_EFI))) {
|
||||||
if (!IS_ERROR(FormatStatus))
|
if (!IS_ERROR(FormatStatus))
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
16
src/rufus.rc
16
src/rufus.rc
|
@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||||
|
|
||||||
IDD_DIALOG DIALOGEX 12, 12, 242, 376
|
IDD_DIALOG DIALOGEX 12, 12, 242, 376
|
||||||
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
|
||||||
CAPTION "Rufus 2.0.0.578"
|
CAPTION "Rufus 2.0.0.579"
|
||||||
FONT 8, "Segoe UI", 400, 0, 0x1
|
FONT 8, "Segoe UI", 400, 0, 0x1
|
||||||
BEGIN
|
BEGIN
|
||||||
DEFPUSHBUTTON "Start",IDC_START,127,339,50,14
|
DEFPUSHBUTTON "Start",IDC_START,127,339,50,14
|
||||||
|
@ -157,7 +157,7 @@ END
|
||||||
|
|
||||||
IDD_DIALOG_XP DIALOGEX 12, 12, 242, 376
|
IDD_DIALOG_XP DIALOGEX 12, 12, 242, 376
|
||||||
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
|
||||||
CAPTION "Rufus 2.0.0.578"
|
CAPTION "Rufus 2.0.0.579"
|
||||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||||
BEGIN
|
BEGIN
|
||||||
DEFPUSHBUTTON "Start",IDC_START,127,339,50,14
|
DEFPUSHBUTTON "Start",IDC_START,127,339,50,14
|
||||||
|
@ -283,7 +283,7 @@ END
|
||||||
IDD_DIALOG_RTL DIALOGEX 12, 12, 242, 376
|
IDD_DIALOG_RTL DIALOGEX 12, 12, 242, 376
|
||||||
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_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
|
EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
|
||||||
CAPTION "Rufus 2.0.0.578"
|
CAPTION "Rufus 2.0.0.579"
|
||||||
FONT 8, "Segoe UI", 400, 0, 0x1
|
FONT 8, "Segoe UI", 400, 0, 0x1
|
||||||
BEGIN
|
BEGIN
|
||||||
DEFPUSHBUTTON "Start",IDC_START,127,339,50,14
|
DEFPUSHBUTTON "Start",IDC_START,127,339,50,14
|
||||||
|
@ -415,7 +415,7 @@ END
|
||||||
IDD_DIALOG_RTL_XP DIALOGEX 12, 12, 242, 376
|
IDD_DIALOG_RTL_XP DIALOGEX 12, 12, 242, 376
|
||||||
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_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
|
EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
|
||||||
CAPTION "Rufus 2.0.0.578"
|
CAPTION "Rufus 2.0.0.579"
|
||||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||||
BEGIN
|
BEGIN
|
||||||
DEFPUSHBUTTON "Start",IDC_START,127,339,50,14
|
DEFPUSHBUTTON "Start",IDC_START,127,339,50,14
|
||||||
|
@ -671,8 +671,8 @@ END
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 2,0,0,578
|
FILEVERSION 2,0,0,579
|
||||||
PRODUCTVERSION 2,0,0,578
|
PRODUCTVERSION 2,0,0,579
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -689,13 +689,13 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
|
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
|
||||||
VALUE "FileDescription", "Rufus"
|
VALUE "FileDescription", "Rufus"
|
||||||
VALUE "FileVersion", "2.0.0.578"
|
VALUE "FileVersion", "2.0.0.579"
|
||||||
VALUE "InternalName", "Rufus"
|
VALUE "InternalName", "Rufus"
|
||||||
VALUE "LegalCopyright", "© 2011-2015 Pete Batard (GPL v3)"
|
VALUE "LegalCopyright", "© 2011-2015 Pete Batard (GPL v3)"
|
||||||
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
|
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
|
||||||
VALUE "OriginalFilename", "rufus.exe"
|
VALUE "OriginalFilename", "rufus.exe"
|
||||||
VALUE "ProductName", "Rufus"
|
VALUE "ProductName", "Rufus"
|
||||||
VALUE "ProductVersion", "2.0.0.578"
|
VALUE "ProductVersion", "2.0.0.579"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Rufus: The Reliable USB Formatting Utility
|
* Rufus: The Reliable USB Formatting Utility
|
||||||
* Standard User I/O Routines (logging, status, etc.)
|
* Standard User I/O Routines (logging, status, etc.)
|
||||||
* Copyright © 2011-2013 Pete Batard <pete@akeo.ie>
|
* Copyright © 2011-2015 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
|
||||||
|
@ -181,7 +181,7 @@ char* SizeToHumanReadable(uint64_t size, BOOL log, BOOL fake_units)
|
||||||
} else if (fake_units) {
|
} else if (fake_units) {
|
||||||
if (hr_size < 8) {
|
if (hr_size < 8) {
|
||||||
static_sprintf(str_size, (fabs((hr_size*10.0)-(floor(hr_size + 0.5)*10.0)) < 0.5)?"%0.0f%s":"%0.1f%s",
|
static_sprintf(str_size, (fabs((hr_size*10.0)-(floor(hr_size + 0.5)*10.0)) < 0.5)?"%0.0f%s":"%0.1f%s",
|
||||||
hr_size, _msg_table[MSG_020+suffix-MSG_000]);
|
hr_size, _msg_table[MSG_020+suffix-MSG_000]);
|
||||||
} else {
|
} else {
|
||||||
t = (double)upo2((uint16_t)hr_size);
|
t = (double)upo2((uint16_t)hr_size);
|
||||||
i_size = (uint16_t)((fabs(1.0f-(hr_size / t)) < 0.05f)?t:hr_size);
|
i_size = (uint16_t)((fabs(1.0f-(hr_size / t)) < 0.05f)?t:hr_size);
|
||||||
|
|
Loading…
Reference in a new issue