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

[efi] add Windows 7 EFI support for XP and Vista

* Requires 7-Zip for WIM extraction as wimgapi.dll is not available
* Also add more comprehensive choice between MBR/GPT and BIOS/UEFI
This commit is contained in:
Pete Batard 2013-01-20 22:46:11 +00:00
parent 84e4aecfcd
commit 0196de6f4d
6 changed files with 233 additions and 88 deletions

View file

@ -749,7 +749,7 @@ static BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSi
uint64_t i, last_sector = DiskSize/SectorSize; uint64_t i, last_sector = DiskSize/SectorSize;
unsigned char* pBuf = (unsigned char*) calloc(SectorSize, 1); unsigned char* pBuf = (unsigned char*) calloc(SectorSize, 1);
PrintStatus(0, TRUE, "Clearing MBR & GPT structures..."); PrintStatus(0, TRUE, "Clearing MBR/GPT structures...");
if (pBuf == NULL) { if (pBuf == NULL) {
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY;
goto out; goto out;
@ -818,7 +818,6 @@ static BOOL WriteMBR(HANDLE hPhysicalDrive)
// FormatEx rewrites the MBR and removes the LBA attribute of FAT16 // FormatEx rewrites the MBR and removes the LBA attribute of FAT16
// and FAT32 partitions - we need to correct this in the MBR // and FAT32 partitions - we need to correct this in the MBR
// TODO: Something else for bootable GPT
buf = (unsigned char*)malloc(SecSize * nSecs); buf = (unsigned char*)malloc(SecSize * nSecs);
if (buf == NULL) { if (buf == NULL) {
uprintf("Could not allocate memory for MBR"); uprintf("Could not allocate memory for MBR");
@ -1110,10 +1109,7 @@ static BOOL RemountVolume(char drive_letter)
*/ */
DWORD WINAPI FormatThread(LPVOID param) DWORD WINAPI FormatThread(LPVOID param)
{ {
int r; int r, pt, bt, fs, dt;
int fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
int dt = (int)ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType));
int pt = (int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme));
BOOL ret; BOOL ret;
DWORD num = (DWORD)(uintptr_t)param; DWORD num = (DWORD)(uintptr_t)param;
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE; HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
@ -1126,6 +1122,11 @@ DWORD WINAPI FormatThread(LPVOID param)
char efi_dst[] = "?:\\efi\\boot\\bootx64.efi"; char efi_dst[] = "?:\\efi\\boot\\bootx64.efi";
FILE* log_fd; FILE* log_fd;
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
dt = (int)ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType));
pt = GETPARTTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
hPhysicalDrive = GetDriveHandle(num, NULL, TRUE, TRUE); hPhysicalDrive = GetDriveHandle(num, NULL, TRUE, TRUE);
if (hPhysicalDrive == INVALID_HANDLE_VALUE) { if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
@ -1239,7 +1240,7 @@ DWORD WINAPI FormatThread(LPVOID param)
goto out; goto out;
} }
if (pt == PT_MBR) { if (pt == PARTITION_STYLE_MBR) {
PrintStatus(0, TRUE, "Writing master boot record..."); PrintStatus(0, TRUE, "Writing master boot record...");
if (!WriteMBR(hPhysicalDrive)) { if (!WriteMBR(hPhysicalDrive)) {
if (!FormatStatus) if (!FormatStatus)
@ -1250,7 +1251,7 @@ DWORD WINAPI FormatThread(LPVOID param)
} }
if (IsChecked(IDC_DOS)) { if (IsChecked(IDC_DOS)) {
if (pt == PT_GPT) { if (bt == BT_UEFI) {
// For once, no need to do anything - just check our sanity // For once, no need to do anything - just check our sanity
if ( (dt != DT_ISO) || (!IS_EFI(iso_report)) || (fs > FS_FAT32) ) { if ( (dt != DT_ISO) || (!IS_EFI(iso_report)) || (fs > FS_FAT32) ) {
uprintf("Spock gone crazy error!\n"); uprintf("Spock gone crazy error!\n");
@ -1312,7 +1313,7 @@ DWORD WINAPI FormatThread(LPVOID param)
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY;
goto out; goto out;
} }
if ((pt == PT_GPT) && (!iso_report.has_efi) && (iso_report.has_win7_efi)) { if ((bt == BT_UEFI) && (!iso_report.has_efi) && (iso_report.has_win7_efi)) {
// TODO: progress // TODO: progress
PrintStatus(0, TRUE, "Win7 EFI boot setup (this may take a while)..."); PrintStatus(0, TRUE, "Win7 EFI boot setup (this may take a while)...");
wim_image[0] = drive_name[0]; wim_image[0] = drive_name[0];
@ -1323,14 +1324,14 @@ DWORD WINAPI FormatThread(LPVOID param)
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH);
} else { } else {
efi_dst[sizeof(efi_dst) - sizeof("\\bootx64.efi")] = '\\'; efi_dst[sizeof(efi_dst) - sizeof("\\bootx64.efi")] = '\\';
if (!WIMExtractFile(wim_image, 1, "Windows\\Boot\\EFI\\bootmgfw.efi", efi_dst)) { if (!WimExtractFile(wim_image, 1, "Windows\\Boot\\EFI\\bootmgfw.efi", efi_dst)) {
uprintf("Failed to setup Win7 EFI boot\n"); uprintf("Failed to setup Win7 EFI boot\n");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH);
} }
} }
} }
} }
if ( (pt == PT_MBR) && (IS_WINPE(iso_report.winpe)) ) { if ( (bt == BT_BIOS) && (IS_WINPE(iso_report.winpe)) ) {
// Apply WinPe fixup // Apply WinPe fixup
if (!SetupWinPE(drive_name[0])) if (!SetupWinPE(drive_name[0]))
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH);

View file

@ -57,24 +57,39 @@ static __inline BOOL DeleteRegistryKey(const char* key_name)
return ((s == ERROR_SUCCESS) || (s == ERROR_FILE_NOT_FOUND)); return ((s == ERROR_SUCCESS) || (s == ERROR_FILE_NOT_FOUND));
} }
/* Read a generic registry key value (create the key if it doesn't exist) */ /* Read a generic registry key value. If a short key_name is used, assume that it belongs to
the application and create the app subkey if required */
static __inline BOOL _GetRegistryKey(const char* key_name, DWORD reg_type, LPBYTE dest, DWORD dest_size) static __inline BOOL _GetRegistryKey(const char* key_name, DWORD reg_type, LPBYTE dest, DWORD dest_size)
{ {
BOOL r = FALSE; BOOL r = FALSE;
size_t i = 0;
LONG s; LONG s;
HKEY hSoftware = NULL, hApp = NULL; HKEY hSoftware = NULL, hApp = NULL;
DWORD dwDisp, dwType = -1, dwSize = dest_size; DWORD dwDisp, dwType = -1, dwSize = dest_size;
char long_key_name[256] = "SOFTWARE\\";
memset(dest, 0, dest_size); memset(dest, 0, dest_size);
for (i=safe_strlen(key_name); i>0; i--) {
if (key_name[i] == '\\')
break;
}
if (i != 0) {
safe_strcat(long_key_name, sizeof(long_key_name), key_name);
long_key_name[sizeof("SOFTWARE\\") + i-1] = 0;
i++;
if (RegOpenKeyExA(HKEY_CURRENT_USER, long_key_name, 0, KEY_READ, &hApp) != ERROR_SUCCESS)
goto out;
} else {
if ( (RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE", 0, KEY_READ|KEY_CREATE_SUB_KEY, &hSoftware) != ERROR_SUCCESS) if ( (RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE", 0, KEY_READ|KEY_CREATE_SUB_KEY, &hSoftware) != ERROR_SUCCESS)
|| (RegCreateKeyExA(hSoftware, COMPANY_NAME "\\" APPLICATION_NAME, 0, NULL, 0, || (RegCreateKeyExA(hSoftware, COMPANY_NAME "\\" APPLICATION_NAME, 0, NULL, 0,
KEY_SET_VALUE|KEY_QUERY_VALUE|KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) ) { KEY_SET_VALUE|KEY_QUERY_VALUE|KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) )
goto out; goto out;
} }
s = RegQueryValueExA(hApp, key_name, NULL, &dwType, (LPBYTE)dest, &dwSize); s = RegQueryValueExA(hApp, &key_name[i], NULL, &dwType, (LPBYTE)dest, &dwSize);
// No key means default value of 0 or empty string // No key means default value of 0 or empty string
if ((s == ERROR_FILE_NOT_FOUND) || ((s == ERROR_SUCCESS) && (dwType = reg_type) && (dwSize = dest_size))) { if ((s == ERROR_FILE_NOT_FOUND) || ((s == ERROR_SUCCESS) && (dwType = reg_type) && (dwSize > 0))) {
r = TRUE; r = TRUE;
} }
out: out:

View file

@ -86,7 +86,8 @@ static const char* FileSystemLabel[FS_MAX] = { "FAT", "FAT32", "NTFS", "exFAT" }
static const char* ClusterSizeLabel[] = { "512 bytes", "1024 bytes","2048 bytes","4096 bytes","8192 bytes", static const char* ClusterSizeLabel[] = { "512 bytes", "1024 bytes","2048 bytes","4096 bytes","8192 bytes",
"16 kilobytes", "32 kilobytes", "64 kilobytes", "128 kilobytes", "256 kilobytes", "512 kilobytes", "16 kilobytes", "32 kilobytes", "64 kilobytes", "128 kilobytes", "256 kilobytes", "512 kilobytes",
"1024 kilobytes","2048 kilobytes","4096 kilobytes","8192 kilobytes","16 megabytes","32 megabytes" }; "1024 kilobytes","2048 kilobytes","4096 kilobytes","8192 kilobytes","16 megabytes","32 megabytes" };
static const char* PartitionSchemeName[PT_MAX] = { "MBR", "GPT" }; static const char* BiosTypeName[BT_MAX] = { "BIOS", "UEFI" };
static const char* PartitionTypeName[2] = { "MBR", "GPT" };
static BOOL existing_key = FALSE; // For LGP set/restore static BOOL existing_key = FALSE; // For LGP set/restore
static BOOL iso_size_check = TRUE; static BOOL iso_size_check = TRUE;
static BOOL log_displayed = FALSE; static BOOL log_displayed = FALSE;
@ -350,7 +351,7 @@ static __inline char* size_to_hr(LARGE_INTEGER size)
/* /*
* Fill the drive properties (size, FS, etc) * Fill the drive properties (size, FS, etc)
*/ */
static BOOL GetDriveInfo(void) static BOOL GetDriveInfo(DWORD DeviceNumber)
{ {
BOOL r; BOOL r;
HANDLE hDrive; HANDLE hDrive;
@ -363,7 +364,8 @@ static BOOL GetDriveInfo(void)
char DrivePath[] = "#:\\", tmp[256], fs_type[32]; char DrivePath[] = "#:\\", tmp[256], fs_type[32];
DWORD i, nb_partitions = 0; DWORD i, nb_partitions = 0;
SelectedDrive.DiskSize = 0; memset(&SelectedDrive, 0, sizeof(SelectedDrive));
SelectedDrive.DeviceNumber = DeviceNumber;
hDrive = GetDriveHandle(SelectedDrive.DeviceNumber, DrivePath, FALSE, FALSE); hDrive = GetDriveHandle(SelectedDrive.DeviceNumber, DrivePath, FALSE, FALSE);
if (hDrive == INVALID_HANDLE_VALUE) if (hDrive == INVALID_HANDLE_VALUE)
@ -389,7 +391,7 @@ static BOOL GetDriveInfo(void)
} else { } else {
switch (DriveLayout->PartitionStyle) { switch (DriveLayout->PartitionStyle) {
case PARTITION_STYLE_MBR: case PARTITION_STYLE_MBR:
SelectedDrive.PartitionType = PT_MBR; SelectedDrive.PartitionType = PARTITION_STYLE_MBR;
for (i=0; i<DriveLayout->PartitionCount; i++) { for (i=0; i<DriveLayout->PartitionCount; i++) {
if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) { if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) {
nb_partitions++; nb_partitions++;
@ -406,11 +408,13 @@ static BOOL GetDriveInfo(void)
DriveLayout->PartitionEntry[i].PartitionLength, DriveLayout->PartitionEntry[i].Mbr.HiddenSectors, DriveLayout->PartitionEntry[i].PartitionLength, DriveLayout->PartitionEntry[i].Mbr.HiddenSectors,
DriveLayout->PartitionEntry[i].Mbr.BootIndicator?"Yes":"No", DriveLayout->PartitionEntry[i].Mbr.BootIndicator?"Yes":"No",
DriveLayout->PartitionEntry[i].Mbr.RecognizedPartition?"Yes":"No"); DriveLayout->PartitionEntry[i].Mbr.RecognizedPartition?"Yes":"No");
if (part_type == 0xee) // Flag a protective MBR for non GPT platforms (XP)
SelectedDrive.has_protective_mbr = TRUE;
} }
} }
break; break;
case PARTITION_STYLE_GPT: case PARTITION_STYLE_GPT:
SelectedDrive.PartitionType = PT_GPT; SelectedDrive.PartitionType = PARTITION_STYLE_GPT;
uprintf("Partition type: GPT, NB Partitions: %d\n", DriveLayout->PartitionCount); uprintf("Partition type: GPT, NB Partitions: %d\n", DriveLayout->PartitionCount);
uprintf("Disk GUID: %s\n", GuidToString(&DriveLayout->Gpt.DiskId)); uprintf("Disk GUID: %s\n", GuidToString(&DriveLayout->Gpt.DiskId));
uprintf("Max parts: %d, Start Offset: %lld, Usable = %lld bytes\n", uprintf("Max parts: %d, Start Offset: %lld, Usable = %lld bytes\n",
@ -428,7 +432,7 @@ static BOOL GetDriveInfo(void)
} }
break; break;
default: default:
SelectedDrive.PartitionType = PT_MBR; SelectedDrive.PartitionType = PARTITION_STYLE_MBR;
uprintf("Partition type: RAW\n"); uprintf("Partition type: RAW\n");
break; break;
} }
@ -480,6 +484,7 @@ static void SetFSFromISO(void)
{ {
int i, fs, selected_fs = FS_UNKNOWN; int i, fs, selected_fs = FS_UNKNOWN;
uint32_t fs_mask = 0; uint32_t fs_mask = 0;
int bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
if (iso_path == NULL) if (iso_path == NULL)
return; return;
@ -490,8 +495,8 @@ static void SetFSFromISO(void)
fs_mask |= 1<<fs; fs_mask |= 1<<fs;
} }
// Syslinux and EFI have precedence over bootmgr // Syslinux and EFI have precedence over bootmgr (unless the user selected BIOS as target type)
if ((iso_report.has_isolinux) || (IS_EFI(iso_report))) { if ((iso_report.has_isolinux) || ( (IS_EFI(iso_report)) && (bt == BT_UEFI))) {
if (fs_mask & (1<<FS_FAT32)) { if (fs_mask & (1<<FS_FAT32)) {
selected_fs = FS_FAT32; selected_fs = FS_FAT32;
} else if (fs_mask & (1<<FS_FAT16)) { } else if (fs_mask & (1<<FS_FAT16)) {
@ -549,7 +554,7 @@ static BOOL PopulateProperties(int ComboIndex)
char capacity[64]; char capacity[64];
static char* suffix[] = { "B", "KB", "MB", "GB", "TB", "PB"}; static char* suffix[] = { "B", "KB", "MB", "GB", "TB", "PB"};
char no_label[] = STR_NO_LABEL; char no_label[] = STR_NO_LABEL;
int i, j, fs; int i, j, pt, bt, fs;
IGNORE_RETVAL(ComboBox_ResetContent(hPartitionScheme)); IGNORE_RETVAL(ComboBox_ResetContent(hPartitionScheme));
IGNORE_RETVAL(ComboBox_ResetContent(hFileSystem)); IGNORE_RETVAL(ComboBox_ResetContent(hFileSystem));
@ -561,8 +566,7 @@ static BOOL PopulateProperties(int ComboIndex)
if (ComboIndex < 0) if (ComboIndex < 0)
return TRUE; return TRUE;
SelectedDrive.DeviceNumber = (DWORD)ComboBox_GetItemData(hDeviceList, ComboIndex); if (!GetDriveInfo((DWORD)ComboBox_GetItemData(hDeviceList, ComboIndex))) // This also populates FS
if (!GetDriveInfo()) // This also populates FS
return FALSE; return FALSE;
SetFSFromISO(); SetFSFromISO();
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)); fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
@ -572,17 +576,31 @@ static BOOL PopulateProperties(int ComboIndex)
for (i=1; i<ARRAYSIZE(suffix); i++) { for (i=1; i<ARRAYSIZE(suffix); i++) {
HumanReadableSize /= 1024.0; HumanReadableSize /= 1024.0;
if (HumanReadableSize < 512.0) { if (HumanReadableSize < 512.0) {
for (j=0; j<PT_MAX; j++) { for (j=0; j<3; j++) {
safe_sprintf(capacity, sizeof(capacity), "%s (1 Partition of %0.2f %s)", // Populate BIOS/MBR, UEFI/MBR and UEFI/GPT targets, with an exception
PartitionSchemeName[j], HumanReadableSize, suffix[i]); // for XP, as it doesn't support GPT at all
IGNORE_RETVAL(ComboBox_SetItemData(hPartitionScheme, ComboBox_AddStringU(hPartitionScheme, capacity), j)); if ((j == 2) && (nWindowsVersion <= WINDOWS_XP))
continue;
bt = (j==0)?BT_BIOS:BT_UEFI;
pt = (j==2)?PARTITION_STYLE_GPT:PARTITION_STYLE_MBR;
safe_sprintf(capacity, sizeof(capacity), "%s/%s (1 Partition of %0.2f %s)",
PartitionTypeName[pt], BiosTypeName[bt], HumanReadableSize, suffix[i]);
IGNORE_RETVAL(ComboBox_SetItemData(hPartitionScheme, ComboBox_AddStringU(hPartitionScheme, capacity), (bt<<16)|pt));
} }
break; break;
} }
} }
if (i >= ARRAYSIZE(suffix)) if (i >= ARRAYSIZE(suffix))
uprintf("Could not populate partition scheme data\n"); uprintf("Could not populate partition scheme data\n");
IGNORE_RETVAL(ComboBox_SetCurSel(hPartitionScheme, SelectedDrive.PartitionType)); if (SelectedDrive.PartitionType == PARTITION_STYLE_GPT) {
j = 2;
} else if (SelectedDrive.has_protective_mbr) {
j = 1;
} else {
j = 0;
}
IGNORE_RETVAL(ComboBox_SetCurSel(hPartitionScheme, j));
// TODO: create a tooltip for hPartitionScheme
CreateTooltip(hDeviceList, DriveID.Table[ComboIndex], -1); CreateTooltip(hDeviceList, DriveID.Table[ComboIndex], -1);
// Set a proposed label according to the size (eg: "256MB", "8GB") // Set a proposed label according to the size (eg: "256MB", "8GB")
@ -638,11 +656,11 @@ BOOL CreatePartition(HANDLE hDrive)
BOOL r; BOOL r;
DWORD size; DWORD size;
LONGLONG size_in_sectors; LONGLONG size_in_sectors;
int pt = (int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)); int pt = GETPARTTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
PrintStatus(0, TRUE, "Partitioning (%s)...", PartitionSchemeName[pt]); PrintStatus(0, TRUE, "Partitioning (%s)...", PartitionTypeName[pt]);
if ((pt == PT_GPT) || (!IsChecked(IDC_EXTRA_PARTITION))) { if ((pt == PARTITION_STYLE_GPT) || (!IsChecked(IDC_EXTRA_PARTITION))) {
// Go with the MS 1 MB wastage at the beginning... // Go with the MS 1 MB wastage at the beginning...
DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart = 1024*1024; DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart = 1024*1024;
} else { } else {
@ -653,7 +671,7 @@ BOOL CreatePartition(HANDLE hDrive)
size_in_sectors = (SelectedDrive.DiskSize - DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart) / SelectedDrive.Geometry.BytesPerSector; size_in_sectors = (SelectedDrive.DiskSize - DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart) / SelectedDrive.Geometry.BytesPerSector;
switch (pt) { switch (pt) {
case PT_MBR: case PARTITION_STYLE_MBR:
CreateDisk.PartitionStyle = PARTITION_STYLE_MBR; CreateDisk.PartitionStyle = PARTITION_STYLE_MBR;
CreateDisk.Mbr.Signature = GetTickCount(); CreateDisk.Mbr.Signature = GetTickCount();
@ -672,7 +690,7 @@ BOOL CreatePartition(HANDLE hDrive)
return FALSE; return FALSE;
} }
break; break;
case PT_GPT: case PARTITION_STYLE_GPT:
CreateDisk.PartitionStyle = PARTITION_STYLE_GPT; CreateDisk.PartitionStyle = PARTITION_STYLE_GPT;
IGNORE_RETVAL(CoCreateGuid(&CreateDisk.Gpt.DiskId)); IGNORE_RETVAL(CoCreateGuid(&CreateDisk.Gpt.DiskId));
CreateDisk.Gpt.MaxPartitionCount = MAX_GPT_PARTITIONS; CreateDisk.Gpt.MaxPartitionCount = MAX_GPT_PARTITIONS;
@ -698,7 +716,7 @@ BOOL CreatePartition(HANDLE hDrive)
DriveLayoutEx.PartitionEntry[0].RewritePartition = TRUE; DriveLayoutEx.PartitionEntry[0].RewritePartition = TRUE;
switch (pt) { switch (pt) {
case PT_MBR: case PARTITION_STYLE_MBR:
DriveLayoutEx.PartitionEntry[0].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack; DriveLayoutEx.PartitionEntry[0].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack;
switch (ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))) { switch (ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))) {
case FS_FAT16: case FS_FAT16:
@ -730,7 +748,7 @@ BOOL CreatePartition(HANDLE hDrive)
// For the remaining partitions, PartitionStyle & PartitionType have already // For the remaining partitions, PartitionStyle & PartitionType have already
// been zeroed => already set to MBR/unused // been zeroed => already set to MBR/unused
break; break;
case PT_GPT: case PARTITION_STYLE_GPT:
DriveLayoutEx.PartitionEntry[0].Gpt.PartitionType = PARTITION_BASIC_DATA_GUID; DriveLayoutEx.PartitionEntry[0].Gpt.PartitionType = PARTITION_BASIC_DATA_GUID;
wcscpy(DriveLayoutEx.PartitionEntry[0].Gpt.Name, L"Microsoft Basic Data"); wcscpy(DriveLayoutEx.PartitionEntry[0].Gpt.Name, L"Microsoft Basic Data");
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[0].Gpt.PartitionId)); IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[0].Gpt.PartitionId));
@ -749,7 +767,7 @@ BOOL CreatePartition(HANDLE hDrive)
return FALSE; return FALSE;
} }
size = sizeof(DriveLayoutEx) - ((pt == PT_GPT)?(3*sizeof(PARTITION_INFORMATION_EX)):0); size = sizeof(DriveLayoutEx) - ((pt == PARTITION_STYLE_GPT)?(3*sizeof(PARTITION_INFORMATION_EX)):0);
r = DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, r = DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
(BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL ); (BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL );
if (!r) { if (!r) {
@ -1241,10 +1259,6 @@ BOOL CALLBACK LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
break; break;
} }
break; break;
// case WM_SHOWWINDOW:
// if (wParam)
// SendMessage(hLog, EM_LINESCROLL, 0, SendMessage(hLog, EM_GETLINECOUNT, 0, 0));
// return FALSE;
case WM_CLOSE: case WM_CLOSE:
ShowWindow(hDlg, SW_HIDE); ShowWindow(hDlg, SW_HIDE);
log_displayed = FALSE; log_displayed = FALSE;
@ -1637,7 +1651,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
DRAWITEMSTRUCT* pDI; DRAWITEMSTRUCT* pDI;
POINT Point; POINT Point;
RECT DialogRect, DesktopRect; RECT DialogRect, DesktopRect;
int nDeviceIndex, fs, pt, i, nWidth, nHeight; int nDeviceIndex, fs, bt, i, nWidth, nHeight;
static DWORD DeviceNum = 0; static DWORD DeviceNum = 0;
wchar_t wtmp[128], wstr[MAX_PATH]; wchar_t wtmp[128], wstr[MAX_PATH];
static UINT uDOSChecked = BST_CHECKED, uQFChecked; static UINT uDOSChecked = BST_CHECKED, uQFChecked;
@ -1787,7 +1801,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
if (HIWORD(wParam) != CBN_SELCHANGE) if (HIWORD(wParam) != CBN_SELCHANGE)
break; break;
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)); fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
pt = (int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)); bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
SetClusterSizes(fs); SetClusterSizes(fs);
// Disable/restore the quick format control depending on large FAT32 // Disable/restore the quick format control depending on large FAT32
if ((fs == FS_FAT32) && (SelectedDrive.DiskSize > LARGE_FAT32_SIZE)) { if ((fs == FS_FAT32) && (SelectedDrive.DiskSize > LARGE_FAT32_SIZE)) {
@ -1812,7 +1826,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
} }
break; break;
} }
if ((fs == FS_EXFAT) || ((pt == PT_GPT) && (fs == FS_NTFS))) { if (fs == FS_EXFAT) {
if (IsWindowEnabled(hDOS)) { if (IsWindowEnabled(hDOS)) {
// unlikely to be supported by BIOSes => don't bother // unlikely to be supported by BIOSes => don't bother
IGNORE_RETVAL(ComboBox_SetCurSel(hDOSType, 0)); IGNORE_RETVAL(ComboBox_SetCurSel(hDOSType, 0));
@ -1824,13 +1838,13 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
break; break;
} }
IGNORE_RETVAL(ComboBox_ResetContent(hDOSType)); IGNORE_RETVAL(ComboBox_ResetContent(hDOSType));
if ((pt == PT_MBR) && ((fs == FS_FAT16) || (fs == FS_FAT32))) { if ((bt == BT_BIOS) && ((fs == FS_FAT16) || (fs == FS_FAT32))) {
IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "MS-DOS"), DT_WINME)); IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "MS-DOS"), DT_WINME));
IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "FreeDOS"), DT_FREEDOS)); IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "FreeDOS"), DT_FREEDOS));
} }
IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "ISO Image"), DT_ISO)); IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "ISO Image"), DT_ISO));
// If needed (advanced mode) also append a Syslinux option // If needed (advanced mode) also append a Syslinux option
if ( (pt == PT_MBR) && (((fs == FS_FAT16) || (fs == FS_FAT32)) && (advanced_mode)) ) if ( (bt == BT_BIOS) && (((fs == FS_FAT16) || (fs == FS_FAT32)) && (advanced_mode)) )
IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "SysLinux"), DT_SYSLINUX)); IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "SysLinux"), DT_SYSLINUX));
if ( ((!advanced_mode) && (selection_default == DT_SYSLINUX)) ) { if ( ((!advanced_mode) && (selection_default == DT_SYSLINUX)) ) {
selection_default = DT_FREEDOS; selection_default = DT_FREEDOS;
@ -1923,24 +1937,37 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
break; break;
} }
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)); fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
pt = (int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)); bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
if ((pt == PT_GPT) && ((!IS_EFI(iso_report)) || ((fs > FS_FAT32)))) { if (bt == BT_UEFI) {
MessageBoxA(hMainDialog, "When using GPT, only EFI bootable ISOs are supported. " if (!IS_EFI(iso_report)) {
"Please select an EFI bootable ISO or change the Partition Scheme to MBR.", "Unsupported GPT ISO...", MB_OK|MB_ICONERROR); MessageBoxA(hMainDialog, "When using UEFI Target Type, only EFI bootable ISO images are supported. "
"Please select an EFI bootable ISO or set the Target Type to BIOS.", "Unsupported ISO...", MB_OK|MB_ICONERROR);
break;
} else if (fs > FS_FAT32) {
MessageBoxA(hMainDialog, "When using UEFI Target Type, only FAT/FAT32 is supported. "
"Please select FAT/FAT32 as the File system or set the Target Type to BIOS.", "Unsupported filesystem...", MB_OK|MB_ICONERROR);
break; break;
} }
else if ((fs == FS_NTFS) && (!iso_report.has_bootmgr) && (!IS_WINPE(iso_report.winpe))) { } else if ((fs == FS_NTFS) && (!iso_report.has_bootmgr) && (!IS_WINPE(iso_report.winpe))) {
if (iso_report.has_isolinux) { if (iso_report.has_isolinux) {
MessageBoxA(hMainDialog, "Only FAT32 is supported for this type of ISO. " MessageBoxA(hMainDialog, "Only FAT/FAT32 is supported for this type of ISO. "
"Please revert the filesystem back from NTFS to FAT32.", "Unsupported filesystem...", MB_OK|MB_ICONERROR); "Please select FAT/FAT32 as the File system.", "Unsupported filesystem...", MB_OK|MB_ICONERROR);
} else { } else {
MessageBoxA(hMainDialog, "Only 'bootmgr' or 'WinPE' based ISO " MessageBoxA(hMainDialog, "Only 'bootmgr' or 'WinPE' based ISO "
"images can currently be used with NTFS.", "Unsupported ISO...", MB_OK|MB_ICONERROR); "images can currently be used with NTFS.", "Unsupported ISO...", MB_OK|MB_ICONERROR);
} }
break; break;
} else if (((fs == FS_FAT16)||(fs == FS_FAT32)) && ((!iso_report.has_isolinux) && (pt != PT_GPT))) { } else if (((fs == FS_FAT16)||(fs == FS_FAT32)) && (!iso_report.has_isolinux)) {
MessageBoxA(hMainDialog, "Only isolinux or EFI based ISO " MessageBoxA(hMainDialog, "FAT/FAT32 can only be used for isolinux based ISO images "
"images can currently be used with FAT/FAT32.", "Unsupported ISO...", MB_OK|MB_ICONERROR); "or when the Target Type is UEFI.", "Unsupported ISO...", MB_OK|MB_ICONERROR);
break;
}
if ((bt == BT_UEFI) && (iso_report.has_win7_efi) && (!WimExtractCheck())) {
if (MessageBoxA(hMainDialog, "Your platform cannot extract files from WIM archives. WIM extraction "
"is required to create EFI bootable Windows 7 and Windows Vista USB drives. You can fix that "
"by installing a recent version of 7-Zip.\r\nDo you want to visit the 7-zip download page?",
"Missing WIM support...", MB_YESNO|MB_ICONERROR) == IDYES)
ShellExecuteA(hDlg, "open", SEVENZIP_URL, NULL, NULL, SW_SHOWNORMAL);
break; break;
} }
} }

View file

@ -51,6 +51,7 @@
#define WHITE RGB(255,255,255) #define WHITE RGB(255,255,255)
#define SEPARATOR_GREY RGB(223,223,223) #define SEPARATOR_GREY RGB(223,223,223)
#define RUFUS_URL "http://rufus.akeo.ie" #define RUFUS_URL "http://rufus.akeo.ie"
#define SEVENZIP_URL "http://sourceforge.net/projects/sevenzip/files/7-Zip/"
#define IGNORE_RETVAL(expr) do { (void)(expr); } while(0) #define IGNORE_RETVAL(expr) do { (void)(expr); } while(0)
#ifndef ARRAYSIZE #ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
@ -150,11 +151,14 @@ enum dos_type {
DT_MAX DT_MAX
}; };
enum part_type { enum bios_type {
PT_MBR = 0, BT_BIOS = 0,
PT_GPT, BT_UEFI,
PT_MAX BT_MAX
}; };
// For the partition types we'll use Microsoft's PARTITION_STYLE_### constants
#define GETBIOSTYPE(x) (((x) >> 16) & 0xFFFF)
#define GETPARTTYPE(x) ((x) & 0xFFFF);
/* Current drive info */ /* Current drive info */
typedef struct { typedef struct {
@ -165,6 +169,7 @@ typedef struct {
char proposed_label[16]; char proposed_label[16];
int PartitionType; int PartitionType;
int FSType; int FSType;
BOOL has_protective_mbr;
struct { struct {
ULONG Allowed; ULONG Allowed;
ULONG Default; ULONG Default;
@ -298,7 +303,8 @@ extern char* get_token_data_buffer(const char* token, unsigned int n, const char
extern char* insert_section_data(const char* filename, const char* section, const char* data, BOOL dos2unix); extern char* insert_section_data(const char* filename, const char* section, const char* data, BOOL dos2unix);
extern char* replace_in_token_data(const char* filename, const char* token, const char* src, const char* rep, BOOL dos2unix); extern char* replace_in_token_data(const char* filename, const char* token, const char* src, const char* rep, BOOL dos2unix);
extern void parse_update(char* buf, size_t len); extern void parse_update(char* buf, size_t len);
extern BOOL WIMExtractFile(const char* wim_image, int index, const char* src, const char* dst); extern BOOL WimExtractCheck(void);
extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst);
__inline static BOOL UnlockDrive(HANDLE hDrive) __inline static BOOL UnlockDrive(HANDLE hDrive)
{ {

View file

@ -30,7 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 206, 316 IDD_DIALOG DIALOGEX 12, 12, 206, 316
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW EXSTYLE WS_EX_APPWINDOW
CAPTION "Rufus v1.3.1.224" CAPTION "Rufus v1.3.1.225"
FONT 8, "MS Shell Dlg", 400, 0, 0x1 FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,278,50,14 DEFPUSHBUTTON "Start",IDC_START,94,278,50,14
@ -40,7 +40,7 @@ BEGIN
COMBOBOX IDC_FILESYSTEM,8,75,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_FILESYSTEM,8,75,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "File system",IDC_STATIC,9,64,51,10 LTEXT "File system",IDC_STATIC,9,64,51,10
COMBOBOX IDC_PARTITION_SCHEME,8,46,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_PARTITION_SCHEME,8,46,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Partition Scheme",IDC_STATIC,9,35,75,8 LTEXT "Partition Scheme and Target Type",IDC_STATIC,9,35,176,8
COMBOBOX IDC_CLUSTERSIZE,8,104,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_CLUSTERSIZE,8,104,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Cluster size",IDC_STATIC,9,93,105,10 LTEXT "Cluster size",IDC_STATIC,9,93,105,10
PUSHBUTTON "About...",IDC_ABOUT,8,278,50,14 PUSHBUTTON "About...",IDC_ABOUT,8,278,50,14
@ -274,8 +274,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,3,1,224 FILEVERSION 1,3,1,225
PRODUCTVERSION 1,3,1,224 PRODUCTVERSION 1,3,1,225
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -292,13 +292,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", "1.3.1.224" VALUE "FileVersion", "1.3.1.225"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "(c) 2011-2012 Pete Batard (GPL v3)" VALUE "LegalCopyright", "(c) 2011-2012 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", "1.3.1.224" VALUE "ProductVersion", "1.3.1.225"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

126
src/vhd.c
View file

@ -17,8 +17,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <windows.h>
#include <io.h>
#include "rufus.h" #include "rufus.h"
#include "msapi_utf8.h" #include "msapi_utf8.h"
#include "registry.h"
static BOOL has_wimgapi = FALSE, has_7z = FALSE;
#define WIM_GENERIC_READ GENERIC_READ #define WIM_GENERIC_READ GENERIC_READ
#define WIM_OPEN_EXISTING OPEN_EXISTING #define WIM_OPEN_EXISTING OPEN_EXISTING
@ -53,9 +59,39 @@ typedef BOOL (WINAPI *WIMCloseHandle_t)(
HANDLE hObj HANDLE hObj
); );
// Extract a file from a WIM image // WIM API Prototypes
static PF_DECL(WIMCreateFile);
static PF_DECL(WIMSetTemporaryPath);
static PF_DECL(WIMLoadImage);
static PF_DECL(WIMExtractImagePath);
static PF_DECL(WIMCloseHandle);
// Find out if we have any way to extraxt WIM files on this platform
BOOL WimExtractCheck(void)
{
char sevenzip_path[MAX_PATH];
PF_INIT(WIMCreateFile, wimgapi);
PF_INIT(WIMSetTemporaryPath, wimgapi);
PF_INIT(WIMLoadImage, wimgapi);
PF_INIT(WIMExtractImagePath, wimgapi);
PF_INIT(WIMCloseHandle, wimgapi);
has_wimgapi = (pfWIMCreateFile && pfWIMSetTemporaryPath && pfWIMLoadImage && pfWIMExtractImagePath && pfWIMCloseHandle);
if (GetRegistryKeyStr("7-Zip\\Path", sevenzip_path, sizeof(sevenzip_path))) {
safe_strcat(sevenzip_path, sizeof(sevenzip_path), "\\7z.exe");
has_7z = (_access(sevenzip_path, 0) != -1);
}
uprintf("WIM extraction method(s) supported: %s%s%s\n", has_7z?"7z":(has_wimgapi?"":"NONE"),
(has_wimgapi && has_7z)?", ":"", has_wimgapi?"wimgapi.dll":"");
return (has_wimgapi || has_7z);
}
// Extract a file from a WIM image using wimgapi.dll (Windows 7 or later)
// NB: Don't bother trying to get progress from a WIM callback - it doesn't work! // NB: Don't bother trying to get progress from a WIM callback - it doesn't work!
BOOL WIMExtractFile(const char* image, int index, const char* src, const char* dst) static BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst)
{ {
BOOL r = FALSE; BOOL r = FALSE;
DWORD dw = 0; DWORD dw = 0;
@ -65,11 +101,6 @@ BOOL WIMExtractFile(const char* image, int index, const char* src, const char* d
wchar_t* wimage = utf8_to_wchar(image); wchar_t* wimage = utf8_to_wchar(image);
wchar_t* wsrc = utf8_to_wchar(src); wchar_t* wsrc = utf8_to_wchar(src);
wchar_t* wdst = utf8_to_wchar(dst); wchar_t* wdst = utf8_to_wchar(dst);
PF_DECL(WIMCreateFile);
PF_DECL(WIMSetTemporaryPath);
PF_DECL(WIMLoadImage);
PF_DECL(WIMExtractImagePath);
PF_DECL(WIMCloseHandle);
PF_INIT_OR_OUT(WIMCreateFile, wimgapi); PF_INIT_OR_OUT(WIMCreateFile, wimgapi);
PF_INIT_OR_OUT(WIMSetTemporaryPath, wimgapi); PF_INIT_OR_OUT(WIMSetTemporaryPath, wimgapi);
@ -77,37 +108,36 @@ BOOL WIMExtractFile(const char* image, int index, const char* src, const char* d
PF_INIT_OR_OUT(WIMExtractImagePath, wimgapi); PF_INIT_OR_OUT(WIMExtractImagePath, wimgapi);
PF_INIT_OR_OUT(WIMCloseHandle, wimgapi); PF_INIT_OR_OUT(WIMCloseHandle, wimgapi);
// TODO: check for NULL and missing wimgapi.dll uprintf("Opening: %s:[%d] (API)\n", image, index);
if (GetTempPathW(ARRAYSIZE(wtemp), wtemp) == 0) { if (GetTempPathW(ARRAYSIZE(wtemp), wtemp) == 0) {
uprintf("Could not fetch temp path: %s\n", WindowsErrorString()); uprintf(" Could not fetch temp path: %s\n", WindowsErrorString());
goto out; goto out;
} }
uprintf("Opening: %s (index #%d)\n", image, index);
hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING, 0, 0, &dw); hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING, 0, 0, &dw);
if (hWim == NULL) { if (hWim == NULL) {
uprintf(" Error: '%s': %s\n", WindowsErrorString()); uprintf(" Could not access image: %s\n", WindowsErrorString());
goto out; goto out;
} }
if (!pfWIMSetTemporaryPath(hWim, wtemp)) { if (!pfWIMSetTemporaryPath(hWim, wtemp)) {
uprintf(" Error setting temp path: %s\n", WindowsErrorString()); uprintf(" Could not set temp path: %s\n", WindowsErrorString());
goto out; goto out;
} }
hImage = pfWIMLoadImage(hWim, (DWORD)index); hImage = pfWIMLoadImage(hWim, (DWORD)index);
if (hImage == NULL) { if (hImage == NULL) {
uprintf(" Error setting index: %s.\n", WindowsErrorString()); uprintf(" Could not set index: %s\n", WindowsErrorString());
goto out; goto out;
} }
uprintf("Extracting: %s (From \\%s)\n", dst, src); uprintf("Extracting: %s (From \\%s)\n", dst, src);
if (!pfWIMExtractImagePath(hImage, wsrc, wdst, 0)) { if (!pfWIMExtractImagePath(hImage, wsrc, wdst, 0)) {
uprintf(" Could not extract file: %s.\n", WindowsErrorString()); uprintf(" Could not extract file: %s\n", WindowsErrorString());
goto out; goto out;
} }
r = TRUE; r = TRUE;
UpdateProgress(OP_FINALIZE, -1.0f);
out: out:
if ((hImage != NULL) || (hWim != NULL)) { if ((hImage != NULL) || (hWim != NULL)) {
@ -120,3 +150,69 @@ out:
safe_free(wdst); safe_free(wdst);
return r; return r;
} }
// Extract a file from a WIM image using 7-Zip
static BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char* dst)
{
size_t i;
STARTUPINFOA si = {0};
PROCESS_INFORMATION pi = {0};
char sevenzip_path[MAX_PATH];
char cmdline[MAX_PATH];
char tmpdst[MAX_PATH];
uprintf("Opening: %s:[%d] (7-Zip)\n", image, index);
if (!GetRegistryKeyStr("7-Zip\\Path", sevenzip_path, sizeof(sevenzip_path))) {
uprintf(" Could not read 7-Zip path from registry\n");
return FALSE;
}
safe_strcat(sevenzip_path, sizeof(sevenzip_path), "\\7z.exe");
if (_access(sevenzip_path, 0) == -1) {
uprintf(" Could not locate 7z.exe at '%s'\n", sevenzip_path);
return FALSE;
}
safe_strcpy(tmpdst, sizeof(tmpdst), dst);
for (i=safe_strlen(tmpdst); i>0; i--) {
if (tmpdst[i] == '\\')
break;
}
tmpdst[i] = 0;
si.cb = sizeof(si);
safe_sprintf(cmdline, sizeof(cmdline), "7z -y e \"%s\" %d\\Windows\\Boot\\EFI\\bootmgfw.efi", image, index);
uprintf("Extracting: %s (From \\%s)\n", dst, src);
if (!CreateProcessU(sevenzip_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, tmpdst, &si, &pi)) {
uprintf(" Could not launch 7z.exe: %s\n", WindowsErrorString());
return FALSE;
}
WaitForSingleObject(pi.hProcess, INFINITE);
UpdateProgress(OP_FINALIZE, -1.0f);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
safe_strcat(tmpdst, sizeof(tmpdst), "\\bootmgfw.efi");
if (_access(tmpdst, 0) == -1) {
uprintf(" 7z.exe did not extract %s\n", tmpdst);
return FALSE;
}
if (rename(tmpdst, dst) != 0) {
uprintf(" Could not rename %s to %s\n", tmpdst, dst);
return FALSE;
}
return TRUE;
}
// Extract a file from a WIM image
BOOL WimExtractFile(const char* image, int index, const char* src, const char* dst)
{
if ((!has_wimgapi) && (!has_7z) && (!WimExtractCheck()))
return FALSE;
// Prefer 7-Zip as, unsurprisingly, it's faster than the Microsoft way,
// but allow fallback if 7-Zip doesn't succeed
return ( (has_7z && WimExtractFile_7z(image, index, src, dst))
|| (has_wimgapi && WimExtractFile_API(image, index, src, dst)) );
}