mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[iso] add support for distros using a NONSTANDARD GRUB 2.0 prefix directory
* Looking at you, openSUSE Live and GeckoLinux!
This commit is contained in:
parent
f669f05403
commit
3528ca773d
7 changed files with 139 additions and 17 deletions
|
@ -375,6 +375,8 @@
|
||||||
<ClCompile Include="..\src\vhd.c" />
|
<ClCompile Include="..\src\vhd.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\res\grub2\grub2_version.h" />
|
||||||
|
<ClInclude Include="..\res\grub\grub_version.h" />
|
||||||
<ClInclude Include="..\src\badblocks.h" />
|
<ClInclude Include="..\src\badblocks.h" />
|
||||||
<ClInclude Include="..\src\bled\bled.h" />
|
<ClInclude Include="..\src\bled\bled.h" />
|
||||||
<ClInclude Include="..\src\drive.h" />
|
<ClInclude Include="..\src\drive.h" />
|
||||||
|
|
|
@ -176,6 +176,12 @@
|
||||||
<ClInclude Include="..\src\re.h">
|
<ClInclude Include="..\src\re.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\res\grub\grub_version.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\res\grub2\grub2_version.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\res\rufus.ico">
|
<None Include="..\res\rufus.ico">
|
||||||
|
|
|
@ -2,4 +2,38 @@
|
||||||
* This file contains the version string of the GRUB 2.x binary embedded in Rufus.
|
* This file contains the version string of the GRUB 2.x binary embedded in Rufus.
|
||||||
* Should be the same as GRUB's PACKAGE_VERSION in config.h.
|
* Should be the same as GRUB's PACKAGE_VERSION in config.h.
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#define GRUB2_PACKAGE_VERSION "2.06"
|
#define GRUB2_PACKAGE_VERSION "2.06"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Also include the 'core.img' patch data for distros using a
|
||||||
|
* NONSTANDARD '/boot/grub2/' prefix directory (openSUSE, Gecko, ...)
|
||||||
|
* This is basically a diff of the 'core.img' generated with
|
||||||
|
* 'grub-mkimage -p/boot/grub' vs 'grub-mkimage -p/boot/grub2'
|
||||||
|
*/
|
||||||
|
|
||||||
|
// For GRUB 2.04
|
||||||
|
static const chunk_t grub_204_chunk1_src = { 0x0208, 1, { 0xce } };
|
||||||
|
static const chunk_t grub_204_chunk1_rep = { 0x0208, 1, { 0xcf } };
|
||||||
|
static const chunk_t grub_204_chunk2_src = { 0x7cf8, 6, { 0x63, 0x25, 0x7e, 0x04, 0xf6, 0x14 } };
|
||||||
|
static const chunk_t grub_204_chunk2_rep = { 0x7cf8, 7, { 0x62, 0xdb, 0x77, 0x57, 0x0c, 0x4e, 0x00 } };
|
||||||
|
|
||||||
|
// For GRUB 2.06
|
||||||
|
static const chunk_t grub_206_chunk1_src = { 0x0208, 1, { 0xcf } };
|
||||||
|
static const chunk_t grub_206_chunk1_rep = { 0x0208, 1, { 0xd0 } };
|
||||||
|
static const chunk_t grub_206_chunk2_src = { 0x95f9, 6, { 0xac, 0x1a, 0xc6, 0x4f, 0x45, 0x2c } };
|
||||||
|
static const chunk_t grub_206_chunk2_rep = { 0x95f9, 7, { 0xab, 0xe7, 0xe4, 0x0a, 0x2e, 0x38, 0x00 } };
|
||||||
|
|
||||||
|
const grub_patch_t grub_patch[2] = {
|
||||||
|
{ "2.04", {
|
||||||
|
{ &grub_204_chunk1_src, &grub_204_chunk1_rep },
|
||||||
|
{ &grub_204_chunk2_src, &grub_204_chunk2_rep },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ "2.06", {
|
||||||
|
{ &grub_206_chunk1_src, &grub_206_chunk1_rep },
|
||||||
|
{ &grub_206_chunk2_src, &grub_206_chunk2_rep },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
30
src/format.c
30
src/format.c
|
@ -73,6 +73,7 @@ extern uint32_t wim_nb_files, wim_proc_files, wim_extra_files;
|
||||||
static int actual_fs_type, wintogo_index = -1, wininst_index = 0;
|
static int actual_fs_type, wintogo_index = -1, wininst_index = 0;
|
||||||
extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, fast_zeroing, enable_file_indexing, write_as_image;
|
extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, fast_zeroing, enable_file_indexing, write_as_image;
|
||||||
extern BOOL use_vds, write_as_esp, is_vds_available;
|
extern BOOL use_vds, write_as_esp, is_vds_available;
|
||||||
|
extern const grub_patch_t grub_patch[2];
|
||||||
uint8_t *grub2_buf = NULL, *sec_buf = NULL;
|
uint8_t *grub2_buf = NULL, *sec_buf = NULL;
|
||||||
long grub2_len;
|
long grub2_len;
|
||||||
|
|
||||||
|
@ -909,8 +910,8 @@ static BOOL WriteSBR(HANDLE hPhysicalDrive)
|
||||||
{
|
{
|
||||||
// TODO: Do we need anything special for 4K sectors?
|
// TODO: Do we need anything special for 4K sectors?
|
||||||
DWORD size, max_size, br_size = 0x200;
|
DWORD size, max_size, br_size = 0x200;
|
||||||
int r, sub_type = boot_type;
|
int i, j, r, sub_type = boot_type;
|
||||||
unsigned char* buf = NULL;
|
uint8_t *buf = NULL, *patched = NULL;
|
||||||
FAKE_FD fake_fd = { 0 };
|
FAKE_FD fake_fd = { 0 };
|
||||||
FILE* fp = (FILE*)&fake_fd;
|
FILE* fp = (FILE*)&fake_fd;
|
||||||
|
|
||||||
|
@ -953,6 +954,31 @@ static BOOL WriteSBR(HANDLE hPhysicalDrive)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: Compute the projected increase in size instead of harcoding it
|
||||||
|
if (img_report.has_grub2 == 2 && ((patched = malloc(size + 16)) != NULL)) {
|
||||||
|
memcpy(patched, buf, size);
|
||||||
|
// Patch GRUB for nonstandard prefix directory
|
||||||
|
for (i = 0; i < ARRAYSIZE(grub_patch); i++) {
|
||||||
|
if (strcmp(img_report.grub2_version, grub_patch[i].version) == 0) {
|
||||||
|
for (j = 0; j < ARRAYSIZE(grub_patch[i].patch); j++) {
|
||||||
|
if (memcmp(&patched[grub_patch[i].patch[j].src->offset], grub_patch[i].patch[j].src->data,
|
||||||
|
grub_patch[i].patch[j].src->size) != 0) {
|
||||||
|
uprintf("ERROR: Did not find expected source data for GRUB patch");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
memcpy(&patched[grub_patch[i].patch[j].rep->offset], grub_patch[i].patch[j].rep->data,
|
||||||
|
grub_patch[i].patch[j].rep->size);
|
||||||
|
if (grub_patch[i].patch[j].rep->size > grub_patch[i].patch[j].src->size)
|
||||||
|
size += grub_patch[i].patch[j].rep->size - grub_patch[i].patch[j].src->size;
|
||||||
|
}
|
||||||
|
safe_free(grub2_buf);
|
||||||
|
grub2_buf = patched;
|
||||||
|
buf = grub2_buf;
|
||||||
|
uprintf("Patched Grub 2.0 SBR for NONSTANDARD prefix");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case BT_MAX:
|
case BT_MAX:
|
||||||
uprintf("Writing protective message SBR");
|
uprintf("Writing protective message SBR");
|
||||||
|
|
55
src/iso.c
55
src/iso.c
|
@ -82,6 +82,7 @@ RUFUS_IMG_REPORT img_report;
|
||||||
int64_t iso_blocking_status = -1;
|
int64_t iso_blocking_status = -1;
|
||||||
extern BOOL preserve_timestamps, enable_ntfs_compression;
|
extern BOOL preserve_timestamps, enable_ntfs_compression;
|
||||||
extern char* archive_path;
|
extern char* archive_path;
|
||||||
|
extern const grub_patch_t grub_patch[2];
|
||||||
BOOL enable_iso = TRUE, enable_joliet = TRUE, enable_rockridge = TRUE, has_ldlinux_c32;
|
BOOL enable_iso = TRUE, enable_joliet = TRUE, enable_rockridge = TRUE, has_ldlinux_c32;
|
||||||
#define ISO_BLOCKING(x) do {x; iso_blocking_status++; } while(0)
|
#define ISO_BLOCKING(x) do {x; iso_blocking_status++; } while(0)
|
||||||
static const char* psz_extract_dir;
|
static const char* psz_extract_dir;
|
||||||
|
@ -100,7 +101,7 @@ static const char* sources_str = "/sources";
|
||||||
static const char* wininst_name[] = { "install.wim", "install.esd", "install.swm" };
|
static const char* wininst_name[] = { "install.wim", "install.esd", "install.swm" };
|
||||||
// We only support GRUB/BIOS (x86) that uses a standard config dir (/boot/grub/i386-pc/)
|
// We only support GRUB/BIOS (x86) that uses a standard config dir (/boot/grub/i386-pc/)
|
||||||
// If the disc was mastered properly, GRUB/EFI will take care of itself
|
// If the disc was mastered properly, GRUB/EFI will take care of itself
|
||||||
static const char* grub_dirname = "/boot/grub/i386-pc";
|
static const char* grub_dirname[] = { "/boot/grub/i386-pc", "/boot/grub2/i386-pc" };
|
||||||
static const char* grub_cfg[] = { "grub.cfg", "loopback.cfg" };
|
static const char* grub_cfg[] = { "grub.cfg", "loopback.cfg" };
|
||||||
static const char* compatresources_dll = "compatresources.dll";
|
static const char* compatresources_dll = "compatresources.dll";
|
||||||
static const char* menu_cfg = "menu.cfg";
|
static const char* menu_cfg = "menu.cfg";
|
||||||
|
@ -211,8 +212,10 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const
|
||||||
}
|
}
|
||||||
} else { // Scan-time checks
|
} else { // Scan-time checks
|
||||||
// Check for GRUB artifacts
|
// Check for GRUB artifacts
|
||||||
if (safe_stricmp(psz_dirname, grub_dirname) == 0)
|
for (i = 0; i < ARRAYSIZE(grub_dirname); i++) {
|
||||||
img_report.has_grub2 = TRUE;
|
if (safe_stricmp(psz_dirname, grub_dirname[i]) == 0)
|
||||||
|
img_report.has_grub2 = (uint8_t)i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for a syslinux v5.0+ file anywhere
|
// Check for a syslinux v5.0+ file anywhere
|
||||||
if (safe_stricmp(psz_basename, ldlinux_c32) == 0) {
|
if (safe_stricmp(psz_basename, ldlinux_c32) == 0) {
|
||||||
|
@ -1092,15 +1095,17 @@ out:
|
||||||
img_report.wininst_version = GetInstallWimVersion(src_iso);
|
img_report.wininst_version = GetInstallWimVersion(src_iso);
|
||||||
}
|
}
|
||||||
if (img_report.has_grub2) {
|
if (img_report.has_grub2) {
|
||||||
|
char grub_path[128];
|
||||||
|
static_sprintf(grub_path, "%s/normal.mod", &grub_dirname[img_report.has_grub2 - 1][1]);
|
||||||
// In case we have a GRUB2 based iso, we extract boot/grub/i386-pc/normal.mod to parse its version
|
// In case we have a GRUB2 based iso, we extract boot/grub/i386-pc/normal.mod to parse its version
|
||||||
img_report.grub2_version[0] = 0;
|
img_report.grub2_version[0] = 0;
|
||||||
// coverity[swapped_arguments]
|
// coverity[swapped_arguments]
|
||||||
if (GetTempFileNameU(temp_dir, APPLICATION_NAME, 0, path) != 0) {
|
if (GetTempFileNameU(temp_dir, APPLICATION_NAME, 0, path) != 0) {
|
||||||
size = (size_t)ExtractISOFile(src_iso, "boot/grub/i386-pc/normal.mod", path, FILE_ATTRIBUTE_NORMAL);
|
size = (size_t)ExtractISOFile(src_iso, grub_path, path, FILE_ATTRIBUTE_NORMAL);
|
||||||
buf = (char*)calloc(size, 1);
|
buf = (char*)calloc(size, 1);
|
||||||
fd = fopen(path, "rb");
|
fd = fopen(path, "rb");
|
||||||
if ((size == 0) || (buf == NULL) || (fd == NULL)) {
|
if ((size == 0) || (buf == NULL) || (fd == NULL)) {
|
||||||
uprintf(" Could not read Grub version from 'boot/grub/i386-pc/normal.mod'");
|
uprintf(" Could not read Grub version from '%s'", grub_path);
|
||||||
} else {
|
} else {
|
||||||
fread(buf, 1, size, fd);
|
fread(buf, 1, size, fd);
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
|
@ -1109,11 +1114,43 @@ out:
|
||||||
free(buf);
|
free(buf);
|
||||||
DeleteFileU(path);
|
DeleteFileU(path);
|
||||||
}
|
}
|
||||||
if (img_report.grub2_version[0] != 0)
|
if (img_report.grub2_version[0] != 0) {
|
||||||
uprintf(" Detected Grub version: %s", img_report.grub2_version);
|
// (Insert "Why is it always you three" meme, with Fedora, Manjaro and openSUSE)
|
||||||
else {
|
// For some obscure reason, openSUSE have decided that their Live images should
|
||||||
|
// use /boot/grub2/ as their prefix directory instead of the standard /boot/grub/
|
||||||
|
// This creates a MAJOR issue because the prefix directory is hardcoded in
|
||||||
|
// 'core.img', and Rufus must install a 'core.img', that is not provided by the
|
||||||
|
// ISO, for the USB to boot (since even trying to pick the one from ISOHybrid
|
||||||
|
// does usually not guarantees the presence of the FAT driver which is mandatory
|
||||||
|
// for ISO boot).
|
||||||
|
// Therefore, when *someone* uses a nonstandard GRUB prefix directory, our base
|
||||||
|
// 'core.img' can't work with their image, since it isn't able to load modules
|
||||||
|
// like 'normal.mod', that are required to access the configuration files. Oh and
|
||||||
|
// you can forget about direct editing the prefix string inside 'core.img' since
|
||||||
|
// GRUB are forcing LZMA compression for BIOS payloads. And it gets even better,
|
||||||
|
// because even if you're trying to be smart and use GRUB's earlyconfig features
|
||||||
|
// to do something like:
|
||||||
|
// if [ -e /boot/grub2/i386-pc/normal.mod ]; then set prefix = ...
|
||||||
|
// you still must embed 'configfile.mod' and 'normal.mod' in 'core.img' in order
|
||||||
|
// to do that, which ends up tripling the file size...
|
||||||
|
// Soooo, since the universe is conspiring against us and in order to cut a long
|
||||||
|
// story short about developers making annoying decisions, we'll take advantage
|
||||||
|
// of the fact that the LZMA replacement section for the 2.04 and 2.06 'core.img'
|
||||||
|
// when using '/boot/grub2' as a prefix is very small and always located at the
|
||||||
|
// very end the file to patch the damn thing and get on with our life!
|
||||||
|
uprintf(" Detected Grub version: %s%s", img_report.grub2_version,
|
||||||
|
img_report.has_grub2 >= 1 ? " with NONSTANDARD prefix" : "");
|
||||||
|
for (k = 0; k < ARRAYSIZE(grub_patch); k++) {
|
||||||
|
if (strcmp(img_report.grub2_version, grub_patch[k].version) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (k >= ARRAYSIZE(grub_patch)) {
|
||||||
|
uprintf(" • Don't have a prefix patch for this version => DROPPED!");
|
||||||
|
img_report.has_grub2 = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
uprintf(" Could not detect Grub version");
|
uprintf(" Could not detect Grub version");
|
||||||
img_report.has_grub2 = FALSE;
|
img_report.has_grub2 = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (img_report.has_compatresources_dll) {
|
if (img_report.has_compatresources_dll) {
|
||||||
|
|
19
src/rufus.h
19
src/rufus.h
|
@ -384,7 +384,7 @@ typedef struct {
|
||||||
BOOLEAN has_efi_syslinux;
|
BOOLEAN has_efi_syslinux;
|
||||||
BOOLEAN needs_syslinux_overwrite;
|
BOOLEAN needs_syslinux_overwrite;
|
||||||
BOOLEAN has_grub4dos;
|
BOOLEAN has_grub4dos;
|
||||||
BOOLEAN has_grub2;
|
uint8_t has_grub2;
|
||||||
BOOLEAN has_compatresources_dll;
|
BOOLEAN has_compatresources_dll;
|
||||||
BOOLEAN has_kolibrios;
|
BOOLEAN has_kolibrios;
|
||||||
BOOLEAN uses_casper;
|
BOOLEAN uses_casper;
|
||||||
|
@ -666,6 +666,23 @@ extern void StrArrayClear(StrArray* arr);
|
||||||
extern void StrArrayDestroy(StrArray* arr);
|
extern void StrArrayDestroy(StrArray* arr);
|
||||||
#define IsStrArrayEmpty(arr) (arr.Index == 0)
|
#define IsStrArrayEmpty(arr) (arr.Index == 0)
|
||||||
|
|
||||||
|
/* Patch structs for GRUB */
|
||||||
|
typedef struct {
|
||||||
|
const uint32_t offset;
|
||||||
|
const uint32_t size;
|
||||||
|
const uint8_t data[];
|
||||||
|
} chunk_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const chunk_t* src;
|
||||||
|
const chunk_t* rep;
|
||||||
|
} patch_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* version;
|
||||||
|
const patch_t patch[2];
|
||||||
|
} grub_patch_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* typedefs for the function prototypes. Use the something like:
|
* typedefs for the function prototypes. Use the something like:
|
||||||
* PF_DECL(FormatEx);
|
* PF_DECL(FormatEx);
|
||||||
|
|
10
src/rufus.rc
10
src/rufus.rc
|
@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||||
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
||||||
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_ACCEPTFILES
|
EXSTYLE WS_EX_ACCEPTFILES
|
||||||
CAPTION "Rufus 3.19.1880"
|
CAPTION "Rufus 3.19.1881"
|
||||||
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
||||||
BEGIN
|
BEGIN
|
||||||
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
||||||
|
@ -395,8 +395,8 @@ END
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 3,19,1880,0
|
FILEVERSION 3,19,1881,0
|
||||||
PRODUCTVERSION 3,19,1880,0
|
PRODUCTVERSION 3,19,1881,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -414,13 +414,13 @@ BEGIN
|
||||||
VALUE "Comments", "https://rufus.ie"
|
VALUE "Comments", "https://rufus.ie"
|
||||||
VALUE "CompanyName", "Akeo Consulting"
|
VALUE "CompanyName", "Akeo Consulting"
|
||||||
VALUE "FileDescription", "Rufus"
|
VALUE "FileDescription", "Rufus"
|
||||||
VALUE "FileVersion", "3.19.1880"
|
VALUE "FileVersion", "3.19.1881"
|
||||||
VALUE "InternalName", "Rufus"
|
VALUE "InternalName", "Rufus"
|
||||||
VALUE "LegalCopyright", "© 2011-2022 Pete Batard (GPL v3)"
|
VALUE "LegalCopyright", "© 2011-2022 Pete Batard (GPL v3)"
|
||||||
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
|
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
|
||||||
VALUE "OriginalFilename", "rufus-3.19.exe"
|
VALUE "OriginalFilename", "rufus-3.19.exe"
|
||||||
VALUE "ProductName", "Rufus"
|
VALUE "ProductName", "Rufus"
|
||||||
VALUE "ProductVersion", "3.19.1880"
|
VALUE "ProductVersion", "3.19.1881"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
Loading…
Reference in a new issue