[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;
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) {
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY;
goto out;
@ -818,7 +818,6 @@ static BOOL WriteMBR(HANDLE hPhysicalDrive)
// FormatEx rewrites the MBR and removes the LBA attribute of FAT16
// and FAT32 partitions - we need to correct this in the MBR
// TODO: Something else for bootable GPT
buf = (unsigned char*)malloc(SecSize * nSecs);
if (buf == NULL) {
uprintf("Could not allocate memory for MBR");
@ -1110,10 +1109,7 @@ static BOOL RemountVolume(char drive_letter)
*/
DWORD WINAPI FormatThread(LPVOID param)
{
int r;
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));
int r, pt, bt, fs, dt;
BOOL ret;
DWORD num = (DWORD)(uintptr_t)param;
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
@ -1126,6 +1122,11 @@ DWORD WINAPI FormatThread(LPVOID param)
char efi_dst[] = "?:\\efi\\boot\\bootx64.efi";
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);
if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
@ -1239,7 +1240,7 @@ DWORD WINAPI FormatThread(LPVOID param)
goto out;
}
if (pt == PT_MBR) {
if (pt == PARTITION_STYLE_MBR) {
PrintStatus(0, TRUE, "Writing master boot record...");
if (!WriteMBR(hPhysicalDrive)) {
if (!FormatStatus)
@ -1250,7 +1251,7 @@ DWORD WINAPI FormatThread(LPVOID param)
}
if (IsChecked(IDC_DOS)) {
if (pt == PT_GPT) {
if (bt == BT_UEFI) {
// For once, no need to do anything - just check our sanity
if ( (dt != DT_ISO) || (!IS_EFI(iso_report)) || (fs > FS_FAT32) ) {
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;
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
PrintStatus(0, TRUE, "Win7 EFI boot setup (this may take a while)...");
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);
} else {
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");
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
if (!SetupWinPE(drive_name[0]))
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));
}
/* 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)
{
BOOL r = FALSE;
size_t i = 0;
LONG s;
HKEY hSoftware = NULL, hApp = NULL;
DWORD dwDisp, dwType = -1, dwSize = dest_size;
char long_key_name[256] = "SOFTWARE\\";
memset(dest, 0, dest_size);
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,
KEY_SET_VALUE|KEY_QUERY_VALUE|KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) ) {
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)
|| (RegCreateKeyExA(hSoftware, COMPANY_NAME "\\" APPLICATION_NAME, 0, NULL, 0,
KEY_SET_VALUE|KEY_QUERY_VALUE|KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) )
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
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;
}
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",
"16 kilobytes", "32 kilobytes", "64 kilobytes", "128 kilobytes", "256 kilobytes", "512 kilobytes",
"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 iso_size_check = TRUE;
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)
*/
static BOOL GetDriveInfo(void)
static BOOL GetDriveInfo(DWORD DeviceNumber)
{
BOOL r;
HANDLE hDrive;
@ -363,7 +364,8 @@ static BOOL GetDriveInfo(void)
char DrivePath[] = "#:\\", tmp[256], fs_type[32];
DWORD i, nb_partitions = 0;
SelectedDrive.DiskSize = 0;
memset(&SelectedDrive, 0, sizeof(SelectedDrive));
SelectedDrive.DeviceNumber = DeviceNumber;
hDrive = GetDriveHandle(SelectedDrive.DeviceNumber, DrivePath, FALSE, FALSE);
if (hDrive == INVALID_HANDLE_VALUE)
@ -389,7 +391,7 @@ static BOOL GetDriveInfo(void)
} else {
switch (DriveLayout->PartitionStyle) {
case PARTITION_STYLE_MBR:
SelectedDrive.PartitionType = PT_MBR;
SelectedDrive.PartitionType = PARTITION_STYLE_MBR;
for (i=0; i<DriveLayout->PartitionCount; i++) {
if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) {
nb_partitions++;
@ -406,11 +408,13 @@ static BOOL GetDriveInfo(void)
DriveLayout->PartitionEntry[i].PartitionLength, DriveLayout->PartitionEntry[i].Mbr.HiddenSectors,
DriveLayout->PartitionEntry[i].Mbr.BootIndicator?"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;
case PARTITION_STYLE_GPT:
SelectedDrive.PartitionType = PT_GPT;
SelectedDrive.PartitionType = PARTITION_STYLE_GPT;
uprintf("Partition type: GPT, NB Partitions: %d\n", DriveLayout->PartitionCount);
uprintf("Disk GUID: %s\n", GuidToString(&DriveLayout->Gpt.DiskId));
uprintf("Max parts: %d, Start Offset: %lld, Usable = %lld bytes\n",
@ -428,7 +432,7 @@ static BOOL GetDriveInfo(void)
}
break;
default:
SelectedDrive.PartitionType = PT_MBR;
SelectedDrive.PartitionType = PARTITION_STYLE_MBR;
uprintf("Partition type: RAW\n");
break;
}
@ -480,6 +484,7 @@ static void SetFSFromISO(void)
{
int i, fs, selected_fs = FS_UNKNOWN;
uint32_t fs_mask = 0;
int bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
if (iso_path == NULL)
return;
@ -490,8 +495,8 @@ static void SetFSFromISO(void)
fs_mask |= 1<<fs;
}
// Syslinux and EFI have precedence over bootmgr
if ((iso_report.has_isolinux) || (IS_EFI(iso_report))) {
// Syslinux and EFI have precedence over bootmgr (unless the user selected BIOS as target type)
if ((iso_report.has_isolinux) || ( (IS_EFI(iso_report)) && (bt == BT_UEFI))) {
if (fs_mask & (1<<FS_FAT32)) {
selected_fs = FS_FAT32;
} else if (fs_mask & (1<<FS_FAT16)) {
@ -549,7 +554,7 @@ static BOOL PopulateProperties(int ComboIndex)
char capacity[64];
static char* suffix[] = { "B", "KB", "MB", "GB", "TB", "PB"};
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(hFileSystem));
@ -561,8 +566,7 @@ static BOOL PopulateProperties(int ComboIndex)
if (ComboIndex < 0)
return TRUE;
SelectedDrive.DeviceNumber = (DWORD)ComboBox_GetItemData(hDeviceList, ComboIndex);
if (!GetDriveInfo()) // This also populates FS
if (!GetDriveInfo((DWORD)ComboBox_GetItemData(hDeviceList, ComboIndex))) // This also populates FS
return FALSE;
SetFSFromISO();
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
@ -572,17 +576,31 @@ static BOOL PopulateProperties(int ComboIndex)
for (i=1; i<ARRAYSIZE(suffix); i++) {
HumanReadableSize /= 1024.0;
if (HumanReadableSize < 512.0) {
for (j=0; j<PT_MAX; j++) {
safe_sprintf(capacity, sizeof(capacity), "%s (1 Partition of %0.2f %s)",
PartitionSchemeName[j], HumanReadableSize, suffix[i]);
IGNORE_RETVAL(ComboBox_SetItemData(hPartitionScheme, ComboBox_AddStringU(hPartitionScheme, capacity), j));
for (j=0; j<3; j++) {
// Populate BIOS/MBR, UEFI/MBR and UEFI/GPT targets, with an exception
// for XP, as it doesn't support GPT at all
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;
}
}
if (i >= ARRAYSIZE(suffix))
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);
// Set a proposed label according to the size (eg: "256MB", "8GB")
@ -638,11 +656,11 @@ BOOL CreatePartition(HANDLE hDrive)
BOOL r;
DWORD size;
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...
DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart = 1024*1024;
} else {
@ -653,7 +671,7 @@ BOOL CreatePartition(HANDLE hDrive)
size_in_sectors = (SelectedDrive.DiskSize - DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart) / SelectedDrive.Geometry.BytesPerSector;
switch (pt) {
case PT_MBR:
case PARTITION_STYLE_MBR:
CreateDisk.PartitionStyle = PARTITION_STYLE_MBR;
CreateDisk.Mbr.Signature = GetTickCount();
@ -672,7 +690,7 @@ BOOL CreatePartition(HANDLE hDrive)
return FALSE;
}
break;
case PT_GPT:
case PARTITION_STYLE_GPT:
CreateDisk.PartitionStyle = PARTITION_STYLE_GPT;
IGNORE_RETVAL(CoCreateGuid(&CreateDisk.Gpt.DiskId));
CreateDisk.Gpt.MaxPartitionCount = MAX_GPT_PARTITIONS;
@ -698,7 +716,7 @@ BOOL CreatePartition(HANDLE hDrive)
DriveLayoutEx.PartitionEntry[0].RewritePartition = TRUE;
switch (pt) {
case PT_MBR:
case PARTITION_STYLE_MBR:
DriveLayoutEx.PartitionEntry[0].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack;
switch (ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))) {
case FS_FAT16:
@ -730,7 +748,7 @@ BOOL CreatePartition(HANDLE hDrive)
// For the remaining partitions, PartitionStyle & PartitionType have already
// been zeroed => already set to MBR/unused
break;
case PT_GPT:
case PARTITION_STYLE_GPT:
DriveLayoutEx.PartitionEntry[0].Gpt.PartitionType = PARTITION_BASIC_DATA_GUID;
wcscpy(DriveLayoutEx.PartitionEntry[0].Gpt.Name, L"Microsoft Basic Data");
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[0].Gpt.PartitionId));
@ -749,7 +767,7 @@ BOOL CreatePartition(HANDLE hDrive)
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,
(BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL );
if (!r) {
@ -1241,10 +1259,6 @@ BOOL CALLBACK LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
break;
}
break;
// case WM_SHOWWINDOW:
// if (wParam)
// SendMessage(hLog, EM_LINESCROLL, 0, SendMessage(hLog, EM_GETLINECOUNT, 0, 0));
// return FALSE;
case WM_CLOSE:
ShowWindow(hDlg, SW_HIDE);
log_displayed = FALSE;
@ -1637,7 +1651,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
DRAWITEMSTRUCT* pDI;
POINT Point;
RECT DialogRect, DesktopRect;
int nDeviceIndex, fs, pt, i, nWidth, nHeight;
int nDeviceIndex, fs, bt, i, nWidth, nHeight;
static DWORD DeviceNum = 0;
wchar_t wtmp[128], wstr[MAX_PATH];
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)
break;
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);
// Disable/restore the quick format control depending on large FAT32
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;
}
if ((fs == FS_EXFAT) || ((pt == PT_GPT) && (fs == FS_NTFS))) {
if (fs == FS_EXFAT) {
if (IsWindowEnabled(hDOS)) {
// unlikely to be supported by BIOSes => don't bother
IGNORE_RETVAL(ComboBox_SetCurSel(hDOSType, 0));
@ -1824,13 +1838,13 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
break;
}
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, "FreeDOS"), DT_FREEDOS));
}
IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "ISO Image"), DT_ISO));
// 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));
if ( ((!advanced_mode) && (selection_default == DT_SYSLINUX)) ) {
selection_default = DT_FREEDOS;
@ -1923,24 +1937,37 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
break;
}
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
pt = (int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme));
if ((pt == PT_GPT) && ((!IS_EFI(iso_report)) || ((fs > FS_FAT32)))) {
MessageBoxA(hMainDialog, "When using GPT, only EFI bootable ISOs are supported. "
"Please select an EFI bootable ISO or change the Partition Scheme to MBR.", "Unsupported GPT ISO...", MB_OK|MB_ICONERROR);
break;
}
else if ((fs == FS_NTFS) && (!iso_report.has_bootmgr) && (!IS_WINPE(iso_report.winpe))) {
bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
if (bt == BT_UEFI) {
if (!IS_EFI(iso_report)) {
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;
}
} else if ((fs == FS_NTFS) && (!iso_report.has_bootmgr) && (!IS_WINPE(iso_report.winpe))) {
if (iso_report.has_isolinux) {
MessageBoxA(hMainDialog, "Only FAT32 is supported for this type of ISO. "
"Please revert the filesystem back from NTFS to FAT32.", "Unsupported filesystem...", MB_OK|MB_ICONERROR);
MessageBoxA(hMainDialog, "Only FAT/FAT32 is supported for this type of ISO. "
"Please select FAT/FAT32 as the File system.", "Unsupported filesystem...", MB_OK|MB_ICONERROR);
} else {
MessageBoxA(hMainDialog, "Only 'bootmgr' or 'WinPE' based ISO "
"images can currently be used with NTFS.", "Unsupported ISO...", MB_OK|MB_ICONERROR);
}
break;
} else if (((fs == FS_FAT16)||(fs == FS_FAT32)) && ((!iso_report.has_isolinux) && (pt != PT_GPT))) {
MessageBoxA(hMainDialog, "Only isolinux or EFI based ISO "
"images can currently be used with FAT/FAT32.", "Unsupported ISO...", MB_OK|MB_ICONERROR);
} else if (((fs == FS_FAT16)||(fs == FS_FAT32)) && (!iso_report.has_isolinux)) {
MessageBoxA(hMainDialog, "FAT/FAT32 can only be used for isolinux based ISO images "
"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;
}
}

View File

@ -51,6 +51,7 @@
#define WHITE RGB(255,255,255)
#define SEPARATOR_GREY RGB(223,223,223)
#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)
#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
@ -150,11 +151,14 @@ enum dos_type {
DT_MAX
};
enum part_type {
PT_MBR = 0,
PT_GPT,
PT_MAX
enum bios_type {
BT_BIOS = 0,
BT_UEFI,
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 */
typedef struct {
@ -165,6 +169,7 @@ typedef struct {
char proposed_label[16];
int PartitionType;
int FSType;
BOOL has_protective_mbr;
struct {
ULONG Allowed;
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* 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 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)
{

View File

@ -30,7 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 206, 316
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "Rufus v1.3.1.224"
CAPTION "Rufus v1.3.1.225"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
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
LTEXT "File system",IDC_STATIC,9,64,51,10
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
LTEXT "Cluster size",IDC_STATIC,9,93,105,10
PUSHBUTTON "About...",IDC_ABOUT,8,278,50,14
@ -274,8 +274,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,3,1,224
PRODUCTVERSION 1,3,1,224
FILEVERSION 1,3,1,225
PRODUCTVERSION 1,3,1,225
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -292,13 +292,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "1.3.1.224"
VALUE "FileVersion", "1.3.1.225"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "(c) 2011-2012 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "1.3.1.224"
VALUE "ProductVersion", "1.3.1.225"
END
END
BLOCK "VarFileInfo"

126
src/vhd.c
View File

@ -17,8 +17,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <windows.h>
#include <io.h>
#include "rufus.h"
#include "msapi_utf8.h"
#include "registry.h"
static BOOL has_wimgapi = FALSE, has_7z = FALSE;
#define WIM_GENERIC_READ GENERIC_READ
#define WIM_OPEN_EXISTING OPEN_EXISTING
@ -53,9 +59,39 @@ typedef BOOL (WINAPI *WIMCloseHandle_t)(
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!
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;
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* wsrc = utf8_to_wchar(src);
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(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(WIMCloseHandle, wimgapi);
// TODO: check for NULL and missing wimgapi.dll
uprintf("Opening: %s:[%d] (API)\n", image, index);
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;
}
uprintf("Opening: %s (index #%d)\n", image, index);
hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING, 0, 0, &dw);
if (hWim == NULL) {
uprintf(" Error: '%s': %s\n", WindowsErrorString());
uprintf(" Could not access image: %s\n", WindowsErrorString());
goto out;
}
if (!pfWIMSetTemporaryPath(hWim, wtemp)) {
uprintf(" Error setting temp path: %s\n", WindowsErrorString());
uprintf(" Could not set temp path: %s\n", WindowsErrorString());
goto out;
}
hImage = pfWIMLoadImage(hWim, (DWORD)index);
if (hImage == NULL) {
uprintf(" Error setting index: %s.\n", WindowsErrorString());
uprintf(" Could not set index: %s\n", WindowsErrorString());
goto out;
}
uprintf("Extracting: %s (From \\%s)\n", dst, src);
if (!pfWIMExtractImagePath(hImage, wsrc, wdst, 0)) {
uprintf(" Could not extract file: %s.\n", WindowsErrorString());
uprintf(" Could not extract file: %s\n", WindowsErrorString());
goto out;
}
r = TRUE;
UpdateProgress(OP_FINALIZE, -1.0f);
out:
if ((hImage != NULL) || (hWim != NULL)) {
@ -120,3 +150,69 @@ out:
safe_free(wdst);
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)) );
}