From 8b2a5b8514ef1f814ea95e78ca3f162477bf5a2d Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 10 Feb 2026 14:01:07 +0000 Subject: [PATCH 01/82] [grub] update GRUB to 2.14 release * Can GRUB *EVER* produce a release archive that is not *UTTERLY BROKEN*??? https://lists.gnu.org/archive/html/grub-devel/2026-01/msg00043.html * Also set version to rufus-next. --- README.md | 1 + configure | 20 ++++++++++---------- configure.ac | 2 +- res/grub2/core.img | Bin 40072 -> 42742 bytes res/grub2/grub2_version.h | 2 +- res/grub2/readme.txt | 8 +++++--- src/rufus.rc | 12 ++++++------ 7 files changed, 24 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index ff0352d8..0b9191f3 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ easily accessible log, or through the [Windows debug facility](https://docs.micr * [__Official Website__](https://rufus.ie) * [FAQ](https://github.com/pbatard/rufus/wiki/FAQ) +* [Security and safety measures](https://github.com/pbatard/rufus/wiki/Security) Enhancements/Bugs ----------------- diff --git a/configure b/configure index 5bf5affe..06fae879 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for rufus 4.12. +# Generated by GNU Autoconf 2.71 for rufus 4.13. # # Report bugs to . # @@ -611,8 +611,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='rufus' PACKAGE_TARNAME='rufus' -PACKAGE_VERSION='4.12' -PACKAGE_STRING='rufus 4.12' +PACKAGE_VERSION='4.13' +PACKAGE_STRING='rufus 4.13' PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues' PACKAGE_URL='https://rufus.ie' @@ -1269,7 +1269,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures rufus 4.12 to adapt to many kinds of systems. +\`configure' configures rufus 4.13 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1336,7 +1336,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of rufus 4.12:";; + short | recursive ) echo "Configuration of rufus 4.13:";; esac cat <<\_ACEOF @@ -1428,7 +1428,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -rufus configure 4.12 +rufus configure 4.13 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -1504,7 +1504,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by rufus $as_me 4.12, which was +It was created by rufus $as_me 4.13, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -2767,7 +2767,7 @@ fi # Define the identity of the package. PACKAGE='rufus' - VERSION='4.12' + VERSION='4.13' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -5313,7 +5313,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by rufus $as_me 4.12, which was +This file was extended by rufus $as_me 4.13, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -5369,7 +5369,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -rufus config.status 4.12 +rufus config.status 4.13 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 0e488ab0..2179a531 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([rufus], [4.12], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie]) +AC_INIT([rufus], [4.13], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie]) AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies]) AC_CONFIG_SRCDIR([src/rufus.c]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/res/grub2/core.img b/res/grub2/core.img index f8d031b7819c5aed634469bcfae713970896d01f..7690b0f2cc214055428cd7011ea7d691039b63f9 100644 GIT binary patch delta 40457 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 b7r~*=fEXCBoa>--S+Nme#;j&p!7^A03G6GB diff --git a/res/grub2/grub2_version.h b/res/grub2/grub2_version.h index 72ed03a6..59636000 100644 --- a/res/grub2/grub2_version.h +++ b/res/grub2/grub2_version.h @@ -4,4 +4,4 @@ */ #pragma once -#define GRUB2_PACKAGE_VERSION "2.12" +#define GRUB2_PACKAGE_VERSION "2.14" diff --git a/res/grub2/readme.txt b/res/grub2/readme.txt index eb37a76d..97374273 100644 --- a/res/grub2/readme.txt +++ b/res/grub2/readme.txt @@ -1,8 +1,10 @@ This directory contains the Grub 2.0 boot records that are used by Rufus -* boot.img and core.img were created from a patched (since the offcial GRUB 2.12 release is *BROKEN*): - https://ftp.gnu.org/gnu/grub/grub-2.12.tar.xz - on a Debian 12.5 x64 system using the commands: +* boot.img and core.img were created from https://ftp.gnu.org/gnu/grub/grub-2.14.tar.xz + with https://github.com/gentoo/gentoo/raw/d51cbeb087dbbe979ff29af645f32071cce2834d/sys-boot/grub/files/grub-2.14-revert-image-base.patch + applied (since GRUB are apparently unable to perform BASIC testing of their releases) + on a Debian 13 x64 system using the commands: + patch -p1 < grub-2.14-revert-image-base.patch ./autogen.sh # --enable-boot-time for Manjaro Linux ./configure --disable-nls --enable-boot-time diff --git a/src/rufus.rc b/src/rufus.rc index 46f51346..73531410 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 4.12.2314" +CAPTION "Rufus 4.13.2315" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -408,8 +408,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,12,2314,0 - PRODUCTVERSION 4,12,2314,0 + FILEVERSION 4,13,2315,0 + PRODUCTVERSION 4,13,2315,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -427,13 +427,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "4.12.2314" + VALUE "FileVersion", "4.13.2315" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2026 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" - VALUE "OriginalFilename", "rufus-4.12.exe" + VALUE "OriginalFilename", "rufus-4.13.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.12.2314" + VALUE "ProductVersion", "4.13.2315" END END BLOCK "VarFileInfo" From 4cdedc76307eeb5677f9a81eca07fe8edd7b9280 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 17 Feb 2026 20:02:43 +0000 Subject: [PATCH 02/82] Rufus 4.13 (Build 2316) * Update UEFI:NTFS to fix regression where the wrong driver for ARM/ARM64 was selected --- ChangeLog.txt | 4 ++++ res/appstore/listing/listing.csv | 15 ++------------- res/uefi/uefi-ntfs.img | Bin 1048576 -> 1048576 bytes src/rufus.rc | 10 +++++----- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 92dfb580..142da25b 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,7 @@ +o Version 4.13 (2026.02.17) [BUGFIX RELEASE] + Fix UEFI:NTFS not selecting the proper driver for ARM/ARM64 + Update embedded GRUB to v2.14 + o Version 4.12 (2026.01.30) Filter out the new Bitdefender VHDs Filter disallowed characters in local account names diff --git a/res/appstore/listing/listing.csv b/res/appstore/listing/listing.csv index ddf3e08e..c9fedf99 100644 --- a/res/appstore/listing/listing.csv +++ b/res/appstore/listing/listing.csv @@ -114,19 +114,8 @@ • Trang web chính thức: https://rufus.ie • Mã nguồn: https://github.com/pbatard/rufus • Nhật ký thay đổi: https://github.com/pbatard/rufus/blob/master/ChangeLog.txt" -"ReleaseNotes","3","Text","• Filter out the new Bitdefender VHDs -• Filter disallowed characters in local account names -• Improve Microsoft Dev Drive detection (courtesy of Martin Kuschnik) -• Improve the pre-formatting partition cleanup code -• Improve error reporting on ISO extraction issues -• Improve detection of drives with long hardware IDs (typically SSDs) -• Improve conflicting process reporting -• Improve support for Nutanix and umbrelOS ISOs -• Fix a TOCTOU vulnerability in Fido script execution (CVE-2026-2398, reported by @independent-arg) -• Fix replacement vulnerabilities for diskcopy.dll and oscdimg.exe -• Fix FFU image creation being erroneously invocated, when trying to save an ISO image -• Fix saving of ISO images to paths that contain spaces -• Update UEFI:NTFS and UEFI DBXs to latest",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +"ReleaseNotes","3","Text","• Fix UEFI:NTFS not selecting the proper driver for ARM/ARM64 +• Update embedded GRUB to v2.14",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "Title","4","Text","Rufus",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "ShortTitle","5","Text","",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "SortTitle","6","Text","",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/res/uefi/uefi-ntfs.img b/res/uefi/uefi-ntfs.img index 33529741b3619c11ec853d8fb0d772655a153e08..57deaef7e4ff03874ee4f014797b66e45f7e3f5f 100644 GIT binary patch delta 12823 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 delta 12664 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 GD*P|w*H6;` diff --git a/src/rufus.rc b/src/rufus.rc index 73531410..6ea3e295 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 4.13.2315" +CAPTION "Rufus 4.13.2316" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -408,8 +408,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,13,2315,0 - PRODUCTVERSION 4,13,2315,0 + FILEVERSION 4,13,2316,0 + PRODUCTVERSION 4,13,2316,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -427,13 +427,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "4.13.2315" + VALUE "FileVersion", "4.13.2316" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2026 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-4.13.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.13.2315" + VALUE "ProductVersion", "4.13.2316" END END BLOCK "VarFileInfo" From eb7b6843eee395ea1d286d82297a599c65035ce6 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 3 Mar 2026 16:20:00 +0000 Subject: [PATCH 03/82] [core] improve GPT partition type reporting * Rather than waste our time reimplementing the wheel, use the descriptions from gdisk. * Also update the DB SHA-266 entries to latest. * Also set version to rufus-next and update GitHub Actions to latest (Closes #2929). --- .github/workflows/coverity.yml | 2 +- .github/workflows/mingw.yml | 4 +- .github/workflows/setup.yml | 4 +- .github/workflows/vs2022.yml | 4 +- configure | 20 +- configure.ac | 2 +- src/db.h | 11 +- src/drive.c | 21 +- src/gpt_types.h | 736 +++++++++++++++++++++++---------- src/license.h | 8 +- src/rufus.h | 4 +- src/rufus.rc | 12 +- src/stdio.c | 31 +- 13 files changed, 582 insertions(+), 277 deletions(-) diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index a34ebb9c..ecfa023a 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -53,7 +53,7 @@ jobs: cov-build.exe --dir cov-int msbuild ${{ env.SOLUTION_FILE_PATH }} /m /p:Configuration=${{ env.BUILD_CONFIGURATION }},Platform=${{ env.TARGET_PLATFORM }} - name: Publish Coverity artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: cov-int path: cov-int/ diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml index 74b788a1..8e1df007 100644 --- a/.github/workflows/mingw.yml +++ b/.github/workflows/mingw.yml @@ -114,7 +114,7 @@ jobs: - name: Upload artifacts if: ${{ github.event_name == 'push' }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: ${{ matrix.sys }} path: ./*.exe @@ -124,7 +124,7 @@ jobs: needs: MinGW-Build steps: - name: Merge Artifacts - uses: actions/upload-artifact/merge@v6 + uses: actions/upload-artifact/merge@v7 if: ${{ github.event_name == 'push' }} with: name: MinGW diff --git a/.github/workflows/setup.yml b/.github/workflows/setup.yml index d737d74f..83ba9e24 100644 --- a/.github/workflows/setup.yml +++ b/.github/workflows/setup.yml @@ -36,7 +36,7 @@ jobs: run: sha256sum ./setup_${{ matrix.TARGET_PLATFORM }}.exe - name: Upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: ${{ matrix.TARGET_PLATFORM }} path: ./*.exe @@ -46,7 +46,7 @@ jobs: needs: VS2022-Build steps: - name: Merge Artifacts - uses: actions/upload-artifact/merge@v5 + uses: actions/upload-artifact/merge@v7 with: name: setup delete-merged: true diff --git a/.github/workflows/vs2022.yml b/.github/workflows/vs2022.yml index ac7b41fa..228a11aa 100644 --- a/.github/workflows/vs2022.yml +++ b/.github/workflows/vs2022.yml @@ -126,7 +126,7 @@ jobs: curl --request POST --url https://www.virustotal.com/api/v3/monitor/items --header 'x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}' --form path='/rufus_${{ matrix.TARGET_PLATFORM }}.exe' --form file=@./rufus_${{ matrix.TARGET_PLATFORM }}.exe - name: Upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 if: ${{ github.event_name == 'push' }} with: name: ${{ matrix.TARGET_PLATFORM }} @@ -139,7 +139,7 @@ jobs: needs: VS2022-Build steps: - name: Merge Artifacts - uses: actions/upload-artifact/merge@v6 + uses: actions/upload-artifact/merge@v7 if: ${{ github.event_name == 'push' }} with: name: VS2022 diff --git a/configure b/configure index 06fae879..8f8dcb92 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for rufus 4.13. +# Generated by GNU Autoconf 2.71 for rufus 4.14. # # Report bugs to . # @@ -611,8 +611,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='rufus' PACKAGE_TARNAME='rufus' -PACKAGE_VERSION='4.13' -PACKAGE_STRING='rufus 4.13' +PACKAGE_VERSION='4.14' +PACKAGE_STRING='rufus 4.14' PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues' PACKAGE_URL='https://rufus.ie' @@ -1269,7 +1269,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures rufus 4.13 to adapt to many kinds of systems. +\`configure' configures rufus 4.14 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1336,7 +1336,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of rufus 4.13:";; + short | recursive ) echo "Configuration of rufus 4.14:";; esac cat <<\_ACEOF @@ -1428,7 +1428,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -rufus configure 4.13 +rufus configure 4.14 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -1504,7 +1504,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by rufus $as_me 4.13, which was +It was created by rufus $as_me 4.14, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -2767,7 +2767,7 @@ fi # Define the identity of the package. PACKAGE='rufus' - VERSION='4.13' + VERSION='4.14' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -5313,7 +5313,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by rufus $as_me 4.13, which was +This file was extended by rufus $as_me 4.14, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -5369,7 +5369,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -rufus config.status 4.13 +rufus config.status 4.14 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 2179a531..94f0e09b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([rufus], [4.13], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie]) +AC_INIT([rufus], [4.14], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie]) AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies]) AC_CONFIG_SRCDIR([src/rufus.c]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/src/db.h b/src/db.h index 2be05621..c3197e9f 100644 --- a/src/db.h +++ b/src/db.h @@ -1,8 +1,8 @@ /* * Rufus: The Reliable USB Formatting Utility * DB of the known SHA256 hash values for Rufus downloadable content (GRUB, Syslinux, etc.) - * as well PE256 hash values for UEFI revoked content (DBX, SkuSiPolicy.p7b) - * Copyright © 2016-2025 Pete Batard + * as well other data for UEFI revoked content (SBAT, certs). + * Copyright © 2016-2026 Pete Batard * * 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 @@ -31,6 +31,8 @@ static uint8_t sha256db[] = { 0x11, 0x0c, 0x50, 0x1b, 0xfa, 0x9e, 0x72, 0xa8, 0x8c, 0xdb, 0xb8, 0xba, 0x11, 0xe1, 0xf0, 0x76, 0x1a, 0xec, 0x28, 0xbf, 0x04, 0x44, 0x67, 0xff, 0x38, 0x2c, 0x06, 0x95, 0xd5, 0x1f, 0x8a, 0x83, // grub-2.04-nonstandard/core.img 0x12, 0xbd, 0x22, 0xd2, 0xb3, 0x69, 0x56, 0x0f, 0x89, 0xb8, 0x50, 0x7e, 0x7e, 0x74, 0xeb, 0xc5, 0xea, 0x44, 0x91, 0x48, 0x75, 0xf0, 0xa4, 0xcb, 0x1e, 0xa6, 0xfb, 0x4e, 0xc9, 0x89, 0x58, 0x17, // syslinux-6.03/pre6/ldlinux.sys 0x15, 0x5f, 0x36, 0x7b, 0xb1, 0x30, 0xfe, 0x05, 0x5c, 0x79, 0x9f, 0x88, 0xb3, 0xc0, 0xc1, 0xa0, 0x0a, 0x18, 0x05, 0x78, 0x22, 0x69, 0xcf, 0x7e, 0x54, 0xaa, 0x61, 0xbd, 0xe3, 0x8e, 0x05, 0x92, // syslinux-6.03/pre3/ldlinux.bss + 0x15, 0x90, 0x28, 0x95, 0x48, 0x7c, 0x08, 0x4c, 0x8f, 0x57, 0x46, 0x66, 0xc3, 0x1e, 0x7f, 0xa3, 0x99, 0xd0, 0x5b, 0x83, 0x1f, 0xd6, 0x1c, 0x1e, 0x3c, 0x3e, 0xee, 0x69, 0xd6, 0x57, 0x69, 0x24, // grub-2.12/core.img + 0x19, 0xba, 0x57, 0x32, 0x9b, 0xe7, 0x45, 0xce, 0xae, 0x46, 0x35, 0x4c, 0x5d, 0x41, 0x1b, 0x7d, 0x8e, 0xfe, 0xc6, 0x80, 0x2c, 0xfd, 0x7f, 0x6f, 0xee, 0x98, 0x6d, 0xf4, 0xb7, 0x63, 0xf6, 0xfe, // grub4dos-0.4.6a/grldr 0x1c, 0xb7, 0x8b, 0x98, 0xbc, 0xd6, 0x76, 0x7b, 0x01, 0x44, 0xf5, 0x00, 0xaf, 0x81, 0xef, 0x4f, 0x3c, 0x54, 0xea, 0xaf, 0xe3, 0xc9, 0x4e, 0x1f, 0xd6, 0x24, 0x68, 0x41, 0x4e, 0x98, 0x92, 0x25, // syslinux-6.03/pre20/ldlinux.bss 0x1c, 0xc6, 0x32, 0x21, 0xfd, 0xf4, 0x46, 0xfc, 0xda, 0xc6, 0xc0, 0x56, 0x35, 0x79, 0x54, 0xc1, 0x5b, 0x61, 0x75, 0xca, 0x1b, 0xc2, 0xa4, 0x9f, 0x85, 0x52, 0xec, 0xca, 0x28, 0xac, 0x3e, 0x51, // syslinux-6.02/ldlinux.bss 0x22, 0x96, 0x82, 0xac, 0x61, 0xb8, 0x8b, 0x11, 0x25, 0xfc, 0xd7, 0xe6, 0x9f, 0x4e, 0x7f, 0x46, 0x7f, 0x68, 0xc5, 0x14, 0x9e, 0xb9, 0x37, 0x1a, 0x98, 0xd8, 0xf2, 0x78, 0x41, 0x40, 0xad, 0x88, // syslinux-5.00/ldlinux.sys @@ -88,7 +90,9 @@ static uint8_t sha256db[] = { 0x8e, 0xc8, 0x42, 0x06, 0x94, 0x4c, 0xd4, 0x3d, 0xf6, 0xba, 0x83, 0x63, 0xc0, 0x81, 0xe4, 0xa0, 0x82, 0x9e, 0x71, 0x9a, 0xbf, 0x5a, 0x46, 0x6d, 0x7c, 0x81, 0x0c, 0x2f, 0x5b, 0x6d, 0x13, 0x75, // syslinux-6.03/pre5/ldlinux.sys 0x95, 0x8d, 0x10, 0xbb, 0x87, 0x28, 0xcc, 0x1f, 0xf1, 0x6a, 0x12, 0xee, 0x6a, 0x60, 0x62, 0x40, 0xa6, 0xb7, 0x4d, 0xab, 0xa0, 0x2b, 0x8c, 0xb8, 0xed, 0x2a, 0xe8, 0x1c, 0x2f, 0xb2, 0x5b, 0x97, // syslinux-6.00/ldlinux.bss 0x9a, 0x0b, 0xc4, 0x1b, 0xd7, 0x95, 0xed, 0xb0, 0x83, 0x0f, 0x1c, 0xc4, 0x82, 0x4b, 0xfa, 0x9d, 0xe0, 0x9d, 0x68, 0x63, 0x92, 0x09, 0x4f, 0x5a, 0xe7, 0xfb, 0xac, 0xfb, 0xb0, 0x17, 0x9d, 0xa6, // syslinux-6.03/pre1/ldlinux.bss + 0x9a, 0x2c, 0x94, 0x67, 0x04, 0x01, 0x7f, 0xa8, 0xdc, 0x4e, 0x03, 0xa8, 0xa5, 0x8d, 0x75, 0x4d, 0x2d, 0x16, 0x07, 0xc2, 0xd2, 0xcd, 0x74, 0xf0, 0xe2, 0x92, 0x01, 0x33, 0xf1, 0x19, 0x28, 0x09, // grub-2.14/core.img 0x9b, 0xcc, 0x65, 0x92, 0xa7, 0xba, 0x7e, 0x73, 0x38, 0xf4, 0xbb, 0xba, 0x27, 0xc6, 0x30, 0x16, 0xb9, 0x5e, 0xcb, 0x1e, 0xc6, 0x8c, 0x0b, 0xe9, 0xb6, 0x99, 0xb2, 0xea, 0x69, 0xcb, 0xab, 0xb2, // syslinux-5.00/ldlinux.c32 + 0xa2, 0xa8, 0x76, 0x93, 0x71, 0xeb, 0x57, 0xc5, 0xe7, 0x9b, 0x3c, 0xea, 0x4a, 0x91, 0x12, 0x75, 0xaf, 0x47, 0x43, 0xf1, 0x0f, 0x42, 0x0e, 0xd6, 0xd2, 0x6e, 0x4e, 0xec, 0x5c, 0x86, 0x50, 0x59, // grub4dos-0.4.6a/grldr.mbr 0xa6, 0x82, 0x43, 0xa0, 0xf2, 0xe5, 0x90, 0xb8, 0x14, 0x02, 0xd6, 0xfa, 0x62, 0xd4, 0xfd, 0x30, 0x94, 0x8c, 0x00, 0x3d, 0xa1, 0x2b, 0xfe, 0xeb, 0x69, 0xba, 0x20, 0x34, 0x17, 0x27, 0x09, 0x4c, // syslinux-6.03/pre14/ldlinux.sys 0xa9, 0x4a, 0x99, 0xe6, 0xde, 0x68, 0x81, 0x44, 0x49, 0x2b, 0x38, 0xdb, 0xee, 0x09, 0xde, 0x07, 0x30, 0xe3, 0x2e, 0x1c, 0xfd, 0x0a, 0xb2, 0x54, 0x99, 0x22, 0xff, 0xa8, 0x04, 0x01, 0xad, 0x49, // syslinux-6.03/pre2/ldlinux.bss 0xa9, 0x95, 0x68, 0x57, 0x9c, 0xd2, 0x51, 0xaf, 0xf1, 0x34, 0xfc, 0xaa, 0xa8, 0x09, 0x91, 0x60, 0x5e, 0x8f, 0xb1, 0x19, 0x74, 0x51, 0xf7, 0x51, 0xaa, 0x4d, 0x6c, 0x84, 0xbf, 0x65, 0xf4, 0xe3, // syslinux-6.03/pre15/ldlinux.sys @@ -100,6 +104,7 @@ static uint8_t sha256db[] = { 0xb3, 0xdc, 0x31, 0x79, 0xf6, 0x2b, 0x20, 0x51, 0xc9, 0x43, 0xe5, 0x2e, 0xeb, 0xf2, 0x29, 0x8a, 0xa4, 0x7e, 0x7c, 0x0a, 0x97, 0x78, 0xe8, 0x62, 0x77, 0xa7, 0x48, 0x2a, 0x27, 0x0a, 0x7a, 0x8e, // syslinux-6.01/ldlinux.bss 0xb4, 0x6a, 0xf2, 0x09, 0x19, 0xe9, 0xf2, 0x1f, 0xa1, 0x52, 0x37, 0x5d, 0xda, 0xc4, 0x58, 0x87, 0x08, 0xc1, 0x22, 0xb3, 0x65, 0x7f, 0x09, 0x01, 0x31, 0x4e, 0x83, 0x45, 0x49, 0xa9, 0x6c, 0xe7, // syslinux-4.07/menu.c32 0xbc, 0x3f, 0xb7, 0x6d, 0xbc, 0xd6, 0x32, 0x37, 0xc3, 0x68, 0x8d, 0x3b, 0x55, 0x3c, 0x99, 0x41, 0x0e, 0x8f, 0xb3, 0x9e, 0x52, 0x00, 0x9d, 0xdc, 0xeb, 0xb8, 0x8e, 0xe7, 0xd2, 0x5a, 0xec, 0xa8, // grub-2.03.5/core.img + 0xbf, 0x05, 0x9b, 0x7f, 0x9d, 0xc5, 0x1d, 0x08, 0xb7, 0xa9, 0x36, 0x81, 0xcc, 0xc7, 0x82, 0xdc, 0x46, 0x4e, 0x43, 0xe6, 0x0d, 0xa4, 0xfb, 0xb6, 0xa1, 0xf5, 0x62, 0xea, 0x0e, 0x2d, 0xd3, 0x1a, // grub-2.14~rc1/core.img 0xbf, 0xf9, 0xc5, 0x89, 0x59, 0x70, 0x4d, 0x1e, 0xbe, 0x25, 0xb4, 0x43, 0xc8, 0x92, 0x3a, 0x42, 0xed, 0x89, 0xaf, 0x8b, 0xd2, 0x92, 0xe7, 0xd7, 0xcb, 0xeb, 0xca, 0xcc, 0xc0, 0x7c, 0xc7, 0x19, // syslinux-5.11/ldlinux.sys 0xc3, 0x3b, 0x31, 0x5f, 0xec, 0xe4, 0xad, 0xc4, 0xc3, 0xb2, 0x75, 0x13, 0x22, 0x84, 0x66, 0xe4, 0x44, 0x99, 0xcd, 0xa7, 0xfd, 0x63, 0x97, 0xc5, 0xab, 0xe0, 0xf8, 0xce, 0x4f, 0xe3, 0x45, 0x39, // syslinux-5.10/ldlinux.c32 0xcc, 0x40, 0xba, 0x03, 0x49, 0x78, 0x2c, 0xb4, 0xc9, 0x02, 0x1e, 0x54, 0xdc, 0xc0, 0xa4, 0x54, 0x0c, 0x3a, 0x8b, 0x96, 0x08, 0x8b, 0x3a, 0x56, 0x48, 0x67, 0x19, 0x26, 0xef, 0x44, 0xd2, 0xf0, // syslinux-6.04/ldlinux.bss @@ -108,7 +113,6 @@ static uint8_t sha256db[] = { 0xd2, 0xc6, 0x93, 0x8d, 0xae, 0x5a, 0xd7, 0x16, 0x0e, 0x9e, 0x6c, 0x61, 0xef, 0x46, 0xb7, 0xfd, 0x14, 0x6e, 0x30, 0xc0, 0x3f, 0xdc, 0x8f, 0x5c, 0x6d, 0xbd, 0xeb, 0x86, 0x22, 0xc8, 0xa7, 0xbd, // syslinux-5.00/ldlinux.bss 0xd3, 0x47, 0x2c, 0x02, 0x26, 0x3a, 0xcf, 0x9c, 0xd1, 0xda, 0x5d, 0xb5, 0x1e, 0x26, 0x3c, 0x54, 0x84, 0xba, 0xd1, 0x3e, 0xa6, 0x86, 0x18, 0xc4, 0x03, 0xd9, 0xcb, 0x01, 0xca, 0x07, 0x0a, 0xee, // syslinux-6.04/ldlinux.c32 0xd5, 0x50, 0x39, 0xef, 0xb6, 0x8d, 0x6e, 0xec, 0xde, 0x68, 0x61, 0xc9, 0x0b, 0xa9, 0xb7, 0x99, 0x44, 0xd1, 0xaa, 0x8b, 0xc3, 0xd6, 0x01, 0xfb, 0x80, 0xfd, 0x08, 0x7b, 0xc6, 0x13, 0x63, 0xf8, // syslinux-6.02/ldlinux.sys - 0xd6, 0xa7, 0x0c, 0xe1, 0x90, 0x2b, 0x22, 0x1a, 0xcb, 0xc1, 0xd5, 0xf5, 0x94, 0x24, 0xa8, 0x22, 0x7b, 0x62, 0xfe, 0x6d, 0x85, 0x34, 0x86, 0x0e, 0x2b, 0x6e, 0x75, 0x7e, 0x01, 0x02, 0xc5, 0x6f, // grub4dos-0.4.6a/grldr 0xd9, 0x1c, 0xbd, 0xf9, 0x01, 0x79, 0x5e, 0x98, 0x19, 0x84, 0x9c, 0x75, 0x3e, 0xa5, 0x3a, 0xd8, 0x59, 0xc6, 0xf2, 0x5d, 0x59, 0x17, 0xa6, 0x75, 0x92, 0x58, 0x3f, 0xd6, 0x5e, 0x6d, 0x00, 0xf0, // syslinux-6.03/pre18/ldlinux.bss 0xda, 0xa3, 0x06, 0xa9, 0x97, 0x0e, 0x37, 0x7d, 0xb4, 0x4c, 0xe7, 0xfa, 0xd8, 0xdd, 0x01, 0xe9, 0xe8, 0x53, 0xc6, 0x8b, 0x1e, 0x3d, 0x84, 0xf3, 0x2a, 0xaf, 0x42, 0x24, 0x6f, 0x77, 0xae, 0x3d, // grub-2.02/core.img 0xe7, 0x87, 0x08, 0xc7, 0x2c, 0x49, 0x8e, 0xcc, 0x14, 0x9e, 0x30, 0xf0, 0xa9, 0x85, 0xd3, 0x73, 0xa3, 0x00, 0xad, 0x5c, 0xf7, 0xd2, 0x88, 0xc7, 0x7d, 0xe8, 0x05, 0x5e, 0x25, 0x66, 0x28, 0x1f, // syslinux-6.03/pre18/ldlinux.sys @@ -118,7 +122,6 @@ static uint8_t sha256db[] = { 0xec, 0xfd, 0xbc, 0x3f, 0x4f, 0x2e, 0x4d, 0x99, 0x16, 0x9c, 0xdd, 0xfb, 0x15, 0x2d, 0x92, 0x4d, 0x7d, 0xe6, 0x8a, 0xb6, 0x7f, 0x4d, 0x12, 0x54, 0x40, 0xfa, 0xbc, 0x9f, 0x00, 0x46, 0xd5, 0xbc, // syslinux-6.03/pre5/ldlinux.bss 0xee, 0xed, 0xc0, 0x4c, 0x13, 0x73, 0xb5, 0xc4, 0x04, 0x4d, 0x1f, 0xde, 0x0d, 0x2f, 0xb8, 0xe2, 0x8c, 0x74, 0xb1, 0x02, 0x9c, 0x99, 0xed, 0x67, 0x0a, 0x15, 0x98, 0x3f, 0x18, 0xa0, 0x4d, 0x36, // syslinux-6.02/ldlinux.c32 0xf5, 0x40, 0x26, 0x1c, 0x09, 0x7d, 0xbd, 0x8a, 0x8a, 0x12, 0x9b, 0x68, 0x99, 0x5f, 0x33, 0xab, 0xe7, 0x1c, 0x29, 0x40, 0xf8, 0x87, 0xc6, 0x68, 0x9b, 0xf8, 0xdc, 0x3f, 0x1a, 0xcf, 0x0b, 0x44, // syslinux-6.03/pre17/ldlinux.bss - 0xf5, 0xc6, 0xe8, 0xe2, 0xc1, 0xeb, 0x73, 0x80, 0x28, 0x5f, 0xa9, 0xcb, 0x1c, 0x91, 0x68, 0xe9, 0x2d, 0x5b, 0x3b, 0x55, 0xcd, 0xe0, 0x52, 0xc0, 0x43, 0xba, 0x81, 0xed, 0x17, 0xb9, 0xac, 0xef, // grub4dos-0.4.6a/grldr.mbr 0xfb, 0x0a, 0x23, 0xca, 0x4d, 0x22, 0xfd, 0xd2, 0xad, 0x4e, 0xfa, 0x1b, 0x21, 0x08, 0xb6, 0x60, 0xd2, 0xff, 0xa3, 0xf2, 0xfb, 0xdd, 0x25, 0x32, 0xdc, 0xf1, 0x3f, 0x49, 0x33, 0x28, 0x46, 0x7b, // syslinux-6.03/pre11/ldlinux.bss 0xfb, 0x49, 0xfd, 0x45, 0x8c, 0xaf, 0x47, 0x5a, 0x16, 0x05, 0x5e, 0x4a, 0x75, 0x5a, 0xc3, 0xe3, 0x95, 0x52, 0xf4, 0xe9, 0x6c, 0xa2, 0x0d, 0xea, 0x53, 0xf5, 0xc4, 0x09, 0x2b, 0x68, 0xfd, 0x4f, // syslinux-6.00/ldlinux.sys }; diff --git a/src/drive.c b/src/drive.c index fbce1bc8..798db108 100644 --- a/src/drive.c +++ b/src/drive.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Drive access function calls - * Copyright © 2011-2025 Pete Batard + * Copyright © 2011-2026 Pete Batard * * 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 @@ -1546,7 +1546,7 @@ static BOOL StoreEspInfo(GUID* guid) return WriteSettingStr(key_name[1], GuidToString(guid, TRUE)); } -static GUID* GetEspGuid(uint8_t index) +static GUID GetEspGuid(uint8_t index) { char key_name[16]; @@ -1574,7 +1574,7 @@ BOOL ToggleEsp(DWORD DriveIndex, uint64_t PartitionOffset) HANDLE hPhysical; DWORD dl_size, size, offset; BYTE layout[4096] = { 0 }, buf[512]; - GUID *guid = NULL, *stored_guid = NULL, mbr_guid; + GUID *guid = NULL, stored_guid = { 0 }, mbr_guid; PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)(void*)layout; typedef struct { const uint8_t mbr_type; @@ -1650,7 +1650,7 @@ BOOL ToggleEsp(DWORD DriveIndex, uint64_t PartitionOffset) // Basic Data -> ESP for (i = 1; i <= MAX_ESP_TOGGLE && esp_index < 0; i++) { stored_guid = GetEspGuid((uint8_t)i); - if (stored_guid != NULL) { + if (!CompareGUID(&stored_guid, &GUID_NULL)) { for (j = 0; j < (int)DriveLayout->PartitionCount && esp_index < 0; j++) { if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) { guid = &DriveLayout->PartitionEntry[j].Gpt.PartitionId; @@ -1660,7 +1660,7 @@ BOOL ToggleEsp(DWORD DriveIndex, uint64_t PartitionOffset) *((uint64_t*)&mbr_guid.Data4) = DriveLayout->PartitionEntry[j].StartingOffset.QuadPart; guid = &mbr_guid; } - if (CompareGUID(stored_guid, guid)) { + if (CompareGUID(&stored_guid, guid)) { esp_index = j; delete_data = TRUE; if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) @@ -2606,9 +2606,8 @@ const char* GetMBRPartitionType(const uint8_t type) const char* GetGPTPartitionType(const GUID* guid) { - int i; - for (i = 0; (i < ARRAYSIZE(gpt_type)) && !CompareGUID(guid, gpt_type[i].guid); i++); - return (i < ARRAYSIZE(gpt_type)) ? gpt_type[i].name : GuidToString(guid, TRUE); + const char* desc = gpt_type_desc(guid); + return desc != NULL ? desc : GuidToString(guid, TRUE); } /* @@ -2653,7 +2652,7 @@ BOOL IsFilteredDrive(DWORD DriveIndex) HANDLE hPhysical = INVALID_HANDLE_VALUE; BYTE layout[4096] = { 0 }; PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)(void*)layout; - GUID* DiskGuid; + GUID DiskGuid; hPhysical = GetPhysicalHandle(DriveIndex, FALSE, FALSE, TRUE); if (hPhysical == INVALID_HANDLE_VALUE) @@ -2669,8 +2668,8 @@ BOOL IsFilteredDrive(DWORD DriveIndex) for (i = 1; i <= MAX_IGNORE_USB; i++) { static_sprintf(setting_name, "IgnoreDisk%02d", i); DiskGuid = StringToGuid(ReadSettingStr(setting_name)); - if (CompareGUID(&DriveLayout->Gpt.DiskId, DiskGuid)) { - uprintf("Device eliminated because it matches Disk GUID %s", GuidToString(DiskGuid, TRUE)); + if (CompareGUID(&DriveLayout->Gpt.DiskId, &DiskGuid)) { + uprintf("Device eliminated because it matches Disk GUID %s", GuidToString(&DiskGuid, TRUE)); ret = TRUE; goto out; } diff --git a/src/gpt_types.h b/src/gpt_types.h index 926056cc..128123aa 100644 --- a/src/gpt_types.h +++ b/src/gpt_types.h @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * GPT Partition Types - * Copyright © 2020 Pete Batard + * Copyright © 2020-2026 Pete Batard * * 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 @@ -24,226 +24,520 @@ #pragma once -/* - * From https://en.wikipedia.org/wiki/GUID_Partition_Table - */ -DEFINE_GUID(PARTITION_ANDROID_BOOT, 0x49A4D17F, 0x93A3, 0x45C1, 0xA0, 0xDE, 0xF5, 0x0B, 0x2E, 0xBE, 0x25, 0x99); -DEFINE_GUID(PARTITION_ANDROID_BOOTLOADER1, 0x2568845D, 0x2332, 0x4675, 0xBC, 0x39, 0x8F, 0xA5, 0xA4, 0x74, 0x8D, 0x15); -DEFINE_GUID(PARTITION_ANDROID_BOOTLOADER2, 0x114EAFFE, 0x1552, 0x4022, 0xB2, 0x6E, 0x9B, 0x05, 0x36, 0x04, 0xCF, 0x84); -DEFINE_GUID(PARTITION_ANDROID_CACHE, 0xA893EF21, 0xE428, 0x470A, 0x9E, 0x55, 0x06, 0x68, 0xFD, 0x91, 0xA2, 0xD9); -DEFINE_GUID(PARTITION_ANDROID_CONFIG, 0xBD59408B, 0x4514, 0x490D, 0xBF, 0x12, 0x98, 0x78, 0xD9, 0x63, 0xF3, 0x78); -DEFINE_GUID(PARTITION_ANDROID_DATA, 0xDC76DDA9, 0x5AC1, 0x491C, 0xAF, 0x42, 0xA8, 0x25, 0x91, 0x58, 0x0C, 0x0D); -DEFINE_GUID(PARTITION_ANDROID_EXT, 0x193D1EA4, 0xB3CA, 0x11E4, 0xB0, 0x75, 0x10, 0x60, 0x4B, 0x88, 0x9D, 0xCF); -DEFINE_GUID(PARTITION_ANDROID_FACTORY1, 0x8F68CC74, 0xC5E5, 0x48DA, 0xBE, 0x91, 0xA0, 0xC8, 0xC1, 0x5E, 0x9C, 0x80); -DEFINE_GUID(PARTITION_ANDROID_FACTORY2, 0x9FDAA6EF, 0x4B3F, 0x40D2, 0xBA, 0x8D, 0xBF, 0xF1, 0x6B, 0xFB, 0x88, 0x7B); -DEFINE_GUID(PARTITION_ANDROID_FASTBOOT, 0x767941D0, 0x2085, 0x11E3, 0xAD, 0x3B, 0x6C, 0xFD, 0xB9, 0x47, 0x11, 0xE9); -DEFINE_GUID(PARTITION_ANDROID_METADATA1, 0x20AC26BE, 0x20B7, 0x11E3, 0x84, 0xC5, 0x6C, 0xFD, 0xB9, 0x47, 0x11, 0xE9); -DEFINE_GUID(PARTITION_ANDROID_METADATA2, 0x19A710A2, 0xB3CA, 0x11E4, 0xB0, 0x26, 0x10, 0x60, 0x4B, 0x88, 0x9D, 0xCF); -DEFINE_GUID(PARTITION_ANDROID_MISC, 0xEF32A33B, 0xA409, 0x486C, 0x91, 0x41, 0x9F, 0xFB, 0x71, 0x1F, 0x62, 0x66); -DEFINE_GUID(PARTITION_ANDROID_OEM, 0xAC6D7924, 0xEB71, 0x4DF8, 0xB4, 0x8D, 0xE2, 0x67, 0xB2, 0x71, 0x48, 0xFF); -DEFINE_GUID(PARTITION_ANDROID_PERSISTENCE, 0xEBC597D0, 0x2053, 0x4B15, 0x8B, 0x64, 0xE0, 0xAA, 0xC7, 0x5F, 0x4D, 0xB1); -DEFINE_GUID(PARTITION_ANDROID_RECOVERY, 0x4177C722, 0x9E92, 0x4AAB, 0x86, 0x44, 0x43, 0x50, 0x2B, 0xFD, 0x55, 0x06); -DEFINE_GUID(PARTITION_ANDROID_SYSTEM, 0x38F428E6, 0xD326, 0x425D, 0x91, 0x40, 0x6E, 0x0E, 0xA1, 0x33, 0x64, 0x7C); -DEFINE_GUID(PARTITION_ANDROID_VENDOR, 0xC5A0AEEC, 0x13EA, 0x11E5, 0xA1, 0xB1, 0x00, 0x1E, 0x67, 0xCA, 0x0C, 0x3C); -DEFINE_GUID(PARTITION_APPLE_APFS, 0x7C3457EF, 0x0000, 0x11AA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC); -DEFINE_GUID(PARTITION_APPLE_BOOT, 0x426F6F74, 0x0000, 0x11AA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC); -DEFINE_GUID(PARTITION_APPLE_FILEVAULT, 0x53746F72, 0x6167, 0x11AA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC); -DEFINE_GUID(PARTITION_APPLE_HFS, 0x48465300, 0x0000, 0x11AA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC); -DEFINE_GUID(PARTITION_APPLE_LABEL, 0x4C616265, 0x6C00, 0x11AA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC); -DEFINE_GUID(PARTITION_APPLE_OFFLINE_RAID, 0x52414944, 0x5F4F, 0x11AA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC); -DEFINE_GUID(PARTITION_APPLE_RAID, 0x52414944, 0x0000, 0x11AA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC); -DEFINE_GUID(PARTITION_APPLE_RAID_CACHE, 0xBBBA6DF5, 0xF46F, 0x4A89, 0x8F, 0x59, 0x87, 0x65, 0xB2, 0x72, 0x75, 0x03); -DEFINE_GUID(PARTITION_APPLE_RAID_SCRATCH, 0x2E313465, 0x19B9, 0x463F, 0x81, 0x26, 0x8A, 0x79, 0x93, 0x77, 0x38, 0x01); -DEFINE_GUID(PARTITION_APPLE_RAID_STATUS, 0xB6FA30DA, 0x92D2, 0x4A9A, 0x96, 0xF1, 0x87, 0x1E, 0xC6, 0x48, 0x62, 0x00); -DEFINE_GUID(PARTITION_APPLE_RAID_VOLUME, 0xFA709C7E, 0x65B1, 0x4593, 0xBF, 0xD5, 0xE7, 0x1D, 0x61, 0xDE, 0x9B, 0x02); -DEFINE_GUID(PARTITION_APPLE_RECOVERY, 0x5265636F, 0x7665, 0x11AA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC); -DEFINE_GUID(PARTITION_APPLE_UFS, 0x55465300, 0x0000, 0x11AA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC); -// Stolen from Solaris below. Great job here, Apple! Then again, Oracle can and *should* go to hell, so who cares... -DEFINE_GUID(PARTITION_APPLE_ZFS, 0x6A898CC3, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_ATARI_DATA, 0x734E5AFE, 0xF61A, 0x11E6, 0xBC, 0x64, 0x92, 0x36, 0x1F, 0x00, 0x26, 0x71); -DEFINE_GUID(PARTITION_BEOS_BFS, 0x42465331, 0x3BA3, 0x10F1, 0x80, 0x2A, 0x48, 0x61, 0x69, 0x6B, 0x75, 0x21); -DEFINE_GUID(PARTITION_CHROMEOS_KERNEL, 0xFE3A2A5D, 0x4F32, 0x41A7, 0xB7, 0x25, 0xAC, 0xCC, 0x32, 0x85, 0xA3, 0x09); -DEFINE_GUID(PARTITION_CHROMEOS_RESERVED, 0x2E0A753D, 0x9E48, 0x43B0, 0x83, 0x37, 0xB1, 0x51, 0x92, 0xCB, 0x1B, 0x5E); -DEFINE_GUID(PARTITION_CHROMEOS_ROOT, 0x3CB8E202, 0x3B7E, 0x47DD, 0x8A, 0x3C, 0x7F, 0xF2, 0xA1, 0x3C, 0xFC, 0xEC); -DEFINE_GUID(PARTITION_COREOS_RAID, 0xBE9067B9, 0xEA49, 0x4F15, 0xB4, 0xF6, 0xF3, 0x6F, 0x8C, 0x9E, 0x18, 0x18); -DEFINE_GUID(PARTITION_COREOS_RESERVED, 0xC95DC21A, 0xDF0E, 0x4340, 0x8D, 0x7B, 0x26, 0xCB, 0xFA, 0x9A, 0x03, 0xE0); -DEFINE_GUID(PARTITION_COREOS_ROOT, 0x3884DD41, 0x8582, 0x4404, 0xB9, 0xA8, 0xE9, 0xB8, 0x4F, 0x2D, 0xF5, 0x0E); -DEFINE_GUID(PARTITION_COREOS_USR, 0x5DFBF5F4, 0x2848, 0x4BAC, 0xAA, 0x5E, 0x0D, 0x9A, 0x20, 0xB7, 0x45, 0xA6); -DEFINE_GUID(PARTITION_FREEBSD_BOOT, 0x83BD6B9D, 0x7F41, 0x11DC, 0xBE, 0x0B, 0x00, 0x15, 0x60, 0xB8, 0x4F, 0x0F); -DEFINE_GUID(PARTITION_FREEBSD_DATA, 0x516E7CB4, 0x6ECF, 0x11D6, 0x8F, 0xF8, 0x00, 0x02, 0x2D, 0x09, 0x71, 0x2B); -DEFINE_GUID(PARTITION_FREEBSD_LVM, 0x516E7CB8, 0x6ECF, 0x11D6, 0x8F, 0xF8, 0x00, 0x02, 0x2D, 0x09, 0x71, 0x2B); -DEFINE_GUID(PARTITION_FREEBSD_SWAP, 0x516E7CB5, 0x6ECF, 0x11D6, 0x8F, 0xF8, 0x00, 0x02, 0x2D, 0x09, 0x71, 0x2B); -DEFINE_GUID(PARTITION_FREEBSD_UFS, 0x516E7CB6, 0x6ECF, 0x11D6, 0x8F, 0xF8, 0x00, 0x02, 0x2D, 0x09, 0x71, 0x2B); -DEFINE_GUID(PARTITION_FREEBSD_ZFS, 0x516E7CBA, 0x6ECF, 0x11D6, 0x8F, 0xF8, 0x00, 0x02, 0x2D, 0x09, 0x71, 0x2B); -DEFINE_GUID(PARTITION_GENERIC_BIOS_BOOT, 0x21686148, 0x6449, 0x6E6F, 0x74, 0x4E, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49); -DEFINE_GUID(PARTITION_GENERIC_XBOOTLDR, 0xBC13C2FF, 0x59E6, 0x4262, 0xA3, 0x52, 0xB2, 0x75, 0xFD, 0x6F, 0x71, 0x72); -DEFINE_GUID(PARTITION_GENERIC_ESP, 0xC12A7328, 0xF81F, 0x11D2, 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B); -DEFINE_GUID(PARTITION_GENERIC_MBR, 0x024DEE41, 0x33E7, 0x11D3, 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F); -DEFINE_GUID(PARTITION_GENERIC_UNUSED, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); -DEFINE_GUID(PARTITION_HPUX_DATA, 0x75894C1E, 0x3AEB, 0x11D3, 0xB7, 0xC1, 0x7B, 0x03, 0xA0, 0x00, 0x00, 0x00); -DEFINE_GUID(PARTITION_HPUX_SERVICE, 0xE2A1E728, 0x32E3, 0x11D6, 0xA6, 0x82, 0x7B, 0x03, 0xA0, 0x00, 0x00, 0x00); -DEFINE_GUID(PARTITION_IBM_GPFS, 0x37AFFC90, 0xEF7D, 0x4E96, 0x91, 0xC3, 0x2D, 0x7A, 0xE0, 0x55, 0xB1, 0x74); -DEFINE_GUID(PARTITION_INTEL_IFF, 0xD3BFE2DE, 0x3DAF, 0x11DF, 0xBA, 0x40, 0xE3, 0xA5, 0x56, 0xD8, 0x95, 0x93); -DEFINE_GUID(PARTITION_LENOVO_BOOT, 0xBFBFAFE7, 0xA34F, 0x448A, 0x9A, 0x5B, 0x62, 0x13, 0xEB, 0x73, 0x6C, 0x22); -DEFINE_GUID(PARTITION_LINUX_BOOT, 0xBC13C2FF, 0x59E6, 0x4262, 0xA3, 0x52, 0xB2, 0x75, 0xFD, 0x6F, 0x71, 0x72); -DEFINE_GUID(PARTITION_LINUX_DATA, 0x0FC63DAF, 0x8483, 0x4772, 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4); -DEFINE_GUID(PARTITION_LINUX_ENCRYPTED, 0x7FFEC5C9, 0x2D00, 0x49B7, 0x89, 0x41, 0x3E, 0xA1, 0x0A, 0x55, 0x86, 0xB7); -DEFINE_GUID(PARTITION_LINUX_HOME, 0x933AC7E1, 0x2EB4, 0x4F13, 0xB8, 0x44, 0x0E, 0x14, 0xE2, 0xAE, 0xF9, 0x15); -DEFINE_GUID(PARTITION_LINUX_LUKS, 0xCA7D7CCB, 0x63ED, 0x4C53, 0x86, 0x1C, 0x17, 0x42, 0x53, 0x60, 0x59, 0xCC); -DEFINE_GUID(PARTITION_LINUX_LVM, 0xE6D6D379, 0xF507, 0x44C2, 0xA2, 0x3C, 0x23, 0x8F, 0x2A, 0x3D, 0xF9, 0x28); -DEFINE_GUID(PARTITION_LINUX_RAID, 0xA19D880F, 0x05FC, 0x4D3B, 0xA0, 0x06, 0x74, 0x3F, 0x0F, 0x84, 0x91, 0x1E); -DEFINE_GUID(PARTITION_LINUX_RESERVED, 0x8DA63339, 0x0007, 0x60C0, 0xC4, 0x36, 0x08, 0x3A, 0xC8, 0x23, 0x09, 0x08); -DEFINE_GUID(PARTITION_LINUX_ROOT_ARM_32, 0x69DAD710, 0x2CE4, 0x4E3C, 0xB1, 0x6C, 0x21, 0xA1, 0xD4, 0x9A, 0xBE, 0xD3); -DEFINE_GUID(PARTITION_LINUX_ROOT_ARM_64, 0xB921B045, 0x1DF0, 0x41C3, 0xAF, 0x44, 0x4C, 0x6F, 0x28, 0x0D, 0x3F, 0xAE); -DEFINE_GUID(PARTITION_LINUX_ROOT_X86_32, 0x44479540, 0xF297, 0x41B2, 0x9A, 0xF7, 0xD1, 0x31, 0xD5, 0xF0, 0x45, 0x8A); -DEFINE_GUID(PARTITION_LINUX_ROOT_X86_64, 0x4F68BCE3, 0xE8CD, 0x4DB1, 0x96, 0xE7, 0xFB, 0xCA, 0xF9, 0x84, 0xB7, 0x09); -DEFINE_GUID(PARTITION_LINUX_SRV, 0x3B8F8425, 0x20E0, 0x4F3B, 0x90, 0x7F, 0x1A, 0x25, 0xA7, 0x6F, 0x98, 0xE8); -DEFINE_GUID(PARTITION_LINUX_SWAP, 0x0657FD6D, 0xA4AB, 0x43C4, 0x84, 0xE5, 0x09, 0x33, 0xC8, 0x4B, 0x4F, 0x4F); -DEFINE_GUID(PARTITION_MICROSOFT_DATA, 0xEBD0A0A2, 0xB9E5, 0x4433, 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7); -DEFINE_GUID(PARTITION_MICROSOFT_LDM_DATA, 0xAF9B60A0, 0x1431, 0x4F62, 0xBC, 0x68, 0x33, 0x11, 0x71, 0x4A, 0x69, 0xAD); -DEFINE_GUID(PARTITION_MICROSOFT_LDM_META, 0x5808C8AA, 0x7E8F, 0x42E0, 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3); -DEFINE_GUID(PARTITION_MICROSOFT_RECOVERY, 0xDE94BBA4, 0x06D1, 0x4D40, 0xA1, 0x6A, 0xBF, 0xD5, 0x01, 0x79, 0xD6, 0xAC); -DEFINE_GUID(PARTITION_MICROSOFT_RESERVED, 0xE3C9E316, 0x0B5C, 0x4DB8, 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE); -DEFINE_GUID(PARTITION_MICROSOFT_STORAGE_SPACES, 0xE75CAF8F, 0xF680, 0x4CEE, 0xAF, 0xA3, 0xB0, 0x01, 0xE5, 0x6E, 0xFC, 0x2D); -DEFINE_GUID(PARTITION_NETBSD_CONCAT, 0x2DB519C4, 0xB10F, 0x11DC, 0xB9, 0x9B, 0x00, 0x19, 0xD1, 0x87, 0x96, 0x48); -DEFINE_GUID(PARTITION_NETBSD_ENCRYPTED, 0x2DB519EC, 0xB10F, 0x11DC, 0xB9, 0x9B, 0x00, 0x19, 0xD1, 0x87, 0x96, 0x48); -DEFINE_GUID(PARTITION_NETBSD_FFS, 0x49F48D5A, 0xB10E, 0x11DC, 0xB9, 0x9B, 0x00, 0x19, 0xD1, 0x87, 0x96, 0x48); -DEFINE_GUID(PARTITION_NETBSD_LFS, 0x49F48D82, 0xB10E, 0x11DC, 0xB9, 0x9B, 0x00, 0x19, 0xD1, 0x87, 0x96, 0x48); -DEFINE_GUID(PARTITION_NETBSD_RAID, 0x49F48DAA, 0xB10E, 0x11DC, 0xB9, 0x9B, 0x00, 0x19, 0xD1, 0x87, 0x96, 0x48); -DEFINE_GUID(PARTITION_NETBSD_SWAP, 0x49F48D32, 0xB10E, 0x11DC, 0xB9, 0x9B, 0x00, 0x19, 0xD1, 0x87, 0x96, 0x48); -DEFINE_GUID(PARTITION_OPENBSD_DATA, 0x824CC7A0, 0x36A8, 0x11E3, 0x89, 0x0A, 0x95, 0x25, 0x19, 0xAD, 0x3F, 0x61); -DEFINE_GUID(PARTITION_PLAN9_DATA, 0xC91818F9, 0x8025, 0x47AF, 0x89, 0xD2, 0xF0, 0x30, 0xD7, 0x00, 0x0C, 0x2C); -DEFINE_GUID(PARTITION_PREP_BOOT, 0x9E1A2D38, 0xC612, 0x4316, 0xAA, 0x26, 0x8B, 0x49, 0x52, 0x1E, 0x5A, 0x8B); -DEFINE_GUID(PARTITION_QNX_DATA, 0xCEF5A9AD, 0x73BC, 0x4601, 0x89, 0xF3, 0xCD, 0xEE, 0xEE, 0xE3, 0x21, 0xA1); -DEFINE_GUID(PARTITION_SOLARIS_ALT, 0x6A9283A5, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_SOLARIS_BACKUP, 0x6A8B642B, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_SOLARIS_BOOT, 0x6A82CB45, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_SOLARIS_HOME, 0x6A90BA39, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_SOLARIS_RESERVED1, 0x6A945A3B, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_SOLARIS_RESERVED2, 0x6A9630D1, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_SOLARIS_RESERVED3, 0x6A980767, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_SOLARIS_RESERVED4, 0x6A96237F, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_SOLARIS_RESERVED5, 0x6A8D2AC7, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -// You sure you don't need a couple more reserved partition GUIDs here, Solaris? -DEFINE_GUID(PARTITION_SOLARIS_ROOT, 0x6A85CF4D, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_SOLARIS_SWAP, 0x6A87C46F, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -//DEFINE_GUID(PARTITION_SOLARIS_USR, 0x6A898CC3, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_SOLARIS_VAR, 0x6A8EF2E9, 0x1DD2, 0x11B2, 0x99, 0xA6, 0x08, 0x00, 0x20, 0x73, 0x66, 0x31); -DEFINE_GUID(PARTITION_SONY_BOOT, 0xF4019732, 0x066E, 0x4E12, 0x82, 0x73, 0x34, 0x6C, 0x56, 0x41, 0x49, 0x4F); -DEFINE_GUID(PARTITION_VERACRYPT_DATA, 0x8C8F8EFF, 0xAC95, 0x4770, 0x81, 0x4A, 0x21, 0x99, 0x4F, 0x2D, 0xBC, 0x8F); -DEFINE_GUID(PARTITION_VMWARE_COREDUMP, 0x9D275380, 0x40AD, 0x11DB, 0xBF, 0x97, 0x00, 0x0C, 0x29, 0x11, 0xD1, 0xB8); -DEFINE_GUID(PARTITION_VMWARE_RESERVED, 0x9198EFFC, 0x31C0, 0x11DB, 0x8F, 0x78, 0x00, 0x0C, 0x29, 0x11, 0xD1, 0xB8); -DEFINE_GUID(PARTITION_VMWARE_VMFS, 0xAA31E02A, 0x400F, 0x11DB, 0x95, 0x90, 0x00, 0x0C, 0x29, 0x11, 0xD1, 0xB8); - typedef struct { - const GUID* guid; - const char* name; -} gpt_type_t; + uint16_t code; + const char* guid_str; + const char* description; +} gpt_type_entry_t; -gpt_type_t gpt_type[] = { - { &PARTITION_ANDROID_BOOT, "Android Boot Partition" }, - { &PARTITION_ANDROID_BOOTLOADER1, "Android Bootloader Partition" }, - { &PARTITION_ANDROID_BOOTLOADER2, "Android Bootloader Partition" }, - { &PARTITION_ANDROID_CACHE, "Android Cache Partition" }, - { &PARTITION_ANDROID_CONFIG, "Android Config Partition" }, - { &PARTITION_ANDROID_DATA, "Android Data Partition" }, - { &PARTITION_ANDROID_EXT, "Android Ext Partition" }, - { &PARTITION_ANDROID_FACTORY1, "Android Factory Partition" }, - { &PARTITION_ANDROID_FACTORY2, "Android Factory Partition" }, - { &PARTITION_ANDROID_FASTBOOT, "Android Fastboot Partition" }, - { &PARTITION_ANDROID_METADATA1, "Android Metadata Partition" }, - { &PARTITION_ANDROID_METADATA2, "Android Metadata Partition" }, - { &PARTITION_ANDROID_MISC, "Android Misc Partition" }, - { &PARTITION_ANDROID_OEM, "Android OEM Partition" }, - { &PARTITION_ANDROID_PERSISTENCE, "Android Persistent Partition" }, - { &PARTITION_ANDROID_RECOVERY, "Android Recovery Partition" }, - { &PARTITION_ANDROID_SYSTEM, "Android System Partition" }, - { &PARTITION_ANDROID_VENDOR, "Android Vendor Partition" }, - { &PARTITION_APPLE_APFS, "Apple APFS Partition" }, - { &PARTITION_APPLE_BOOT, "Apple Boot Partition" }, - { &PARTITION_APPLE_FILEVAULT, "Apple Filevault Partition" }, - { &PARTITION_APPLE_HFS, "Apple HFS+ Partition" }, - { &PARTITION_APPLE_LABEL, "Apple Label Partition" }, - { &PARTITION_APPLE_OFFLINE_RAID, "Apple RAID Partition (Offline)" }, - { &PARTITION_APPLE_RAID, "Apple RAID Partition" }, - { &PARTITION_APPLE_RAID_CACHE, "Apple RAID Cache Partition" }, - { &PARTITION_APPLE_RAID_SCRATCH, "Apple RAID Scratch Partition" }, - { &PARTITION_APPLE_RAID_STATUS, "Apple RAID Status Partition" }, - { &PARTITION_APPLE_RAID_VOLUME, "Apple RAID Volume Partition" }, - { &PARTITION_APPLE_RECOVERY, "Apple Recovery Partition" }, - { &PARTITION_APPLE_UFS, "Apple UFS Partition" }, - { &PARTITION_APPLE_ZFS, "Apple ZFS Partition" }, - { &PARTITION_ATARI_DATA, "Atari Data Partition" }, - { &PARTITION_BEOS_BFS, "BeOS BFS Partition" }, - { &PARTITION_CHROMEOS_KERNEL, "Chrome OS Kernel Partition" }, - { &PARTITION_CHROMEOS_RESERVED, "Chrome OS Reserved Partition" }, - { &PARTITION_CHROMEOS_ROOT, "Chrome OS Root Partition" }, - { &PARTITION_COREOS_RAID, "CoreOS Raid Partition" }, - { &PARTITION_COREOS_RESERVED, "CoreOS Reserved Partition" }, - { &PARTITION_COREOS_ROOT, "CoreOS Root Partition" }, - { &PARTITION_COREOS_USR, "CoreOS Usr Partition" }, - { &PARTITION_FREEBSD_BOOT, "FreeBSD Boot Partition" }, - { &PARTITION_FREEBSD_DATA, "FreeBSD Data Partition" }, - { &PARTITION_FREEBSD_LVM, "FreeBSD LVM Partition" }, - { &PARTITION_FREEBSD_SWAP, "FreeBSD Swap Partition" }, - { &PARTITION_FREEBSD_UFS, "FreeBSD UFS Partition" }, - { &PARTITION_FREEBSD_ZFS, "FreeBSD ZFS Partition" }, - { &PARTITION_GENERIC_BIOS_BOOT, "BIOS Boot Partition" }, - { &PARTITION_GENERIC_XBOOTLDR, "Extended Boot Loader Partition" }, - { &PARTITION_GENERIC_ESP, "EFI System Partition" }, - { &PARTITION_GENERIC_MBR, "MBR Partition" }, - { &PARTITION_GENERIC_UNUSED, "Unused Partition" }, - { &PARTITION_HPUX_DATA, "HP-UX Data Partition" }, - { &PARTITION_HPUX_SERVICE, "HP-UX Service Partition" }, - { &PARTITION_IBM_GPFS, "IBM GPFS Partition" }, - { &PARTITION_INTEL_IFF, "Intel Fast Flash Partition" }, - { &PARTITION_LENOVO_BOOT, "Lenovo Boot Partition" }, - { &PARTITION_LINUX_BOOT, "Linux Boot Partition" }, - { &PARTITION_LINUX_DATA, "Linux Data Partition" }, - { &PARTITION_LINUX_ENCRYPTED, "Linux Encrypted Partition" }, - { &PARTITION_LINUX_HOME, "Linux Home Partition" }, - { &PARTITION_LINUX_LUKS, "Linux LUKS Partition" }, - { &PARTITION_LINUX_LVM, "Linux LVM Partition" }, - { &PARTITION_LINUX_RAID, "Linux RAID Partition" }, - { &PARTITION_LINUX_RESERVED, "Linux Reserved Partition" }, - { &PARTITION_LINUX_ROOT_ARM_32, "Linux Boot Partition (ARM)" }, - { &PARTITION_LINUX_ROOT_ARM_64, "Linux Boot Partition (ARM64)" }, - { &PARTITION_LINUX_ROOT_X86_32, "Linux Boot Partition (x86-32)" }, - { &PARTITION_LINUX_ROOT_X86_64, "Linux Boot Partition (x86-64)" }, - { &PARTITION_LINUX_SRV, "Linux Srv Partition" }, - { &PARTITION_LINUX_SWAP, "Linux Swap Partition" }, - { &PARTITION_MICROSOFT_DATA, "Microsoft Basic Data Partition" }, - { &PARTITION_MICROSOFT_LDM_DATA, "Microsoft LDM Data Partition" }, - { &PARTITION_MICROSOFT_LDM_META, "Microsoft LDM Metadata Partition" }, - { &PARTITION_MICROSOFT_RECOVERY, "Microsoft Recovery Partition" }, - { &PARTITION_MICROSOFT_RESERVED, "Microsoft System Reserved Partition" }, - { &PARTITION_MICROSOFT_STORAGE_SPACES, "Microsoft Storage Spaces Partition" }, - { &PARTITION_NETBSD_CONCAT, "NetBSD Concatenated Partition" }, - { &PARTITION_NETBSD_ENCRYPTED, "NetBSD Encrypted Partition" }, - { &PARTITION_NETBSD_FFS, "NetBSD FFS Partition" }, - { &PARTITION_NETBSD_LFS, "NetBSD LFS Partition" }, - { &PARTITION_NETBSD_RAID, "NetBSD RAID Partition" }, - { &PARTITION_NETBSD_SWAP, "NetBSD Swap Partition" }, - { &PARTITION_OPENBSD_DATA, "OpenBSD Data Partition" }, - { &PARTITION_PLAN9_DATA, "Plan 9 Data Partition" }, - { &PARTITION_PREP_BOOT, "PReP Boot Partition" }, - { &PARTITION_QNX_DATA, "QNX Data Partition" }, - { &PARTITION_SOLARIS_ALT, "Solaris Alternate Sector Partition" }, - { &PARTITION_SOLARIS_BACKUP, "Solaris Backup Partition" }, - { &PARTITION_SOLARIS_BOOT, "Solaris Boot Partition" }, - { &PARTITION_SOLARIS_HOME, "Solaris Home Partition" }, - { &PARTITION_SOLARIS_RESERVED1, "Solaris Reserved Partition" }, - { &PARTITION_SOLARIS_RESERVED2, "Solaris Reserved Partition" }, - { &PARTITION_SOLARIS_RESERVED3, "Solaris Reserved Partition" }, - { &PARTITION_SOLARIS_RESERVED4, "Solaris Reserved Partition" }, - { &PARTITION_SOLARIS_RESERVED5, "Solaris Reserved Partition" }, - { &PARTITION_SOLARIS_ROOT, "Solaris Root Partition" }, - { &PARTITION_SOLARIS_SWAP, "Solaris Swap Partition" }, -// { &PARTITION_SOLARIS_USR, "Solaris Usr Partition" }, - { &PARTITION_SOLARIS_VAR, "Solaris Var Partition" }, - { &PARTITION_SONY_BOOT, "Sony Boot Partition" }, - { &PARTITION_VERACRYPT_DATA, "VeraCrypt Data Partition" }, - { &PARTITION_VMWARE_COREDUMP, "VMware Coredump Partition" }, - { &PARTITION_VMWARE_RESERVED, "VMware Reserved Partition" }, - { &PARTITION_VMWARE_VMFS, "VMware VMFS Partition" }, +#define AddType(code, guid, desc, ...) { code, guid, desc }, + +/* + * Because we value our sanity, we build our GPT entries from code lifted + * verbatim from Debian's gdisk's parttypes.cc and use AddType() as a macro + * to create a static table. + */ +static const gpt_type_entry_t gpt_type_table[] = { + // From https://salsa.debian.org/debian/gdisk/-/blob/master/parttypes.cc + // Semicolons after Addtype() *MUST* be removed. + + // Start with the "unused entry," which should normally appear only + // on empty partition table entries.... + AddType(0x0000, "00000000-0000-0000-0000-000000000000", "Unused entry", 0) + + // DOS/Windows partition types, most of which are hidden from the "L" listing + // (they're available mainly for MBR-to-GPT conversions). + AddType(0x0100, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // FAT-12 + AddType(0x0400, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // FAT-16 < 32M + AddType(0x0600, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // FAT-16 + AddType(0x0700, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 1) // NTFS (or HPFS) + AddType(0x0701, "558D43C5-A1AC-43C0-AAC8-D1472B2923D1", "Microsoft Storage Replica", 1) + AddType(0x0702, "90B6FF38-B98F-4358-A21F-48F35B4A8AD3", "ArcaOS Type 1", 1) + AddType(0x0b00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // FAT-32 + AddType(0x0c00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // FAT-32 LBA + AddType(0x0c01, "E3C9E316-0B5C-4DB8-817D-F92DF00215AE", "Microsoft reserved") + AddType(0x0e00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // FAT-16 LBA + AddType(0x1100, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // Hidden FAT-12 + AddType(0x1400, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // Hidden FAT-16 < 32M + AddType(0x1600, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // Hidden FAT-16 + AddType(0x1700, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // Hidden NTFS (or HPFS) + AddType(0x1b00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // Hidden FAT-32 + AddType(0x1c00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // Hidden FAT-32 LBA + AddType(0x1e00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Microsoft basic data", 0) // Hidden FAT-16 LBA + AddType(0x2700, "DE94BBA4-06D1-4D40-A16A-BFD50179D6AC", "Windows RE") + + // Open Network Install Environment (ONIE) specific types. + // See http://www.onie.org/ and + // https://github.com/opencomputeproject/onie/blob/master/patches/gptfdisk/add-onie-partition-types.patch + AddType(0x3000, "7412F7D5-A156-4B13-81DC-867174929325", "ONIE boot") + AddType(0x3001, "D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149", "ONIE config") + + // Plan 9; see http://man.cat-v.org/9front/8/prep + AddType(0x3900, "C91818F9-8025-47AF-89D2-F030D7000C2C", "Plan 9") + + // PowerPC reference platform boot partition + AddType(0x4100, "9E1A2D38-C612-4316-AA26-8B49521E5A8B", "PowerPC PReP boot") + + // Windows LDM ("dynamic disk") types + AddType(0x4200, "AF9B60A0-1431-4F62-BC68-3311714A69AD", "Windows LDM data") // Logical disk manager + AddType(0x4201, "5808C8AA-7E8F-42E0-85D2-E1E90434CFB3", "Windows LDM metadata") // Logical disk manager + AddType(0x4202, "E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D", "Windows Storage Spaces") // A newer LDM-type setup + + // An oddball IBM filesystem.... + AddType(0x7501, "37AFFC90-EF7D-4E96-91C3-2D7AE055B174", "IBM GPFS") // General Parallel File System (GPFS) + + // ChromeOS-specific partition types... + // Values taken from vboot_reference/firmware/lib/cgptlib/include/gpt.h in + // ChromeOS source code, retrieved 12/23/2010. They're also at + // http://www.chromium.org/chromium-os/chromiumos-design-docs/disk-format. + // These have no MBR equivalents, AFAIK, so I'm using 0x7Fxx values, since they're close + // to the Linux values. + AddType(0x7f00, "FE3A2A5D-4F32-41A7-B725-ACCC3285A309", "ChromeOS kernel") + AddType(0x7f01, "3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC", "ChromeOS root") + AddType(0x7f02, "2E0A753D-9E48-43B0-8337-B15192CB1B5E", "ChromeOS reserved") + AddType(0x7f03, "CAB6E88E-ABF3-4102-A07A-D4BB9BE3C1D3", "ChromeOS firmware") + AddType(0x7f04, "09845860-705F-4BB5-B16C-8A8A099CAF52", "ChromeOS mini-OS") + AddType(0x7f05, "3F0F8318-F146-4E6B-8222-C28C8F02E0D5", "ChromeOS hibernate") + + // Linux-specific partition types.... + AddType(0x8200, "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", "Linux swap") // Linux swap (or Solaris on MBR) + AddType(0x8300, "0FC63DAF-8483-4772-8E79-3D69D8477DE4", "Linux filesystem") // Linux native + AddType(0x8301, "8DA63339-0007-60C0-C436-083AC8230908", "Linux reserved") + // See https://www.freedesktop.org/software/systemd/man/systemd-gpt-auto-generator.html + // and https://systemd.io/DISCOVERABLE_PARTITIONS + AddType(0x8302, "933AC7E1-2EB4-4F13-B844-0E14E2AEF915", "Linux /home") // Linux /home (auto-mounted by systemd) + AddType(0x8303, "44479540-F297-41B2-9AF7-D131D5F0458A", "Linux x86 root (/)") // Linux / on x86 (auto-mounted by systemd) + AddType(0x8304, "4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709", "Linux x86-64 root (/)") // Linux / on x86-64 (auto-mounted by systemd) + AddType(0x8305, "B921B045-1DF0-41C3-AF44-4C6F280D3FAE", "Linux ARM64 root (/)") // Linux / on 64-bit ARM (auto-mounted by systemd) + AddType(0x8306, "3B8F8425-20E0-4F3B-907F-1A25A76F98E8", "Linux /srv") // Linux /srv (auto-mounted by systemd) + AddType(0x8307, "69DAD710-2CE4-4E3C-B16C-21A1D49ABED3", "Linux ARM32 root (/)") // Linux / on 32-bit ARM (auto-mounted by systemd) + AddType(0x8308, "7FFEC5C9-2D00-49B7-8941-3EA10A5586B7", "Linux dm-crypt") + AddType(0x8309, "CA7D7CCB-63ED-4C53-861C-1742536059CC", "Linux LUKS") + AddType(0x830A, "993D8D3D-F80E-4225-855A-9DAF8ED7EA97", "Linux IA-64 root (/)") // Linux / on Itanium (auto-mounted by systemd) + AddType(0x830B, "D13C5D3B-B5D1-422A-B29F-9454FDC89D76", "Linux x86 root verity") + AddType(0x830C, "2C7357ED-EBD2-46D9-AEC1-23D437EC2BF5", "Linux x86-64 root verity") + AddType(0x830D, "7386CDF2-203C-47A9-A498-F2ECCE45A2D6", "Linux ARM32 root verity") + AddType(0x830E, "DF3300CE-D69F-4C92-978C-9BFB0F38D820", "Linux ARM64 root verity") + AddType(0x830F, "86ED10D5-B607-45BB-8957-D350F23D0571", "Linux IA-64 root verity") + AddType(0x8310, "4D21B016-B534-45C2-A9FB-5C16E091FD2D", "Linux /var") // Linux /var (auto-mounted by systemd) + AddType(0x8311, "7EC6F557-3BC5-4ACA-B293-16EF5DF639D1", "Linux /var/tmp") // Linux /var/tmp (auto-mounted by systemd) + // https://systemd.io/HOME_DIRECTORY/ + AddType(0x8312, "773F91EF-66D4-49B5-BD83-D683BF40AD16", "Linux user's home") // used by systemd-homed + AddType(0x8313, "75250D76-8CC6-458E-BD66-BD47CC81A812", "Linux x86 /usr ") // Linux /usr on x86 (auto-mounted by systemd) + AddType(0x8314, "8484680C-9521-48C6-9C11-B0720656F69E", "Linux x86-64 /usr") // Linux /usr on x86-64 (auto-mounted by systemd) + AddType(0x8315, "7D0359A3-02B3-4F0A-865C-654403E70625", "Linux ARM32 /usr") // Linux /usr on 32-bit ARM (auto-mounted by systemd) + AddType(0x8316, "B0E01050-EE5F-4390-949A-9101B17104E9", "Linux ARM64 /usr") // Linux /usr on 64-bit ARM (auto-mounted by systemd) + AddType(0x8317, "4301D2A6-4E3B-4B2A-BB94-9E0B2C4225EA", "Linux IA-64 /usr") // Linux /usr on Itanium (auto-mounted by systemd) + AddType(0x8318, "8F461B0D-14EE-4E81-9AA9-049B6FB97ABD", "Linux x86 /usr verity") + AddType(0x8319, "77FF5F63-E7B6-4633-ACF4-1565B864C0E6", "Linux x86-64 /usr verity") + AddType(0x831A, "C215D751-7BCD-4649-BE90-6627490A4C05", "Linux ARM32 /usr verity") + AddType(0x831B, "6E11A4E7-FBCA-4DED-B9E9-E1A512BB664E", "Linux ARM64 /usr verity") + AddType(0x831C, "6A491E03-3BE7-4545-8E38-83320E0EA880", "Linux IA-64 /usr verity") + AddType(0x831D, "6523F8AE-3EB1-4E2A-A05A-18B695AE656F", "Linux Alpha root (/)") + AddType(0x831E, "D27F46ED-2919-4CB8-BD25-9531F3C16534", "Linux ARC root (/)") + AddType(0x831F, "77055800-792C-4F94-B39A-98C91B762BB6", "Linux LoongArch root (/)") + AddType(0x8320, "E9434544-6E2C-47CC-BAE2-12D6DEAFB44C", "Linux MIPS-32 BE root (/)") + AddType(0x8321, "D113AF76-80EF-41B4-BDB6-0CFF4D3D4A25", "Linux MIPS-64 BE root (/)") + AddType(0x8322, "37C58C8A-D913-4156-A25F-48B1B64E07F0", "Linux MIPS-32 LE root (/)") + AddType(0x8323, "700BDA43-7A34-4507-B179-EEB93D7A7CA3", "Linux MIPS-64 LE root (/)") + AddType(0x8324, "1AACDB3B-5444-4138-BD9E-E5C2239B2346", "Linux PA-RISC root (/)") + AddType(0x8325, "1DE3F1EF-FA98-47B5-8DCD-4A860A654D78", "Linux PowerPC-32 root (/)") + AddType(0x8326, "912ADE1D-A839-4913-8964-A10EEE08FBD2", "Linux PowerPC-64 BE root (/)") + AddType(0x8327, "C31C45E6-3F39-412E-80FB-4809C4980599", "Linux PowerPC-64 LE root (/)") + AddType(0x8328, "60D5A7FE-8E7D-435C-B714-3DD8162144E1", "Linux RISC-V-32 root (/)") + AddType(0x8329, "72EC70A6-CF74-40E6-BD49-4BDA08E8F224", "Linux RISC-V-64 root (/)") + AddType(0x832A, "08A7ACEA-624C-4A20-91E8-6E0FA67D23F9", "Linux s390 root (/)") + AddType(0x832B, "5EEAD9A9-FE09-4A1E-A1D7-520D00531306", "Linux s390x root (/)") + AddType(0x832C, "C50CDD70-3862-4CC3-90E1-809A8C93EE2C", "Linux TILE-Gx root (/)") + AddType(0x832D, "E18CF08C-33EC-4C0D-8246-C6C6FB3DA024", "Linux Alpha /usr") + AddType(0x832E, "7978A683-6316-4922-BBEE-38BFF5A2FECC", "Linux ARC /usr") + AddType(0x832F, "E611C702-575C-4CBE-9A46-434FA0BF7E3F", "Linux LoongArch /usr") + AddType(0x8330, "773B2ABC-2A99-4398-8BF5-03BAAC40D02B", "Linux MIPS-32 BE /usr") + AddType(0x8331, "57E13958-7331-4365-8E6E-35EEEE17C61B", "Linux MIPS-64 BE /usr") + AddType(0x8332, "0F4868E9-9952-4706-979F-3ED3A473E947", "Linux MIPS-32 LE /usr") + AddType(0x8333, "C97C1F32-BA06-40B4-9F22-236061B08AA8", "Linux MIPS-64 LE /usr") + AddType(0x8334, "DC4A4480-6917-4262-A4EC-DB9384949F25", "Linux PA-RISC /usr") + AddType(0x8335, "7D14FEC5-CC71-415D-9D6C-06BF0B3C3EAF", "Linux PowerPC-32 /usr") + AddType(0x8336, "2C9739E2-F068-46B3-9FD0-01C5A9AFBCCA", "Linux PowerPC-64 BE /usr") + AddType(0x8337, "15BB03AF-77E7-4D4A-B12B-C0D084F7491C", "Linux PowerPC-64 LE /usr") + AddType(0x8338, "B933FB22-5C3F-4F91-AF90-E2BB0FA50702", "Linux RISC-V-32 /usr") + AddType(0x8339, "BEAEC34B-8442-439B-A40B-984381ED097D", "Linux RISC-V-64 /usr") + AddType(0x833A, "CD0F869B-D0FB-4CA0-B141-9EA87CC78D66", "Linux s390 /usr") + AddType(0x833B, "8A4F5770-50AA-4ED3-874A-99B710DB6FEA", "Linux s390x /usr") + AddType(0x833C, "55497029-C7C1-44CC-AA39-815ED1558630", "Linux TILE-Gx /usr") + AddType(0x833D, "FC56D9E9-E6E5-4C06-BE32-E74407CE09A5", "Linux Alpha root verity") + AddType(0x833E, "24B2D975-0F97-4521-AFA1-CD531E421B8D", "Linux ARC root verity") + AddType(0x833F, "F3393B22-E9AF-4613-A948-9D3BFBD0C535", "Linux LoongArch root verity") + AddType(0x8340, "7A430799-F711-4C7E-8E5B-1D685BD48607", "Linux MIPS-32 BE root verity") + AddType(0x8341, "579536F8-6A33-4055-A95A-DF2D5E2C42A8", "Linux MIPS-64 BE root verity") + AddType(0x8342, "D7D150D2-2A04-4A33-8F12-16651205FF7B", "Linux MIPS-32 LE root verity") + AddType(0x8343, "16B417F8-3E06-4F57-8DD2-9B5232F41AA6", "Linux MIPS-64 LE root verity") + AddType(0x8344, "D212A430-FBC5-49F9-A983-A7FEEF2B8D0E", "Linux PA-RISC root verity") + AddType(0x8345, "906BD944-4589-4AAE-A4E4-DD983917446A", "Linux PowerPC-64 LE root verity") + AddType(0x8346, "9225A9A3-3C19-4D89-B4F6-EEFF88F17631", "Linux PowerPC-64 BE root verity") + AddType(0x8347, "98CFE649-1588-46DC-B2F0-ADD147424925", "Linux PowerPC-32 root verity") + AddType(0x8348, "AE0253BE-1167-4007-AC68-43926C14C5DE", "Linux RISC-V-32 root verity") + AddType(0x8349, "B6ED5582-440B-4209-B8DA-5FF7C419EA3D", "Linux RISC-V-64 root verity") + AddType(0x834A, "7AC63B47-B25C-463B-8DF8-B4A94E6C90E1", "Linux s390 root verity") + AddType(0x834B, "B325BFBE-C7BE-4AB8-8357-139E652D2F6B", "Linux s390x root verity") + AddType(0x834C, "966061EC-28E4-4B2E-B4A5-1F0A825A1D84", "Linux TILE-Gx root verity") + AddType(0x834D, "8CCE0D25-C0D0-4A44-BD87-46331BF1DF67", "Linux Alpha /usr verity") + AddType(0x834E, "FCA0598C-D880-4591-8C16-4EDA05C7347C", "Linux ARC /usr verity") + AddType(0x834F, "F46B2C26-59AE-48F0-9106-C50ED47F673D", "Linux LoongArch /usr verity") + AddType(0x8350, "6E5A1BC8-D223-49B7-BCA8-37A5FCCEB996", "Linux MIPS-32 BE /usr verity") + AddType(0x8351, "81CF9D90-7458-4DF4-8DCF-C8A3A404F09B", "Linux MIPS-64 BE /usr verity") + AddType(0x8352, "46B98D8D-B55C-4E8F-AAB3-37FCA7F80752", "Linux MIPS-32 LE /usr verity") + AddType(0x8353, "3C3D61FE-B5F3-414D-BB71-8739A694A4EF", "Linux MIPS-64 LE /usr verity") + AddType(0x8354, "5843D618-EC37-48D7-9F12-CEA8E08768B2", "Linux PA-RISC /usr verity") + AddType(0x8355, "EE2B9983-21E8-4153-86D9-B6901A54D1CE", "Linux PowerPC-64 LE /usr verity") + AddType(0x8356, "BDB528A5-A259-475F-A87D-DA53FA736A07", "Linux PowerPC-64 BE /usr verity") + AddType(0x8357, "DF765D00-270E-49E5-BC75-F47BB2118B09", "Linux PowerPC-32 /usr verity") + AddType(0x8358, "CB1EE4E3-8CD0-4136-A0A4-AA61A32E8730", "Linux RISC-V-32 /usr verity") + AddType(0x8359, "8F1056BE-9B05-47C4-81D6-BE53128E5B54", "Linux RISC-V-64 /usr verity") + AddType(0x835A, "B663C618-E7BC-4D6D-90AA-11B756BB1797", "Linux s390 /usr verity") + AddType(0x835B, "31741CC4-1A2A-4111-A581-E00B447D2D06", "Linux s390x /usr verity") + AddType(0x835C, "2FB4BF56-07FA-42DA-8132-6B139F2026AE", "Linux TILE-Gx /usr verity") + AddType(0x835D, "D46495B7-A053-414F-80F7-700C99921EF8", "Linux Alpha root verity signature") + AddType(0x835E, "143A70BA-CBD3-4F06-919F-6C05683A78BC", "Linux ARC root verity signature") + AddType(0x835F, "42B0455F-EB11-491D-98D3-56145BA9D037", "Linux ARM32 root verity signature") + AddType(0x8360, "6DB69DE6-29F4-4758-A7A5-962190F00CE3", "Linux ARM64 root verity signature") + AddType(0x8361, "E98B36EE-32BA-4882-9B12-0CE14655F46A", "Linux IA-64 root verity signature") + AddType(0x8362, "5AFB67EB-ECC8-4F85-AE8E-AC1E7C50E7D0", "Linux LoongArch root verity signature") + AddType(0x8363, "BBA210A2-9C5D-45EE-9E87-FF2CCBD002D0", "Linux MIPS-32 BE root verity signature") + AddType(0x8364, "43CE94D4-0F3D-4999-8250-B9DEAFD98E6E", "Linux MIPS-64 BE root verity signature") + AddType(0x8365, "C919CC1F-4456-4EFF-918C-F75E94525CA5", "Linux MIPS-32 LE root verity signature") + AddType(0x8366, "904E58EF-5C65-4A31-9C57-6AF5FC7C5DE7", "Linux MIPS-64 LE root verity signature") + AddType(0x8367, "15DE6170-65D3-431C-916E-B0DCD8393F25", "Linux PA-RISC root verity signature") + AddType(0x8368, "D4A236E7-E873-4C07-BF1D-BF6CF7F1C3C6", "Linux PowerPC-64 LE root verity signature") + AddType(0x8369, "F5E2C20C-45B2-4FFA-BCE9-2A60737E1AAF", "Linux PowerPC-64 BE root verity signature") + AddType(0x836A, "1B31B5AA-ADD9-463A-B2ED-BD467FC857E7", "Linux PowerPC-32 root verity signature") + AddType(0x836B, "3A112A75-8729-4380-B4CF-764D79934448", "Linux RISC-V-32 root verity signature") + AddType(0x836C, "EFE0F087-EA8D-4469-821A-4C2A96A8386A", "Linux RISC-V-64 root verity signature") + AddType(0x836D, "3482388E-4254-435A-A241-766A065F9960", "Linux s390 root verity signature") + AddType(0x836E, "C80187A5-73A3-491A-901A-017C3FA953E9", "Linux s390x root verity signature") + AddType(0x836F, "B3671439-97B0-4A53-90F7-2D5A8F3AD47B", "Linux TILE-Gx root verity signature") + AddType(0x8370, "41092B05-9FC8-4523-994F-2DEF0408B176", "Linux x86-64 root verity signature") + AddType(0x8371, "5996FC05-109C-48DE-808B-23FA0830B676", "Linux x86 root verity signature") + AddType(0x8372, "5C6E1C76-076A-457A-A0FE-F3B4CD21CE6E", "Linux Alpha /usr verity signature") + AddType(0x8373, "94F9A9A1-9971-427A-A400-50CB297F0F35", "Linux ARC /usr verity signature") + AddType(0x8374, "D7FF812F-37D1-4902-A810-D76BA57B975A", "Linux ARM32 /usr verity signature") + AddType(0x8375, "C23CE4FF-44BD-4B00-B2D4-B41B3419E02A", "Linux ARM64 /usr verity signature") + AddType(0x8376, "8DE58BC2-2A43-460D-B14E-A76E4A17B47F", "Linux IA-64 /usr verity signature") + AddType(0x8377, "B024F315-D330-444C-8461-44BBDE524E99", "Linux LoongArch /usr verity signature") + AddType(0x8378, "97AE158D-F216-497B-8057-F7F905770F54", "Linux MIPS-32 BE /usr verity signature") + AddType(0x8379, "05816CE2-DD40-4AC6-A61D-37D32DC1BA7D", "Linux MIPS-64 BE /usr verity signature") + AddType(0x837A, "3E23CA0B-A4BC-4B4E-8087-5AB6A26AA8A9", "Linux MIPS-32 LE /usr verity signature") + AddType(0x837B, "F2C2C7EE-ADCC-4351-B5C6-EE9816B66E16", "Linux MIPS-64 LE /usr verity signature") + AddType(0x837C, "450DD7D1-3224-45EC-9CF2-A43A346D71EE", "Linux PA-RISC /usr verity signature") + AddType(0x837D, "C8BFBD1E-268E-4521-8BBA-BF314C399557", "Linux PowerPC-64 LE /usr verity signature") + AddType(0x837E, "0B888863-D7F8-4D9E-9766-239FCE4D58AF", "Linux PowerPC-64 BE /usr verity signature") + AddType(0x837F, "7007891D-D371-4A80-86A4-5CB875B9302E", "Linux PowerPC-32 /usr verity signature") + AddType(0x8380, "C3836A13-3137-45BA-B583-B16C50FE5EB4", "Linux RISC-V-32 /usr verity signature") + AddType(0x8381, "D2F9000A-7A18-453F-B5CD-4D32F77A7B32", "Linux RISC-V-64 /usr verity signature") + AddType(0x8382, "17440E4F-A8D0-467F-A46E-3912AE6EF2C5", "Linux s390 /usr verity signature") + AddType(0x8383, "3F324816-667B-46AE-86EE-9B0C0C6C11B4", "Linux s390x /usr verity signature") + AddType(0x8384, "4EDE75E2-6CCC-4CC8-B9C7-70334B087510", "Linux TILE-Gx /usr verity signature") + AddType(0x8385, "E7BB33FB-06CF-4E81-8273-E543B413E2E2", "Linux x86-64 /usr verity signature") + AddType(0x8386, "974A71C0-DE41-43C3-BE5D-5C5CCD1AD2C0", "Linux x86 /usr verity signature") + + // Used by Intel Rapid Start technology + AddType(0x8400, "D3BFE2DE-3DAF-11DF-BA40-E3A556D89593", "Intel Rapid Start") + // This is another Intel-associated technology, so I'm keeping it close to the previous one.... + AddType(0x8401, "7C5222BD-8F5D-4087-9C00-BF9843C7B58C", "SPDK block device") + + // Type codes for Container Linux (formerly CoreOS; https://coreos.com) + AddType(0x8500, "5DFBF5F4-2848-4BAC-AA5E-0D9A20B745A6", "Container Linux /usr") + AddType(0x8501, "3884DD41-8582-4404-B9A8-E9B84F2DF50E", "Container Linux resizable rootfs") + AddType(0x8502, "C95DC21A-DF0E-4340-8D7B-26CBFA9A03E0", "Container Linux /OEM customizations") + AddType(0x8503, "BE9067B9-EA49-4F15-B4F6-F36F8C9E1818", "Container Linux root on RAID") + + // Another Linux type code.... + AddType(0x8e00, "E6D6D379-F507-44C2-A23C-238F2A3DF928", "Linux LVM") + + // Android type codes.... + // from Wikipedia, https://gist.github.com/culots/704afd126dec2f45c22d0c9d42cb7fab, + // and my own Android devices' partition tables + AddType(0xa000, "2568845D-2332-4675-BC39-8FA5A4748D15", "Android bootloader") + AddType(0xa001, "114EAFFE-1552-4022-B26E-9B053604CF84", "Android bootloader 2") + AddType(0xa002, "49A4D17F-93A3-45C1-A0DE-F50B2EBE2599", "Android boot 1") + AddType(0xa003, "4177C722-9E92-4AAB-8644-43502BFD5506", "Android recovery 1") + AddType(0xa004, "EF32A33B-A409-486C-9141-9FFB711F6266", "Android misc") + AddType(0xa005, "20AC26BE-20B7-11E3-84C5-6CFDB94711E9", "Android metadata") + AddType(0xa006, "38F428E6-D326-425D-9140-6E0EA133647C", "Android system 1") + AddType(0xa007, "A893EF21-E428-470A-9E55-0668FD91A2D9", "Android cache") + AddType(0xa008, "DC76DDA9-5AC1-491C-AF42-A82591580C0D", "Android data") + AddType(0xa009, "EBC597D0-2053-4B15-8B64-E0AAC75F4DB1", "Android persistent") + AddType(0xa00a, "8F68CC74-C5E5-48DA-BE91-A0C8C15E9C80", "Android factory") + AddType(0xa00b, "767941D0-2085-11E3-AD3B-6CFDB94711E9", "Android fastboot/tertiary") + AddType(0xa00c, "AC6D7924-EB71-4DF8-B48D-E267B27148FF", "Android OEM") + AddType(0xa00d, "C5A0AEEC-13EA-11E5-A1B1-001E67CA0C3C", "Android vendor") + AddType(0xa00e, "BD59408B-4514-490D-BF12-9878D963F378", "Android config") + AddType(0xa00f, "9FDAA6EF-4B3F-40D2-BA8D-BFF16BFB887B", "Android factory (alt)") + AddType(0xa010, "19A710A2-B3CA-11E4-B026-10604B889DCF", "Android meta") + AddType(0xa011, "193D1EA4-B3CA-11E4-B075-10604B889DCF", "Android EXT") + AddType(0xa012, "DEA0BA2C-CBDD-4805-B4F9-F428251C3E98", "Android SBL1") + AddType(0xa013, "8C6B52AD-8A9E-4398-AD09-AE916E53AE2D", "Android SBL2") + AddType(0xa014, "05E044DF-92F1-4325-B69E-374A82E97D6E", "Android SBL3") + AddType(0xa015, "400FFDCD-22E0-47E7-9A23-F16ED9382388", "Android APPSBL") + AddType(0xa016, "A053AA7F-40B8-4B1C-BA08-2F68AC71A4F4", "Android QSEE/tz") + AddType(0xa017, "E1A6A689-0C8D-4CC6-B4E8-55A4320FBD8A", "Android QHEE/hyp") + AddType(0xa018, "098DF793-D712-413D-9D4E-89D711772228", "Android RPM") + AddType(0xa019, "D4E0D938-B7FA-48C1-9D21-BC5ED5C4B203", "Android WDOG debug/sdi") + AddType(0xa01a, "20A0C19C-286A-42FA-9CE7-F64C3226A794", "Android DDR") + AddType(0xa01b, "A19F205F-CCD8-4B6D-8F1E-2D9BC24CFFB1", "Android CDT") + AddType(0xa01c, "66C9B323-F7FC-48B6-BF96-6F32E335A428", "Android RAM dump") + AddType(0xa01d, "303E6AC3-AF15-4C54-9E9B-D9A8FBECF401", "Android SEC") + AddType(0xa01e, "C00EEF24-7709-43D6-9799-DD2B411E7A3C", "Android PMIC") + AddType(0xa01f, "82ACC91F-357C-4A68-9C8F-689E1B1A23A1", "Android misc 1") + AddType(0xa020, "E2802D54-0545-E8A1-A1E8-C7A3E245ACD4", "Android misc 2") + AddType(0xa021, "65ADDCF4-0C5C-4D9A-AC2D-D90B5CBFCD03", "Android device info") + AddType(0xa022, "E6E98DA2-E22A-4D12-AB33-169E7DEAA507", "Android APDP") + AddType(0xa023, "ED9E8101-05FA-46B7-82AA-8D58770D200B", "Android MSADP") + AddType(0xa024, "11406F35-1173-4869-807B-27DF71802812", "Android DPO") + AddType(0xa025, "9D72D4E4-9958-42DA-AC26-BEA7A90B0434", "Android recovery 2") + AddType(0xa026, "6C95E238-E343-4BA8-B489-8681ED22AD0B", "Android persist") + AddType(0xa027, "EBBEADAF-22C9-E33B-8F5D-0E81686A68CB", "Android modem ST1") + AddType(0xa028, "0A288B1F-22C9-E33B-8F5D-0E81686A68CB", "Android modem ST2") + AddType(0xa029, "57B90A16-22C9-E33B-8F5D-0E81686A68CB", "Android FSC") + AddType(0xa02a, "638FF8E2-22C9-E33B-8F5D-0E81686A68CB", "Android FSG 1") + AddType(0xa02b, "2013373E-1AC4-4131-BFD8-B6A7AC638772", "Android FSG 2") + AddType(0xa02c, "2C86E742-745E-4FDD-BFD8-B6A7AC638772", "Android SSD") + AddType(0xa02d, "DE7D4029-0F5B-41C8-AE7E-F6C023A02B33", "Android keystore") + AddType(0xa02e, "323EF595-AF7A-4AFA-8060-97BE72841BB9", "Android encrypt") + AddType(0xa02f, "45864011-CF89-46E6-A445-85262E065604", "Android EKSST") + AddType(0xa030, "8ED8AE95-597F-4C8A-A5BD-A7FF8E4DFAA9", "Android RCT") + AddType(0xa031, "DF24E5ED-8C96-4B86-B00B-79667DC6DE11", "Android spare1") + AddType(0xa032, "7C29D3AD-78B9-452E-9DEB-D098D542F092", "Android spare2") + AddType(0xa033, "379D107E-229E-499D-AD4F-61F5BCF87BD4", "Android spare3") + AddType(0xa034, "0DEA65E5-A676-4CDF-823C-77568B577ED5", "Android spare4") + AddType(0xa035, "4627AE27-CFEF-48A1-88FE-99C3509ADE26", "Android raw resources") + AddType(0xa036, "20117F86-E985-4357-B9EE-374BC1D8487D", "Android boot 2") + AddType(0xa037, "86A7CB80-84E1-408C-99AB-694F1A410FC7", "Android FOTA") + AddType(0xa038, "97D7B011-54DA-4835-B3C4-917AD6E73D74", "Android system 2") + AddType(0xa039, "5594C694-C871-4B5F-90B1-690A6F68E0F7", "Android cache") + AddType(0xa03a, "1B81E7E6-F50D-419B-A739-2AEEF8DA3335", "Android user data") + AddType(0xa03b, "98523EC6-90FE-4C67-B50A-0FC59ED6F56D", "LG (Android) advanced flasher") + AddType(0xa03c, "2644BCC0-F36A-4792-9533-1738BED53EE3", "Android PG1FS") + AddType(0xa03d, "DD7C91E9-38C9-45C5-8A12-4A80F7E14057", "Android PG2FS") + AddType(0xa03e, "7696D5B6-43FD-4664-A228-C563C4A1E8CC", "Android board info") + AddType(0xa03f, "0D802D54-058D-4A20-AD2D-C7A362CEACD4", "Android MFG") + AddType(0xa040, "10A0C19C-516A-5444-5CE3-664C3226A794", "Android limits") + + // Atari TOS partition type + AddType(0xa200, "734E5AFE-F61A-11E6-BC64-92361F002671", "Atari TOS basic data") + + // FreeBSD partition types.... + // Note: Rather than extract FreeBSD disklabel data, convert FreeBSD + // partitions in-place, and let FreeBSD sort out the details.... + AddType(0xa500, "516E7CB4-6ECF-11D6-8FF8-00022D09712B", "FreeBSD disklabel") + AddType(0xa501, "83BD6B9D-7F41-11DC-BE0B-001560B84F0F", "FreeBSD boot") + AddType(0xa502, "516E7CB5-6ECF-11D6-8FF8-00022D09712B", "FreeBSD swap") + AddType(0xa503, "516E7CB6-6ECF-11D6-8FF8-00022D09712B", "FreeBSD UFS") + AddType(0xa504, "516E7CBA-6ECF-11D6-8FF8-00022D09712B", "FreeBSD ZFS") + AddType(0xa505, "516E7CB8-6ECF-11D6-8FF8-00022D09712B", "FreeBSD Vinum/RAID") + AddType(0xa506, "74BA7DD9-A689-11E1-BD04-00E081286ACF", "FreeBSD nandfs") + + // Midnight BSD partition types.... + AddType(0xa580, "85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7", "Midnight BSD data") + AddType(0xa581, "85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7", "Midnight BSD boot") + AddType(0xa582, "85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7", "Midnight BSD swap") + AddType(0xa583, "0394Ef8B-237E-11E1-B4B3-E89A8F7FC3A7", "Midnight BSD UFS") + AddType(0xa584, "85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7", "Midnight BSD ZFS") + AddType(0xa585, "85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7", "Midnight BSD Vinum") + + // OpenBSD partition type.... + AddType(0xa600, "824CC7A0-36A8-11E3-890A-952519AD3F61", "OpenBSD disklabel") + + // A MacOS partition type, separated from others by NetBSD partition types... + AddType(0xa800, "55465300-0000-11AA-AA11-00306543ECAC", "Apple UFS") // Mac OS X + + // NetBSD partition types. Note that the main entry sets it up as a + // FreeBSD disklabel. I'm not 100% certain this is the correct behavior. + AddType(0xa900, "516E7CB4-6ECF-11D6-8FF8-00022D09712B", "FreeBSD disklabel", 0) // NetBSD disklabel + AddType(0xa901, "49F48D32-B10E-11DC-B99B-0019D1879648", "NetBSD swap") + AddType(0xa902, "49F48D5A-B10E-11DC-B99B-0019D1879648", "NetBSD FFS") + AddType(0xa903, "49F48D82-B10E-11DC-B99B-0019D1879648", "NetBSD LFS") + AddType(0xa904, "2DB519C4-B10F-11DC-B99B-0019D1879648", "NetBSD concatenated") + AddType(0xa905, "2DB519EC-B10F-11DC-B99B-0019D1879648", "NetBSD encrypted") + AddType(0xa906, "49F48DAA-B10E-11DC-B99B-0019D1879648", "NetBSD RAID") + + // Mac OS partition types (See also 0xa800, above).... + AddType(0xab00, "426F6F74-0000-11AA-AA11-00306543ECAC", "Recovery HD") + AddType(0xaf00, "48465300-0000-11AA-AA11-00306543ECAC", "Apple HFS/HFS+") + AddType(0xaf01, "52414944-0000-11AA-AA11-00306543ECAC", "Apple RAID") + AddType(0xaf02, "52414944-5F4F-11AA-AA11-00306543ECAC", "Apple RAID offline") + AddType(0xaf03, "4C616265-6C00-11AA-AA11-00306543ECAC", "Apple label") + AddType(0xaf04, "5265636F-7665-11AA-AA11-00306543ECAC", "AppleTV recovery") + AddType(0xaf05, "53746F72-6167-11AA-AA11-00306543ECAC", "Apple Core Storage") + AddType(0xaf06, "B6FA30DA-92D2-4A9A-96F1-871EC6486200", "Apple SoftRAID Status") + AddType(0xaf07, "2E313465-19B9-463F-8126-8A7993773801", "Apple SoftRAID Scratch") + AddType(0xaf08, "FA709C7E-65B1-4593-BFD5-E71D61DE9B02", "Apple SoftRAID Volume") + AddType(0xaf09, "BBBA6DF5-F46F-4A89-8F59-8765B2727503", "Apple SoftRAID Cache") + AddType(0xaf0a, "7C3457EF-0000-11AA-AA11-00306543ECAC", "Apple APFS") + AddType(0xaf0b, "69646961-6700-11AA-AA11-00306543ECAC", "Apple APFS Pre-Boot") + AddType(0xaf0c, "52637672-7900-11AA-AA11-00306543ECAC", "Apple APFS Recovery") + + // U-Boot boot loader; see https://lists.denx.de/pipermail/u-boot/2020-November/432928.html + // and https://source.denx.de/u-boot/u-boot/-/blob/v2021.07/include/part_efi.h#L59-61 + AddType(0xb000, "3DE21764-95BD-54BD-A5C3-4ABE786F38A8", "U-Boot boot loader") + + // QNX Power-Safe (QNX6) + AddType(0xb300, "CEF5A9AD-73BC-4601-89F3-CDEEEEE321A1", "QNX6 Power-Safe") + + // Barebox boot loader; see https://barebox.org/doc/latest/user/state.html?highlight=guid#sd-emmc-and-ata + AddType(0xbb00, "4778ED65-BF42-45FA-9C5B-287A1DC4AAB1", "Barebox boot loader") + + // Acronis Secure Zone + AddType(0xbc00, "0311FC50-01CA-4725-AD77-9ADBB20ACE98", "Acronis Secure Zone") + + // Solaris partition types (one of which is shared with MacOS) + AddType(0xbe00, "6A82CB45-1DD2-11B2-99A6-080020736631", "Solaris boot") + AddType(0xbf00, "6A85CF4D-1DD2-11B2-99A6-080020736631", "Solaris root") + AddType(0xbf01, "6A898CC3-1DD2-11B2-99A6-080020736631", "Solaris /usr & Mac ZFS") // Solaris/MacOS + AddType(0xbf02, "6A87C46F-1DD2-11B2-99A6-080020736631", "Solaris swap") + AddType(0xbf03, "6A8B642B-1DD2-11B2-99A6-080020736631", "Solaris backup") + AddType(0xbf04, "6A8EF2E9-1DD2-11B2-99A6-080020736631", "Solaris /var") + AddType(0xbf05, "6A90BA39-1DD2-11B2-99A6-080020736631", "Solaris /home") + AddType(0xbf06, "6A9283A5-1DD2-11B2-99A6-080020736631", "Solaris alternate sector") + AddType(0xbf07, "6A945A3B-1DD2-11B2-99A6-080020736631", "Solaris Reserved 1") + AddType(0xbf08, "6A9630D1-1DD2-11B2-99A6-080020736631", "Solaris Reserved 2") + AddType(0xbf09, "6A980767-1DD2-11B2-99A6-080020736631", "Solaris Reserved 3") + AddType(0xbf0a, "6A96237F-1DD2-11B2-99A6-080020736631", "Solaris Reserved 4") + AddType(0xbf0b, "6A8D2AC7-1DD2-11B2-99A6-080020736631", "Solaris Reserved 5") + + // I can find no MBR equivalents for these, but they're on the + // Wikipedia page for GPT, so here we go.... + AddType(0xc001, "75894C1E-3AEB-11D3-B7C1-7B03A0000000", "HP-UX data") + AddType(0xc002, "E2A1E728-32E3-11D6-A682-7B03A0000000", "HP-UX service") + + // Open Network Install Environment (ONIE) partitions.... + AddType(0xe100, "7412F7D5-A156-4B13-81DC-867174929325", "ONIE boot") + AddType(0xe101, "D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149", "ONIE config") + + // Veracrypt (https://www.veracrypt.fr/en/Home.html) encrypted partition + AddType(0xe900, "8C8F8EFF-AC95-4770-814A-21994F2DBC8F", "Veracrypt data") + + // See https://systemd.io/BOOT_LOADER_SPECIFICATION/ + AddType(0xea00, "BC13C2FF-59E6-4262-A352-B275FD6F7172", "XBOOTLDR partition") + + // Type code for Haiku; uses BeOS MBR code as hex code base + AddType(0xeb00, "42465331-3BA3-10F1-802A-4861696B7521", "Haiku BFS") + + // Manufacturer-specific ESP-like partitions (in order in which they were added) + AddType(0xed00, "F4019732-066E-4E12-8273-346C5641494F", "Sony system partition") + AddType(0xed01, "BFBFAFE7-A34F-448A-9A5B-6213EB736C22", "Lenovo system partition") + + // EFI system and related partitions + AddType(0xef00, "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", "EFI system partition") // Parted identifies these as having the "boot flag" set + AddType(0xef01, "024DEE41-33E7-11D3-9D69-0008C781F39F", "MBR partition scheme") // Used to nest MBR in GPT + AddType(0xef02, "21686148-6449-6E6F-744E-656564454649", "BIOS boot partition") // Used by GRUB + + // Fuscia OS codes; see https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/system/public/zircon/hw/gpt.h + AddType(0xf100, "FE8A2634-5E2E-46BA-99E3-3A192091A350", "Fuchsia boot loader (slot A/B/R)") + AddType(0xf101, "D9FD4535-106C-4CEC-8D37-DFC020CA87CB", "Fuchsia durable mutable encrypted system data") + AddType(0xf102, "A409E16B-78AA-4ACC-995C-302352621A41", "Fuchsia durable mutable boot loader") + AddType(0xf103, "F95D940E-CABA-4578-9B93-BB6C90F29D3E", "Fuchsia factory ro system data") + AddType(0xf104, "10B8DBAA-D2BF-42A9-98C6-A7C5DB3701E7", "Fuchsia factory ro bootloader data") + AddType(0xf105, "49FD7CB8-DF15-4E73-B9D9-992070127F0F", "Fuchsia Volume Manager") + AddType(0xf106, "421A8BFC-85D9-4D85-ACDA-B64EEC0133E9", "Fuchsia verified boot metadata (slot A/B/R)") + AddType(0xf107, "9B37FFF6-2E58-466A-983A-F7926D0B04E0", "Fuchsia Zircon boot image (slot A/B/R)") + AddType(0xf108, "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", "Fuchsia ESP") + AddType(0xf109, "606B000B-B7C7-4653-A7D5-B737332C899D", "Fuchsia System") + AddType(0xf10a, "08185F0C-892D-428A-A789-DBEEC8F55E6A", "Fuchsia Data") + AddType(0xf10b, "48435546-4953-2041-494E-5354414C4C52", "Fuchsia Install") + AddType(0xf10c, "2967380E-134C-4CBB-B6DA-17E7CE1CA45D", "Fuchsia Blob") + AddType(0xf10d, "41D0E340-57E3-954E-8C1E-17ECAC44CFF5", "Fuchsia FVM") + AddType(0xf10e, "DE30CC86-1F4A-4A31-93C4-66F147D33E05", "Fuchsia Zircon boot image (slot A)") + AddType(0xf10f, "23CC04DF-C278-4CE7-8471-897D1A4BCDF7", "Fuchsia Zircon boot image (slot B)") + AddType(0xf110, "A0E5CF57-2DEF-46BE-A80C-A2067C37CD49", "Fuchsia Zircon boot image (slot R)") + AddType(0xf111, "4E5E989E-4C86-11E8-A15B-480FCF35F8E6", "Fuchsia sys-config") + AddType(0xf112, "5A3A90BE-4C86-11E8-A15B-480FCF35F8E6", "Fuchsia factory-config") + AddType(0xf113, "5ECE94FE-4C86-11E8-A15B-480FCF35F8E6", "Fuchsia bootloader") + AddType(0xf114, "8B94D043-30BE-4871-9DFA-D69556E8C1F3", "Fuchsia guid-test") + AddType(0xf115, "A13B4D9A-EC5F-11E8-97D8-6C3BE52705BF", "Fuchsia verified boot metadata (A)") + AddType(0xf116, "A288ABF2-EC5F-11E8-97D8-6C3BE52705BF", "Fuchsia verified boot metadata (B)") + AddType(0xf117, "6A2460C3-CD11-4E8B-80A8-12CCE268ED0A", "Fuchsia verified boot metadata (R)") + AddType(0xf118, "1D75395D-F2C6-476B-A8B7-45CC1C97B476", "Fuchsia misc") + AddType(0xf119, "900B0FC5-90CD-4D4F-84F9-9F8ED579DB88", "Fuchsia emmc-boot1") + AddType(0xf11a, "B2B2E8D1-7C10-4EBC-A2D0-4614568260AD", "Fuchsia emmc-boot2") + + // Ceph type codes; see https://github.com/ceph/ceph/blob/9bcc42a3e6b08521694b5c0228b2c6ed7b3d312e/src/ceph-disk#L76-L81 + // and Wikipedia + AddType(0xf800, "4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D", "Ceph OSD") // Ceph Object Storage Daemon + AddType(0xf801, "4FBD7E29-9D25-41B8-AFD0-5EC00CEFF05D", "Ceph dm-crypt OSD") // Ceph Object Storage Daemon (encrypted) + AddType(0xf802, "45B0969E-9B03-4F30-B4C6-B4B80CEFF106", "Ceph journal") + AddType(0xf803, "45B0969E-9B03-4F30-B4C6-5EC00CEFF106", "Ceph dm-crypt journal") + AddType(0xf804, "89C57F98-2FE5-4DC0-89C1-F3AD0CEFF2BE", "Ceph disk in creation") + AddType(0xf805, "89C57F98-2FE5-4DC0-89C1-5EC00CEFF2BE", "Ceph dm-crypt disk in creation") + AddType(0xf806, "CAFECAFE-9B03-4F30-B4C6-B4B80CEFF106", "Ceph block") + AddType(0xf807, "30CD0809-C2B2-499C-8879-2D6B78529876", "Ceph block DB") + AddType(0xf808, "5CE17FCE-4087-4169-B7FF-056CC58473F9", "Ceph block write-ahead log") + AddType(0xf809, "FB3AABF9-D25F-47CC-BF5E-721D1816496B", "Ceph lockbox for dm-crypt keys") + AddType(0xf80a, "4FBD7E29-8AE0-4982-BF9D-5A8D867AF560", "Ceph multipath OSD") + AddType(0xf80b, "45B0969E-8AE0-4982-BF9D-5A8D867AF560", "Ceph multipath journal") + AddType(0xf80c, "CAFECAFE-8AE0-4982-BF9D-5A8D867AF560", "Ceph multipath block 1") + AddType(0xf80d, "7F4A666A-16F3-47A2-8445-152EF4D03F6C", "Ceph multipath block 2") + AddType(0xf80e, "EC6D6385-E346-45DC-BE91-DA2A7C8B3261", "Ceph multipath block DB") + AddType(0xf80f, "01B41E1B-002A-453C-9F17-88793989FF8F", "Ceph multipath block write-ahead log") + AddType(0xf810, "CAFECAFE-9B03-4F30-B4C6-5EC00CEFF106", "Ceph dm-crypt block") + AddType(0xf811, "93B0052D-02D9-4D8A-A43B-33A3EE4DFBC3", "Ceph dm-crypt block DB") + AddType(0xf812, "306E8683-4FE2-4330-B7C0-00A917C16966", "Ceph dm-crypt block write-ahead log") + AddType(0xf813, "45B0969E-9B03-4F30-B4C6-35865CEFF106", "Ceph dm-crypt LUKS journal") + AddType(0xf814, "CAFECAFE-9B03-4F30-B4C6-35865CEFF106", "Ceph dm-crypt LUKS block") + AddType(0xf815, "166418DA-C469-4022-ADF4-B30AFD37F176", "Ceph dm-crypt LUKS block DB") + AddType(0xf816, "86A32090-3647-40B9-BBBD-38D8C573AA86", "Ceph dm-crypt LUKS block write-ahead log") + AddType(0xf817, "4FBD7E29-9D25-41B8-AFD0-35865CEFF05D", "Ceph dm-crypt LUKS OSD") + + // VMWare ESX partition types codes + AddType(0xfb00, "AA31E02A-400F-11DB-9590-000C2911D1B8", "VMWare VMFS") + AddType(0xfb01, "9198EFFC-31C0-11DB-8F78-000C2911D1B8", "VMWare reserved") + AddType(0xfc00, "9D275380-40AD-11DB-BF97-000C2911D1B8", "VMWare kcore crash protection") + + // A straggler Linux partition type.... + AddType(0xfd00, "A19D880F-05FC-4D3B-A006-743F0F84911E", "Linux RAID") }; +#undef AddType + +static inline const gpt_type_entry_t* gpt_type_lookup(uint16_t code) +{ + for (int i = 0; i < ARRAYSIZE(gpt_type_table); i++) { + if (gpt_type_table[i].code == code) + return &gpt_type_table[i]; + } + return NULL; +} + +static inline const char* gpt_type_desc(const GUID* guid) +{ + const char* guid_str = GuidToString(guid, TRUE); + if (guid_str == NULL) + return NULL; + for (int i = 0; i < ARRAYSIZE(gpt_type_table); i++) { + if (_strnicmp(&guid_str[1], gpt_type_table[i].guid_str, 36) == 0) + return gpt_type_table[i].description; + } + return NULL; +} + +static inline const char* gpt_type_guid_str(uint16_t code) +{ + const gpt_type_entry_t* e = gpt_type_lookup(code); + return (e != NULL) ? e->guid_str : NULL; +} + +static inline const char* gpt_type_description(uint16_t code) +{ + const gpt_type_entry_t* e = gpt_type_lookup(code); + return (e != NULL) ? e->description : NULL; +} + +static inline GUID gpt_type_guid(uint16_t code) +{ + return StringToGuid(gpt_type_guid_str(code)); +} + +// Also redefine the constant GUIDs we use in the application +DEFINE_GUID(PARTITION_GENERIC_ESP, 0xC12A7328, 0xF81F, 0x11D2, 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B); +DEFINE_GUID(PARTITION_LINUX_DATA, 0x0FC63DAF, 0x8483, 0x4772, 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4); +DEFINE_GUID(PARTITION_MICROSOFT_DATA, 0xEBD0A0A2, 0xB9E5, 0x4433, 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7); +DEFINE_GUID(PARTITION_MICROSOFT_RESERVED, 0xE3C9E316, 0x0B5C, 0x4DB8, 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE); diff --git a/src/license.h b/src/license.h index 4ddeae4c..a7781b49 100644 --- a/src/license.h +++ b/src/license.h @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Licensing Data - * Copyright © 2011-2025 Pete Batard + * Copyright © 2011-2026 Pete Batard * * 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 @@ -110,9 +110,11 @@ const char* additional_copyrights = "https://sourceforge.net/projects/smartmontools\\line\n" "GNU General Public License (GPL) v2 or later\\line\n" "\\line\n" -"FS Type description from GNU fdisk:\\line\n" +"Partition and FS Type identification from GNU fdisk and GPT fdisk:\\line\n" "https://www.gnu.org/software/fdisk\\line\n" -"GNU General Public License (GPL) v3 or later\\line\n" +"https://www.rodsbooks.com/gdisk\\line\n" +"https://salsa.debian.org/debian/gdisk\\line\n" +"GNU General Public License (GPL) v2 or later\\line\n" "\\line\n" "Speed/ETA computation from GNU wget:\\line\n" "https://www.gnu.org/software/wget\\line\n" diff --git a/src/rufus.h b/src/rufus.h index 1f011224..14723810 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -1,6 +1,6 @@ /* * Rufus: The Reliable USB Formatting Utility - * Copyright © 2011-2025 Pete Batard + * Copyright © 2011-2026 Pete Batard * * 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 @@ -784,7 +784,7 @@ extern void _UpdateProgressWithInfo(int op, int msg, uint64_t processed, uint64_ #define UpdateProgressWithInfoInit(hProgressDialog, bNoAltMode) UpdateProgressWithInfo(OP_INIT, (int)bNoAltMode, (uint64_t)(uintptr_t)hProgressDialog, 0); extern const char* StrError(DWORD error_code, BOOL use_default_locale); extern char* GuidToString(const GUID* guid, BOOL bDecorated); -extern GUID* StringToGuid(const char* str); +extern GUID StringToGuid(const char* str); extern char* SizeToHumanReadable(uint64_t size, BOOL copy_to_log, BOOL fake_units); extern char* TimestampToHumanReadable(uint64_t ts); extern HWND MyCreateDialog(HINSTANCE hInstance, int Dialog_ID, HWND hWndParent, DLGPROC lpDialogFunc); diff --git a/src/rufus.rc b/src/rufus.rc index 6ea3e295..ecc30772 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 4.13.2316" +CAPTION "Rufus 4.14.2317" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -408,8 +408,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,13,2316,0 - PRODUCTVERSION 4,13,2316,0 + FILEVERSION 4,14,2317,0 + PRODUCTVERSION 4,14,2317,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -427,13 +427,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "4.13.2316" + VALUE "FileVersion", "4.14.2317" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2026 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" - VALUE "OriginalFilename", "rufus-4.13.exe" + VALUE "OriginalFilename", "rufus-4.14.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.13.2316" + VALUE "ProductVersion", "4.14.2317" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index 8726b0d1..042622d3 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Standard User I/O Routines (logging, status, error, etc.) - * Copyright © 2011-2025 Pete Batard + * Copyright © 2011-2026 Pete Batard * Copyright © 2020 Mattiwatti * * This program is free software: you can redistribute it and/or modify @@ -365,18 +365,25 @@ char* GuidToString(const GUID* guid, BOOL bDecorated) return guid_string; } -GUID* StringToGuid(const char* str) +GUID StringToGuid(const char* str) { - static GUID guid; - - if (str == NULL) return NULL; - if (sscanf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - (uint32_t*)&guid.Data1, (uint32_t*)&guid.Data2, (uint32_t*)&guid.Data3, - (uint32_t*)&guid.Data4[0], (uint32_t*)&guid.Data4[1], (uint32_t*)&guid.Data4[2], - (uint32_t*)&guid.Data4[3], (uint32_t*)&guid.Data4[4], (uint32_t*)&guid.Data4[5], - (uint32_t*)&guid.Data4[6], (uint32_t*)&guid.Data4[7]) != 11) - return NULL; - return &guid; + GUID guid = { 0 }; + uint32_t d1, d2, d3, b0, b1, b2, b3, b4, b5, b6, b7; + if (str != NULL && sscanf(str[0] == '{' ? &str[1] : str, "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x", + &d1, &d2, &d3, &b0, &b1, &b2, &b3, &b4, &b5, &b6, &b7) == 11) { + guid.Data1 = d1; + guid.Data2 = (uint16_t)d2; + guid.Data3 = (uint16_t)d3; + guid.Data4[0] = (uint8_t)b0; + guid.Data4[1] = (uint8_t)b1; + guid.Data4[2] = (uint8_t)b2; + guid.Data4[3] = (uint8_t)b3; + guid.Data4[4] = (uint8_t)b4; + guid.Data4[5] = (uint8_t)b5; + guid.Data4[6] = (uint8_t)b6; + guid.Data4[7] = (uint8_t)b7; + } + return guid; } // Find upper power of 2 From 073a100c8e0bfaf496f1374114cc39e15d28918f Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 6 Mar 2026 17:36:44 +0000 Subject: [PATCH 04/82] [wue] add an option to copy SkuSiPolicy.p7b to the ESP on install * This basically accomplishes the steps described in https://support.microsoft.com/kb/5042562 on first logon. * Note that we use the installed system's SkuSiPolicy.p7b rather than the host system's, even if the latter is usually more up to date, because otherwise, the user may run into Error code: 0xc0000428 on first reboot. * Likewise, we do not provide this option for Windows To Go, as it could prevent the existing Windows install from booting, and we'd have to extract SkuSiPolicy.p7b from `install.wim` to do so. * Also remove dead code related to SkuSiPolicy.p7b hash parsing (which Microsoft no longer uses). * Closes #2919 (though it doesn't actually address the issue reported there, which we couldn't replicate). --- res/loc/rufus.loc | 3 +- src/format.c | 1 - src/license.h | 5 -- src/pki.c | 121 +--------------------------------------------- src/rufus.c | 5 +- src/rufus.h | 7 ++- src/rufus.rc | 10 ++-- src/wue.c | 77 ++++++++++++++--------------- 8 files changed, 50 insertions(+), 179 deletions(-) diff --git a/res/loc/rufus.loc b/res/loc/rufus.loc index 1eef1169..c2ea67a9 100644 --- a/res/loc/rufus.loc +++ b/res/loc/rufus.loc @@ -577,6 +577,7 @@ t MSG_320 "Refreshing partition layout (%s)..." t MSG_321 "The image you have selected is an ISOHybrid, but its creators have not made it compatible with ISO/File " "copy mode.\nAs a result, DD image writing mode will be enforced." t MSG_322 "Unable to open or read '%s'" +t MSG_324 "Apply SkuSiPolicy.p7b on installation (See KB5042562)" t MSG_325 "Applying Windows customization: %s" t MSG_326 "Applying user options..." t MSG_327 "Windows User Experience" @@ -609,7 +610,7 @@ t MSG_346 "Restrict Windows to S-Mode (INCOMPATIBLE with online account bypass)" t MSG_347 "Expert Mode" t MSG_348 "Extracting archive files: %s" t MSG_349 "Use Rufus MBR" -t MSG_350 "Use 'Windows CA 2023' signed bootloaders (requires a compatible target PC)" +t MSG_350 "Use 'Windows CA 2023' signed bootloaders (Requires a compatible target PC)" t MSG_351 "Checking for UEFI bootloader revocation..." t MSG_352 "Checking for UEFI DBX updates..." t MSG_353 "DBX update available" diff --git a/src/format.c b/src/format.c index 8bbe644c..621a40c1 100644 --- a/src/format.c +++ b/src/format.c @@ -1979,7 +1979,6 @@ try_clear: } } } - CopySKUSiPolicy(drive_name); if ( (target_type == TT_BIOS) && HAS_WINPE(img_report) ) { // Apply WinPE fixup if (!SetupWinPE(drive_name[0])) diff --git a/src/license.h b/src/license.h index a7781b49..f107aaec 100644 --- a/src/license.h +++ b/src/license.h @@ -144,11 +144,6 @@ const char* additional_copyrights = "https://github.com/u-boot/u-boot\\line\n" "GNU General Public License (GPL) v2 or later\\line\n" "\\line\n" -"SkuSiPolicy.p7b parsing derived from:\\line\n" -"https://gist.github.com/mattifestation/92e545bf1ee5b68eeb71d254cec2f78e\\line\n" -"by Matthew Graeber, with contributions by James Forshaw\\line\n" -"BSD 3-Clause\\line\n" -"\\line\n" "About and License dialogs inspired by WinSCP by Martin Prikryl\\line\n" "https://winscp.net/\\line\n" "GNU General Public License (GPL) v3 or later\\line\n" diff --git a/src/pki.c b/src/pki.c index 7ebef247..bc39c703 100644 --- a/src/pki.c +++ b/src/pki.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * PKI functions (code signing, etc.) - * Copyright © 2015-2024 Pete Batard + * Copyright © 2015-2026 Pete Batard * * 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 @@ -260,7 +260,7 @@ const char* WinPKIErrorString(void) } } -// Mostly from https://support.microsoft.com/en-us/kb/323809 +// Mostly from https://support.microsoft.com/kb/323809 char* GetSignatureName(const char* path, const char* country_code, uint8_t* thumbprint, BOOL bSilent) { static char szSubjectName[128]; @@ -900,120 +900,3 @@ out: CryptReleaseContext(hProv, 0); return r; } - -// The following SkuSiPolicy.p7b parsing code is derived from: -// https://gist.github.com/mattifestation/92e545bf1ee5b68eeb71d254cec2f78e -// by Matthew Graeber, with contributions by James Forshaw. -BOOL ParseSKUSiPolicy(void) -{ - char path[MAX_PATH]; - wchar_t* wpath = NULL; - BOOL r = FALSE; - DWORD i, dwEncoding, dwContentType, dwFormatType; - DWORD dwPolicySize = 0, dwBaseIndex = 0, dwSizeCount; - HCRYPTMSG hMsg = NULL; - CRYPT_DATA_BLOB pkcsData = { 0 }; - DWORD* pdwEkuRules; - BYTE* pbRule; - CIHeader* Header; - CIFileRuleHeader* FileRuleHeader; - CIFileRuleData* FileRuleData; - - pe256ssp_size = 0; - safe_free(pe256ssp); - // Must use sysnative for WOW - static_sprintf(path, "%s\\SecureBootUpdates\\SKUSiPolicy.p7b", sysnative_dir); - wpath = utf8_to_wchar(path); - if (wpath == NULL) - goto out; - - r = CryptQueryObject(CERT_QUERY_OBJECT_FILE, wpath, CERT_QUERY_CONTENT_FLAG_ALL, - CERT_QUERY_FORMAT_FLAG_ALL, 0, &dwEncoding, &dwContentType, &dwFormatType, NULL, - &hMsg, NULL); - if (!r || dwContentType != CERT_QUERY_CONTENT_PKCS7_SIGNED) - goto out; - - r = CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, NULL, &pkcsData.cbData); - if (!r || pkcsData.cbData == 0) { - uprintf("ParseSKUSiPolicy: Failed to retreive CMSG_CONTENT_PARAM size: %s", WindowsErrorString()); - goto out; - } - pkcsData.pbData = malloc(pkcsData.cbData); - if (pkcsData.pbData == NULL) - goto out; - r = CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, pkcsData.pbData, &pkcsData.cbData); - if (!r) { - uprintf("ParseSKUSiPolicy: Failed to retreive CMSG_CONTENT_PARAM: %s", WindowsErrorString()); - goto out; - } - - // Now process the actual Security Policy content - if (pkcsData.pbData[0] == 4) { - dwPolicySize = pkcsData.pbData[1]; - dwBaseIndex = 2; - if ((dwPolicySize & 0x80) == 0x80) { - dwSizeCount = dwPolicySize & 0x7F; - dwBaseIndex += dwSizeCount; - dwPolicySize = 0; - for (i = 0; i < dwSizeCount; i++) { - dwPolicySize = dwPolicySize << 8; - dwPolicySize = dwPolicySize | pkcsData.pbData[2 + i]; - } - } - } - - // Sanity checks - Header = (CIHeader*)&pkcsData.pbData[dwBaseIndex]; - if (Header->HeaderLength + sizeof(uint32_t) != sizeof(CIHeader)) { - uprintf("ParseSKUSiPolicy: Unexpected Code Integrity Header size (0x%02x)", Header->HeaderLength); - goto out; - } - if (!CompareGUID(&Header->PolicyTypeGUID, &SKU_CODE_INTEGRITY_POLICY)) { - uprintf("ParseSKUSiPolicy: Unexpected Policy Type GUID %s", GuidToString(&Header->PolicyTypeGUID, TRUE)); - goto out; - } - - // Skip the EKU Rules - pdwEkuRules = (DWORD*) &pkcsData.pbData[dwBaseIndex + sizeof(CIHeader)]; - for (i = 0; i < Header->EKURuleEntryCount; i++) - pdwEkuRules = &pdwEkuRules[(*pdwEkuRules + (2 * sizeof(DWORD) - 1)) / sizeof(DWORD)]; - - // Process the Files Rules - pbRule = (BYTE*)pdwEkuRules; - pe256ssp = malloc(Header->FileRuleEntryCount * PE256_HASHSIZE); - if (pe256ssp == NULL) - goto out; - for (i = 0; i < Header->FileRuleEntryCount; i++) { - FileRuleHeader = (CIFileRuleHeader*)pbRule; - pbRule = &pbRule[sizeof(CIFileRuleHeader)]; - if (FileRuleHeader->FileNameLength != 0) { -// uprintf("%S", FileRuleHeader->FileName); - pbRule = &pbRule[((FileRuleHeader->FileNameLength + sizeof(DWORD) - 1) / sizeof(DWORD)) * sizeof(DWORD)]; - } - FileRuleData = (CIFileRuleData*)pbRule; - if (FileRuleData->HashLength > 0x80) { - uprintf("ParseSKUSiPolicy: Unexpected hash length for entry %d (0x%02x)", i, FileRuleData->HashLength); - // We're probably screwed, so bail out - break; - } - // We are only interested in 'DENY' type with PE256 hashes - if (FileRuleHeader->Type == CI_DENY && FileRuleData->HashLength == PE256_HASHSIZE) { - // Microsoft has the bad habit of duplicating entries - only add a hash if it's different from previous entry - if ((pe256ssp_size == 0) || - (memcmp(&pe256ssp[(pe256ssp_size - 1) * PE256_HASHSIZE], FileRuleData->Hash, PE256_HASHSIZE) != 0)) { - memcpy(&pe256ssp[pe256ssp_size * PE256_HASHSIZE], FileRuleData->Hash, PE256_HASHSIZE); - pe256ssp_size++; - } - } - pbRule = &pbRule[sizeof(CIFileRuleData) + ((FileRuleData->HashLength + sizeof(DWORD) - 1) / sizeof(DWORD)) * sizeof(DWORD)]; - } - - r = TRUE; - -out: - if (hMsg != NULL) - CryptMsgClose(hMsg); - free(pkcsData.pbData); - free(wpath); - return r; -} diff --git a/src/rufus.c b/src/rufus.c index 543a8ac4..dd3636af 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -93,7 +93,7 @@ static char uppercase_select[2][64], uppercase_start[64], uppercase_close[64], u extern HANDLE update_check_thread; extern HIMAGELIST hUpImageList, hDownImageList; -extern BOOL enable_iso, enable_joliet, enable_rockridge, enable_extra_hashes, is_bootloader_revoked; +extern BOOL enable_iso, enable_joliet, enable_rockridge, enable_extra_hashes; extern BOOL validate_md5sum, cpu_has_sha1_accel, cpu_has_sha256_accel, toggle_dark_mode; extern BYTE* fido_script; extern HWND hFidoDlg; @@ -1505,7 +1505,6 @@ static DWORD WINAPI BootCheckThread(LPVOID param) char tmp[MAX_PATH], tmp2[MAX_PATH], c; syslinux_ldlinux_len[0] = 0; syslinux_ldlinux_len[1] = 0; - is_bootloader_revoked = FALSE; safe_free(grub2_buf); if (ComboBox_GetCurSel(hDeviceList) == CB_ERR) @@ -1688,6 +1687,8 @@ static DWORD WINAPI BootCheckThread(LPVOID param) if (img_report.win_version.build >= 26200) { StrArrayAdd(&options, lmprintf(MSG_350), TRUE); MAP_BIT(UNATTEND_USE_MS2023_BOOTLOADERS); + StrArrayAdd(&options, lmprintf(MSG_324), TRUE); + MAP_BIT(UNATTEND_APPLY_SKUSIPOLICY); } if (expert_mode) { StrArrayAdd(&options, lmprintf(MSG_346), TRUE); diff --git a/src/rufus.h b/src/rufus.h index 14723810..4c9e71b8 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -685,8 +685,9 @@ typedef struct { #define UNATTEND_DISABLE_BITLOCKER 0x00080 #define UNATTEND_FORCE_S_MODE 0x00100 #define UNATTEND_USE_MS2023_BOOTLOADERS 0x00200 -#define UNATTEND_FULL_MASK 0x003FF -#define UNATTEND_DEFAULT_MASK 0x002FF // Mask of values that are persisted +#define UNATTEND_APPLY_SKUSIPOLICY 0x00400 +#define UNATTEND_FULL_MASK 0x007FF +#define UNATTEND_DEFAULT_MASK 0x006FF // Mask of values that are persisted #define UNATTEND_WINDOWS_TO_GO 0x10000 // Special flag for Windows To Go #define UNATTEND_WINPE_SETUP_MASK (UNATTEND_SECUREBOOT_TPM_MINRAM) @@ -815,7 +816,6 @@ extern BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan); extern BOOL ExtractZip(const char* src_zip, const char* dest_dir); extern int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_file, DWORD attributes); extern uint32_t ReadISOFileToBuffer(const char* iso, const char* iso_file, uint8_t** buf); -extern BOOL CopySKUSiPolicy(const char* drive_name); extern BOOL HasEfiImgBootLoaders(void); extern BOOL DumpFatDir(const char* path, int32_t cluster); extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs); @@ -866,7 +866,6 @@ extern int GetIssuerCertificateInfo(uint8_t* cert, cert_info_t* info); extern uint64_t GetSignatureTimeStamp(const char* path); extern LONG ValidateSignature(HWND hDlg, const char* path); extern BOOL ValidateOpensslSignature(BYTE* pbBuffer, DWORD dwBufferLen, BYTE* pbSignature, DWORD dwSigLen); -extern BOOL ParseSKUSiPolicy(void); extern BOOL IsFontAvailable(const char* font_name); extern BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries); diff --git a/src/rufus.rc b/src/rufus.rc index ecc30772..3fc39d57 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 4.14.2317" +CAPTION "Rufus 4.14.2318" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -408,8 +408,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,14,2317,0 - PRODUCTVERSION 4,14,2317,0 + FILEVERSION 4,14,2318,0 + PRODUCTVERSION 4,14,2318,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -427,13 +427,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "4.14.2317" + VALUE "FileVersion", "4.14.2318" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2026 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-4.14.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.14.2317" + VALUE "ProductVersion", "4.14.2318" END END BLOCK "VarFileInfo" diff --git a/src/wue.c b/src/wue.c index 3e0f382d..5c10c957 100644 --- a/src/wue.c +++ b/src/wue.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Windows User Experience - * Copyright © 2022-2025 Pete Batard + * Copyright © 2022-2026 Pete Batard * * 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 @@ -47,7 +47,6 @@ const char* bypass_name[] = { "BypassTPMCheck", "BypassSecureBootCheck", "Bypass int unattend_xml_flags = 0, wintogo_index = -1, wininst_index = 0; int unattend_xml_mask = UNATTEND_DEFAULT_SELECTION_MASK; char *unattend_xml_path = NULL, unattend_username[MAX_USERNAME_LENGTH]; -BOOL is_bootloader_revoked = FALSE; extern BOOL validate_md5sum; extern uint64_t md5sum_totalbytes; @@ -65,7 +64,7 @@ char* CreateUnattendXml(int arch, int flags) { const static char* xml_arch_names[5] = { "x86", "amd64", "arm", "arm64" }; const static char* unallowed_account_names[] = { "Administrator", "Guest", "KRBTGT", "Local", "NONE" }; - static char path[MAX_PATH]; + static char path[MAX_PATH], tmp[MAX_PATH]; char* tzstr; FILE* fd; TIME_ZONE_INFORMATION tz_info; @@ -140,7 +139,8 @@ char* CreateUnattendXml(int arch, int flags) } if (flags & UNATTEND_OOBE_MASK) { - order = 1; + StrArray first_logon_commands = STRARRAY_EMPTY; + StrArrayCreate(&first_logon_commands, 8); fprintf(fd, " \n"); if (flags & UNATTEND_OOBE_SHELL_SETUP_MASK) { fprintf(fd, " sections in unattend.xml. Don't ask me how I know... :( - fprintf(fd, " \n"); - fprintf(fd, " \n"); - fprintf(fd, " %d\n", order++); - fprintf(fd, " net user "%s" /logonpasswordchg:yes\n", unattend_username); - fprintf(fd, " \n"); - // Some people report that using the `net user` command above might reset the password expiration to 90 days... + static_sprintf(tmp, "net user "%s" /logonpasswordchg:yes", unattend_username); + StrArrayAdd(&first_logon_commands, tmp, TRUE); + // The `net user` command above might reset the password expiration to 90 days... // To alleviate that, blanket set passwords on the target machine to never expire. - fprintf(fd, " \n"); - fprintf(fd, " %d\n", order++); - fprintf(fd, " net accounts /maxpwage:unlimited\n"); - fprintf(fd, " \n"); - fprintf(fd, " \n"); + StrArrayAdd(&first_logon_commands, "net accounts /maxpwage:unlimited", TRUE); } } + + // Apply SkuSiPolicy.p7b, if the user requested it and we're not creating a Windows To Go drive. + // See https://support.microsoft.com/kb/5042562. We do it post install, on first logon, because + // we'd have to patch tons of files otherwise. And we *ALWAYS* use the installed system's + // SkuSiPolicy.p7b instead of the host system's, even if the latter might be more recent, on + // account that the bootloaders from the installed system might be trailing behind, and wills + // produce the 0xc0000428 signature validation error on (re)boot if the system hasn't gone + // through a full Windows Update cycle. + if (flags & UNATTEND_APPLY_SKUSIPOLICY) { + StrArrayAdd(&first_logon_commands, "cmd /c mountvol S: /S && " + "copy %WINDIR%\\system32\\SecureBootUpdates\\SkuSiPolicy.p7b S:\\EFI\\Microsoft\\Boot && " + "mountvol S: /D", TRUE); + } + + // Now that we have all the commands to run, create the FirstLogonCommands section. + for (order = 1; order <= (int)first_logon_commands.Index; order++) { + if (order == 1) + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " %d\n", order); + fprintf(fd, " %s\n", first_logon_commands.String[order - 1]); + fprintf(fd, " \n"); + if (order == first_logon_commands.Index) + fprintf(fd, " \n"); + } + StrArrayDestroy(&first_logon_commands); + fprintf(fd, " \n"); } if (flags & UNATTEND_OOBE_INTERNATIONAL_MASK) { @@ -510,31 +530,6 @@ out: return ((img_report.win_version.major != 0) && (img_report.win_version.build != 0)); } -// Copy this system's SkuSiPolicy.p7b to the target drive so that UEFI bootloaders -// revoked by Windows through WDAC policy do get flagged as revoked. -BOOL CopySKUSiPolicy(const char* drive_name) -{ - BOOL r = FALSE; - char src[MAX_PATH], dst[MAX_PATH]; - struct __stat64 stat64 = { 0 }; - - // Only copy SkuPolicy if we warned about the bootloader being revoked. - if ((target_type != TT_UEFI) || !IS_WINDOWS_1X(img_report) || - (pe256ssp_size == 0) || !is_bootloader_revoked) - return r; - - static_sprintf(src, "%s\\SecureBootUpdates\\SKUSiPolicy.p7b", system_dir); - static_sprintf(dst, "%s\\EFI\\Microsoft\\Boot\\SKUSiPolicy.p7b", drive_name); - if ((_stat64U(dst, &stat64) != 0) && (_stat64U(src, &stat64) == 0)) { - uprintf("Copying: %s (%s) (from %s)", dst, SizeToHumanReadable(stat64.st_size, FALSE, FALSE), src); - r = CopyFileU(src, dst, TRUE); - if (!r) - uprintf(" Error writing file: %s", WindowsErrorString()); - } - - return r; -} - /// /// Checks which versions of Windows are available in an install image /// to set our extraction index. Asks the user to select one if needed. @@ -739,8 +734,6 @@ BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp) ErrorStatus = RUFUS_ERROR(APPERR(ERROR_ISO_EXTRACT)); } - CopySKUSiPolicy((use_esp) ? ms_efi : drive_name); - UpdateProgressWithInfo(OP_FILE_COPY, MSG_267, 99, 100); // Setting internal drives offline for Windows To Go is crucial if, for instance, you are using ReFS From 1d4c62ba0d0a30f6fe218f1b288dac4eccf884e8 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 11 Mar 2026 10:55:04 +0000 Subject: [PATCH 05/82] [wue] add an option to perform a fully unattended/silent install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Note that this will completely repartition and erase the first disk available on the target system ⚠WITHOUT ANY PROMPT⚠. * Also, this is dependent on the local account name and duplicate regional WUE options to be selected. * With a special mention to Claude AI, that said that detecting whether a one or multiple disks were available was impossible to accomplish using only unattend XML commands... which we therefore promptly managed to disprove. Please wake me up when there is any semblance of "intelligence" in the LLMs that are currently destroying our planet... --- res/loc/rufus.loc | 3 +- src/resource.h | 39 +++--- src/rufus.c | 27 ++-- src/rufus.h | 22 +++- src/rufus.rc | 11 +- src/stdfn.c | 185 ++++++++++++++------------- src/stdlg.c | 129 +++++++++++++++---- src/wue.c | 310 ++++++++++++++++++++++++++++++++++++++++------ 8 files changed, 533 insertions(+), 193 deletions(-) diff --git a/res/loc/rufus.loc b/res/loc/rufus.loc index c2ea67a9..8c04063f 100644 --- a/res/loc/rufus.loc +++ b/res/loc/rufus.loc @@ -577,7 +577,8 @@ t MSG_320 "Refreshing partition layout (%s)..." t MSG_321 "The image you have selected is an ISOHybrid, but its creators have not made it compatible with ISO/File " "copy mode.\nAs a result, DD image writing mode will be enforced." t MSG_322 "Unable to open or read '%s'" -t MSG_324 "Apply SkuSiPolicy.p7b on installation (See KB5042562)" +t MSG_323 "Apply SkuSiPolicy.p7b on installation (See KB5042562)" +t MSG_324 "⚠SILENTLY⚠ erase disk and install:" t MSG_325 "Applying Windows customization: %s" t MSG_326 "Applying user options..." t MSG_327 "Windows User Experience" diff --git a/src/resource.h b/src/resource.h index 9be19993..5b8b4d9f 100644 --- a/src/resource.h +++ b/src/resource.h @@ -173,25 +173,26 @@ #define IDC_SELECTION_CHOICE15 1092 #define IDC_SELECTION_CHOICEMAX 1093 #define IDC_SELECTION_USERNAME 1094 -#define IDC_LIST_ICON 1095 -#define IDC_LIST_TEXT 1096 -#define IDC_LIST_LINE 1097 -#define IDC_LIST_ITEM1 1098 -#define IDC_LIST_ITEM2 1099 -#define IDC_LIST_ITEM3 1100 -#define IDC_LIST_ITEM4 1101 -#define IDC_LIST_ITEM5 1102 -#define IDC_LIST_ITEM6 1103 -#define IDC_LIST_ITEM7 1104 -#define IDC_LIST_ITEM8 1105 -#define IDC_LIST_ITEM9 1106 -#define IDC_LIST_ITEM10 1107 -#define IDC_LIST_ITEM11 1108 -#define IDC_LIST_ITEM12 1109 -#define IDC_LIST_ITEM13 1110 -#define IDC_LIST_ITEM14 1111 -#define IDC_LIST_ITEM15 1112 -#define IDC_LIST_ITEMMAX 1113 +#define IDC_SELECTION_EDITION 1095 +#define IDC_LIST_ICON 1100 +#define IDC_LIST_TEXT 1101 +#define IDC_LIST_LINE 1102 +#define IDC_LIST_ITEM1 1103 +#define IDC_LIST_ITEM2 1104 +#define IDC_LIST_ITEM3 1105 +#define IDC_LIST_ITEM4 1106 +#define IDC_LIST_ITEM5 1107 +#define IDC_LIST_ITEM6 1108 +#define IDC_LIST_ITEM7 1109 +#define IDC_LIST_ITEM8 1110 +#define IDC_LIST_ITEM9 1111 +#define IDC_LIST_ITEM10 1112 +#define IDC_LIST_ITEM11 1113 +#define IDC_LIST_ITEM12 1114 +#define IDC_LIST_ITEM13 1115 +#define IDC_LIST_ITEM14 1116 +#define IDC_LIST_ITEM15 1117 +#define IDC_LIST_ITEMMAX 1118 #define IDS_DEVICE_TXT 2000 #define IDS_PARTITION_TYPE_TXT 2001 #define IDS_FILE_SYSTEM_TXT 2002 diff --git a/src/rufus.c b/src/rufus.c index dd3636af..790da244 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -1490,7 +1490,7 @@ out: // Likewise, boot check will block message processing => use a thread static DWORD WINAPI BootCheckThread(LPVOID param) { - int i, r, username_index = -1; + int i, r; FILE *fd; uint32_t len; WPARAM ret = BOOTCHECK_CANCEL; @@ -1503,6 +1503,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param) const char* syslinux = "syslinux"; const char* ldlinux_ext[3] = { "sys", "bss", "c32" }; char tmp[MAX_PATH], tmp2[MAX_PATH], c; + selection_dialog_options_t selection_options = { 0, -1, -1, -1 }; syslinux_ldlinux_len[0] = 0; syslinux_ldlinux_len[1] = 0; safe_free(grub2_buf); @@ -1610,7 +1611,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param) MAP_BIT(UNATTEND_NO_ONLINE_ACCOUNT); } StrArrayAdd(&options, lmprintf(MSG_333), TRUE); - username_index = _log2(b); + selection_options.username_index = _log2(b); MAP_BIT(UNATTEND_SET_USER); StrArrayAdd(&options, lmprintf(MSG_334), TRUE); MAP_BIT(UNATTEND_DUPLICATE_LOCALE); @@ -1620,8 +1621,9 @@ static DWORD WINAPI BootCheckThread(LPVOID param) StrArrayAdd(&options, lmprintf(MSG_346), TRUE); MAP_BIT(UNATTEND_FORCE_S_MODE); } + selection_options.mask = remap16(unattend_xml_mask, map, FALSE); i = CustomSelectionDialog(BS_AUTOCHECKBOX, lmprintf(MSG_327), lmprintf(MSG_328), - options.String, options.Index, remap16(unattend_xml_mask, map, FALSE), username_index); + options.String, options.Index, &selection_options); StrArrayDestroy(&options); if (i < 0) goto out; @@ -1676,26 +1678,35 @@ static DWORD WINAPI BootCheckThread(LPVOID param) MAP_BIT(UNATTEND_NO_ONLINE_ACCOUNT); } StrArrayAdd(&options, lmprintf(MSG_333), TRUE); - username_index = _log2(b); + selection_options.username_index = _log2(b); MAP_BIT(UNATTEND_SET_USER); StrArrayAdd(&options, lmprintf(MSG_334), TRUE); + selection_options.regional_index = _log2(b); MAP_BIT(UNATTEND_DUPLICATE_LOCALE); StrArrayAdd(&options, lmprintf(MSG_331), TRUE); MAP_BIT(UNATTEND_NO_DATA_COLLECTION); - StrArrayAdd(&options, lmprintf(MSG_335), TRUE); - MAP_BIT(UNATTEND_DISABLE_BITLOCKER); + if (IS_WINDOWS_11(img_report)) { + StrArrayAdd(&options, lmprintf(MSG_335), TRUE); + MAP_BIT(UNATTEND_DISABLE_BITLOCKER); + } if (img_report.win_version.build >= 26200) { StrArrayAdd(&options, lmprintf(MSG_350), TRUE); MAP_BIT(UNATTEND_USE_MS2023_BOOTLOADERS); - StrArrayAdd(&options, lmprintf(MSG_324), TRUE); + StrArrayAdd(&options, lmprintf(MSG_323), TRUE); MAP_BIT(UNATTEND_APPLY_SKUSIPOLICY); } + if (IS_WINDOWS_11(img_report)) { + StrArrayAdd(&options, lmprintf(MSG_324), TRUE); + selection_options.edition_index = _log2(b); + MAP_BIT(UNATTEND_SILENT_INSTALL); + } if (expert_mode) { StrArrayAdd(&options, lmprintf(MSG_346), TRUE); MAP_BIT(UNATTEND_FORCE_S_MODE); } + selection_options.mask = remap16(unattend_xml_mask, map, FALSE); i = CustomSelectionDialog(BS_AUTOCHECKBOX, lmprintf(MSG_327), lmprintf(MSG_328), - options.String, options.Index, remap16(unattend_xml_mask, map, FALSE), username_index); + options.String, options.Index, &selection_options); StrArrayDestroy(&options); if (i < 0) goto out; diff --git a/src/rufus.h b/src/rufus.h index 4c9e71b8..401769eb 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -507,6 +507,14 @@ typedef struct { char* Label; } IMG_SAVE; +// Options for the custom selection dialog +typedef struct { + int mask; + int username_index; + int edition_index; + int regional_index; +} selection_dialog_options_t; + /* * Structure and macros used for the extensions specification of FileDialog() * You can use: @@ -686,15 +694,17 @@ typedef struct { #define UNATTEND_FORCE_S_MODE 0x00100 #define UNATTEND_USE_MS2023_BOOTLOADERS 0x00200 #define UNATTEND_APPLY_SKUSIPOLICY 0x00400 -#define UNATTEND_FULL_MASK 0x007FF +#define UNATTEND_SILENT_INSTALL 0x00800 +#define UNATTEND_FULL_MASK 0x00FFF #define UNATTEND_DEFAULT_MASK 0x006FF // Mask of values that are persisted #define UNATTEND_WINDOWS_TO_GO 0x10000 // Special flag for Windows To Go -#define UNATTEND_WINPE_SETUP_MASK (UNATTEND_SECUREBOOT_TPM_MINRAM) +#define UNATTEND_WINPE_SETUP_MASK (UNATTEND_SECUREBOOT_TPM_MINRAM | UNATTEND_SILENT_INSTALL) #define UNATTEND_SPECIALIZE_DEPLOYMENT_MASK (UNATTEND_NO_ONLINE_ACCOUNT) #define UNATTEND_OOBE_SHELL_SETUP_MASK (UNATTEND_NO_DATA_COLLECTION | UNATTEND_SET_USER | UNATTEND_DUPLICATE_LOCALE) #define UNATTEND_OOBE_INTERNATIONAL_MASK (UNATTEND_DUPLICATE_LOCALE) -#define UNATTEND_OOBE_MASK (UNATTEND_OOBE_SHELL_SETUP_MASK | UNATTEND_OOBE_INTERNATIONAL_MASK | UNATTEND_DISABLE_BITLOCKER | UNATTEND_USE_MS2023_BOOTLOADERS) +#define UNATTEND_OOBE_MASK (UNATTEND_OOBE_SHELL_SETUP_MASK | UNATTEND_OOBE_INTERNATIONAL_MASK | UNATTEND_DISABLE_BITLOCKER | \ + UNATTEND_USE_MS2023_BOOTLOADERS | UNATTEND_APPLY_SKUSIPOLICY) #define UNATTEND_OFFLINE_SERVICING_MASK (UNATTEND_OFFLINE_INTERNAL_DRIVES | UNATTEND_FORCE_S_MODE) #define UNATTEND_DEFAULT_SELECTION_MASK (UNATTEND_SECUREBOOT_TPM_MINRAM | UNATTEND_NO_ONLINE_ACCOUNT | UNATTEND_OFFLINE_INTERNAL_DRIVES) @@ -769,6 +779,8 @@ extern StrArray modified_files; * Shared prototypes */ extern void GetWindowsVersion(windows_version_t* WindowsVersion); +extern const char* GetEditionName(DWORD ProductType); +extern int GetEditions(StrArray* version_name, StrArray* version_index); extern version_t* GetExecutableVersion(const char* path); extern const char* WindowsErrorString(void); extern void DumpBufferHex(void *buf, size_t size); @@ -806,8 +818,8 @@ extern void DestroyTooltip(HWND hWnd); extern void DestroyAllTooltips(void); extern int NotificationEx(int type, const char* dont_display_setting, const notification_info* more_info, const char* title, const char* format, ...); #define Notification(type, title, ...) NotificationEx(type, NULL, NULL, title, __VA_ARGS__) -extern int CustomSelectionDialog(int style, char* title, char* message, char** choices, int size, int mask, int username_index); -#define SelectionDialog(title, message, choices, size) CustomSelectionDialog(BS_AUTORADIOBUTTON, title, message, choices, size, 1, -1) +extern int CustomSelectionDialog(int style, char* title, char* message, char** choices, int size, selection_dialog_options_t* options); +#define SelectionDialog(title, message, choices, size) CustomSelectionDialog(BS_AUTORADIOBUTTON, title, message, choices, size, NULL) extern void ListDialog(char* title, char* message, char** items, int size); extern SIZE GetTextSize(HWND hCtrl, char* txt); extern BOOL ExtractAppIcon(const char* filename, BOOL bSilent); diff --git a/src/rufus.rc b/src/rufus.rc index 3fc39d57..967272f0 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 4.14.2318" +CAPTION "Rufus 4.14.2319" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -176,6 +176,7 @@ BEGIN CONTROL "Choice 15",IDC_SELECTION_CHOICE15,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE | WS_TABSTOP,35,200,269,10,WS_EX_TRANSPARENT CONTROL "Choice 16",IDC_SELECTION_CHOICEMAX,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE | WS_TABSTOP,35,213,269,10,WS_EX_TRANSPARENT EDITTEXT IDC_SELECTION_USERNAME,197,57,0,9,ES_AUTOHSCROLL | NOT WS_VISIBLE | WS_TABSTOP | WS_BORDER + COMBOBOX IDC_SELECTION_EDITION,197,57,0,9,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END IDD_LIST DIALOGEX 0, 0, 312, 59 @@ -408,8 +409,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,14,2318,0 - PRODUCTVERSION 4,14,2318,0 + FILEVERSION 4,14,2319,0 + PRODUCTVERSION 4,14,2319,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -427,13 +428,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "4.14.2318" + VALUE "FileVersion", "4.14.2319" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2026 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-4.14.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.14.2318" + VALUE "ProductVersion", "4.14.2319" END END BLOCK "VarFileInfo" diff --git a/src/stdfn.c b/src/stdfn.c index 43819d4b..4014f777 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -216,109 +216,109 @@ uint32_t htab_hash(char* str, htab_table* htab) return idx; } -static const char* GetEdition(DWORD ProductType) +const char* GetEditionName(DWORD ProductType) { - static char unknown_edition_str[64]; + static char unknown_edition_str[64] = ""; // From: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getproductinfo // These values can be found in the winnt.h header. switch (ProductType) { case 0x00000000: return ""; // Undefined - case 0x00000001: return "Ultimate"; - case 0x00000002: return "Home Basic"; - case 0x00000003: return "Home Premium"; - case 0x00000004: return "Enterprise"; - case 0x00000005: return "Home Basic N"; - case 0x00000006: return "Business"; - case 0x00000007: return "Server Standard"; - case 0x00000008: return "Server Datacenter"; - case 0x00000009: return "Smallbusiness Server"; - case 0x0000000A: return "Server Enterprise"; - case 0x0000000B: return "Starter"; - case 0x0000000C: return "Server Datacenter (Core)"; - case 0x0000000D: return "Server Standard (Core)"; - case 0x0000000E: return "Server Enterprise (Core)"; - case 0x00000010: return "Business N"; - case 0x00000011: return "Web Server"; - case 0x00000012: return "HPC Edition"; - case 0x00000013: return "Storage Server (Essentials)"; - case 0x0000001A: return "Home Premium N"; - case 0x0000001B: return "Enterprise N"; - case 0x0000001C: return "Ultimate N"; - case 0x00000022: return "Home Server"; - case 0x00000024: return "Server Standard without Hyper-V"; - case 0x00000025: return "Server Datacenter without Hyper-V"; - case 0x00000026: return "Server Enterprise without Hyper-V"; - case 0x00000027: return "Server Datacenter without Hyper-V (Core)"; - case 0x00000028: return "Server Standard without Hyper-V (Core)"; - case 0x00000029: return "Server Enterprise without Hyper-V (Core)"; - case 0x0000002A: return "Hyper-V Server"; - case 0x0000002F: return "Starter N"; - case 0x00000030: return "Pro"; - case 0x00000031: return "Pro N"; - case 0x00000034: return "Server Solutions Premium"; - case 0x00000035: return "Server Solutions Premium (Core)"; - case 0x00000040: return "Server Hyper Core V"; - case 0x00000042: return "Starter E"; - case 0x00000043: return "Home Basic E"; - case 0x00000044: return "Premium E"; - case 0x00000045: return "Pro E"; - case 0x00000046: return "Enterprise E"; - case 0x00000047: return "Ultimate E"; - case 0x00000048: return "Enterprise (Eval)"; - case 0x0000004F: return "Server Standard (Eval)"; - case 0x00000050: return "Server Datacenter (Eval)"; - case 0x00000054: return "Enterprise N (Eval)"; - case 0x00000057: return "Thin PC"; + case 0x00000001: return " Ultimate"; + case 0x00000002: return " Home Basic"; + case 0x00000003: return " Home Premium"; + case 0x00000004: return " Enterprise"; + case 0x00000005: return " Home Basic N"; + case 0x00000006: return " Business"; + case 0x00000007: return " Server Standard"; + case 0x00000008: return " Server Datacenter"; + case 0x00000009: return " Smallbusiness Server"; + case 0x0000000A: return " Server Enterprise"; + case 0x0000000B: return " Starter"; + case 0x0000000C: return " Server Datacenter (Core)"; + case 0x0000000D: return " Server Standard (Core)"; + case 0x0000000E: return " Server Enterprise (Core)"; + case 0x00000010: return " Business N"; + case 0x00000011: return " Web Server"; + case 0x00000012: return " HPC Edition"; + case 0x00000013: return " Storage Server (Essentials)"; + case 0x0000001A: return " Home Premium N"; + case 0x0000001B: return " Enterprise N"; + case 0x0000001C: return " Ultimate N"; + case 0x00000022: return " Home Server"; + case 0x00000024: return " Server Standard without Hyper-V"; + case 0x00000025: return " Server Datacenter without Hyper-V"; + case 0x00000026: return " Server Enterprise without Hyper-V"; + case 0x00000027: return " Server Datacenter without Hyper-V (Core)"; + case 0x00000028: return " Server Standard without Hyper-V (Core)"; + case 0x00000029: return " Server Enterprise without Hyper-V (Core)"; + case 0x0000002A: return " Hyper-V Server"; + case 0x0000002F: return " Starter N"; + case 0x00000030: return " Pro"; + case 0x00000031: return " Pro N"; + case 0x00000034: return " Server Solutions Premium"; + case 0x00000035: return " Server Solutions Premium (Core)"; + case 0x00000040: return " Server Hyper Core V"; + case 0x00000042: return " Starter E"; + case 0x00000043: return " Home Basic E"; + case 0x00000044: return " Premium E"; + case 0x00000045: return " Pro E"; + case 0x00000046: return " Enterprise E"; + case 0x00000047: return " Ultimate E"; + case 0x00000048: return " Enterprise (Eval)"; + case 0x0000004F: return " Server Standard (Eval)"; + case 0x00000050: return " Server Datacenter (Eval)"; + case 0x00000054: return " Enterprise N (Eval)"; + case 0x00000057: return " Thin PC"; case 0x00000058: case 0x00000059: case 0x0000005A: case 0x0000005B: case 0x0000005C: return "Embedded"; - case 0x00000062: return "Home N"; - case 0x00000063: return "Home China"; - case 0x00000064: return "Home Single Language"; - case 0x00000065: return "Home"; - case 0x00000067: return "Pro with Media Center"; + case 0x00000062: return " Home N"; + case 0x00000063: return " Home China"; + case 0x00000064: return " Home Single Language"; + case 0x00000065: return " Home"; + case 0x00000067: return " Pro with Media Center"; case 0x00000069: case 0x0000006A: case 0x0000006B: case 0x0000006C: return "Embedded"; - case 0x0000006F: return "Home Connected"; - case 0x00000070: return "Pro Student"; - case 0x00000071: return "Home Connected N"; - case 0x00000072: return "Pro Student N"; - case 0x00000073: return "Home Connected Single Language"; - case 0x00000074: return "Home Connected China"; - case 0x00000079: return "Education"; - case 0x0000007A: return "Education N"; - case 0x0000007D: return "Enterprise LTSB"; - case 0x0000007E: return "Enterprise LTSB N"; - case 0x0000007F: return "Pro S"; - case 0x00000080: return "Pro S N"; - case 0x00000081: return "Enterprise LTSB (Eval)"; - case 0x00000082: return "Enterprise LTSB N (Eval)"; - case 0x0000008A: return "Pro Single Language"; - case 0x0000008B: return "Pro China"; - case 0x0000008C: return "Enterprise Subscription"; - case 0x0000008D: return "Enterprise Subscription N"; - case 0x00000091: return "Server Datacenter SA (Core)"; - case 0x00000092: return "Server Standard SA (Core)"; - case 0x00000095: return "Utility VM"; - case 0x000000A1: return "Pro for Workstations"; - case 0x000000A2: return "Pro for Workstations N"; - case 0x000000A4: return "Pro for Education"; - case 0x000000A5: return "Pro for Education N"; - case 0x000000AB: return "Enterprise G"; // I swear Microsoft are just making up editions... - case 0x000000AC: return "Enterprise G N"; - case 0x000000B2: return "Cloud"; - case 0x000000B3: return "Cloud N"; - case 0x000000B6: return "Home OS"; + case 0x0000006F: return " Home Connected"; + case 0x00000070: return " Pro Student"; + case 0x00000071: return " Home Connected N"; + case 0x00000072: return " Pro Student N"; + case 0x00000073: return " Home Connected Single Language"; + case 0x00000074: return " Home Connected China"; + case 0x00000079: return " Education"; + case 0x0000007A: return " Education N"; + case 0x0000007D: return " Enterprise LTSB"; + case 0x0000007E: return " Enterprise LTSB N"; + case 0x0000007F: return " Pro S"; + case 0x00000080: return " Pro S N"; + case 0x00000081: return " Enterprise LTSB (Eval)"; + case 0x00000082: return " Enterprise LTSB N (Eval)"; + case 0x0000008A: return " Pro Single Language"; + case 0x0000008B: return " Pro China"; + case 0x0000008C: return " Enterprise Subscription"; + case 0x0000008D: return " Enterprise Subscription N"; + case 0x00000091: return " Server Datacenter SA (Core)"; + case 0x00000092: return " Server Standard SA (Core)"; + case 0x00000095: return " Utility VM"; + case 0x000000A1: return " Pro for Workstations"; + case 0x000000A2: return " Pro for Workstations N"; + case 0x000000A4: return " Pro for Education"; + case 0x000000A5: return " Pro for Education N"; + case 0x000000AB: return " Enterprise G"; // I swear Microsoft are just making up editions... + case 0x000000AC: return " Enterprise G N"; + case 0x000000B2: return " Cloud"; + case 0x000000B3: return " Cloud N"; + case 0x000000B6: return " Home OS"; case 0x000000B7: case 0x000000CB: return "Cloud E"; - case 0x000000B9: return "IoT OS"; + case 0x000000B9: return " IoT OS"; case 0x000000BA: case 0x000000CA: return "Cloud E N"; - case 0x000000BB: return "IoT Edge OS"; - case 0x000000BC: return "IoT Enterprise"; - case 0x000000BD: return "Lite"; - case 0x000000BF: return "IoT Enterprise S"; + case 0x000000BB: return " IoT Edge OS"; + case 0x000000BC: return " IoT Enterprise"; + case 0x000000BD: return " Lite"; + case 0x000000BF: return " IoT Enterprise S"; case 0x000000C0: case 0x000000C2: case 0x000000C3: case 0x000000C4: case 0x000000C5: case 0x000000C6: return "XBox"; case 0x000000C7: case 0x000000C8: case 0x00000196: case 0x00000197: case 0x00000198: return "Azure Server"; - case 0xABCDABCD: return "(Unlicensed)"; + case 0xABCDABCD: return " (Unlicensed)"; default: - static_sprintf(unknown_edition_str, "(Unknown Edition 0x%02X)", (uint32_t)ProductType); + static_sprintf(unknown_edition_str, " (Unknown Edition 0x%02X)", (uint32_t)ProductType); return unknown_edition_str; } } @@ -475,10 +475,9 @@ void GetWindowsVersion(windows_version_t* windows_version) else if (vi.wServicePackMajor) safe_sprintf(vptr, vlen, "%s SP%u %s", w, vi.wServicePackMajor, arch_name); else - safe_sprintf(vptr, vlen, "%s%s%s %s", - w, (dwProductType != 0) ? " " : "", GetEdition(dwProductType), arch_name); + safe_sprintf(vptr, vlen, "%s%s %s", w, GetEditionName(dwProductType), arch_name); - windows_version->Edition = (int)dwProductType; + windows_version->Edition = dwProductType; // Add the build number (including UBR if available) windows_version->BuildNumber = vi.dwBuildNumber; diff --git a/src/stdlg.c b/src/stdlg.c index 57ae3200..38bd7cb3 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Standard Dialog Routines (Browse for folder, About, etc) - * Copyright © 2011-2025 Pete Batard + * Copyright © 2011-2026 Pete Batard * * 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 @@ -48,6 +48,7 @@ /* Globals */ extern BOOL is_x86_64, appstore_version; extern char unattend_username[MAX_USERNAME_LENGTH], *sbat_level_txt, *sb_active_txt, *sb_revoked_txt; +extern int unattend_edition_index; extern HICON hSmallIcon, hBigIcon; static HICON hMessageIcon = (HICON)INVALID_HANDLE_VALUE; static char* szMessageText = NULL; @@ -787,8 +788,39 @@ int NotificationEx(int type, const char* dont_display_setting, const notificatio return (int)ret; } +static int GetComboBoxMinWidth(HWND hCtrl, StrArray* array) +{ + HDC hDC = GetDC(hCtrl); + HFONT hFont = (HFONT)SendMessage(hCtrl, WM_GETFONT, 0, 0); + HFONT hOldFont = (HFONT)SelectObject(hDC, hFont); + SIZE size; + uint32_t i; + int max_width = 0, arrow_width, padding; + + if (array == NULL || array->String == NULL) { + ReleaseDC(hCtrl, hDC); + return 0; + } + + for (i = 0; i < array->Index; i++) { + GetTextExtentPoint32A(hDC, array->String[i], (int)strlen(array->String[i]), &size); + if (size.cx > max_width) + max_width = size.cx; + } + SelectObject(hDC, hOldFont); + ReleaseDC(hCtrl, hDC); + + // Add the dropdown arrow button width + some padding + arrow_width = GetSystemMetrics(SM_CXVSCROLL); + padding = GetSystemMetrics(SM_CXEDGE) * 4 + 8; + + return max_width + arrow_width + padding; +} + // We only ever display one selection dialog, so set some params as globals -static int selection_dialog_style, selection_dialog_mask, selection_dialog_username_index; +static int selection_dialog_style; +static selection_dialog_options_t* selection_options = NULL; +static BOOL silent_install_checked = FALSE; /* * Custom dialog for radio button selection dialog @@ -803,19 +835,22 @@ static INT_PTR CALLBACK CustomSelectionCallback(HWND hDlg, UINT message, WPARAM static LRESULT disabled[9] = { HTLEFT, HTRIGHT, HTTOP, HTBOTTOM, HTSIZE, HTTOPLEFT, HTTOPRIGHT, HTBOTTOMLEFT, HTBOTTOMRIGHT }; static HBRUSH background_brush, separator_brush; - char username[128] = { 0 }; + static HFONT hDlgFont = NULL; + char username[128] = { 0 }, str[MAX_PATH]; int i, m, dw, dh, r = -1, mw; DWORD size = sizeof(username); LRESULT loc; // To use the system message font NONCLIENTMETRICS ncm; RECT rc, rc2; - static HFONT hDlgFont = NULL; HWND hCtrl; HDC hDC; switch (message) { case WM_INITDIALOG: + StrArray version_name = { 0 }, version_index = { 0 }; + StrArrayCreate(&version_name, 16); + StrArrayCreate(&version_index, 16); SetDarkModeForDlg(hDlg); // Don't overflow our max radio button if (nDialogItems > (IDC_SELECTION_CHOICEMAX - IDC_SELECTION_CHOICE1 + 1)) { @@ -852,23 +887,27 @@ static INT_PTR CALLBACK CustomSelectionCallback(HWND hDlg, UINT message, WPARAM mw = rc.right - rc.left - ddw; // ddw seems to work okay as a fudge dw = mw; + r = GetEditions(&version_name, &version_index); + // Change the default icon and set the text Static_SetIcon(GetDlgItem(hDlg, IDC_SELECTION_ICON), LoadIcon(NULL, IDI_QUESTION)); SetWindowTextU(hDlg, szMessageTitle); SetWindowTextU(GetDlgItem(hDlg, IDCANCEL), lmprintf(MSG_007)); SetWindowTextU(GetDlgItem(hDlg, IDC_SELECTION_TEXT), szMessageText); for (i = 0; i < nDialogItems; i++) { - char* str = szDialogItem[i]; + static_strcpy(str, szDialogItem[i]); SetWindowTextU(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), str); ShowWindow(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), SW_SHOW); - // Compute the maximum line's width (with some extra for the username field if needed) - if (i == selection_dialog_username_index) { - str = calloc(strlen(szDialogItem[i]) + strlen(base_username) + 8, 1); - sprintf(str, "%s __%s__", szDialogItem[i], base_username); + // Compute the maximum line's width (with some extra for the username and edition fields) + if (selection_options != NULL && i == selection_options->username_index) { + static_sprintf(str, "%s __%s__", szDialogItem[i], base_username); + mw = max(mw, GetTextSize(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), str).cx); + } else if (selection_options != NULL && i == selection_options->edition_index) { + mw = max(mw, GetTextSize(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), str).cx + + GetComboBoxMinWidth(GetDlgItem(hDlg, IDC_SELECTION_EDITION), &version_name)); + } else { + mw = max(mw, GetTextSize(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), str).cx); } - mw = max(mw, GetTextSize(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), str).cx); - if (i == selection_dialog_username_index) - free(str); } // If our maximum line's width is greater than the default, set a nonzero delta width dw = (mw <= dw) ? 0 : mw - dw; @@ -887,12 +926,12 @@ static INT_PTR CALLBACK CustomSelectionCallback(HWND hDlg, UINT message, WPARAM ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), 0, dh, dw, 0, 1.0f); // If required, set up the the username edit box - if (selection_dialog_username_index != -1) { + if (selection_options != NULL && selection_options->username_index != -1) { unattend_username[0] = 0; - hCtrl = GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_dialog_username_index); + hCtrl = GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->username_index); GetClientRect(hCtrl, &rc); ResizeMoveCtrl(hDlg, hCtrl, 0, 0, - (rc.left - rc.right) + GetTextSize(hCtrl, szDialogItem[selection_dialog_username_index]).cx + ddw, 0, 1.0f); + (rc.left - rc.right) + GetTextSize(hCtrl, szDialogItem[selection_options->username_index]).cx + ddw, 0, 1.0f); GetWindowRect(hCtrl, &rc); SetWindowPos(GetDlgItem(hDlg, IDC_SELECTION_USERNAME), hCtrl, rc.left, rc.top, 0, 0, SWP_NOMOVE | SWP_NOSIZE); hCtrl = GetDlgItem(hDlg, IDC_SELECTION_USERNAME); @@ -905,6 +944,25 @@ static INT_PTR CALLBACK CustomSelectionCallback(HWND hDlg, UINT message, WPARAM ShowWindow(hCtrl, SW_SHOW); } + // If required, set up the the edition combo box + if (selection_options != NULL && selection_options->edition_index != -1 && version_name.String != NULL && version_name.Index > 0) { + hCtrl = GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->edition_index); + GetClientRect(hCtrl, &rc); + ResizeMoveCtrl(hDlg, hCtrl, 0, 0, + (rc.left - rc.right) + GetTextSize(hCtrl, szDialogItem[selection_options->edition_index]).cx + ddw, 0, 1.0f); + GetWindowRect(hCtrl, &rc); + SetWindowPos(GetDlgItem(hDlg, IDC_SELECTION_EDITION), hCtrl, rc.left, rc.top, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + hCtrl = GetDlgItem(hDlg, IDC_SELECTION_EDITION); + GetWindowRect(hCtrl, &rc2); + ResizeMoveCtrl(hDlg, hCtrl, right_to_left_mode ? rc2.right - rc.left : rc.right - rc2.left, rc.top - rc2.top, + GetComboBoxMinWidth(hCtrl, &version_name), 0, 1.0f); + for (i = 0; i < (int)version_name.Index; i++) + IGNORE_RETVAL(ComboBox_SetItemData(hCtrl, ComboBox_AddStringU(hCtrl, version_name.String[i]), + (LPARAM)atoi(version_index.String[i]))); + IGNORE_RETVAL(ComboBox_SetCurSel(hCtrl, unattend_edition_index)); + ShowWindow(hCtrl, SW_SHOW); + } + if (nDialogItems > 2) { GetWindowRect(GetDlgItem(hDlg, IDC_SELECTION_CHOICE2), &rc); GetWindowRect(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + nDialogItems - 1), &rc2); @@ -922,8 +980,17 @@ static INT_PTR CALLBACK CustomSelectionCallback(HWND hDlg, UINT message, WPARAM // Set the default selection for (i = 0, m = 1; i < nDialogItems; i++, m <<= 1) - Button_SetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), (m & selection_dialog_mask) ? BST_CHECKED : BST_UNCHECKED); + Button_SetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), + ((selection_options == NULL && i == 0) || (selection_options != NULL && (m & selection_options->mask))) ? BST_CHECKED : BST_UNCHECKED); + if (selection_options != NULL && selection_options->username_index > 0 && selection_options->edition_index > 0) { + BOOL enable = Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->username_index)); + EnableWindow(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->edition_index), enable); + EnableWindow(GetDlgItem(hDlg, IDC_SELECTION_EDITION), enable); + } + SetDarkModeForChild(hDlg); + StrArrayDestroy(&version_name); + StrArrayDestroy(&version_index); return (INT_PTR)TRUE; case WM_CTLCOLORSTATIC: // Change the background colour for static text and icon @@ -945,12 +1012,29 @@ static INT_PTR CALLBACK CustomSelectionCallback(HWND hDlg, UINT message, WPARAM safe_delete_object(hDlgFont); break; case WM_COMMAND: - switch (LOWORD(wParam)) { + WORD command = LOWORD(wParam); + if (command >= IDC_SELECTION_CHOICE1 && command < IDC_SELECTION_CHOICEMAX) { + // Check if the local account name or regional settings checkbox was clicked and enable/disable the silent install option + if (selection_options != NULL && selection_options->username_index > 0 && selection_options->edition_index > 0 && selection_options->regional_index > 0 && + (command - IDC_SELECTION_CHOICE1 == selection_options->username_index || command - IDC_SELECTION_CHOICE1 == selection_options->regional_index)) { + BOOL enable = Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->username_index)) && + Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->regional_index)); + hCtrl = GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->edition_index); + if (!enable && IsWindowEnabled(hCtrl)) { + silent_install_checked = (Button_GetCheck(hCtrl) == BST_CHECKED); + Button_SetCheck(hCtrl, FALSE); + } else if (enable && !IsWindowEnabled(hCtrl)) { + Button_SetCheck(hCtrl, silent_install_checked); + } + EnableWindow(hCtrl, enable); + EnableWindow(GetDlgItem(hDlg, IDC_SELECTION_EDITION), enable); + } + } else switch (LOWORD(wParam)) { case IDOK: for (r = 0, i = 0, m = 1; i < nDialogItems; i++, m <<= 1) if (Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i)) == BST_CHECKED) r += m; - if (selection_dialog_username_index != -1) { + if (selection_options != NULL && selection_options->username_index != -1) { GetWindowTextU(GetDlgItem(hDlg, IDC_SELECTION_USERNAME), unattend_username, MAX_USERNAME_LENGTH); // Perform string sanitization (NB: GetWindowTextU always terminates the string) for (i = 0; unattend_username[i] != 0; i++) { @@ -958,6 +1042,8 @@ static INT_PTR CALLBACK CustomSelectionCallback(HWND hDlg, UINT message, WPARAM unattend_username[i] = '_'; } } + if (selection_options != NULL && selection_options->edition_index != -1) + unattend_edition_index = (int)ComboBox_GetCurItemData(GetDlgItem(hDlg, IDC_SELECTION_EDITION)); // Fall through case IDNO: case IDCANCEL: @@ -972,7 +1058,7 @@ static INT_PTR CALLBACK CustomSelectionCallback(HWND hDlg, UINT message, WPARAM /* * Display an item selection dialog */ -int CustomSelectionDialog(int style, char* title, char* message, char** choices, int size, int mask, int username_index) +int CustomSelectionDialog(int style, char* title, char* message, char** choices, int size, selection_dialog_options_t* options) { int ret; @@ -981,10 +1067,9 @@ int CustomSelectionDialog(int style, char* title, char* message, char** choices, szMessageText = message; szDialogItem = choices; nDialogItems = size; + selection_options = options; selection_dialog_style = style; - selection_dialog_mask = mask; - selection_dialog_username_index = username_index; - assert(selection_dialog_style == BS_AUTORADIOBUTTON || selection_dialog_style == BS_AUTOCHECKBOX); + assert(style == BS_AUTORADIOBUTTON || style == BS_AUTOCHECKBOX); ret = (int)MyDialogBox(hMainInstance, IDD_SELECTION, hMainDialog, CustomSelectionCallback); dialog_showing--; diff --git a/src/wue.c b/src/wue.c index 5c10c957..6e8d68c4 100644 --- a/src/wue.c +++ b/src/wue.c @@ -46,13 +46,58 @@ const char* bypass_name[] = { "BypassTPMCheck", "BypassSecureBootCheck", "Bypass int unattend_xml_flags = 0, wintogo_index = -1, wininst_index = 0; int unattend_xml_mask = UNATTEND_DEFAULT_SELECTION_MASK; +int unattend_edition_index = 1; char *unattend_xml_path = NULL, unattend_username[MAX_USERNAME_LENGTH]; +uint32_t removable_section[2] = { 0, 0 }; extern BOOL validate_md5sum; extern uint64_t md5sum_totalbytes; extern StrArray modified_files; extern const char* efi_archname[ARCH_MAX]; +// Get the UI language provided by the ISO's boot.wim +char* GetUILanguage(void) +{ + static char ui_language[8]; + int r; + char wim_path[4 * MAX_PATH] = ""; + wchar_t* xml = NULL; + ezxml_t pxml = NULL; + size_t xml_len; + WIMStruct* wim = NULL; + + assert(safe_strlen(image_path) + 32 < ARRAYSIZE(wim_path)); + static_strcpy(ui_language, "en-US"); + static_strcpy(wim_path, image_path); + static_strcat(wim_path, "|sources/boot.wim"); + + r = wimlib_open_wimU(wim_path, 0, &wim); + if (r != 0) { + uprintf("Could not open WIM: Error %d", r); + goto out; + } + + r = wimlib_get_xml_data(wim, (void**)&xml, &xml_len); + if (r != 0) { + uprintf("Could not read WIM XML index: Error %d", r); + goto out; + } + + pxml = ezxml_parse_str((char*)xml, xml_len); + if (pxml == NULL) + goto out; + + char* lang = ezxml_get_val(pxml, "IMAGE", 1, "WINDOWS", 0, "LANGUAGES", 0, "LANGUAGE", -1); + if (lang != NULL) + static_strcpy(ui_language, lang); + +out: + ezxml_free(pxml); + free(xml); + wimlib_free(wim); + return ui_language; +} + /// /// Create an installation answer file containing the sections specified by the flags. /// @@ -70,6 +115,8 @@ char* CreateUnattendXml(int arch, int flags) TIME_ZONE_INFORMATION tz_info; int i, order; unattend_xml_flags = flags; + StrArray commands = STRARRAY_EMPTY; + StrArrayCreate(&commands, 8); if (arch < ARCH_X86_32 || arch > ARCH_ARM_64 || flags == 0) { uprintf("Note: No Windows User Experience options selected"); return NULL; @@ -86,24 +133,104 @@ char* CreateUnattendXml(int arch, int flags) fprintf(fd, "\n"); fprintf(fd, "\n"); - // This part produces the unbecoming display of a command prompt window during initial setup as well - // as alters the layout and options of the initial Windows installer screens, which may scare users. - // So, in format.c, we'll try to insert the registry keys directly and drop this section. However, - // because Microsoft prevents Store apps from editing an offline registry, we do need this fallback. if (flags & UNATTEND_WINPE_SETUP_MASK) { - order = 1; fprintf(fd, " \n"); fprintf(fd, " \n", xml_arch_names[arch]); // WinPE will complain if we don't provide a product key. *Any* product key. This is soooo idiotic... fprintf(fd, " \n"); + fprintf(fd, " true\n"); fprintf(fd, " \n"); fprintf(fd, " \n"); fprintf(fd, " \n"); fprintf(fd, " \n"); + if (flags & UNATTEND_SILENT_INSTALL) { + uprintf("• Silent Install"); + // Automatically partition the disk and set the installation target + fprintf(fd, " \n"); + fprintf(fd, " OnError\n"); + if (flags & UNATTEND_DISABLE_BITLOCKER) + fprintf(fd, " true\n"); + // The following ensures that we display the disk selection screen if only the boot media is + // available (i.e. if the system does not see any target for installation). In that case the + // letter assignment below fails and the UI is displayed allowing the user to provide drivers. + // This also prevents the install media from being scratched, when it's the only disk. + // With a special mention to Claude AI, that explicitly said this could not be accomplished... + fprintf(fd, " \n"); + fprintf(fd, " 1 \n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " 1\n"); + fprintf(fd, " 1\n"); + // You REALLY don't want to use 'U' for the drive letter below. Don't ask me how I know!!! + fprintf(fd, " D\n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " 0 \n"); + fprintf(fd, " true \n"); + fprintf(fd, " \n"); + // NB: Don't bother creating a recovery partition. Windows setup will do it for us. + fprintf(fd, " \n"); + fprintf(fd, " 1\n"); + fprintf(fd, " EFI\n"); + fprintf(fd, " 260\n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " 2\n"); + fprintf(fd, " MSR\n"); + fprintf(fd, " 16\n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " 3\n"); + fprintf(fd, " Primary\n"); + fprintf(fd, " true\n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " 1\n"); + fprintf(fd, " 1\n"); + fprintf(fd, " \n"); + fprintf(fd, " FAT32\n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " 2\n"); + fprintf(fd, " 3\n"); + fprintf(fd, " \n"); + fprintf(fd, " C\n"); + fprintf(fd, " NTFS\n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " OnError\n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " /IMAGE/INDEX\n"); + fprintf(fd, " %d\n", unattend_edition_index); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " 0\n"); + fprintf(fd, " 3\n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " \n"); + } if (flags & UNATTEND_SECUREBOOT_TPM_MINRAM) { + // This part produces the unbecoming display of a command prompt window during initial setup as well + // as alters the layout and options of the initial Windows installer screens, which may scare users. + // So, in format.c, we'll try to insert the registry keys directly and drop this section. However, + // because Microsoft prevents Store apps from editing an offline registry, we do need this fallback. + // NB: We could probably avoid this by running powershell with -WindowStyle "Hidden" but hey... uprintf("• Bypass SB/TPM/RAM"); + order = 1; + removable_section[0] = (uint32_t)ftell(fd); fprintf(fd, " \n"); for (i = 0; i < ARRAYSIZE(bypass_name); i++) { fprintf(fd, " \n"); @@ -112,46 +239,60 @@ char* CreateUnattendXml(int arch, int flags) fprintf(fd, " \n"); } fprintf(fd, " \n"); + removable_section[1] = (uint32_t)ftell(fd); } fprintf(fd, " \n"); + if (flags & UNATTEND_SILENT_INSTALL) { + fprintf(fd, " \n", xml_arch_names[arch]); + // Set the language from the tag of the boot.wim index + fprintf(fd, " %s\n", GetUILanguage()); + fprintf(fd, " \n"); + } fprintf(fd, " \n"); } if (flags & UNATTEND_SPECIALIZE_DEPLOYMENT_MASK) { - order = 1; fprintf(fd, " \n"); fprintf(fd, " \n", xml_arch_names[arch]); - fprintf(fd, " \n"); // This part was picked from https://github.com/AveYo/MediaCreationTool.bat/blob/main/bypass11/AutoUnattend.xml // NB: This is INCOMPATIBLE with S-Mode below if (flags & UNATTEND_NO_ONLINE_ACCOUNT) { + StrArrayAdd(&commands, "reg add \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OOBE\" /v BypassNRO /t REG_DWORD /d 1 /f", TRUE); uprintf("• Bypass online account requirement"); - fprintf(fd, " \n"); - fprintf(fd, " %d\n", order++); - fprintf(fd, " reg add HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OOBE /v BypassNRO /t REG_DWORD /d 1 /f\n"); - fprintf(fd, " \n"); } - fprintf(fd, " \n"); + // Now that we have all the commands to run, create the RunSynchronous section. + for (order = 1; order <= (int)commands.Index; order++) { + if (order == 1) + fprintf(fd, " \n"); + fprintf(fd, " \n"); + fprintf(fd, " %d\n", order); + fprintf(fd, " %s\n", commands.String[order - 1]); + fprintf(fd, " \n"); + if (order == commands.Index) + fprintf(fd, " \n"); + } fprintf(fd, " \n"); fprintf(fd, " \n"); + StrArrayClear(&commands); } if (flags & UNATTEND_OOBE_MASK) { - StrArray first_logon_commands = STRARRAY_EMPTY; - StrArrayCreate(&first_logon_commands, 8); fprintf(fd, " \n"); if (flags & UNATTEND_OOBE_SHELL_SETUP_MASK) { fprintf(fd, " \n", xml_arch_names[arch]); // https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-oobe-protectyourpc - // It is really super insidous of Microsoft to call this option "ProtectYourPC", when it's really only about + // It is really super disingenuous of Microsoft to call this option "ProtectYourPC", when it's really only about // data collection. But of course, if it was called "AllowDataCollection", everyone would turn it off... if (flags & UNATTEND_NO_DATA_COLLECTION) { uprintf("• Disable data collection"); fprintf(fd, " \n"); + fprintf(fd, " true\n"); fprintf(fd, " 3\n"); fprintf(fd, " \n"); } @@ -200,14 +341,13 @@ char* CreateUnattendXml(int arch, int flags) // Since we set a blank password, we'll ask the user to change it at next logon. // NB: In case you wanna try, please be aware that Microsoft doesn't let you have multiple // sections in unattend.xml. Don't ask me how I know... :( - static_sprintf(tmp, "net user "%s" /logonpasswordchg:yes", unattend_username); - StrArrayAdd(&first_logon_commands, tmp, TRUE); + static_sprintf(tmp, "net user \"%s\" /logonpasswordchg:yes", unattend_username); + StrArrayAdd(&commands, tmp, TRUE); // The `net user` command above might reset the password expiration to 90 days... // To alleviate that, blanket set passwords on the target machine to never expire. - StrArrayAdd(&first_logon_commands, "net accounts /maxpwage:unlimited", TRUE); + StrArrayAdd(&commands, "net accounts /maxpwage:unlimited", TRUE); } } - // Apply SkuSiPolicy.p7b, if the user requested it and we're not creating a Windows To Go drive. // See https://support.microsoft.com/kb/5042562. We do it post install, on first logon, because // we'd have to patch tons of files otherwise. And we *ALWAYS* use the installed system's @@ -216,25 +356,25 @@ char* CreateUnattendXml(int arch, int flags) // produce the 0xc0000428 signature validation error on (re)boot if the system hasn't gone // through a full Windows Update cycle. if (flags & UNATTEND_APPLY_SKUSIPOLICY) { - StrArrayAdd(&first_logon_commands, "cmd /c mountvol S: /S && " + uprintf("• Apply SkuSiPolicy.p7b"); + // TODO: Could we hide this using PowerShell? + StrArrayAdd(&commands, "cmd /c mountvol S: /S && " "copy %WINDIR%\\system32\\SecureBootUpdates\\SkuSiPolicy.p7b S:\\EFI\\Microsoft\\Boot && " "mountvol S: /D", TRUE); } - // Now that we have all the commands to run, create the FirstLogonCommands section. - for (order = 1; order <= (int)first_logon_commands.Index; order++) { + for (order = 1; order <= (int)commands.Index; order++) { if (order == 1) fprintf(fd, " \n"); fprintf(fd, " \n"); fprintf(fd, " %d\n", order); - fprintf(fd, " %s\n", first_logon_commands.String[order - 1]); + fprintf(fd, " %s\n", commands.String[order - 1]); fprintf(fd, " \n"); - if (order == first_logon_commands.Index) + if (order == commands.Index) fprintf(fd, " \n"); } - StrArrayDestroy(&first_logon_commands); - fprintf(fd, " \n"); + StrArrayClear(&commands); } if (flags & UNATTEND_OOBE_INTERNATIONAL_MASK) { uprintf("• Use the same regional options as this user's"); @@ -294,6 +434,7 @@ char* CreateUnattendXml(int arch, int flags) if (flags & UNATTEND_USE_MS2023_BOOTLOADERS) uprintf("• Use 'Windows CA 2023' signed bootloaders"); + StrArrayDestroy(&commands); fprintf(fd, "\n"); fclose(fd); return path; @@ -530,6 +671,86 @@ out: return ((img_report.win_version.major != 0) && (img_report.win_version.build != 0)); } +int GetEditions(StrArray* version_name, StrArray* version_index) +{ + int i, r, n = -1; + WIMStruct* wim = NULL; + const char* edition_suffix; + char *install_names[MAX_WININST], *edition_name; + wchar_t wim_path[4 * MAX_PATH] = L"", * xml = NULL; + size_t xml_len; + BOOL bNonStandard = FALSE; + ezxml_t index = NULL, image = NULL; + + // If we have multiple windows install images, ask the user the one to use + if (img_report.wininst_index > 1) { + for (i = 0; i < img_report.wininst_index; i++) + install_names[i] = &img_report.wininst_path[i][2]; + wininst_index = _log2(SelectionDialog(lmprintf(MSG_130), lmprintf(MSG_131), install_names, img_report.wininst_index)); + if (wininst_index < 0) + return -2; + if (wininst_index >= MAX_WININST) + wininst_index = 0; + } + + assert(utf8_to_wchar_get_size(image_path) <= ARRAYSIZE(wim_path)); + utf8_to_wchar_no_alloc(image_path, wim_path, ARRAYSIZE(wim_path)); + if (!img_report.is_windows_img) { + wcscat(wim_path, L"|"); + assert(utf8_to_wchar_get_size(image_path) + utf8_to_wchar_get_size(&img_report.wininst_path[wininst_index][2]) <= ARRAYSIZE(wim_path)); + utf8_to_wchar_no_alloc(&img_report.wininst_path[wininst_index][2], + &wim_path[wcslen(wim_path)], (int)ARRAYSIZE(wim_path) - wcslen(wim_path)); + } + + r = wimlib_open_wim(wim_path, 0, &wim); + if (r != 0) { + uprintf("Could not open WIM: %d", r); + goto out; + } + r = wimlib_get_xml_data(wim, (void**)&xml, &xml_len); + if (r != 0) { + uprintf("Could not read WIM XML index: %d", r); + goto out; + } + + index = ezxml_parse_str((char*)xml, xml_len); + if (index == NULL) { + uprintf("Could not parse WIM XML"); + goto out; + } + + edition_suffix = GetEditionName(WindowsVersion.Edition); + unattend_edition_index = 1; + for (n = 0, image = ezxml_child(index, "IMAGE"); + StrArrayAdd(version_index, ezxml_attr(image, "INDEX"), TRUE) >= 0; + image = image->next, n++) { + // Try to match this host's edition with an index from the image + edition_name = ezxml_child_val(image, "NAME"); + if (edition_name != NULL) { + if (strlen(edition_name) > safe_strlen(edition_suffix) && + stricmp(&edition_name[strlen(edition_name) - safe_strlen(edition_suffix)], edition_suffix) == 0) + unattend_edition_index = atoi(ezxml_attr(image, "INDEX")) - 1; + } + // Some people are apparently creating *unofficial* Windows ISOs that don't have DISPLAYNAME elements. + // If we are parsing such an ISO, try to fall back to using DESCRIPTION. + if (StrArrayAdd(version_name, ezxml_child_val(image, "DISPLAYNAME"), TRUE) < 0) { + if (StrArrayAdd(version_name, ezxml_child_val(image, "DESCRIPTION"), TRUE) < 0) { + uprintf("WARNING: Could not find a description for image index %d", n + 1); + StrArrayAdd(version_name, "Unknown Windows Version", TRUE); + } + bNonStandard = TRUE; + } + } + if (bNonStandard) + uprintf("WARNING: Nonstandard Windows image (missing entries)"); + +out: + free(xml); + ezxml_free(index); + wimlib_free(wim); + return n; +} + /// /// Checks which versions of Windows are available in an install image /// to set our extraction index. Asks the user to select one if needed. @@ -773,7 +994,7 @@ BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp) /// A bitmap of unattend flags to apply. /// TRUE on success, FALSE on error. BOOL ApplyWindowsCustomization(char drive_letter, int flags) -// NB: Work with a copy of unattend_xml_flags as a paremeter since we will modify it. +// NB: Work with a copy of unattend_xml_flags as a parameter since we will modify it. { BOOL r = FALSE, is_hive_mounted = FALSE, update_boot_wim = FALSE; int i, wim_index = 2, wuc_index = 0, num_replaced = 0; @@ -791,12 +1012,12 @@ BOOL ApplyWindowsCustomization(char drive_letter, int flags) char path[MAX_PATH], *rep, *tmp_dir_end; uint8_t* buf = NULL; uint16_t setup_arch; - size_t len; + uint32_t len; HKEY hKey = NULL, hSubKey = NULL; LSTATUS status; DWORD dwDisp, dwVal = 1, dwSize; FILE* fd_md5sum; - WIMStruct* wim; + WIMStruct* wim = NULL; StrArray files; struct wimlib_update_command wuc[2] = { 0 }; @@ -845,7 +1066,7 @@ BOOL ApplyWindowsCustomization(char drive_letter, int flags) dwSize = read_file(setup_exe, &buf); if (dwSize != 0) { setup_arch = GetPeArch(buf); - free(buf); + safe_free(buf); if (setup_arch != IMAGE_FILE_MACHINE_AMD64 && setup_arch != IMAGE_FILE_MACHINE_ARM64) { uprintf("WARNING: Unsupported arch 0x%x -- in-place upgrade wrapper will not be added", setup_arch); } else if (!MoveFileExU(setup_exe, setup_dll, 0)) { @@ -870,6 +1091,7 @@ BOOL ApplyWindowsCustomization(char drive_letter, int flags) } else { uprintf("Could not create '%s' bypass wrapper", setup_exe); } + buf = NULL; } } } @@ -948,19 +1170,27 @@ BOOL ApplyWindowsCustomization(char drive_letter, int flags) wuc[wuc_index].add.wim_target_path = L"Windows\\System32\\config\\SYSTEM"; wuc_index++; - // We were successfull in creating the keys so disable the windowsPE section from unattend.xml - // We do this by replacing '' with '' - // (provided that the registry key creation was the only item for this pass) + // We were successfull in creating the keys so remove this part from unattend.xml if ((flags & UNATTEND_WINPE_SETUP_MASK) == UNATTEND_SECUREBOOT_TPM_MINRAM) { + // If this is all we used the WindowsPE pass for, then we just replace + // '' with '' if (replace_in_token_data(unattend_xml_path, " entries from windowsPE (and only windowsPE). - assert(FALSE); + // Otherwise, remove the relevant section from our temporary unattend.xml + len = read_file(unattend_xml_path, &buf); + if (len != 0 && removable_section[0] != 0 && removable_section[0] < len && removable_section[1] < len) { + memmove(&buf[removable_section[0]], &buf[removable_section[1]], len - removable_section[1]); + len -= removable_section[1] - removable_section[0]; + if (write_file(unattend_xml_path, buf, len) != len) + uprintf("Failed to remove 'WindowsPE' section from unattend.xml"); + } else { + uprintf("Failed to remove 'WindowsPE' section from unattend.xml"); + } + safe_free(buf); } + // Remove the flags, since we accomplished the registry creation outside of unattend. + flags &= ~UNATTEND_SECUREBOOT_TPM_MINRAM; UpdateProgressWithInfoForce(OP_PATCH, MSG_325, 102, PATCH_PROGRESS_TOTAL); } @@ -1016,7 +1246,7 @@ BOOL ApplyWindowsCustomization(char drive_letter, int flags) WIMLIB_EXTRACT_FLAG_NO_ACLS | WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE) != 0) { uprintf("Could not extract 2023 signed UEFI bootloaders - Ignoring option"); } else { - len = strlen(tmp_path[1]); + len = (uint32_t)strlen(tmp_path[1]); tmp_dir_end = &tmp_path[1][len]; // Copy/override the Font files From d4d537fc5baf5ae7dd51d7971f1466907e90c9bd Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 11 Mar 2026 15:47:06 +0000 Subject: [PATCH 06/82] [uefi] change the name of the UEFI:NTFS partition to RUFUS_BOOT * This should make it more explicit to Windows users to identify the installation media. * Also update crazy-max/ghaction-upx to latest (Closes #2936). * Also fix a Coverity warning and use improve StrArray handling/init. --- .github/workflows/vs2022.yml | 2 +- res/uefi/readme.txt | 8 +++++--- res/uefi/uefi-ntfs.img | Bin 1048576 -> 1048576 bytes src/dev.c | 2 +- src/drive.c | 2 +- src/rufus.h | 1 - src/rufus.rc | 10 +++++----- src/wue.c | 6 +++--- 8 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.github/workflows/vs2022.yml b/.github/workflows/vs2022.yml index 228a11aa..f19f80d3 100644 --- a/.github/workflows/vs2022.yml +++ b/.github/workflows/vs2022.yml @@ -51,7 +51,7 @@ jobs: msbuild-architecture: x64 - name: Install UPX - uses: crazy-max/ghaction-upx@v3 + uses: crazy-max/ghaction-upx@v4 with: install-only: true diff --git a/res/uefi/readme.txt b/res/uefi/readme.txt index 76fb335d..bf8f3f26 100644 --- a/res/uefi/readme.txt +++ b/res/uefi/readme.txt @@ -25,10 +25,12 @@ o Secure Boot signed UEFI:NTFS bootloader binaries [3]. The above means that, if booting an NTFS partition on an x86_32, x86_64 or ARM64 system, Secure Boot does not need to be disabled. -The FAT partition was created on Debian GNU/Linux using the following commands +The FAT partition was created on Debian GNU/Linux using the following commands: dd if=/dev/zero of=uefi-ntfs.img bs=512 count=2048 - mkfs.vfat -n UEFI_NTFS uefi-ntfs.img -and then mounting the uefi-ntfs.img image and copying the relevant files. + chown 1000:100 uefi-ntfs.img + mkfs.vfat -n RUFUS_BOOT uefi-ntfs.img + mount -t vfat uefi-ntfs.img /mnt/hd -o rw,uid=1000,gid=100 +and then copying the relevant files. [1] https://github.com/pbatard/ntfs-3g [2] https://github.com/pbatard/efifs diff --git a/res/uefi/uefi-ntfs.img b/res/uefi/uefi-ntfs.img index 57deaef7e4ff03874ee4f014797b66e45f7e3f5f..d9ff7dc606ea992c208a9676ec1c763d63eca084 100644 GIT binary patch delta 505 zcmZo@aA;_7n4r!#_1YPUpisBa;CLs0|B#KQr#TG~Tm=pWhEqK0G3hZ7ngI-4-8>bb zK!CyQCQtfgLoOSES#Mwp6Kn%^Gj816$W`w?@dC@FAYL7iBCsJKni*_}o*v8$1&ARq z`N@_+CTtK5lZ%6__$*+0PbHQ_I|EI1Wydg*g^-a^2qUAc*v!F3PTq`QevYydgj*Cf zF)+rM!J!6d*CDp1q-{xzydQMnvLLfl zZX660hq8-7Y-@=4W+e7!5ZeZ-K7`3i2*L)&hHdzdumZ*lVN5_rHnO%wF||c8w?(nE lMFH7tZBguPQ5Z2ykCf0u);>u)0~C~t^x-G1Mlp>n7|ka%>V{K)e2A` zz#t+tJ8-fgmyJNHDpcXA1lxe!j2kyMa@D&}yudOkh*t-s2y6(5W(FIgrw21b0b&SD zezIkd37aTb!{p*1E53TTxrrsw&OlRL*+E7^Q~=!tQptj8B(nTu%P54AQC4g0sIu#1t{n?dYmi1=qDws8oPl~4;<9O!G?@E>6Xj2FU~ zfR1crZHr=Ri(+nzVrh#4vf0|A*xRBw+M+nyqPW_kxZ9$5+M;;dqWG3Y@h<}a%=nIZ diff --git a/src/dev.c b/src/dev.c index f5d5ece6..c8bee183 100644 --- a/src/dev.c +++ b/src/dev.c @@ -476,7 +476,7 @@ BOOL GetDevices(DWORD devnum) const char* bitdefender_label = "Bitdefender Partition"; // Hash table and String Array used to match a Device ID with the parent hub's Device Interface Path htab_table htab_devid = HTAB_EMPTY; - StrArray dev_if_path = STRARRAY_EMPTY; + StrArray dev_if_path = { 0 }; char letter_name[] = " (?:)"; char drive_name[] = "?:\\"; char setting_name[32]; diff --git a/src/drive.c b/src/drive.c index 798db108..8c398ab1 100644 --- a/src/drive.c +++ b/src/drive.c @@ -1944,7 +1944,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys if (buf != NULL) { if (SetFilePointerEx(hPhysical, DriveLayout->PartitionEntry[i].StartingOffset, NULL, FILE_BEGIN) && ReadFile(hPhysical, buf, SelectedDrive.SectorSize, &size, NULL)) { - isUefiNtfs = (strncmp(&buf[0x2B], "UEFI_NTFS", 9) == 0); + isUefiNtfs = (strncmp(&buf[0x2B], "UEFI_NTFS", 9) == 0) || (strncmp(&buf[0x2B], "RUFUS_BOOT", 10) == 0); } free(buf); } diff --git a/src/rufus.h b/src/rufus.h index 401769eb..b86c5757 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -735,7 +735,6 @@ typedef struct { uint32_t Index; // Current array size uint32_t Max; // Maximum array size } StrArray; -#define STRARRAY_EMPTY { NULL, 0, 0 }; extern void StrArrayCreate(StrArray* arr, uint32_t initial_size); extern int32_t StrArrayAdd(StrArray* arr, const char* str, BOOL); extern int32_t StrArrayAddUnique(StrArray* arr, const char* str, BOOL); diff --git a/src/rufus.rc b/src/rufus.rc index 967272f0..b867f998 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 4.14.2319" +CAPTION "Rufus 4.14.2320" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -409,8 +409,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,14,2319,0 - PRODUCTVERSION 4,14,2319,0 + FILEVERSION 4,14,2320,0 + PRODUCTVERSION 4,14,2320,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -428,13 +428,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "4.14.2319" + VALUE "FileVersion", "4.14.2320" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2026 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-4.14.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.14.2319" + VALUE "ProductVersion", "4.14.2320" END END BLOCK "VarFileInfo" diff --git a/src/wue.c b/src/wue.c index 6e8d68c4..9d7d6c0b 100644 --- a/src/wue.c +++ b/src/wue.c @@ -115,8 +115,7 @@ char* CreateUnattendXml(int arch, int flags) TIME_ZONE_INFORMATION tz_info; int i, order; unattend_xml_flags = flags; - StrArray commands = STRARRAY_EMPTY; - StrArrayCreate(&commands, 8); + StrArray commands = { 0 }; if (arch < ARCH_X86_32 || arch > ARCH_ARM_64 || flags == 0) { uprintf("Note: No Windows User Experience options selected"); return NULL; @@ -133,6 +132,7 @@ char* CreateUnattendXml(int arch, int flags) fprintf(fd, "\n"); fprintf(fd, "\n"); + StrArrayCreate(&commands, 8); if (flags & UNATTEND_WINPE_SETUP_MASK) { fprintf(fd, " \n"); fprintf(fd, " Date: Fri, 13 Mar 2026 23:15:27 +0000 Subject: [PATCH 07/82] [wue] add a new 'QoL Enhancements' option * This option disables most of the unwanted crap that Microsoft tries to push onto users by default. * Also make sure the Silent Install option is only enabled if the 'Disable data collection' check box is checked. * Also add a big scary warning for the Silent Install option. --- res/loc/rufus.loc | 7 ++++- src/rufus.c | 19 +++++++------- src/rufus.h | 10 +++++--- src/rufus.rc | 10 ++++---- src/stdlg.c | 13 +++++++--- src/wue.c | 65 ++++++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 99 insertions(+), 25 deletions(-) diff --git a/res/loc/rufus.loc b/res/loc/rufus.loc index 8c04063f..58ffc1f2 100644 --- a/res/loc/rufus.loc +++ b/res/loc/rufus.loc @@ -578,7 +578,7 @@ t MSG_321 "The image you have selected is an ISOHybrid, but its creators have no "copy mode.\nAs a result, DD image writing mode will be enforced." t MSG_322 "Unable to open or read '%s'" t MSG_323 "Apply SkuSiPolicy.p7b on installation (See KB5042562)" -t MSG_324 "⚠SILENTLY⚠ erase disk and install:" +t MSG_324 "QoL Improvements (Don't force Copilot, OneDrive, Outlook, Fast Startup, etc.)" t MSG_325 "Applying Windows customization: %s" t MSG_326 "Applying user options..." t MSG_327 "Windows User Experience" @@ -619,6 +619,11 @@ t MSG_354 "Rufus has found an updated version of the DBX files used to perform U "- Select 'Yes' to connect to the Internet and download this content\n" "- Select 'No' to cancel the operation\n\n" "Note: The files will be downloaded in the application's directory and will be reused automatically if present." +t MSG_355 "⚠SILENTLY⚠ erase disk and install:" +t MSG_356 "You have selected to use the \"silent\" Windows installation option.\n\n" + "This is an advanced option, reserved for people who want to create media that does not prompt the user during Windows installation and therefore UNCONDITIONALLY ERASES the " + "first detected disk on the target system, without asking. If you are not careful, using this option can result in IRREVERSIBLE DATA LOSS!\n\nIf this is not what you want, " + "please select 'No' to go back and uncheck the option.\nOtherwise, if you agree that the whole responsibility for any data loss will be entirely with YOU, select 'Yes'." # The following messages are for the Windows Store listing only and are not used by the application t MSG_900 "Rufus is a utility that helps format and create bootable USB flash drives, such as USB keys/pendrives, memory sticks, etc." t MSG_901 "Official site: %s" diff --git a/src/rufus.c b/src/rufus.c index 790da244..67409f95 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -1503,7 +1503,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param) const char* syslinux = "syslinux"; const char* ldlinux_ext[3] = { "sys", "bss", "c32" }; char tmp[MAX_PATH], tmp2[MAX_PATH], c; - selection_dialog_options_t selection_options = { 0, -1, -1, -1 }; + selection_dialog_options_t selection_options = { 0, -1, -1, -1, -1 }; syslinux_ldlinux_len[0] = 0; syslinux_ldlinux_len[1] = 0; safe_free(grub2_buf); @@ -1684,21 +1684,22 @@ static DWORD WINAPI BootCheckThread(LPVOID param) selection_options.regional_index = _log2(b); MAP_BIT(UNATTEND_DUPLICATE_LOCALE); StrArrayAdd(&options, lmprintf(MSG_331), TRUE); + selection_options.privacy_index = _log2(b); MAP_BIT(UNATTEND_NO_DATA_COLLECTION); if (IS_WINDOWS_11(img_report)) { StrArrayAdd(&options, lmprintf(MSG_335), TRUE); MAP_BIT(UNATTEND_DISABLE_BITLOCKER); - } - if (img_report.win_version.build >= 26200) { - StrArrayAdd(&options, lmprintf(MSG_350), TRUE); - MAP_BIT(UNATTEND_USE_MS2023_BOOTLOADERS); - StrArrayAdd(&options, lmprintf(MSG_323), TRUE); - MAP_BIT(UNATTEND_APPLY_SKUSIPOLICY); - } - if (IS_WINDOWS_11(img_report)) { StrArrayAdd(&options, lmprintf(MSG_324), TRUE); + MAP_BIT(UNATTEND_QOL_ENHANCEMENTS); + StrArrayAdd(&options, lmprintf(MSG_355), TRUE); selection_options.edition_index = _log2(b); MAP_BIT(UNATTEND_SILENT_INSTALL); + if (img_report.win_version.build >= 26200) { + StrArrayAdd(&options, lmprintf(MSG_350), TRUE); + MAP_BIT(UNATTEND_USE_MS2023_BOOTLOADERS); + StrArrayAdd(&options, lmprintf(MSG_323), TRUE); + MAP_BIT(UNATTEND_APPLY_SKUSIPOLICY); + } } if (expert_mode) { StrArrayAdd(&options, lmprintf(MSG_346), TRUE); diff --git a/src/rufus.h b/src/rufus.h index b86c5757..8a730fbf 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -513,6 +513,7 @@ typedef struct { int username_index; int edition_index; int regional_index; + int privacy_index; } selection_dialog_options_t; /* @@ -695,16 +696,17 @@ typedef struct { #define UNATTEND_USE_MS2023_BOOTLOADERS 0x00200 #define UNATTEND_APPLY_SKUSIPOLICY 0x00400 #define UNATTEND_SILENT_INSTALL 0x00800 -#define UNATTEND_FULL_MASK 0x00FFF -#define UNATTEND_DEFAULT_MASK 0x006FF // Mask of values that are persisted +#define UNATTEND_QOL_ENHANCEMENTS 0x01000 +#define UNATTEND_FULL_MASK 0x01FFF +#define UNATTEND_DEFAULT_MASK 0x016FF // Mask of values that are persisted #define UNATTEND_WINDOWS_TO_GO 0x10000 // Special flag for Windows To Go #define UNATTEND_WINPE_SETUP_MASK (UNATTEND_SECUREBOOT_TPM_MINRAM | UNATTEND_SILENT_INSTALL) -#define UNATTEND_SPECIALIZE_DEPLOYMENT_MASK (UNATTEND_NO_ONLINE_ACCOUNT) +#define UNATTEND_SPECIALIZE_DEPLOYMENT_MASK (UNATTEND_NO_ONLINE_ACCOUNT | UNATTEND_QOL_ENHANCEMENTS) #define UNATTEND_OOBE_SHELL_SETUP_MASK (UNATTEND_NO_DATA_COLLECTION | UNATTEND_SET_USER | UNATTEND_DUPLICATE_LOCALE) #define UNATTEND_OOBE_INTERNATIONAL_MASK (UNATTEND_DUPLICATE_LOCALE) #define UNATTEND_OOBE_MASK (UNATTEND_OOBE_SHELL_SETUP_MASK | UNATTEND_OOBE_INTERNATIONAL_MASK | UNATTEND_DISABLE_BITLOCKER | \ - UNATTEND_USE_MS2023_BOOTLOADERS | UNATTEND_APPLY_SKUSIPOLICY) + UNATTEND_USE_MS2023_BOOTLOADERS | UNATTEND_APPLY_SKUSIPOLICY | UNATTEND_QOL_ENHANCEMENTS) #define UNATTEND_OFFLINE_SERVICING_MASK (UNATTEND_OFFLINE_INTERNAL_DRIVES | UNATTEND_FORCE_S_MODE) #define UNATTEND_DEFAULT_SELECTION_MASK (UNATTEND_SECUREBOOT_TPM_MINRAM | UNATTEND_NO_ONLINE_ACCOUNT | UNATTEND_OFFLINE_INTERNAL_DRIVES) diff --git a/src/rufus.rc b/src/rufus.rc index b867f998..7afe85db 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 4.14.2320" +CAPTION "Rufus 4.14.2321" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -409,8 +409,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,14,2320,0 - PRODUCTVERSION 4,14,2320,0 + FILEVERSION 4,14,2321,0 + PRODUCTVERSION 4,14,2321,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -428,13 +428,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "4.14.2320" + VALUE "FileVersion", "4.14.2321" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2026 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-4.14.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.14.2320" + VALUE "ProductVersion", "4.14.2321" END END BLOCK "VarFileInfo" diff --git a/src/stdlg.c b/src/stdlg.c index 38bd7cb3..76fe3193 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -1014,11 +1014,13 @@ static INT_PTR CALLBACK CustomSelectionCallback(HWND hDlg, UINT message, WPARAM case WM_COMMAND: WORD command = LOWORD(wParam); if (command >= IDC_SELECTION_CHOICE1 && command < IDC_SELECTION_CHOICEMAX) { - // Check if the local account name or regional settings checkbox was clicked and enable/disable the silent install option + // Check if local account + regional settings + data collection checkboxes are clicked and enable/disable the silent install option if (selection_options != NULL && selection_options->username_index > 0 && selection_options->edition_index > 0 && selection_options->regional_index > 0 && - (command - IDC_SELECTION_CHOICE1 == selection_options->username_index || command - IDC_SELECTION_CHOICE1 == selection_options->regional_index)) { + (command - IDC_SELECTION_CHOICE1 == selection_options->username_index || command - IDC_SELECTION_CHOICE1 == selection_options->regional_index || + command - IDC_SELECTION_CHOICE1 == selection_options->privacy_index)) { BOOL enable = Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->username_index)) && - Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->regional_index)); + Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->regional_index)) && + Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->privacy_index)); hCtrl = GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->edition_index); if (!enable && IsWindowEnabled(hCtrl)) { silent_install_checked = (Button_GetCheck(hCtrl) == BST_CHECKED); @@ -1031,6 +1033,11 @@ static INT_PTR CALLBACK CustomSelectionCallback(HWND hDlg, UINT message, WPARAM } } else switch (LOWORD(wParam)) { case IDOK: + // Produce a big scary warning if the silent install option was selected + if (selection_options != NULL && selection_options->edition_index >= 0 && + Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + selection_options->edition_index)) && + Notification(MB_YESNO | MB_ICONWARNING, APPLICATION_NAME, lmprintf(MSG_356)) != IDYES) + break; for (r = 0, i = 0, m = 1; i < nDialogItems; i++, m <<= 1) if (Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i)) == BST_CHECKED) r += m; diff --git a/src/wue.c b/src/wue.c index 9d7d6c0b..e9e5f995 100644 --- a/src/wue.c +++ b/src/wue.c @@ -132,7 +132,7 @@ char* CreateUnattendXml(int arch, int flags) fprintf(fd, "\n"); fprintf(fd, "\n"); - StrArrayCreate(&commands, 8); + StrArrayCreate(&commands, 16); if (flags & UNATTEND_WINPE_SETUP_MASK) { fprintf(fd, " \n"); fprintf(fd, "