diff --git a/DOC/BuildVentoyFromSource.txt b/DOC/BuildVentoyFromSource.txt
new file mode 100644
index 00000000000..e25502571e2
--- /dev/null
+++ b/DOC/BuildVentoyFromSource.txt
@@ -0,0 +1,203 @@
+
+==========================================
+1. Compile Enviroment
+==========================================
+ My build envrioment is CentOS 7.8 x86_64. So here I first explain how to create the build environment from scratch.
+ Because Ventoy is based on many open source projects, so the envrioment is important. I suggest you test it on a virtual machine first.
+
+1.1 Install CentOS 7.8
+ I use CentOS-7-x86_64-Everything-2003.iso and select Minimal install
+
+1.2 Install Packages
+ yum install \
+ libXpm net-tools bzip2 wget vim gcc gcc-c++ samba dos2unix glibc-devel glibc.i686 glibc-devel.i686 \
+ mpfr.i686 mpfr-devel.i686 zlib.i686 rsync autogen autoconf automake libtool gettext* bison binutils \
+ flex device-mapper-devel SDL libpciaccess libusb freetype freetype-devel gnu-free-* qemu-* virt-* \
+ libvirt* vte* NetworkManager-bluetooth brlapi fuse-devel dejavu* gnu-efi* pesign shim \
+ iscsi-initiator-utils grub2-tools zip nasm acpica-tools glibc-static zlib-static
+
+
+
+==========================================
+2. Download Source Code
+==========================================
+2.1 Download Ventoy source code from github and decompress it.
+ Next I assume that you have unzipped the code into the /home directory (check /home/Ventoy-master/README.md file for the directory level).
+
+2.2 Download third-part source code
+
+ https://www.fefe.de/dietlibc/dietlibc-0.34.tar.xz ===> /home/Ventoy-master/DOC/dietlibc-0.34.tar.xz
+ https://ftp.gnu.org/gnu/grub/grub-2.04.tar.xz ===> /home/Ventoy-master/GRUB2/grub-2.04.tar.xz
+ https://codeload.github.com/tianocore/edk2/zip/edk2-stable201911 ===> /home/Ventoy-master/EDK2/edk2-edk2-stable201911.zip
+ https://codeload.github.com/relan/exfat/zip/v1.3.0 ===> /home/Ventoy-master/ExFAT/exfat-1.3.0.zip
+ https://gitee.com/mirrors/libfuse/repository/archive/fuse-2.9.9.zip ===> /home/Ventoy-master/ExFAT/mirrors-libfuse-fuse-2.9.9.zip
+ http://ultra-embedded.com/releases/fat_io_lib.zip ===> /home/Ventoy-master/vtoyfat/fat_io_lib/fat_io_lib.zip
+
+
+
+==========================================
+3. All in one script
+==========================================
+ I have made the whole build process in all_in_one.sh, you can run this script to build and pack ventoy.
+ If you want to compile a certain part separately, you can continue to refer to the later chapters of this text.
+
+ cd /home/Ventoy-master/INSTALL
+ sh all_in_one.sh
+
+ It should be noted that, some part of Ventoy has 32bit&64bit version (like 4.9 4.10 4.11 follows)
+ all_in_one.sh only build 64bit version of them, if you want to rebuild the 32bit verison. You should create a 32bit CentOS environment and build them.
+ Fortunately these parts are few modified, you only need to build once or you can directly use the binary I have built.
+
+ Besides, after a fully compile and pack, you can only build the part you modified (for example grub2) and run ventoy_pack.sh to generate the package.
+
+
+
+==========================================
+4. Build every part of Ventoy
+==========================================
+4.1 == Build grub2 ==
+ cd /home/Ventoy-master/GRUB2
+ sh buildgrub.sh
+
+4.2 == Build ipxe.krn ==
+ cd /home/Ventoy-master/IPXE
+ sh buildipxe.sh
+
+4.3 == Build Ventoy2Disk.exe ==
+ Ventoy2Disk.exe is the installer in Windows platform. And it must be built in Windows with Microsoft Visual Studio (2013+).
+ Open /home/Ventoy-master/Ventoy2Disk/Ventoy2Disk.sln with Visual Studio and build it.
+
+4.4 == Build vtoyjump64.exe/vtoyjump32.exe ==
+ vtoyjump64.exe/vtoyjump32.exe is used to mount iso file in windows PE. You should install Microsoft Visual Studio (2013+) to build it.
+ Open /home/Ventoy-master/vtoyjump/vtoyjump.sln with Visual Studio and build it (64&32).
+
+4.5 == Build dmsetup ==
+ Please refer to DMSETUP/build.txt
+
+4.6 == Build ventoy_x64.efi ==
+ cd /home/Ventoy-master/EDK2
+ sh buildedk.sh
+
+4.7 == Build VtoyTool ==
+ cd /home/Ventoy-master/VtoyTool
+ sh build.sh
+
+4.8 == Build vtoyfat ==
+ cd /home/Ventoy-master/vtoyfat/fat_io_lib
+ sh buildlib.sh
+ cd /home/Ventoy-master/vtoyfat
+ sh build.sh
+
+4.9 == Build exfat-util ==
+ cd /home/Ventoy-master/ExFAT
+ sh buidlibfuse.sh
+ sh buidexfat.sh
+
+ After that, copy EXFAT/shared/mkexfatfs ===> /home/Ventoy-master/INSTALL/tool/mkexfatfs_64
+ After that, copy EXFAT/shared/mount.exfat-fuse ===> /home/Ventoy-master/INSTALL/tool/mount.exfat-fuse_64
+
+ Use the same build step to build exfat-util 32bit in a 32bit CentOS system and get mkexfatfs_32 and mount.exfat-fuse_32
+
+4.10 == Build vtoy_fuse_iso_64/vtoy_fuse_iso_32 ==
+ cd /home/Ventoy-master/FUSEISO
+ sh build_libfuse.sh
+ sh build.sh
+
+ Use the same build step to build in a 32bit CentOS system and get vtoy_fuse_iso_32
+
+4.11 == Build unsquashfs_64/unsquashfs_32 ==
+ cd /home/Ventoy-master/SQUASHFS/SRC
+ sh build_lz4.sh
+ sh build_lzma.sh
+ sh build_lzo.sh
+ sh build_zstd.sh
+
+ cd /home/Ventoy-master/SQUASHFS/squashfs-tools-4.4/squashfs-tools
+ sh build.sh
+
+ Use the same build step to build in a 32bit CentOS system and get unsquashfs_32
+
+4.12 == Build vblade_64/vblade_32 ==
+ cd /home/Ventoy-master/VBLADE/vblade-master
+ sh build.sh
+
+4.13 == Build zstdcat ==
+ Please refer to ZSTD/build.txt
+
+4.14 == Build vtoy_gen_uuid ==
+ cd /home/Ventoy-master/GenUUID
+ sh build.sh
+
+4.15 == Build xzminidec ==
+ cd /home/Ventoy-master/xz-embedded-20130513/userspace
+ make -f ventoy_makefile
+ strip --strip-all xzminidec
+
+4.16 == Build iso9660_x64.efi ==
+ This efi driver is from https://github.com/pbatard/efifs
+ Follow all the build instructions in this project. I modified 3 files (the original and modified source are at /home/Ventoy-master/EDK2/efiffs)
+
+
+
+==========================================
+5. Binaries
+==========================================
+ There some binaries in Ventoy install package. These files are downloaded from other open source project's website, such as busybox.
+ Here is the list of the binaries, their SHA-256 and the download urls:
+
+5.1 IMG/cpio/ventoy/tool/lz4cat
+ https://create.stephan-brumme.com/smallz4 smallz4cat-x32-v1.4
+ SHA-256: 13d293ddeedb469f51da41167f79b2cbdb904e681716f6e6191b233dbb162438
+
+5.2 IMG/cpio/ventoy/tool/ar
+ https://busybox.net/downloads/binaries/1.30.0-i686 busybox_AR
+ SHA-256: f29b7d81a983c0c85d22496f4a833c18f2528a1b666eb7d47c93084c1ed66ae0
+
+5.3 IMG/cpio/ventoy/tool/inotifyd
+ https://busybox.net/downloads/binaries/1.30.0-i686 busybox_INOTIFYD
+ SHA-256: 3532162a8695e91a1ed9ddea28b2cb22259a90e93d5d9c4a517b6c36842c686f
+
+5.4 IMG/cpio/ventoy/busybox/tmpsh
+ https://busybox.net/downloads/binaries/1.27.1-i686 busybox_ASH
+ SHA-256: 44a6274bca580c2758ffc173fc76d18bb855b1fe8dcf70efd9ee75cbd57dee97
+
+5.5 IMG/cpio/ventoy/busybox/tmpxz
+ https://busybox.net/downloads/binaries/1.27.1-i686 busybox_XZ
+ SHA-256: f6cdb6293680424c29b89bde0685ca27f455166c9b302cd6082ef90681456291
+
+5.6 INSTALL/tool/xzcat
+ https://busybox.net/downloads/binaries/1.30.0-i686/ busybox_XZCAT
+ SHA-256: 7399db642c2beaf52a16ab5264ffc55cfd1ff5699a524f63e5d48edf84e20f44
+
+5.7 INSTALL/tool/hexdump
+ https://busybox.net/downloads/binaries/1.30.0-i686/ busybox_HEXDUMP
+ SHA-256: cde08b6a2cf5ad914f05203e18e3f7c2ed6060a63604e3d75536f19b55e8e0af
+
+5.8 imdisk
+ download http://www.ltr-data.se/files/imdiskinst.exe and extract it by 7zip.
+
+ INSTALL/ventoy/imdisk/64/imdisk.sys --> sys/amd64/imdisk.sys SHA-256: 6702202220268787e361f5a82dae53362c8e6c6dcd240bb01b44dd77ae0788da
+ INSTALL/ventoy/imdisk/64/imdisk.exe --> cli/amd64/imdisk.exe SHA-256: 9759175380af836869443e5f21ce2e33022125d154bc6b3d1c04dc36b190de04
+ INSTALL/ventoy/imdisk/64/imdisk.cpl --> cpl/amd64/imdisk.cpl SHA-256: aea2ebbea2b073c947263744962af8a3eab025ff4c9d825c543e380e738a4c99
+
+ INSTALL/ventoy/imdisk/32/imdisk.sys --> sys/i386/imdisk.sys SHA-256: a94caec2f71a924d6a914c093ad4b905d7cfdea3f515ed48aaa8c3950b2dc191
+ INSTALL/ventoy/imdisk/32/imdisk.exe --> cli/i386/imdisk.exe SHA-256: 33b53858e2139704cf603b115a3e5e1dfd4daeaaed4d3e03c633f2df3b55dbaa
+ INSTALL/ventoy/imdisk/32/imdisk.cpl --> cpl/i386/imdisk.cpl SHA-256: b781d3e2d286ac8bf548f44e50cbbb3fe78203296e41e4d2e73b407668f88f2d
+
+5.9 INSTALL/ventoy/memdisk
+ https://mirrors.edge.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.gz
+ decompress it and memdisk is at syslinux-6.03/bios/memdisk/memdisk
+ SHA-256: 3f6cd656b8a14109cd3f906fee2dd2e75418f983a5e1bfdb64f44f7765588cbb
+
+
+5.10 UEFIinSecureBoot
+ https://github.com/ValdikSS/Super-UEFIinSecureBoot-Disk/releases Super-UEFIinSecureBoot-Disk_minimal_v3.zip
+ unzip it and get Super-UEFIinSecureBoot-Disk_minimal.img, extract the img by 7zip.
+
+ INSTALL/EFI/BOOT/BOOTX64.EFI --> EFI/BOOT/BOOTX64.EFI SHA-256: 475552c7476ad45e42344eee8b30d44c264d200ac2468428aa86fc8795fb6e34
+ INSTALL/EFI/BOOT/grubx64.efi --> EFI/BOOT/grubx64.efi SHA-256: 25d858157349dc52fa70f3cdf5c62fe1e0bae37ddfc3a6b6528af9a3c745775f
+ INSTALL/EFI/BOOT/MokManager.efi --> EFI/BOOT/MokManager.efi SHA-256: 3bf1f46cee0832355c7dd1dba880dea9bcaa78cc44375a1559d43bc9db18933b
+
+
+
+
\ No newline at end of file
diff --git a/DOC/installdietlibc.sh b/DOC/installdietlibc.sh
new file mode 100644
index 00000000000..ac8350b4391
--- /dev/null
+++ b/DOC/installdietlibc.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+if ! [ -f ./dietlibc-0.34.tar.xz ]; then
+ echo "No dietlibc-0.34.tar.xz found ..."
+ exit 1
+fi
+
+rm -rf /opt/diet32
+rm -rf /opt/diet64
+
+tar -xvf dietlibc-0.34.tar.xz
+cd dietlibc-0.34
+
+prefix=/opt/diet64 make -j 4
+prefix=/opt/diet64 make install 2>/dev/null
+
+cd ..
+rm -rf dietlibc-0.34
+
+tar -xvf dietlibc-0.34.tar.xz
+cd dietlibc-0.34
+
+sed "s/MYARCH:=.*/MYARCH=i386/" -i Makefile
+sed "s/CC=gcc/CC=gcc -m32/" -i Makefile
+
+prefix=/opt/diet32 make -j 4
+prefix=/opt/diet32 make install 2>/dev/null
+
+cd ..
+rm -rf dietlibc-0.34
+
+echo ""
+echo " ================ success ==============="
+echo ""
diff --git a/EDK2/README.txt b/EDK2/README.txt
deleted file mode 100644
index 3d8022358f9..00000000000
--- a/EDK2/README.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-
-========== About Source Code =============
-Ventoy add an UEFI application module in MdeModulePkg, so I only put the module's source code here.
-You can download the EDK2 code from https://github.com/tianocore/edk2 and merge the code together.
-
-
-========== Build =============
-Follow the EDK2's build instructions
diff --git a/EDK2/buildedk.sh b/EDK2/buildedk.sh
new file mode 100644
index 00000000000..bc99afc8750
--- /dev/null
+++ b/EDK2/buildedk.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+rm -rf edk2-edk2-stable201911
+
+unzip edk2-edk2-stable201911.zip
+
+/bin/cp -a ./edk2_mod/edk2-edk2-stable201911 ./
+
+cd edk2-edk2-stable201911
+
+VTEFI_PATH=Build/MdeModule/RELEASE_GCC48/X64/MdeModulePkg/Application/Ventoy/Ventoy/OUTPUT/Ventoy.efi
+DST_PATH=../../INSTALL/ventoy/ventoy_x64.efi
+
+rm -f $VTEFI_PATH
+rm -f $DST_PATH
+
+make -j 4 -C BaseTools/
+
+source ./edksetup.sh
+build -p MdeModulePkg/MdeModulePkg.dsc -a X64 -b RELEASE -t GCC48
+
+if [ -e $VTEFI_PATH ]; then
+ echo -e '\n\n====================== SUCCESS ========================\n\n'
+ cp -a $VTEFI_PATH $DST_PATH
+ cd ..
+else
+ echo -e '\n\n====================== FAILED ========================\n\n'
+ cd ..
+ exit 1
+fi
+
+
+
diff --git a/EDK2/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.c b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.c
similarity index 100%
rename from EDK2/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.c
rename to EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.c
diff --git a/EDK2/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.h b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.h
similarity index 100%
rename from EDK2/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.h
rename to EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.h
diff --git a/EDK2/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.inf b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.inf
similarity index 100%
rename from EDK2/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.inf
rename to EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.inf
diff --git a/EDK2/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/VentoyDebug.c b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/VentoyDebug.c
similarity index 100%
rename from EDK2/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/VentoyDebug.c
rename to EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/VentoyDebug.c
diff --git a/EDK2/edk2-edk2-stable201911/MdeModulePkg/MdeModulePkg.dsc b/EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/MdeModulePkg.dsc
similarity index 100%
rename from EDK2/edk2-edk2-stable201911/MdeModulePkg/MdeModulePkg.dsc
rename to EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/MdeModulePkg.dsc
diff --git a/EDK2/efiffs/mod/grub/grub-core/fs/iso9660.c b/EDK2/efiffs/mod/grub/grub-core/fs/iso9660.c
new file mode 100644
index 00000000000..b691cd6dcd4
--- /dev/null
+++ b/EDK2/efiffs/mod/grub/grub-core/fs/iso9660.c
@@ -0,0 +1,1141 @@
+/* iso9660.c - iso9660 implementation with extensions:
+ SUSP, Rock Ridge. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define GRUB_ISO9660_FSTYPE_DIR 0040000
+#define GRUB_ISO9660_FSTYPE_REG 0100000
+#define GRUB_ISO9660_FSTYPE_SYMLINK 0120000
+#define GRUB_ISO9660_FSTYPE_MASK 0170000
+
+#define GRUB_ISO9660_LOG2_BLKSZ 2
+#define GRUB_ISO9660_BLKSZ 2048
+
+#define GRUB_ISO9660_RR_DOT 2
+#define GRUB_ISO9660_RR_DOTDOT 4
+
+#define GRUB_ISO9660_VOLDESC_BOOT 0
+#define GRUB_ISO9660_VOLDESC_PRIMARY 1
+#define GRUB_ISO9660_VOLDESC_SUPP 2
+#define GRUB_ISO9660_VOLDESC_PART 3
+#define GRUB_ISO9660_VOLDESC_END 255
+
+extern int g_fs_name_nocase;
+/* The head of a volume descriptor. */
+PRAGMA_BEGIN_PACKED
+struct grub_iso9660_voldesc
+{
+ grub_uint8_t type;
+ grub_uint8_t magic[5];
+ grub_uint8_t version;
+} GRUB_PACKED;
+
+struct grub_iso9660_date2
+{
+ grub_uint8_t year;
+ grub_uint8_t month;
+ grub_uint8_t day;
+ grub_uint8_t hour;
+ grub_uint8_t minute;
+ grub_uint8_t second;
+ grub_uint8_t offset;
+} GRUB_PACKED;
+
+/* A directory entry. */
+struct grub_iso9660_dir
+{
+ grub_uint8_t len;
+ grub_uint8_t ext_sectors;
+ grub_uint32_t first_sector;
+ grub_uint32_t first_sector_be;
+ grub_uint32_t size;
+ grub_uint32_t size_be;
+ struct grub_iso9660_date2 mtime;
+ grub_uint8_t flags;
+ grub_uint8_t unused2[6];
+#define MAX_NAMELEN 255
+ grub_uint8_t namelen;
+} GRUB_PACKED;
+
+struct grub_iso9660_date
+{
+ grub_uint8_t year[4];
+ grub_uint8_t month[2];
+ grub_uint8_t day[2];
+ grub_uint8_t hour[2];
+ grub_uint8_t minute[2];
+ grub_uint8_t second[2];
+ grub_uint8_t hundredth[2];
+ grub_uint8_t offset;
+} GRUB_PACKED;
+
+/* The primary volume descriptor. Only little endian is used. */
+struct grub_iso9660_primary_voldesc
+{
+ struct grub_iso9660_voldesc voldesc;
+ grub_uint8_t unused1[33];
+ grub_uint8_t volname[32];
+ grub_uint8_t unused2[16];
+ grub_uint8_t escape[32];
+ grub_uint8_t unused3[12];
+ grub_uint32_t path_table_size;
+ grub_uint8_t unused4[4];
+ grub_uint32_t path_table;
+ grub_uint8_t unused5[12];
+ struct grub_iso9660_dir rootdir;
+ grub_uint8_t unused6[624];
+ struct grub_iso9660_date created;
+ struct grub_iso9660_date modified;
+} GRUB_PACKED;
+
+/* A single entry in the path table. */
+struct grub_iso9660_path
+{
+ grub_uint8_t len;
+ grub_uint8_t sectors;
+ grub_uint32_t first_sector;
+ grub_uint16_t parentdir;
+ grub_uint8_t name[0];
+} GRUB_PACKED;
+
+/* An entry in the System Usage area of the directory entry. */
+struct grub_iso9660_susp_entry
+{
+ grub_uint8_t sig[2];
+ grub_uint8_t len;
+/*! MSVC compilers cannot handle a zero sized array in the middle
+ of a struct, and grub_iso9660_susp_entry is reused within
+ grub_iso9660_susp_ce. Therefore, instead of defining:
+ grub_uint8_t version;
+ grub_uint8_t data[];
+ we leverage the fact that these attributes are the same size
+ and use an union. The only gotcha is that the actual
+ payload of u.data[] starts at 1, not 0. */
+ union {
+ grub_uint8_t version;
+ grub_uint8_t data[1];
+ } u;
+} GRUB_PACKED;
+
+/* The CE entry. This is used to describe the next block where data
+ can be found. */
+struct grub_iso9660_susp_ce
+{
+ struct grub_iso9660_susp_entry entry;
+ grub_uint32_t blk;
+ grub_uint32_t blk_be;
+ grub_uint32_t off;
+ grub_uint32_t off_be;
+ grub_uint32_t len;
+ grub_uint32_t len_be;
+} GRUB_PACKED;
+PRAGMA_END_PACKED
+
+struct grub_iso9660_data
+{
+ struct grub_iso9660_primary_voldesc voldesc;
+ grub_disk_t disk;
+ int rockridge;
+ int susp_skip;
+ int joliet;
+ struct grub_fshelp_node *node;
+};
+
+struct grub_fshelp_node
+{
+ struct grub_iso9660_data *data;
+ grub_size_t have_dirents, alloc_dirents;
+ int have_symlink;
+ struct grub_iso9660_dir dirents[8];
+ char symlink[0];
+};
+
+enum
+ {
+ FLAG_TYPE_PLAIN = 0,
+ FLAG_TYPE_DIR = 2,
+ FLAG_TYPE = 3,
+ FLAG_MORE_EXTENTS = 0x80
+ };
+
+static grub_dl_t my_mod;
+
+
+static grub_err_t
+iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int32_t *nix)
+{
+ struct grub_datetime datetime;
+
+ if (! i->year[0] && ! i->year[1]
+ && ! i->year[2] && ! i->year[3]
+ && ! i->month[0] && ! i->month[1]
+ && ! i->day[0] && ! i->day[1]
+ && ! i->hour[0] && ! i->hour[1]
+ && ! i->minute[0] && ! i->minute[1]
+ && ! i->second[0] && ! i->second[1]
+ && ! i->hundredth[0] && ! i->hundredth[1])
+ return grub_error (GRUB_ERR_BAD_NUMBER, "empty date");
+ datetime.year = (i->year[0] - '0') * 1000 + (i->year[1] - '0') * 100
+ + (i->year[2] - '0') * 10 + (i->year[3] - '0');
+ datetime.month = (i->month[0] - '0') * 10 + (i->month[1] - '0');
+ datetime.day = (i->day[0] - '0') * 10 + (i->day[1] - '0');
+ datetime.hour = (i->hour[0] - '0') * 10 + (i->hour[1] - '0');
+ datetime.minute = (i->minute[0] - '0') * 10 + (i->minute[1] - '0');
+ datetime.second = (i->second[0] - '0') * 10 + (i->second[1] - '0');
+
+ if (!grub_datetime2unixtime (&datetime, nix))
+ return grub_error (GRUB_ERR_BAD_NUMBER, "incorrect date");
+ *nix -= i->offset * 60 * 15;
+ return GRUB_ERR_NONE;
+}
+
+static int
+iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int32_t *nix)
+{
+ struct grub_datetime datetime;
+
+ datetime.year = i->year + 1900;
+ datetime.month = i->month;
+ datetime.day = i->day;
+ datetime.hour = i->hour;
+ datetime.minute = i->minute;
+ datetime.second = i->second;
+
+ if (!grub_datetime2unixtime (&datetime, nix))
+ return 0;
+ *nix -= i->offset * 60 * 15;
+ return 1;
+}
+
+static grub_err_t
+read_node (grub_fshelp_node_t node, grub_off_t off, grub_size_t len, char *buf)
+{
+ grub_size_t i = 0;
+
+ while (len > 0)
+ {
+ grub_size_t toread;
+ grub_err_t err;
+ while (i < node->have_dirents
+ && off >= grub_le_to_cpu32 (node->dirents[i].size))
+ {
+ off -= grub_le_to_cpu32 (node->dirents[i].size);
+ i++;
+ }
+ if (i == node->have_dirents)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "read out of range");
+ toread = grub_le_to_cpu32 (node->dirents[i].size);
+ if (toread > len)
+ toread = len;
+ err = grub_disk_read (node->data->disk,
+ ((grub_disk_addr_t) grub_le_to_cpu32 (node->dirents[i].first_sector)) << GRUB_ISO9660_LOG2_BLKSZ,
+ off, toread, buf);
+ if (err)
+ return err;
+ len -= toread;
+ off += toread;
+ buf += toread;
+ }
+ return GRUB_ERR_NONE;
+}
+
+/* Iterate over the susp entries, starting with block SUA_BLOCK on the
+ offset SUA_POS with a size of SUA_SIZE bytes. Hook is called for
+ every entry. */
+static grub_err_t
+grub_iso9660_susp_iterate (grub_fshelp_node_t node, grub_off_t off,
+ grub_ssize_t sua_size,
+ grub_err_t (*hook)
+ (struct grub_iso9660_susp_entry *entry, void *hook_arg),
+ void *hook_arg)
+{
+ char *sua;
+ struct grub_iso9660_susp_entry *entry;
+ grub_err_t err;
+
+ if (sua_size <= 0)
+ return GRUB_ERR_NONE;
+
+ sua = grub_malloc (sua_size);
+ if (!sua)
+ return grub_errno;
+
+ /* Load a part of the System Usage Area. */
+ err = read_node (node, off, sua_size, sua);
+ if (err)
+ return err;
+
+ for (entry = (struct grub_iso9660_susp_entry *) sua; (char *) entry < (char *) sua + sua_size - 1 && entry->len > 0;
+ entry = (struct grub_iso9660_susp_entry *)
+ ((char *) entry + entry->len))
+ {
+ /* The last entry. */
+ if (grub_strncmp ((char *) entry->sig, "ST", 2) == 0)
+ break;
+
+ /* Additional entries are stored elsewhere. */
+ if (grub_strncmp ((char *) entry->sig, "CE", 2) == 0)
+ {
+ struct grub_iso9660_susp_ce *ce;
+ grub_disk_addr_t ce_block;
+
+ ce = (struct grub_iso9660_susp_ce *) entry;
+ sua_size = grub_le_to_cpu32 (ce->len);
+ off = grub_le_to_cpu32 (ce->off);
+ ce_block = grub_le_to_cpu32 (ce->blk) << GRUB_ISO9660_LOG2_BLKSZ;
+
+ grub_free (sua);
+ sua = grub_malloc (sua_size);
+ if (!sua)
+ return grub_errno;
+
+ /* Load a part of the System Usage Area. */
+ err = grub_disk_read (node->data->disk, ce_block, off,
+ sua_size, sua);
+ if (err)
+ return err;
+
+ entry = (struct grub_iso9660_susp_entry *) sua;
+ }
+
+ if (hook (entry, hook_arg))
+ {
+ grub_free (sua);
+ return 0;
+ }
+ }
+
+ grub_free (sua);
+ return 0;
+}
+
+static char *
+grub_iso9660_convert_string (grub_uint8_t *us, int len)
+{
+ char *p;
+ int i;
+ grub_uint16_t t[MAX_NAMELEN / 2 + 1];
+
+ p = grub_malloc (len * GRUB_MAX_UTF8_PER_UTF16 + 1);
+ if (! p)
+ return NULL;
+
+ for (i=0; isig, "ER", 2) == 0)
+ {
+ data->rockridge = 1;
+ return 1;
+ }
+ return 0;
+}
+
+static grub_err_t
+set_rockridge (struct grub_iso9660_data *data)
+{
+ int sua_pos;
+ int sua_size;
+ char *sua;
+ struct grub_iso9660_dir rootdir;
+ struct grub_iso9660_susp_entry *entry;
+
+ data->rockridge = 0;
+
+ /* Read the system use area and test it to see if SUSP is
+ supported. */
+ if (grub_disk_read (data->disk,
+ (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
+ << GRUB_ISO9660_LOG2_BLKSZ), 0,
+ sizeof (rootdir), (char *) &rootdir))
+ return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
+
+ sua_pos = (sizeof (rootdir) + rootdir.namelen
+ + (rootdir.namelen % 2) - 1);
+ sua_size = rootdir.len - sua_pos;
+
+ if (!sua_size)
+ return GRUB_ERR_NONE;
+
+ sua = grub_malloc (sua_size);
+ if (! sua)
+ return grub_errno;
+
+ if (grub_disk_read (data->disk,
+ (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
+ << GRUB_ISO9660_LOG2_BLKSZ), sua_pos,
+ sua_size, sua))
+ {
+ grub_free (sua);
+ return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
+ }
+
+ entry = (struct grub_iso9660_susp_entry *) sua;
+
+ /* Test if the SUSP protocol is used on this filesystem. */
+ if (grub_strncmp ((char *) entry->sig, "SP", 2) == 0)
+ {
+ struct grub_fshelp_node rootnode;
+
+ rootnode.data = data;
+ rootnode.alloc_dirents = ARRAY_SIZE (rootnode.dirents);
+ rootnode.have_dirents = 1;
+ rootnode.have_symlink = 0;
+ rootnode.dirents[0] = data->voldesc.rootdir;
+
+ /* The 2nd data byte stored how many bytes are skipped every time
+ to get to the SUA (System Usage Area). */
+ data->susp_skip = entry->u.data[1 + 2];
+ entry = (struct grub_iso9660_susp_entry *) ((char *) entry + entry->len);
+
+ /* Iterate over the entries in the SUA area to detect
+ extensions. */
+ if (grub_iso9660_susp_iterate (&rootnode,
+ sua_pos, sua_size, susp_iterate_set_rockridge,
+ data))
+ {
+ grub_free (sua);
+ return grub_errno;
+ }
+ }
+ grub_free (sua);
+ return GRUB_ERR_NONE;
+}
+
+static struct grub_iso9660_data *
+grub_iso9660_mount (grub_disk_t disk)
+{
+ struct grub_iso9660_data *data = 0;
+ struct grub_iso9660_primary_voldesc voldesc;
+ int block;
+
+ data = grub_zalloc (sizeof (struct grub_iso9660_data));
+ if (! data)
+ return 0;
+
+ data->disk = disk;
+
+ block = 16;
+ do
+ {
+ int copy_voldesc = 0;
+
+ /* Read the superblock. */
+ if (grub_disk_read (disk, block << GRUB_ISO9660_LOG2_BLKSZ, 0,
+ sizeof (struct grub_iso9660_primary_voldesc),
+ (char *) &voldesc))
+ {
+ grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
+ goto fail;
+ }
+
+ if (grub_strncmp ((char *) voldesc.voldesc.magic, "CD001", 5) != 0)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
+ goto fail;
+ }
+
+ if (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_PRIMARY)
+ copy_voldesc = 1;
+ else if (!data->rockridge
+ && (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_SUPP)
+ && (voldesc.escape[0] == 0x25) && (voldesc.escape[1] == 0x2f)
+ &&
+ ((voldesc.escape[2] == 0x40) || /* UCS-2 Level 1. */
+ (voldesc.escape[2] == 0x43) || /* UCS-2 Level 2. */
+ (voldesc.escape[2] == 0x45))) /* UCS-2 Level 3. */
+ {
+ copy_voldesc = 1;
+ data->joliet = 1;
+ }
+
+ if (copy_voldesc)
+ {
+ grub_memcpy((char *) &data->voldesc, (char *) &voldesc,
+ sizeof (struct grub_iso9660_primary_voldesc));
+ if (set_rockridge (data))
+ goto fail;
+ }
+
+ block++;
+ } while (voldesc.voldesc.type != GRUB_ISO9660_VOLDESC_END);
+
+ return data;
+
+ fail:
+ grub_free (data);
+ return 0;
+}
+
+
+static char *
+grub_iso9660_read_symlink (grub_fshelp_node_t node)
+{
+ return node->have_symlink
+ ? grub_strdup (node->symlink
+ + (node->have_dirents) * sizeof (node->dirents[0])
+ - sizeof (node->dirents)) : grub_strdup ("");
+}
+
+static grub_off_t
+get_node_size (grub_fshelp_node_t node)
+{
+ grub_off_t ret = 0;
+ grub_size_t i;
+
+ for (i = 0; i < node->have_dirents; i++)
+ ret += grub_le_to_cpu32 (node->dirents[i].size);
+ return ret;
+}
+
+struct iterate_dir_ctx
+{
+ char *filename;
+ int filename_alloc;
+ enum grub_fshelp_filetype type;
+ char *symlink;
+ int was_continue;
+};
+
+ /* Extend the symlink. */
+static void
+add_part (struct iterate_dir_ctx *ctx,
+ const char *part,
+ int len2)
+{
+ int size = ctx->symlink ? grub_strlen (ctx->symlink) : 0;
+
+ ctx->symlink = grub_realloc (ctx->symlink, size + len2 + 1);
+ if (! ctx->symlink)
+ return;
+
+ grub_memcpy (ctx->symlink + size, part, len2);
+ ctx->symlink[size + len2] = 0;
+}
+
+static grub_err_t
+susp_iterate_dir (struct grub_iso9660_susp_entry *entry,
+ void *_ctx)
+{
+ struct iterate_dir_ctx *ctx = _ctx;
+
+ /* The filename in the rock ridge entry. */
+ if (grub_strncmp ("NM", (char *) entry->sig, 2) == 0)
+ {
+ /* The flags are stored at the data position 0, here the
+ filename type is stored. */
+ /* FIXME: Fix this slightly improper cast. */
+ if (entry->u.data[1 + 0] & GRUB_ISO9660_RR_DOT)
+ ctx->filename = (char *) ".";
+ else if (entry->u.data[1 + 0] & GRUB_ISO9660_RR_DOTDOT)
+ ctx->filename = (char *) "..";
+ else if (entry->len >= 5)
+ {
+ grub_size_t off = 0, csize = 1;
+ char *old;
+ csize = entry->len - 5;
+ old = ctx->filename;
+ if (ctx->filename_alloc)
+ {
+ off = grub_strlen (ctx->filename);
+ ctx->filename = grub_realloc (ctx->filename, csize + off + 1);
+ }
+ else
+ {
+ off = 0;
+ ctx->filename = grub_zalloc (csize + 1);
+ }
+ if (!ctx->filename)
+ {
+ ctx->filename = old;
+ return grub_errno;
+ }
+ ctx->filename_alloc = 1;
+ grub_memcpy (ctx->filename + off, (char *) &entry->u.data[1 + 1], csize);
+ ctx->filename[off + csize] = '\0';
+ }
+ }
+ /* The mode information (st_mode). */
+ else if (grub_strncmp ((char *) entry->sig, "PX", 2) == 0)
+ {
+ /* At position 0 of the PX record the st_mode information is
+ stored (little-endian). */
+ grub_uint32_t mode = ((entry->u.data[1 + 0] + (entry->u.data[1 + 1] << 8))
+ & GRUB_ISO9660_FSTYPE_MASK);
+
+ switch (mode)
+ {
+ case GRUB_ISO9660_FSTYPE_DIR:
+ ctx->type = GRUB_FSHELP_DIR;
+ break;
+ case GRUB_ISO9660_FSTYPE_REG:
+ ctx->type = GRUB_FSHELP_REG;
+ break;
+ case GRUB_ISO9660_FSTYPE_SYMLINK:
+ ctx->type = GRUB_FSHELP_SYMLINK;
+ break;
+ default:
+ ctx->type = GRUB_FSHELP_UNKNOWN;
+ }
+ }
+ else if (grub_strncmp ("SL", (char *) entry->sig, 2) == 0)
+ {
+ unsigned int pos = 1;
+
+ /* The symlink is not stored as a POSIX symlink, translate it. */
+ while (pos + sizeof (*entry) < entry->len)
+ {
+ /* The current position is the `Component Flag'. */
+ switch (entry->u.data[1 + pos] & 30)
+ {
+ case 0:
+ {
+ /* The data on pos + 2 is the actual data, pos + 1
+ is the length. Both are part of the `Component
+ Record'. */
+ if (ctx->symlink && !ctx->was_continue)
+ add_part (ctx, "/", 1);
+ add_part (ctx, (char *) &entry->u.data[1 + pos + 2],
+ entry->u.data[1 + pos + 1]);
+ ctx->was_continue = (entry->u.data[1 + pos] & 1);
+ break;
+ }
+
+ case 2:
+ add_part (ctx, "./", 2);
+ break;
+
+ case 4:
+ add_part (ctx, "../", 3);
+ break;
+
+ case 8:
+ add_part (ctx, "/", 1);
+ break;
+ }
+ /* In pos + 1 the length of the `Component Record' is
+ stored. */
+ pos += entry->u.data[1 + pos + 1] + 2;
+ }
+
+ /* Check if `grub_realloc' failed. */
+ if (grub_errno)
+ return grub_errno;
+ }
+
+ return 0;
+}
+
+static int
+grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
+ grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
+{
+ struct grub_iso9660_dir dirent;
+ grub_off_t offset = 0;
+ grub_off_t len;
+ struct iterate_dir_ctx ctx;
+
+ len = get_node_size (dir);
+
+ for (; offset < len; offset += dirent.len)
+ {
+ ctx.symlink = 0;
+ ctx.was_continue = 0;
+
+ if (read_node (dir, offset, sizeof (dirent), (char *) &dirent))
+ return 0;
+
+ /* The end of the block, skip to the next one. */
+ if (!dirent.len)
+ {
+ offset = (offset / GRUB_ISO9660_BLKSZ + 1) * GRUB_ISO9660_BLKSZ;
+ continue;
+ }
+
+ {
+ char name[MAX_NAMELEN + 1];
+ int nameoffset = offset + sizeof (dirent);
+ struct grub_fshelp_node *node;
+ int sua_off = (sizeof (dirent) + dirent.namelen + 1
+ - (dirent.namelen % 2));
+ int sua_size = dirent.len - sua_off;
+
+ sua_off += offset + dir->data->susp_skip;
+
+ ctx.filename = 0;
+ ctx.filename_alloc = 0;
+ ctx.type = GRUB_FSHELP_UNKNOWN;
+
+ if (dir->data->rockridge
+ && grub_iso9660_susp_iterate (dir, sua_off, sua_size,
+ susp_iterate_dir, &ctx))
+ return 0;
+
+ /* Read the name. */
+ if (read_node (dir, nameoffset, dirent.namelen, (char *) name))
+ return 0;
+
+ node = grub_malloc (sizeof (struct grub_fshelp_node));
+ if (!node)
+ return 0;
+
+ node->alloc_dirents = ARRAY_SIZE (node->dirents);
+ node->have_dirents = 1;
+
+ /* Setup a new node. */
+ node->data = dir->data;
+ node->have_symlink = 0;
+
+ /* If the filetype was not stored using rockridge, use
+ whatever is stored in the iso9660 filesystem. */
+ if (ctx.type == GRUB_FSHELP_UNKNOWN)
+ {
+ if ((dirent.flags & FLAG_TYPE) == FLAG_TYPE_DIR)
+ ctx.type = GRUB_FSHELP_DIR;
+ else
+ ctx.type = GRUB_FSHELP_REG;
+ }
+
+ /* . and .. */
+ if (!ctx.filename && dirent.namelen == 1 && name[0] == 0)
+ ctx.filename = (char *) ".";
+
+ if (!ctx.filename && dirent.namelen == 1 && name[0] == 1)
+ ctx.filename = (char *) "..";
+
+ if (g_fs_name_nocase)
+ ctx.type |= GRUB_FSHELP_CASE_INSENSITIVE;
+
+ /* The filename was not stored in a rock ridge entry. Read it
+ from the iso9660 filesystem. */
+ if (!dir->data->joliet && !ctx.filename)
+ {
+ char *ptr;
+ name[dirent.namelen] = '\0';
+ ctx.filename = grub_strrchr (name, ';');
+ if (ctx.filename)
+ *ctx.filename = '\0';
+ /* ISO9660 names are not case-preserving. */
+ ctx.type |= GRUB_FSHELP_CASE_INSENSITIVE;
+ for (ptr = name; *ptr; ptr++)
+ *ptr = grub_tolower (*ptr);
+ if (ptr != name && *(ptr - 1) == '.')
+ *(ptr - 1) = 0;
+ ctx.filename = name;
+ }
+
+ if (dir->data->joliet && !ctx.filename)
+ {
+ char *semicolon;
+
+ ctx.filename = grub_iso9660_convert_string
+ ((grub_uint8_t *) name, dirent.namelen >> 1);
+
+ semicolon = grub_strrchr (ctx.filename, ';');
+ if (semicolon)
+ *semicolon = '\0';
+
+ ctx.filename_alloc = 1;
+ }
+
+ node->dirents[0] = dirent;
+ while (dirent.flags & FLAG_MORE_EXTENTS)
+ {
+ offset += dirent.len;
+ if (read_node (dir, offset, sizeof (dirent), (char *) &dirent))
+ {
+ if (ctx.filename_alloc)
+ grub_free (ctx.filename);
+ grub_free (node);
+ return 0;
+ }
+ if (node->have_dirents >= node->alloc_dirents)
+ {
+ struct grub_fshelp_node *new_node;
+ node->alloc_dirents *= 2;
+ new_node = grub_realloc (node,
+ sizeof (struct grub_fshelp_node)
+ + ((node->alloc_dirents
+ - ARRAY_SIZE (node->dirents))
+ * sizeof (node->dirents[0])));
+ if (!new_node)
+ {
+ if (ctx.filename_alloc)
+ grub_free (ctx.filename);
+ grub_free (node);
+ return 0;
+ }
+ node = new_node;
+ }
+ node->dirents[node->have_dirents++] = dirent;
+ }
+ if (ctx.symlink)
+ {
+ if ((node->alloc_dirents - node->have_dirents)
+ * sizeof (node->dirents[0]) < grub_strlen (ctx.symlink) + 1)
+ {
+ struct grub_fshelp_node *new_node;
+ new_node = grub_realloc (node,
+ sizeof (struct grub_fshelp_node)
+ + ((node->alloc_dirents
+ - ARRAY_SIZE (node->dirents))
+ * sizeof (node->dirents[0]))
+ + grub_strlen (ctx.symlink) + 1);
+ if (!new_node)
+ {
+ if (ctx.filename_alloc)
+ grub_free (ctx.filename);
+ grub_free (node);
+ return 0;
+ }
+ node = new_node;
+ }
+ node->have_symlink = 1;
+ grub_strcpy (node->symlink
+ + node->have_dirents * sizeof (node->dirents[0])
+ - sizeof (node->dirents), ctx.symlink);
+ grub_free (ctx.symlink);
+ ctx.symlink = 0;
+ ctx.was_continue = 0;
+ }
+ if (hook (ctx.filename, ctx.type, node, hook_data))
+ {
+ if (ctx.filename_alloc)
+ grub_free (ctx.filename);
+ return 1;
+ }
+ if (ctx.filename_alloc)
+ grub_free (ctx.filename);
+ }
+ }
+
+ return 0;
+}
+
+
+
+/* Context for grub_iso9660_dir. */
+struct grub_iso9660_dir_ctx
+{
+ grub_fs_dir_hook_t hook;
+ void *hook_data;
+};
+
+/* Helper for grub_iso9660_dir. */
+static int
+grub_iso9660_dir_iter (const char *filename,
+ enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node, void *data)
+{
+ struct grub_iso9660_dir_ctx *ctx = data;
+ struct grub_dirhook_info info;
+
+ grub_memset (&info, 0, sizeof (info));
+ info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+ info.mtimeset = !!iso9660_to_unixtime2 (&node->dirents[0].mtime, &info.mtime);
+
+ grub_free (node);
+ return ctx->hook (filename, &info, ctx->hook_data);
+}
+
+static grub_err_t
+grub_iso9660_dir (grub_device_t device, const char *path,
+ grub_fs_dir_hook_t hook, void *hook_data)
+{
+ struct grub_iso9660_dir_ctx ctx = { hook, hook_data };
+ struct grub_iso9660_data *data = 0;
+ struct grub_fshelp_node rootnode;
+ struct grub_fshelp_node *foundnode;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_iso9660_mount (device->disk);
+ if (! data)
+ goto fail;
+
+ rootnode.data = data;
+ rootnode.alloc_dirents = 0;
+ rootnode.have_dirents = 1;
+ rootnode.have_symlink = 0;
+ rootnode.dirents[0] = data->voldesc.rootdir;
+
+ /* Use the fshelp function to traverse the path. */
+ if (grub_fshelp_find_file (path, &rootnode,
+ &foundnode,
+ grub_iso9660_iterate_dir,
+ grub_iso9660_read_symlink,
+ GRUB_FSHELP_DIR))
+ goto fail;
+
+ /* List the files in the directory. */
+ grub_iso9660_iterate_dir (foundnode, grub_iso9660_dir_iter, &ctx);
+
+ if (foundnode != &rootnode)
+ grub_free (foundnode);
+
+ fail:
+ grub_free (data);
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+
+/* Open a file named NAME and initialize FILE. */
+static grub_err_t
+grub_iso9660_open (struct grub_file *file, const char *name)
+{
+ struct grub_iso9660_data *data;
+ struct grub_fshelp_node rootnode;
+ struct grub_fshelp_node *foundnode;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_iso9660_mount (file->device->disk);
+ if (!data)
+ goto fail;
+
+ rootnode.data = data;
+ rootnode.alloc_dirents = 0;
+ rootnode.have_dirents = 1;
+ rootnode.have_symlink = 0;
+ rootnode.dirents[0] = data->voldesc.rootdir;
+
+ /* Use the fshelp function to traverse the path. */
+ if (grub_fshelp_find_file (name, &rootnode,
+ &foundnode,
+ grub_iso9660_iterate_dir,
+ grub_iso9660_read_symlink,
+ GRUB_FSHELP_REG))
+ goto fail;
+
+ data->node = foundnode;
+ file->data = data;
+ file->size = get_node_size (foundnode);
+ file->offset = 0;
+
+ return 0;
+
+ fail:
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+
+static grub_ssize_t
+grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len)
+{
+ struct grub_iso9660_data *data =
+ (struct grub_iso9660_data *) file->data;
+ grub_err_t err;
+
+ /* XXX: The file is stored in as a single extent. */
+ data->disk->read_hook = file->read_hook;
+ data->disk->read_hook_data = file->read_hook_data;
+ err = read_node (data->node, file->offset, len, buf);
+ data->disk->read_hook = NULL;
+
+ if (err || grub_errno)
+ return -1;
+
+ return len;
+}
+
+
+static grub_err_t
+grub_iso9660_close (grub_file_t file)
+{
+ struct grub_iso9660_data *data =
+ (struct grub_iso9660_data *) file->data;
+ grub_free (data->node);
+ grub_free (data);
+
+ grub_dl_unref (my_mod);
+
+ return GRUB_ERR_NONE;
+}
+
+
+static grub_err_t
+grub_iso9660_label (grub_device_t device, char **label)
+{
+ struct grub_iso9660_data *data;
+ data = grub_iso9660_mount (device->disk);
+
+ if (data)
+ {
+ if (data->joliet)
+ *label = grub_iso9660_convert_string (data->voldesc.volname, 16);
+ else
+ *label = grub_strndup ((char *) data->voldesc.volname, 32);
+ if (*label)
+ {
+ char *ptr;
+ for (ptr = *label; *ptr;ptr++);
+ ptr--;
+ while (ptr >= *label && *ptr == ' ')
+ *ptr-- = 0;
+ }
+
+ grub_free (data);
+ }
+ else
+ *label = 0;
+
+ return grub_errno;
+}
+
+
+static grub_err_t
+grub_iso9660_uuid (grub_device_t device, char **uuid)
+{
+ struct grub_iso9660_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_iso9660_mount (disk);
+ if (data)
+ {
+ if (! data->voldesc.modified.year[0] && ! data->voldesc.modified.year[1]
+ && ! data->voldesc.modified.year[2] && ! data->voldesc.modified.year[3]
+ && ! data->voldesc.modified.month[0] && ! data->voldesc.modified.month[1]
+ && ! data->voldesc.modified.day[0] && ! data->voldesc.modified.day[1]
+ && ! data->voldesc.modified.hour[0] && ! data->voldesc.modified.hour[1]
+ && ! data->voldesc.modified.minute[0] && ! data->voldesc.modified.minute[1]
+ && ! data->voldesc.modified.second[0] && ! data->voldesc.modified.second[1]
+ && ! data->voldesc.modified.hundredth[0] && ! data->voldesc.modified.hundredth[1])
+ {
+ grub_error (GRUB_ERR_BAD_NUMBER, "no creation date in filesystem to generate UUID");
+ *uuid = NULL;
+ }
+ else
+ {
+ *uuid = grub_xasprintf ("%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c",
+ data->voldesc.modified.year[0],
+ data->voldesc.modified.year[1],
+ data->voldesc.modified.year[2],
+ data->voldesc.modified.year[3],
+ data->voldesc.modified.month[0],
+ data->voldesc.modified.month[1],
+ data->voldesc.modified.day[0],
+ data->voldesc.modified.day[1],
+ data->voldesc.modified.hour[0],
+ data->voldesc.modified.hour[1],
+ data->voldesc.modified.minute[0],
+ data->voldesc.modified.minute[1],
+ data->voldesc.modified.second[0],
+ data->voldesc.modified.second[1],
+ data->voldesc.modified.hundredth[0],
+ data->voldesc.modified.hundredth[1]);
+ }
+ }
+ else
+ *uuid = NULL;
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+/* Get writing time of filesystem. */
+static grub_err_t
+grub_iso9660_mtime (grub_device_t device, grub_int32_t *timebuf)
+{
+ struct grub_iso9660_data *data;
+ grub_disk_t disk = device->disk;
+ grub_err_t err;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_iso9660_mount (disk);
+ if (!data)
+ {
+ grub_dl_unref (my_mod);
+ return grub_errno;
+ }
+ err = iso9660_to_unixtime (&data->voldesc.modified, timebuf);
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return err;
+}
+
+
+
+
+static struct grub_fs grub_iso9660_fs =
+ {
+ .name = "iso9660",
+ .fs_dir = grub_iso9660_dir,
+ .fs_open = grub_iso9660_open,
+ .fs_read = grub_iso9660_read,
+ .fs_close = grub_iso9660_close,
+ .fs_label = grub_iso9660_label,
+ .fs_uuid = grub_iso9660_uuid,
+ .fs_mtime = grub_iso9660_mtime,
+#ifdef GRUB_UTIL
+ .reserved_first_sector = 1,
+ .blocklist_install = 1,
+#endif
+ .next = 0
+ };
+
+GRUB_MOD_INIT(iso9660)
+{
+ grub_fs_register (&grub_iso9660_fs);
+ my_mod = mod;
+}
+
+GRUB_MOD_FINI(iso9660)
+{
+ grub_fs_unregister (&grub_iso9660_fs);
+}
diff --git a/EDK2/efiffs/mod/src/file.c b/EDK2/efiffs/mod/src/file.c
new file mode 100644
index 00000000000..9c17cc9676d
--- /dev/null
+++ b/EDK2/efiffs/mod/src/file.c
@@ -0,0 +1,794 @@
+/* file.c - SimpleFileIo Interface */
+/*
+ * Copyright © 2014-2017 Pete Batard
+ * Based on iPXE's efi_driver.c and efi_file.c:
+ * Copyright © 2011,2013 Michael Brown .
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "driver.h"
+
+/**
+ * Get EFI file name (for debugging)
+ *
+ * @v file EFI file
+ * @ret Name Name
+ */
+static const CHAR16 *
+FileName(EFI_GRUB_FILE *File)
+{
+ EFI_STATUS Status;
+ static CHAR16 Path[MAX_PATH];
+
+ Status = Utf8ToUtf16NoAlloc(File->path, Path, sizeof(Path));
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not convert filename to UTF16");
+ return NULL;
+ }
+
+ return Path;
+}
+
+/* Simple hook to populate the timestamp and directory flag when opening a file */
+static INT32
+InfoHook(const CHAR8 *name, const GRUB_DIRHOOK_INFO *Info, VOID *Data)
+{
+ EFI_GRUB_FILE *File = (EFI_GRUB_FILE *) Data;
+
+ /* Look for a specific file */
+ if (strcmpa(name, File->basename) != 0)
+ return 0;
+
+ File->IsDir = (BOOLEAN) (Info->Dir);
+ if (Info->MtimeSet)
+ File->Mtime = Info->Mtime;
+
+ return 0;
+}
+
+/**
+ * Open file
+ *
+ * @v This File handle
+ * @ret new New file handle
+ * @v Name File name
+ * @v Mode File mode
+ * @v Attributes File attributes (for newly-created files)
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileOpen(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New,
+ CHAR16 *Name, UINT64 Mode, UINT64 Attributes)
+{
+ EFI_STATUS Status;
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+ EFI_GRUB_FILE *NewFile;
+
+ // TODO: Use dynamic buffers?
+ char path[MAX_PATH], clean_path[MAX_PATH], *dirname;
+ INTN i, len;
+ BOOLEAN AbsolutePath = (*Name == L'\\');
+
+ PrintInfo(L"Open(" PERCENT_P L"%s, \"%s\")\n", (UINTN) This,
+ IS_ROOT(File)?L" ":L"", Name);
+
+ /* Fail unless opening read-only */
+ if (Mode != EFI_FILE_MODE_READ) {
+ PrintWarning(L"File '%s' can only be opened in read-only mode\n", Name);
+ return EFI_WRITE_PROTECTED;
+ }
+
+ /* Additional failures */
+ if ((StrCmp(Name, L"..") == 0) && IS_ROOT(File)) {
+ PrintInfo(L"Trying to open 's parent\n");
+ return EFI_NOT_FOUND;
+ }
+
+ /* See if we're trying to reopen current (which the EFI Shell insists on doing) */
+ if ((*Name == 0) || (StrCmp(Name, L".") == 0)) {
+ PrintInfo(L" Reopening %s\n", IS_ROOT(File)?L"":FileName(File));
+ File->RefCount++;
+ *New = This;
+ PrintInfo(L" RET: " PERCENT_P L"\n", (UINTN) *New);
+ return EFI_SUCCESS;
+ }
+
+ /* If we have an absolute path, don't bother completing with the parent */
+ if (AbsolutePath) {
+ len = 0;
+ } else {
+ strcpya(path, File->path);
+ len = strlena(path);
+ /* Add delimiter if needed */
+ if ((len == 0) || (path[len-1] != '/'))
+ path[len++] = '/';
+ }
+
+ /* Copy the rest of the path (converted to UTF-8) */
+ Status = Utf16ToUtf8NoAlloc(Name, &path[len], sizeof(path) - len);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not convert path to UTF-8");
+ return Status;
+ }
+ /* Convert the delimiters */
+ for (i = strlena(path) - 1 ; i >= len; i--) {
+ if (path[i] == '\\')
+ path[i] = '/';
+ }
+
+ /* We only want to handle with absolute paths */
+ clean_path[0] = '/';
+ /* Find out if we're dealing with root by removing the junk */
+ CopyPathRelative(&clean_path[1], path, MAX_PATH - 1);
+ if (clean_path[1] == 0) {
+ /* We're dealing with the root */
+ PrintInfo(L" Reopening \n");
+ *New = &File->FileSystem->RootFile->EfiFile;
+ /* Must make sure that DirIndex is reset too (NB: no concurrent access!) */
+ File->FileSystem->RootFile->DirIndex = 0;
+ PrintInfo(L" RET: " PERCENT_P L"\n", (UINTN) *New);
+ return EFI_SUCCESS;
+ }
+
+ // TODO: eventually we should seek for already opened files and increase RefCount
+ /* Allocate and initialise an instance of a file */
+ Status = GrubCreateFile(&NewFile, File->FileSystem);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not instantiate file");
+ return Status;
+ }
+
+ NewFile->path = AllocatePool(strlena(clean_path)+1);
+ if (NewFile->path == NULL) {
+ GrubDestroyFile(NewFile);
+ PrintError(L"Could not instantiate path\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ strcpya(NewFile->path, clean_path);
+
+ /* Isolate the basename and dirname */
+ for (i = strlena(clean_path) - 1; i >= 0; i--) {
+ if (clean_path[i] == '/') {
+ clean_path[i] = 0;
+ break;
+ }
+ }
+ dirname = (i <= 0) ? "/" : clean_path;
+ NewFile->basename = &NewFile->path[i+1];
+
+ /* Find if we're working with a directory and fill the grub timestamp */
+ Status = GrubDir(NewFile, dirname, InfoHook, (VOID *) NewFile);
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_NOT_FOUND)
+ PrintStatusError(Status, L"Could not get file attributes for '%s'", Name);
+ FreePool(NewFile->path);
+ GrubDestroyFile(NewFile);
+ return Status;
+ }
+
+ /* Finally we can call on GRUB open() if it's a regular file */
+ if (!NewFile->IsDir) {
+ Status = GrubOpen(NewFile);
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_NOT_FOUND)
+ PrintStatusError(Status, L"Could not open file '%s'", Name);
+ FreePool(NewFile->path);
+ GrubDestroyFile(NewFile);
+ return Status;
+ }
+ }
+
+ NewFile->RefCount++;
+ *New = &NewFile->EfiFile;
+
+ PrintInfo(L" RET: " PERCENT_P L"\n", (UINTN) *New);
+ return EFI_SUCCESS;
+}
+
+/* Ex version */
+static EFI_STATUS EFIAPI
+FileOpenEx(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New, CHAR16 *Name,
+ UINT64 Mode, UINT64 Attributes, EFI_FILE_IO_TOKEN *Token)
+{
+ return FileOpen(This, New, Name, Mode, Attributes);
+}
+
+
+/**
+ * Close file
+ *
+ * @v This File handle
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileClose(EFI_FILE_HANDLE This)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintInfo(L"Close(" PERCENT_P L"|'%s') %s\n", (UINTN) This, FileName(File),
+ IS_ROOT(File)?L"":L"");
+
+ /* Nothing to do it this is the root */
+ if (IS_ROOT(File))
+ return EFI_SUCCESS;
+
+ if (--File->RefCount == 0) {
+ /* Close the file if it's a regular one */
+ if (!File->IsDir)
+ GrubClose(File);
+ /* NB: basename points into File->path and does not need to be freed */
+ if (File->path != NULL)
+ FreePool(File->path);
+ GrubDestroyFile(File);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Close and delete file
+ *
+ * @v This File handle
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileDelete(EFI_FILE_HANDLE This)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintError(L"Cannot delete '%s'\n", FileName(File));
+
+ /* Close file */
+ FileClose(This);
+
+ /* Warn of failure to delete */
+ return EFI_WARN_DELETE_FAILURE;
+}
+
+/* GRUB uses a callback for each directory entry, whereas EFI uses repeated
+ * firmware generated calls to FileReadDir() to get the info for each entry,
+ * so we have to reconcile the twos. For now, we'll re-issue a call to GRUB
+ * dir(), and run through all the entries (to find the one we
+ * are interested in) multiple times. Maybe later we'll try to optimize this
+ * by building a one-off chained list of entries that we can parse...
+ */
+static INT32
+DirHook(const CHAR8 *name, const GRUB_DIRHOOK_INFO *DirInfo, VOID *Data)
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data;
+ INT64 *Index = (INT64 *) &Info->FileSize;
+ CHAR8 *filename = (CHAR8 *) (UINTN) Info->PhysicalSize;
+ EFI_TIME Time = { 1970, 01, 01, 00, 00, 00, 0, 0, 0, 0, 0};
+
+ // Eliminate '.' or '..'
+ if ((name[0] == '.') && ((name[1] == 0) || ((name[1] == '.') && (name[2] == 0))))
+ return 0;
+
+ /* Ignore any entry that doesn't match our index */
+ if ((*Index)-- != 0)
+ return 0;
+
+ strcpya(filename, name);
+
+ Status = Utf8ToUtf16NoAlloc(filename, Info->FileName, (INTN)(Info->Size - sizeof(EFI_FILE_INFO)));
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_BUFFER_TOO_SMALL)
+ PrintStatusError(Status, L"Could not convert directory entry to UTF-8");
+ return (INT32) Status;
+ }
+ /* The Info struct size already accounts for the extra NUL */
+ Info->Size = sizeof(*Info) + StrLen(Info->FileName) * sizeof(CHAR16);
+
+ // Oh, and of course GRUB uses a 32 bit signed mtime value (seriously, wtf guys?!?)
+ if (DirInfo->MtimeSet)
+ GrubTimeToEfiTime(DirInfo->Mtime, &Time);
+ CopyMem(&Info->CreateTime, &Time, sizeof(Time));
+ CopyMem(&Info->LastAccessTime, &Time, sizeof(Time));
+ CopyMem(&Info->ModificationTime, &Time, sizeof(Time));
+
+ Info->Attribute = EFI_FILE_READ_ONLY;
+ if (DirInfo->Dir)
+ Info->Attribute |= EFI_FILE_DIRECTORY;
+
+ return 0;
+}
+
+/**
+ * Read directory entry
+ *
+ * @v file EFI file
+ * @v Len Length to read
+ * @v Data Data buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS
+FileReadDir(EFI_GRUB_FILE *File, UINTN *Len, VOID *Data)
+{
+ EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data;
+ EFI_STATUS Status;
+ /* We temporarily repurpose the FileSize as a *signed* entry index */
+ INT64 *Index = (INT64 *) &Info->FileSize;
+ /* And PhysicalSize as a pointer to our filename */
+ CHAR8 **basename = (CHAR8 **) &Info->PhysicalSize;
+ CHAR8 path[MAX_PATH];
+ EFI_GRUB_FILE *TmpFile = NULL;
+ INTN len;
+
+ /* Unless we can fit our maximum size, forget it */
+ if (*Len < sizeof(EFI_FILE_INFO)) {
+ *Len = MINIMUM_INFO_LENGTH;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ /* Populate our Info template */
+ ZeroMem(Data, *Len);
+ Info->Size = *Len;
+ *Index = File->DirIndex;
+ strcpya(path, File->path);
+ len = strlena(path);
+ if (path[len-1] != '/')
+ path[len++] = '/';
+ *basename = &path[len];
+
+ /* Invoke GRUB's directory listing */
+ Status = GrubDir(File, File->path, DirHook, Data);
+ if (*Index >= 0) {
+ /* No more entries */
+ *Len = 0;
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR(Status)) {
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ *Len = MINIMUM_INFO_LENGTH;
+ } else {
+ PrintStatusError(Status, L"Directory listing failed");
+ }
+ return Status;
+ }
+
+ /* Our Index/FileSize must be reset */
+ Info->FileSize = 0;
+ Info->PhysicalSize = 0;
+
+ /* For regular files, we still need to fill the size */
+ if (!(Info->Attribute & EFI_FILE_DIRECTORY)) {
+ /* Open the file and read its size */
+ Status = GrubCreateFile(&TmpFile, File->FileSystem);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Unable to create temporary file");
+ return Status;
+ }
+ TmpFile->path = path;
+
+ Status = GrubOpen(TmpFile);
+ if (EFI_ERROR(Status)) {
+ // TODO: EFI_NO_MAPPING is returned for links...
+ PrintStatusError(Status, L"Unable to obtain the size of '%s'", Info->FileName);
+ /* Non fatal error */
+ } else {
+ Info->FileSize = GrubGetFileSize(TmpFile);
+ Info->PhysicalSize = GrubGetFileSize(TmpFile);
+ GrubClose(TmpFile);
+ }
+ GrubDestroyFile(TmpFile);
+ }
+
+ *Len = (UINTN) Info->Size;
+ /* Advance to the next entry */
+ File->DirIndex++;
+
+// PrintInfo(L" Entry[%d]: '%s' %s\n", File->DirIndex-1, Info->FileName,
+// (Info->Attribute&EFI_FILE_DIRECTORY)?L"":L"");
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Read from file
+ *
+ * @v This File handle
+ * @v Len Length to read
+ * @v Data Data buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileRead(EFI_FILE_HANDLE This, UINTN *Len, VOID *Data)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintInfo(L"Read(" PERCENT_P L"|'%s', %d) %s\n", (UINTN) This, FileName(File),
+ *Len, File->IsDir?L"":L"");
+
+ /* If this is a directory, then fetch the directory entries */
+ if (File->IsDir)
+ return FileReadDir(File, Len, Data);
+
+ return GrubRead(File, Data, Len);
+}
+
+/* Ex version */
+static EFI_STATUS EFIAPI
+FileReadEx(IN EFI_FILE_PROTOCOL *This, IN OUT EFI_FILE_IO_TOKEN *Token)
+{
+ return FileRead(This, &(Token->BufferSize), Token->Buffer);
+}
+
+/**
+ * Write to file
+ *
+ * @v This File handle
+ * @v Len Length to write
+ * @v Data Data buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileWrite(EFI_FILE_HANDLE This, UINTN *Len, VOID *Data)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintError(L"Cannot write to '%s'\n", FileName(File));
+ return EFI_WRITE_PROTECTED;
+}
+
+/* Ex version */
+static EFI_STATUS EFIAPI
+FileWriteEx(IN EFI_FILE_PROTOCOL *This, IN OUT EFI_FILE_IO_TOKEN *Token)
+{
+ return FileWrite(This, &(Token->BufferSize), Token->Buffer);
+}
+
+/**
+ * Set file position
+ *
+ * @v This File handle
+ * @v Position New file position
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileSetPosition(EFI_FILE_HANDLE This, UINT64 Position)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+ UINT64 FileSize;
+
+ PrintInfo(L"SetPosition(" PERCENT_P L"|'%s', %lld) %s\n", (UINTN) This,
+ FileName(File), Position, (File->IsDir)?L"":L"");
+
+ /* If this is a directory, reset the Index to the start */
+ if (File->IsDir) {
+ if (Position != 0)
+ return EFI_INVALID_PARAMETER;
+ File->DirIndex = 0;
+ return EFI_SUCCESS;
+ }
+
+ /* Fail if we attempt to seek past the end of the file (since
+ * we do not support writes).
+ */
+ FileSize = GrubGetFileSize(File);
+ if (Position > FileSize) {
+ PrintError(L"'%s': Cannot seek to #%llx of %llx\n",
+ FileName(File), Position, FileSize);
+ return EFI_UNSUPPORTED;
+ }
+
+ /* Set position */
+ GrubSetFileOffset(File, Position);
+ PrintDebug(L"'%s': Position set to %llx\n",
+ FileName(File), Position);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Get file position
+ *
+ * @v This File handle
+ * @ret Position New file position
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileGetPosition(EFI_FILE_HANDLE This, UINT64 *Position)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintInfo(L"GetPosition(" PERCENT_P L"|'%s', %lld)\n", (UINTN) This, FileName(File));
+
+ if (File->IsDir)
+ *Position = File->DirIndex;
+ else
+ *Position = GrubGetFileOffset(File);
+ return EFI_SUCCESS;
+}
+
+/**
+ * Get file information
+ *
+ * @v This File handle
+ * @v Type Type of information
+ * @v Len Buffer size
+ * @v Data Buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileGetInfo(EFI_FILE_HANDLE This, EFI_GUID *Type, UINTN *Len, VOID *Data)
+{
+ EFI_STATUS Status;
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+ EFI_FILE_SYSTEM_INFO *FSInfo = (EFI_FILE_SYSTEM_INFO *) Data;
+ EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data;
+ EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *VLInfo = (EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Data;
+ EFI_TIME Time;
+ CHAR8* label;
+ UINTN tmpLen;
+
+ PrintInfo(L"GetInfo(" PERCENT_P L"|'%s', %d) %s\n", (UINTN) This,
+ FileName(File), *Len, File->IsDir?L"":L"");
+
+ /* Determine information to return */
+ if (CompareMem(Type, &gEfiFileInfoGuid, sizeof(*Type)) == 0) {
+
+ /* Fill file information */
+ PrintExtra(L"Get regular file information\n");
+ if (*Len < sizeof(EFI_FILE_INFO)) {
+ *Len = MINIMUM_INFO_LENGTH;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ ZeroMem(Data, sizeof(EFI_FILE_INFO));
+
+ Info->Attribute = EFI_FILE_READ_ONLY;
+ GrubTimeToEfiTime(File->Mtime, &Time);
+ CopyMem(&Info->CreateTime, &Time, sizeof(Time));
+ CopyMem(&Info->LastAccessTime, &Time, sizeof(Time));
+ CopyMem(&Info->ModificationTime, &Time, sizeof(Time));
+
+ if (File->IsDir) {
+ Info->Attribute |= EFI_FILE_DIRECTORY;
+ } else {
+ Info->FileSize = GrubGetFileSize(File);
+ Info->PhysicalSize = GrubGetFileSize(File);
+ }
+
+ tmpLen = (UINTN)(Info->Size - sizeof(EFI_FILE_INFO) - 1);
+ Status = Utf8ToUtf16NoAllocUpdateLen(File->basename, Info->FileName, &tmpLen);
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ PrintStatusError(Status, L"Could not convert basename to UTF-16");
+ } else {
+ *Len = MINIMUM_INFO_LENGTH;
+ }
+ return Status;
+ }
+
+ /* The Info struct size already accounts for the extra NUL */
+ Info->Size = sizeof(EFI_FILE_INFO) + tmpLen;
+ *Len = (INTN)Info->Size;
+ return EFI_SUCCESS;
+
+ } else if (CompareMem(Type, &gEfiFileSystemInfoGuid, sizeof(*Type)) == 0) {
+
+ /* Get file system information */
+ PrintExtra(L"Get file system information\n");
+ if (*Len < sizeof(EFI_FILE_SYSTEM_INFO)) {
+ *Len = MINIMUM_FS_INFO_LENGTH;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ ZeroMem(Data, sizeof(EFI_FILE_INFO));
+ FSInfo->Size = *Len;
+ FSInfo->ReadOnly = 1;
+ /* NB: This should really be cluster size, but we don't have access to that */
+ if (File->FileSystem->BlockIo2 != NULL) {
+ FSInfo->BlockSize = File->FileSystem->BlockIo2->Media->BlockSize;
+ } else {
+ FSInfo->BlockSize = File->FileSystem->BlockIo->Media->BlockSize;
+ }
+ if (FSInfo->BlockSize == 0) {
+ PrintWarning(L"Corrected Media BlockSize\n");
+ FSInfo->BlockSize = 512;
+ }
+ if (File->FileSystem->BlockIo2 != NULL) {
+ FSInfo->VolumeSize = (File->FileSystem->BlockIo2->Media->LastBlock + 1) *
+ FSInfo->BlockSize;
+ } else {
+ FSInfo->VolumeSize = (File->FileSystem->BlockIo->Media->LastBlock + 1) *
+ FSInfo->BlockSize;
+ }
+ /* No idea if we can easily get this for GRUB, and the device is RO anyway */
+ FSInfo->FreeSpace = 0;
+
+ Status = GrubLabel(File, &label);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not read disk label");
+ FSInfo->VolumeLabel[0] = 0;
+ *Len = sizeof(EFI_FILE_SYSTEM_INFO);
+ } else {
+ tmpLen = (INTN)(FSInfo->Size - sizeof(EFI_FILE_SYSTEM_INFO) - 1);
+ Status = Utf8ToUtf16NoAllocUpdateLen(label, FSInfo->VolumeLabel, &tmpLen);
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ PrintStatusError(Status, L"Could not convert label to UTF-16");
+ } else {
+ *Len = MINIMUM_FS_INFO_LENGTH;
+ }
+ return Status;
+ }
+ FSInfo->Size = sizeof(EFI_FILE_SYSTEM_INFO) - 1 + tmpLen;
+ *Len = (INTN)FSInfo->Size;
+ }
+ return EFI_SUCCESS;
+
+ } else if (CompareMem(Type, &gEfiFileSystemVolumeLabelInfoIdGuid, sizeof(*Type)) == 0) {
+
+ /* Get the volume label */
+ Status = GrubLabel(File, &label);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not read disk label");
+ }
+ else {
+ Status = Utf8ToUtf16NoAllocUpdateLen(label, VLInfo->VolumeLabel, Len);
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_BUFFER_TOO_SMALL)
+ PrintStatusError(Status, L"Could not convert label to UTF-16");
+ return Status;
+ }
+ }
+ return EFI_SUCCESS;
+
+ } else {
+
+ Print(L"'%s': Cannot get information of type ", FileName(File));
+ PrintGuid(Type);
+ Print(L"\n");
+ return EFI_UNSUPPORTED;
+
+ }
+}
+
+/**
+ * Set file information
+ *
+ * @v This File handle
+ * @v Type Type of information
+ * @v Len Buffer size
+ * @v Data Buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileSetInfo(EFI_FILE_HANDLE This, EFI_GUID *Type, UINTN Len, VOID *Data)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ Print(L"Cannot set information of type ");
+ PrintGuid(Type);
+ Print(L" for file '%s'\n", FileName(File));
+
+ return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * Flush file modified data
+ *
+ * @v This File handle
+ * @v Type Type of information
+ * @v Len Buffer size
+ * @v Data Buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileFlush(EFI_FILE_HANDLE This)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintInfo(L"Flush(" PERCENT_P L"|'%s')\n", (UINTN) This, FileName(File));
+ return EFI_SUCCESS;
+}
+
+/* Ex version */
+static EFI_STATUS EFIAPI
+FileFlushEx(EFI_FILE_HANDLE This, EFI_FILE_IO_TOKEN *Token)
+{
+ return FileFlush(This);
+}
+
+/**
+ * Open root directory
+ *
+ * @v This EFI simple file system
+ * @ret Root File handle for the root directory
+ * @ret Status EFI status code
+ */
+EFI_STATUS EFIAPI
+FileOpenVolume(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, EFI_FILE_HANDLE *Root)
+{
+ EFI_FS *FSInstance = _CR(This, EFI_FS, FileIoInterface);
+
+ PrintInfo(L"OpenVolume\n");
+ *Root = &FSInstance->RootFile->EfiFile;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Install the EFI simple file system protocol
+ * If successful this call instantiates a new FS#: drive, that is made
+ * available on the next 'map -r'. Note that all this call does is add
+ * the FS protocol. OpenVolume won't be called until a process tries
+ * to access a file or the root directory on the volume.
+ */
+EFI_STATUS
+FSInstall(EFI_FS *This, EFI_HANDLE ControllerHandle)
+{
+ EFI_STATUS Status;
+
+ /* Check if it's a filesystem we can handle */
+ if (!GrubFSProbe(This))
+ return EFI_UNSUPPORTED;
+
+ PrintInfo(L"FSInstall: %s\n", This->DevicePathString);
+
+ /* Initialize the root handle */
+ Status = GrubCreateFile(&This->RootFile, This);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not create root file");
+ return Status;
+ }
+
+ /* Setup the EFI part */
+ This->RootFile->EfiFile.Revision = EFI_FILE_PROTOCOL_REVISION2;
+ This->RootFile->EfiFile.Open = FileOpen;
+ This->RootFile->EfiFile.Close = FileClose;
+ This->RootFile->EfiFile.Delete = FileDelete;
+ This->RootFile->EfiFile.Read = FileRead;
+ This->RootFile->EfiFile.Write = FileWrite;
+ This->RootFile->EfiFile.GetPosition = FileGetPosition;
+ This->RootFile->EfiFile.SetPosition = FileSetPosition;
+ This->RootFile->EfiFile.GetInfo = FileGetInfo;
+ This->RootFile->EfiFile.SetInfo = FileSetInfo;
+ This->RootFile->EfiFile.Flush = FileFlush;
+ This->RootFile->EfiFile.OpenEx = FileOpenEx;
+ This->RootFile->EfiFile.ReadEx = FileReadEx;
+ This->RootFile->EfiFile.WriteEx = FileWriteEx;
+ This->RootFile->EfiFile.FlushEx = FileFlushEx;
+
+ /* Setup the other attributes */
+ This->RootFile->path = "/";
+ This->RootFile->basename = &This->RootFile->path[1];
+ This->RootFile->IsDir = TRUE;
+
+ /* Install the simple file system protocol. */
+ Status = BS->InstallMultipleProtocolInterfaces(&ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid, &This->FileIoInterface,
+ NULL);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not install simple file system protocol");
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/* Uninstall EFI simple file system protocol */
+VOID
+FSUninstall(EFI_FS *This, EFI_HANDLE ControllerHandle)
+{
+ PrintInfo(L"FSUninstall: %s\n", This->DevicePathString);
+
+ BS->UninstallMultipleProtocolInterfaces(ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid, &This->FileIoInterface,
+ NULL);
+}
diff --git a/EDK2/efiffs/mod/src/logging.c b/EDK2/efiffs/mod/src/logging.c
new file mode 100644
index 00000000000..64d30f7d535
--- /dev/null
+++ b/EDK2/efiffs/mod/src/logging.c
@@ -0,0 +1,86 @@
+/* logging.c - EFI logging */
+/*
+ * Copyright © 2014-2017 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "driver.h"
+
+/* Not defined in gnu-efi yet */
+#define SHELL_VARIABLE_GUID { \
+ 0x158def5a, 0xf656, 0x419c, { 0xb0, 0x27, 0x7a, 0x31, 0x92, 0xc0, 0x79, 0xd2 } \
+}
+extern EFI_GUID gShellVariableGuid;
+EFI_GUID ShellVariable = SHELL_VARIABLE_GUID;
+
+static UINTN PrintNone(IN CONST CHAR16 *fmt, ... ) { return 0; }
+Print_t PrintError = PrintNone;
+Print_t PrintWarning = PrintNone;
+Print_t PrintInfo = PrintNone;
+Print_t PrintDebug = PrintNone;
+Print_t PrintExtra = PrintNone;
+Print_t* PrintTable[] = { &PrintError, &PrintWarning, &PrintInfo,
+ &PrintDebug, &PrintExtra };
+
+/* Global driver verbosity level */
+#if !defined(DEFAULT_LOGLEVEL)
+#define DEFAULT_LOGLEVEL FS_LOGLEVEL_NONE
+#endif
+UINTN LogLevel = DEFAULT_LOGLEVEL;
+
+/**
+ * Print status
+ *
+ * @v Status EFI status code
+ */
+VOID
+PrintStatus(EFI_STATUS Status)
+{
+#if defined(__MAKEWITH_GNUEFI)
+ CHAR16 StatusString[64];
+ StatusToString(StatusString, Status);
+ // Make sure the Status is unsigned 32 bits
+ Print(L": [%d] %s\n", (Status & 0x7FFFFFFF), StatusString);
+#else
+ Print(L": [%d]\n", (Status & 0x7FFFFFFF));
+#endif
+}
+
+int g_fs_name_nocase = 0;
+/*
+ * You can control the verbosity of the driver output by setting the shell environment
+ * variable FS_LOGGING to one of the values defined in the FS_LOGLEVEL constants
+ */
+VOID
+SetLogging(VOID)
+{
+ EFI_STATUS Status;
+ CHAR16 LogVar[4];
+ UINTN i, LogVarSize = sizeof(LogVar);
+
+ i = LogVarSize;
+ Status = RT->GetVariable(L"FS_NAME_NOCASE", &ShellVariable, NULL, &i, LogVar);
+ if (Status == EFI_SUCCESS)
+ g_fs_name_nocase = 1;
+
+ Status = RT->GetVariable(L"FS_LOGGING", &ShellVariable, NULL, &LogVarSize, LogVar);
+ if (Status == EFI_SUCCESS)
+ LogLevel = Atoi(LogVar);
+
+ for (i=0; i.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define GRUB_ISO9660_FSTYPE_DIR 0040000
+#define GRUB_ISO9660_FSTYPE_REG 0100000
+#define GRUB_ISO9660_FSTYPE_SYMLINK 0120000
+#define GRUB_ISO9660_FSTYPE_MASK 0170000
+
+#define GRUB_ISO9660_LOG2_BLKSZ 2
+#define GRUB_ISO9660_BLKSZ 2048
+
+#define GRUB_ISO9660_RR_DOT 2
+#define GRUB_ISO9660_RR_DOTDOT 4
+
+#define GRUB_ISO9660_VOLDESC_BOOT 0
+#define GRUB_ISO9660_VOLDESC_PRIMARY 1
+#define GRUB_ISO9660_VOLDESC_SUPP 2
+#define GRUB_ISO9660_VOLDESC_PART 3
+#define GRUB_ISO9660_VOLDESC_END 255
+
+/* The head of a volume descriptor. */
+PRAGMA_BEGIN_PACKED
+struct grub_iso9660_voldesc
+{
+ grub_uint8_t type;
+ grub_uint8_t magic[5];
+ grub_uint8_t version;
+} GRUB_PACKED;
+
+struct grub_iso9660_date2
+{
+ grub_uint8_t year;
+ grub_uint8_t month;
+ grub_uint8_t day;
+ grub_uint8_t hour;
+ grub_uint8_t minute;
+ grub_uint8_t second;
+ grub_uint8_t offset;
+} GRUB_PACKED;
+
+/* A directory entry. */
+struct grub_iso9660_dir
+{
+ grub_uint8_t len;
+ grub_uint8_t ext_sectors;
+ grub_uint32_t first_sector;
+ grub_uint32_t first_sector_be;
+ grub_uint32_t size;
+ grub_uint32_t size_be;
+ struct grub_iso9660_date2 mtime;
+ grub_uint8_t flags;
+ grub_uint8_t unused2[6];
+#define MAX_NAMELEN 255
+ grub_uint8_t namelen;
+} GRUB_PACKED;
+
+struct grub_iso9660_date
+{
+ grub_uint8_t year[4];
+ grub_uint8_t month[2];
+ grub_uint8_t day[2];
+ grub_uint8_t hour[2];
+ grub_uint8_t minute[2];
+ grub_uint8_t second[2];
+ grub_uint8_t hundredth[2];
+ grub_uint8_t offset;
+} GRUB_PACKED;
+
+/* The primary volume descriptor. Only little endian is used. */
+struct grub_iso9660_primary_voldesc
+{
+ struct grub_iso9660_voldesc voldesc;
+ grub_uint8_t unused1[33];
+ grub_uint8_t volname[32];
+ grub_uint8_t unused2[16];
+ grub_uint8_t escape[32];
+ grub_uint8_t unused3[12];
+ grub_uint32_t path_table_size;
+ grub_uint8_t unused4[4];
+ grub_uint32_t path_table;
+ grub_uint8_t unused5[12];
+ struct grub_iso9660_dir rootdir;
+ grub_uint8_t unused6[624];
+ struct grub_iso9660_date created;
+ struct grub_iso9660_date modified;
+} GRUB_PACKED;
+
+/* A single entry in the path table. */
+struct grub_iso9660_path
+{
+ grub_uint8_t len;
+ grub_uint8_t sectors;
+ grub_uint32_t first_sector;
+ grub_uint16_t parentdir;
+ grub_uint8_t name[0];
+} GRUB_PACKED;
+
+/* An entry in the System Usage area of the directory entry. */
+struct grub_iso9660_susp_entry
+{
+ grub_uint8_t sig[2];
+ grub_uint8_t len;
+/*! MSVC compilers cannot handle a zero sized array in the middle
+ of a struct, and grub_iso9660_susp_entry is reused within
+ grub_iso9660_susp_ce. Therefore, instead of defining:
+ grub_uint8_t version;
+ grub_uint8_t data[];
+ we leverage the fact that these attributes are the same size
+ and use an union. The only gotcha is that the actual
+ payload of u.data[] starts at 1, not 0. */
+ union {
+ grub_uint8_t version;
+ grub_uint8_t data[1];
+ } u;
+} GRUB_PACKED;
+
+/* The CE entry. This is used to describe the next block where data
+ can be found. */
+struct grub_iso9660_susp_ce
+{
+ struct grub_iso9660_susp_entry entry;
+ grub_uint32_t blk;
+ grub_uint32_t blk_be;
+ grub_uint32_t off;
+ grub_uint32_t off_be;
+ grub_uint32_t len;
+ grub_uint32_t len_be;
+} GRUB_PACKED;
+PRAGMA_END_PACKED
+
+struct grub_iso9660_data
+{
+ struct grub_iso9660_primary_voldesc voldesc;
+ grub_disk_t disk;
+ int rockridge;
+ int susp_skip;
+ int joliet;
+ struct grub_fshelp_node *node;
+};
+
+struct grub_fshelp_node
+{
+ struct grub_iso9660_data *data;
+ grub_size_t have_dirents, alloc_dirents;
+ int have_symlink;
+ struct grub_iso9660_dir dirents[8];
+ char symlink[0];
+};
+
+enum
+ {
+ FLAG_TYPE_PLAIN = 0,
+ FLAG_TYPE_DIR = 2,
+ FLAG_TYPE = 3,
+ FLAG_MORE_EXTENTS = 0x80
+ };
+
+static grub_dl_t my_mod;
+
+
+static grub_err_t
+iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int32_t *nix)
+{
+ struct grub_datetime datetime;
+
+ if (! i->year[0] && ! i->year[1]
+ && ! i->year[2] && ! i->year[3]
+ && ! i->month[0] && ! i->month[1]
+ && ! i->day[0] && ! i->day[1]
+ && ! i->hour[0] && ! i->hour[1]
+ && ! i->minute[0] && ! i->minute[1]
+ && ! i->second[0] && ! i->second[1]
+ && ! i->hundredth[0] && ! i->hundredth[1])
+ return grub_error (GRUB_ERR_BAD_NUMBER, "empty date");
+ datetime.year = (i->year[0] - '0') * 1000 + (i->year[1] - '0') * 100
+ + (i->year[2] - '0') * 10 + (i->year[3] - '0');
+ datetime.month = (i->month[0] - '0') * 10 + (i->month[1] - '0');
+ datetime.day = (i->day[0] - '0') * 10 + (i->day[1] - '0');
+ datetime.hour = (i->hour[0] - '0') * 10 + (i->hour[1] - '0');
+ datetime.minute = (i->minute[0] - '0') * 10 + (i->minute[1] - '0');
+ datetime.second = (i->second[0] - '0') * 10 + (i->second[1] - '0');
+
+ if (!grub_datetime2unixtime (&datetime, nix))
+ return grub_error (GRUB_ERR_BAD_NUMBER, "incorrect date");
+ *nix -= i->offset * 60 * 15;
+ return GRUB_ERR_NONE;
+}
+
+static int
+iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int32_t *nix)
+{
+ struct grub_datetime datetime;
+
+ datetime.year = i->year + 1900;
+ datetime.month = i->month;
+ datetime.day = i->day;
+ datetime.hour = i->hour;
+ datetime.minute = i->minute;
+ datetime.second = i->second;
+
+ if (!grub_datetime2unixtime (&datetime, nix))
+ return 0;
+ *nix -= i->offset * 60 * 15;
+ return 1;
+}
+
+static grub_err_t
+read_node (grub_fshelp_node_t node, grub_off_t off, grub_size_t len, char *buf)
+{
+ grub_size_t i = 0;
+
+ while (len > 0)
+ {
+ grub_size_t toread;
+ grub_err_t err;
+ while (i < node->have_dirents
+ && off >= grub_le_to_cpu32 (node->dirents[i].size))
+ {
+ off -= grub_le_to_cpu32 (node->dirents[i].size);
+ i++;
+ }
+ if (i == node->have_dirents)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "read out of range");
+ toread = grub_le_to_cpu32 (node->dirents[i].size);
+ if (toread > len)
+ toread = len;
+ err = grub_disk_read (node->data->disk,
+ ((grub_disk_addr_t) grub_le_to_cpu32 (node->dirents[i].first_sector)) << GRUB_ISO9660_LOG2_BLKSZ,
+ off, toread, buf);
+ if (err)
+ return err;
+ len -= toread;
+ off += toread;
+ buf += toread;
+ }
+ return GRUB_ERR_NONE;
+}
+
+/* Iterate over the susp entries, starting with block SUA_BLOCK on the
+ offset SUA_POS with a size of SUA_SIZE bytes. Hook is called for
+ every entry. */
+static grub_err_t
+grub_iso9660_susp_iterate (grub_fshelp_node_t node, grub_off_t off,
+ grub_ssize_t sua_size,
+ grub_err_t (*hook)
+ (struct grub_iso9660_susp_entry *entry, void *hook_arg),
+ void *hook_arg)
+{
+ char *sua;
+ struct grub_iso9660_susp_entry *entry;
+ grub_err_t err;
+
+ if (sua_size <= 0)
+ return GRUB_ERR_NONE;
+
+ sua = grub_malloc (sua_size);
+ if (!sua)
+ return grub_errno;
+
+ /* Load a part of the System Usage Area. */
+ err = read_node (node, off, sua_size, sua);
+ if (err)
+ return err;
+
+ for (entry = (struct grub_iso9660_susp_entry *) sua; (char *) entry < (char *) sua + sua_size - 1 && entry->len > 0;
+ entry = (struct grub_iso9660_susp_entry *)
+ ((char *) entry + entry->len))
+ {
+ /* The last entry. */
+ if (grub_strncmp ((char *) entry->sig, "ST", 2) == 0)
+ break;
+
+ /* Additional entries are stored elsewhere. */
+ if (grub_strncmp ((char *) entry->sig, "CE", 2) == 0)
+ {
+ struct grub_iso9660_susp_ce *ce;
+ grub_disk_addr_t ce_block;
+
+ ce = (struct grub_iso9660_susp_ce *) entry;
+ sua_size = grub_le_to_cpu32 (ce->len);
+ off = grub_le_to_cpu32 (ce->off);
+ ce_block = grub_le_to_cpu32 (ce->blk) << GRUB_ISO9660_LOG2_BLKSZ;
+
+ grub_free (sua);
+ sua = grub_malloc (sua_size);
+ if (!sua)
+ return grub_errno;
+
+ /* Load a part of the System Usage Area. */
+ err = grub_disk_read (node->data->disk, ce_block, off,
+ sua_size, sua);
+ if (err)
+ return err;
+
+ entry = (struct grub_iso9660_susp_entry *) sua;
+ }
+
+ if (hook (entry, hook_arg))
+ {
+ grub_free (sua);
+ return 0;
+ }
+ }
+
+ grub_free (sua);
+ return 0;
+}
+
+static char *
+grub_iso9660_convert_string (grub_uint8_t *us, int len)
+{
+ char *p;
+ int i;
+ grub_uint16_t t[MAX_NAMELEN / 2 + 1];
+
+ p = grub_malloc (len * GRUB_MAX_UTF8_PER_UTF16 + 1);
+ if (! p)
+ return NULL;
+
+ for (i=0; isig, "ER", 2) == 0)
+ {
+ data->rockridge = 1;
+ return 1;
+ }
+ return 0;
+}
+
+static grub_err_t
+set_rockridge (struct grub_iso9660_data *data)
+{
+ int sua_pos;
+ int sua_size;
+ char *sua;
+ struct grub_iso9660_dir rootdir;
+ struct grub_iso9660_susp_entry *entry;
+
+ data->rockridge = 0;
+
+ /* Read the system use area and test it to see if SUSP is
+ supported. */
+ if (grub_disk_read (data->disk,
+ (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
+ << GRUB_ISO9660_LOG2_BLKSZ), 0,
+ sizeof (rootdir), (char *) &rootdir))
+ return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
+
+ sua_pos = (sizeof (rootdir) + rootdir.namelen
+ + (rootdir.namelen % 2) - 1);
+ sua_size = rootdir.len - sua_pos;
+
+ if (!sua_size)
+ return GRUB_ERR_NONE;
+
+ sua = grub_malloc (sua_size);
+ if (! sua)
+ return grub_errno;
+
+ if (grub_disk_read (data->disk,
+ (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
+ << GRUB_ISO9660_LOG2_BLKSZ), sua_pos,
+ sua_size, sua))
+ {
+ grub_free (sua);
+ return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
+ }
+
+ entry = (struct grub_iso9660_susp_entry *) sua;
+
+ /* Test if the SUSP protocol is used on this filesystem. */
+ if (grub_strncmp ((char *) entry->sig, "SP", 2) == 0)
+ {
+ struct grub_fshelp_node rootnode;
+
+ rootnode.data = data;
+ rootnode.alloc_dirents = ARRAY_SIZE (rootnode.dirents);
+ rootnode.have_dirents = 1;
+ rootnode.have_symlink = 0;
+ rootnode.dirents[0] = data->voldesc.rootdir;
+
+ /* The 2nd data byte stored how many bytes are skipped every time
+ to get to the SUA (System Usage Area). */
+ data->susp_skip = entry->u.data[1 + 2];
+ entry = (struct grub_iso9660_susp_entry *) ((char *) entry + entry->len);
+
+ /* Iterate over the entries in the SUA area to detect
+ extensions. */
+ if (grub_iso9660_susp_iterate (&rootnode,
+ sua_pos, sua_size, susp_iterate_set_rockridge,
+ data))
+ {
+ grub_free (sua);
+ return grub_errno;
+ }
+ }
+ grub_free (sua);
+ return GRUB_ERR_NONE;
+}
+
+static struct grub_iso9660_data *
+grub_iso9660_mount (grub_disk_t disk)
+{
+ struct grub_iso9660_data *data = 0;
+ struct grub_iso9660_primary_voldesc voldesc;
+ int block;
+
+ data = grub_zalloc (sizeof (struct grub_iso9660_data));
+ if (! data)
+ return 0;
+
+ data->disk = disk;
+
+ block = 16;
+ do
+ {
+ int copy_voldesc = 0;
+
+ /* Read the superblock. */
+ if (grub_disk_read (disk, block << GRUB_ISO9660_LOG2_BLKSZ, 0,
+ sizeof (struct grub_iso9660_primary_voldesc),
+ (char *) &voldesc))
+ {
+ grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
+ goto fail;
+ }
+
+ if (grub_strncmp ((char *) voldesc.voldesc.magic, "CD001", 5) != 0)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
+ goto fail;
+ }
+
+ if (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_PRIMARY)
+ copy_voldesc = 1;
+ else if (!data->rockridge
+ && (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_SUPP)
+ && (voldesc.escape[0] == 0x25) && (voldesc.escape[1] == 0x2f)
+ &&
+ ((voldesc.escape[2] == 0x40) || /* UCS-2 Level 1. */
+ (voldesc.escape[2] == 0x43) || /* UCS-2 Level 2. */
+ (voldesc.escape[2] == 0x45))) /* UCS-2 Level 3. */
+ {
+ copy_voldesc = 1;
+ data->joliet = 1;
+ }
+
+ if (copy_voldesc)
+ {
+ grub_memcpy((char *) &data->voldesc, (char *) &voldesc,
+ sizeof (struct grub_iso9660_primary_voldesc));
+ if (set_rockridge (data))
+ goto fail;
+ }
+
+ block++;
+ } while (voldesc.voldesc.type != GRUB_ISO9660_VOLDESC_END);
+
+ return data;
+
+ fail:
+ grub_free (data);
+ return 0;
+}
+
+
+static char *
+grub_iso9660_read_symlink (grub_fshelp_node_t node)
+{
+ return node->have_symlink
+ ? grub_strdup (node->symlink
+ + (node->have_dirents) * sizeof (node->dirents[0])
+ - sizeof (node->dirents)) : grub_strdup ("");
+}
+
+static grub_off_t
+get_node_size (grub_fshelp_node_t node)
+{
+ grub_off_t ret = 0;
+ grub_size_t i;
+
+ for (i = 0; i < node->have_dirents; i++)
+ ret += grub_le_to_cpu32 (node->dirents[i].size);
+ return ret;
+}
+
+struct iterate_dir_ctx
+{
+ char *filename;
+ int filename_alloc;
+ enum grub_fshelp_filetype type;
+ char *symlink;
+ int was_continue;
+};
+
+ /* Extend the symlink. */
+static void
+add_part (struct iterate_dir_ctx *ctx,
+ const char *part,
+ int len2)
+{
+ int size = ctx->symlink ? grub_strlen (ctx->symlink) : 0;
+
+ ctx->symlink = grub_realloc (ctx->symlink, size + len2 + 1);
+ if (! ctx->symlink)
+ return;
+
+ grub_memcpy (ctx->symlink + size, part, len2);
+ ctx->symlink[size + len2] = 0;
+}
+
+static grub_err_t
+susp_iterate_dir (struct grub_iso9660_susp_entry *entry,
+ void *_ctx)
+{
+ struct iterate_dir_ctx *ctx = _ctx;
+
+ /* The filename in the rock ridge entry. */
+ if (grub_strncmp ("NM", (char *) entry->sig, 2) == 0)
+ {
+ /* The flags are stored at the data position 0, here the
+ filename type is stored. */
+ /* FIXME: Fix this slightly improper cast. */
+ if (entry->u.data[1 + 0] & GRUB_ISO9660_RR_DOT)
+ ctx->filename = (char *) ".";
+ else if (entry->u.data[1 + 0] & GRUB_ISO9660_RR_DOTDOT)
+ ctx->filename = (char *) "..";
+ else if (entry->len >= 5)
+ {
+ grub_size_t off = 0, csize = 1;
+ char *old;
+ csize = entry->len - 5;
+ old = ctx->filename;
+ if (ctx->filename_alloc)
+ {
+ off = grub_strlen (ctx->filename);
+ ctx->filename = grub_realloc (ctx->filename, csize + off + 1);
+ }
+ else
+ {
+ off = 0;
+ ctx->filename = grub_zalloc (csize + 1);
+ }
+ if (!ctx->filename)
+ {
+ ctx->filename = old;
+ return grub_errno;
+ }
+ ctx->filename_alloc = 1;
+ grub_memcpy (ctx->filename + off, (char *) &entry->u.data[1 + 1], csize);
+ ctx->filename[off + csize] = '\0';
+ }
+ }
+ /* The mode information (st_mode). */
+ else if (grub_strncmp ((char *) entry->sig, "PX", 2) == 0)
+ {
+ /* At position 0 of the PX record the st_mode information is
+ stored (little-endian). */
+ grub_uint32_t mode = ((entry->u.data[1 + 0] + (entry->u.data[1 + 1] << 8))
+ & GRUB_ISO9660_FSTYPE_MASK);
+
+ switch (mode)
+ {
+ case GRUB_ISO9660_FSTYPE_DIR:
+ ctx->type = GRUB_FSHELP_DIR;
+ break;
+ case GRUB_ISO9660_FSTYPE_REG:
+ ctx->type = GRUB_FSHELP_REG;
+ break;
+ case GRUB_ISO9660_FSTYPE_SYMLINK:
+ ctx->type = GRUB_FSHELP_SYMLINK;
+ break;
+ default:
+ ctx->type = GRUB_FSHELP_UNKNOWN;
+ }
+ }
+ else if (grub_strncmp ("SL", (char *) entry->sig, 2) == 0)
+ {
+ unsigned int pos = 1;
+
+ /* The symlink is not stored as a POSIX symlink, translate it. */
+ while (pos + sizeof (*entry) < entry->len)
+ {
+ /* The current position is the `Component Flag'. */
+ switch (entry->u.data[1 + pos] & 30)
+ {
+ case 0:
+ {
+ /* The data on pos + 2 is the actual data, pos + 1
+ is the length. Both are part of the `Component
+ Record'. */
+ if (ctx->symlink && !ctx->was_continue)
+ add_part (ctx, "/", 1);
+ add_part (ctx, (char *) &entry->u.data[1 + pos + 2],
+ entry->u.data[1 + pos + 1]);
+ ctx->was_continue = (entry->u.data[1 + pos] & 1);
+ break;
+ }
+
+ case 2:
+ add_part (ctx, "./", 2);
+ break;
+
+ case 4:
+ add_part (ctx, "../", 3);
+ break;
+
+ case 8:
+ add_part (ctx, "/", 1);
+ break;
+ }
+ /* In pos + 1 the length of the `Component Record' is
+ stored. */
+ pos += entry->u.data[1 + pos + 1] + 2;
+ }
+
+ /* Check if `grub_realloc' failed. */
+ if (grub_errno)
+ return grub_errno;
+ }
+
+ return 0;
+}
+
+static int
+grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
+ grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
+{
+ struct grub_iso9660_dir dirent;
+ grub_off_t offset = 0;
+ grub_off_t len;
+ struct iterate_dir_ctx ctx;
+
+ len = get_node_size (dir);
+
+ for (; offset < len; offset += dirent.len)
+ {
+ ctx.symlink = 0;
+ ctx.was_continue = 0;
+
+ if (read_node (dir, offset, sizeof (dirent), (char *) &dirent))
+ return 0;
+
+ /* The end of the block, skip to the next one. */
+ if (!dirent.len)
+ {
+ offset = (offset / GRUB_ISO9660_BLKSZ + 1) * GRUB_ISO9660_BLKSZ;
+ continue;
+ }
+
+ {
+ char name[MAX_NAMELEN + 1];
+ int nameoffset = offset + sizeof (dirent);
+ struct grub_fshelp_node *node;
+ int sua_off = (sizeof (dirent) + dirent.namelen + 1
+ - (dirent.namelen % 2));
+ int sua_size = dirent.len - sua_off;
+
+ sua_off += offset + dir->data->susp_skip;
+
+ ctx.filename = 0;
+ ctx.filename_alloc = 0;
+ ctx.type = GRUB_FSHELP_UNKNOWN;
+
+ if (dir->data->rockridge
+ && grub_iso9660_susp_iterate (dir, sua_off, sua_size,
+ susp_iterate_dir, &ctx))
+ return 0;
+
+ /* Read the name. */
+ if (read_node (dir, nameoffset, dirent.namelen, (char *) name))
+ return 0;
+
+ node = grub_malloc (sizeof (struct grub_fshelp_node));
+ if (!node)
+ return 0;
+
+ node->alloc_dirents = ARRAY_SIZE (node->dirents);
+ node->have_dirents = 1;
+
+ /* Setup a new node. */
+ node->data = dir->data;
+ node->have_symlink = 0;
+
+ /* If the filetype was not stored using rockridge, use
+ whatever is stored in the iso9660 filesystem. */
+ if (ctx.type == GRUB_FSHELP_UNKNOWN)
+ {
+ if ((dirent.flags & FLAG_TYPE) == FLAG_TYPE_DIR)
+ ctx.type = GRUB_FSHELP_DIR;
+ else
+ ctx.type = GRUB_FSHELP_REG;
+ }
+
+ /* . and .. */
+ if (!ctx.filename && dirent.namelen == 1 && name[0] == 0)
+ ctx.filename = (char *) ".";
+
+ if (!ctx.filename && dirent.namelen == 1 && name[0] == 1)
+ ctx.filename = (char *) "..";
+
+ /* The filename was not stored in a rock ridge entry. Read it
+ from the iso9660 filesystem. */
+ if (!dir->data->joliet && !ctx.filename)
+ {
+ char *ptr;
+ name[dirent.namelen] = '\0';
+ ctx.filename = grub_strrchr (name, ';');
+ if (ctx.filename)
+ *ctx.filename = '\0';
+ /* ISO9660 names are not case-preserving. */
+ ctx.type |= GRUB_FSHELP_CASE_INSENSITIVE;
+ for (ptr = name; *ptr; ptr++)
+ *ptr = grub_tolower (*ptr);
+ if (ptr != name && *(ptr - 1) == '.')
+ *(ptr - 1) = 0;
+ ctx.filename = name;
+ }
+
+ if (dir->data->joliet && !ctx.filename)
+ {
+ char *semicolon;
+
+ ctx.filename = grub_iso9660_convert_string
+ ((grub_uint8_t *) name, dirent.namelen >> 1);
+
+ semicolon = grub_strrchr (ctx.filename, ';');
+ if (semicolon)
+ *semicolon = '\0';
+
+ ctx.filename_alloc = 1;
+ }
+
+ node->dirents[0] = dirent;
+ while (dirent.flags & FLAG_MORE_EXTENTS)
+ {
+ offset += dirent.len;
+ if (read_node (dir, offset, sizeof (dirent), (char *) &dirent))
+ {
+ if (ctx.filename_alloc)
+ grub_free (ctx.filename);
+ grub_free (node);
+ return 0;
+ }
+ if (node->have_dirents >= node->alloc_dirents)
+ {
+ struct grub_fshelp_node *new_node;
+ node->alloc_dirents *= 2;
+ new_node = grub_realloc (node,
+ sizeof (struct grub_fshelp_node)
+ + ((node->alloc_dirents
+ - ARRAY_SIZE (node->dirents))
+ * sizeof (node->dirents[0])));
+ if (!new_node)
+ {
+ if (ctx.filename_alloc)
+ grub_free (ctx.filename);
+ grub_free (node);
+ return 0;
+ }
+ node = new_node;
+ }
+ node->dirents[node->have_dirents++] = dirent;
+ }
+ if (ctx.symlink)
+ {
+ if ((node->alloc_dirents - node->have_dirents)
+ * sizeof (node->dirents[0]) < grub_strlen (ctx.symlink) + 1)
+ {
+ struct grub_fshelp_node *new_node;
+ new_node = grub_realloc (node,
+ sizeof (struct grub_fshelp_node)
+ + ((node->alloc_dirents
+ - ARRAY_SIZE (node->dirents))
+ * sizeof (node->dirents[0]))
+ + grub_strlen (ctx.symlink) + 1);
+ if (!new_node)
+ {
+ if (ctx.filename_alloc)
+ grub_free (ctx.filename);
+ grub_free (node);
+ return 0;
+ }
+ node = new_node;
+ }
+ node->have_symlink = 1;
+ grub_strcpy (node->symlink
+ + node->have_dirents * sizeof (node->dirents[0])
+ - sizeof (node->dirents), ctx.symlink);
+ grub_free (ctx.symlink);
+ ctx.symlink = 0;
+ ctx.was_continue = 0;
+ }
+ if (hook (ctx.filename, ctx.type, node, hook_data))
+ {
+ if (ctx.filename_alloc)
+ grub_free (ctx.filename);
+ return 1;
+ }
+ if (ctx.filename_alloc)
+ grub_free (ctx.filename);
+ }
+ }
+
+ return 0;
+}
+
+
+
+/* Context for grub_iso9660_dir. */
+struct grub_iso9660_dir_ctx
+{
+ grub_fs_dir_hook_t hook;
+ void *hook_data;
+};
+
+/* Helper for grub_iso9660_dir. */
+static int
+grub_iso9660_dir_iter (const char *filename,
+ enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node, void *data)
+{
+ struct grub_iso9660_dir_ctx *ctx = data;
+ struct grub_dirhook_info info;
+
+ grub_memset (&info, 0, sizeof (info));
+ info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+ info.mtimeset = !!iso9660_to_unixtime2 (&node->dirents[0].mtime, &info.mtime);
+
+ grub_free (node);
+ return ctx->hook (filename, &info, ctx->hook_data);
+}
+
+static grub_err_t
+grub_iso9660_dir (grub_device_t device, const char *path,
+ grub_fs_dir_hook_t hook, void *hook_data)
+{
+ struct grub_iso9660_dir_ctx ctx = { hook, hook_data };
+ struct grub_iso9660_data *data = 0;
+ struct grub_fshelp_node rootnode;
+ struct grub_fshelp_node *foundnode;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_iso9660_mount (device->disk);
+ if (! data)
+ goto fail;
+
+ rootnode.data = data;
+ rootnode.alloc_dirents = 0;
+ rootnode.have_dirents = 1;
+ rootnode.have_symlink = 0;
+ rootnode.dirents[0] = data->voldesc.rootdir;
+
+ /* Use the fshelp function to traverse the path. */
+ if (grub_fshelp_find_file (path, &rootnode,
+ &foundnode,
+ grub_iso9660_iterate_dir,
+ grub_iso9660_read_symlink,
+ GRUB_FSHELP_DIR))
+ goto fail;
+
+ /* List the files in the directory. */
+ grub_iso9660_iterate_dir (foundnode, grub_iso9660_dir_iter, &ctx);
+
+ if (foundnode != &rootnode)
+ grub_free (foundnode);
+
+ fail:
+ grub_free (data);
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+
+/* Open a file named NAME and initialize FILE. */
+static grub_err_t
+grub_iso9660_open (struct grub_file *file, const char *name)
+{
+ struct grub_iso9660_data *data;
+ struct grub_fshelp_node rootnode;
+ struct grub_fshelp_node *foundnode;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_iso9660_mount (file->device->disk);
+ if (!data)
+ goto fail;
+
+ rootnode.data = data;
+ rootnode.alloc_dirents = 0;
+ rootnode.have_dirents = 1;
+ rootnode.have_symlink = 0;
+ rootnode.dirents[0] = data->voldesc.rootdir;
+
+ /* Use the fshelp function to traverse the path. */
+ if (grub_fshelp_find_file (name, &rootnode,
+ &foundnode,
+ grub_iso9660_iterate_dir,
+ grub_iso9660_read_symlink,
+ GRUB_FSHELP_REG))
+ goto fail;
+
+ data->node = foundnode;
+ file->data = data;
+ file->size = get_node_size (foundnode);
+ file->offset = 0;
+
+ return 0;
+
+ fail:
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+
+static grub_ssize_t
+grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len)
+{
+ struct grub_iso9660_data *data =
+ (struct grub_iso9660_data *) file->data;
+ grub_err_t err;
+
+ /* XXX: The file is stored in as a single extent. */
+ data->disk->read_hook = file->read_hook;
+ data->disk->read_hook_data = file->read_hook_data;
+ err = read_node (data->node, file->offset, len, buf);
+ data->disk->read_hook = NULL;
+
+ if (err || grub_errno)
+ return -1;
+
+ return len;
+}
+
+
+static grub_err_t
+grub_iso9660_close (grub_file_t file)
+{
+ struct grub_iso9660_data *data =
+ (struct grub_iso9660_data *) file->data;
+ grub_free (data->node);
+ grub_free (data);
+
+ grub_dl_unref (my_mod);
+
+ return GRUB_ERR_NONE;
+}
+
+
+static grub_err_t
+grub_iso9660_label (grub_device_t device, char **label)
+{
+ struct grub_iso9660_data *data;
+ data = grub_iso9660_mount (device->disk);
+
+ if (data)
+ {
+ if (data->joliet)
+ *label = grub_iso9660_convert_string (data->voldesc.volname, 16);
+ else
+ *label = grub_strndup ((char *) data->voldesc.volname, 32);
+ if (*label)
+ {
+ char *ptr;
+ for (ptr = *label; *ptr;ptr++);
+ ptr--;
+ while (ptr >= *label && *ptr == ' ')
+ *ptr-- = 0;
+ }
+
+ grub_free (data);
+ }
+ else
+ *label = 0;
+
+ return grub_errno;
+}
+
+
+static grub_err_t
+grub_iso9660_uuid (grub_device_t device, char **uuid)
+{
+ struct grub_iso9660_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_iso9660_mount (disk);
+ if (data)
+ {
+ if (! data->voldesc.modified.year[0] && ! data->voldesc.modified.year[1]
+ && ! data->voldesc.modified.year[2] && ! data->voldesc.modified.year[3]
+ && ! data->voldesc.modified.month[0] && ! data->voldesc.modified.month[1]
+ && ! data->voldesc.modified.day[0] && ! data->voldesc.modified.day[1]
+ && ! data->voldesc.modified.hour[0] && ! data->voldesc.modified.hour[1]
+ && ! data->voldesc.modified.minute[0] && ! data->voldesc.modified.minute[1]
+ && ! data->voldesc.modified.second[0] && ! data->voldesc.modified.second[1]
+ && ! data->voldesc.modified.hundredth[0] && ! data->voldesc.modified.hundredth[1])
+ {
+ grub_error (GRUB_ERR_BAD_NUMBER, "no creation date in filesystem to generate UUID");
+ *uuid = NULL;
+ }
+ else
+ {
+ *uuid = grub_xasprintf ("%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c",
+ data->voldesc.modified.year[0],
+ data->voldesc.modified.year[1],
+ data->voldesc.modified.year[2],
+ data->voldesc.modified.year[3],
+ data->voldesc.modified.month[0],
+ data->voldesc.modified.month[1],
+ data->voldesc.modified.day[0],
+ data->voldesc.modified.day[1],
+ data->voldesc.modified.hour[0],
+ data->voldesc.modified.hour[1],
+ data->voldesc.modified.minute[0],
+ data->voldesc.modified.minute[1],
+ data->voldesc.modified.second[0],
+ data->voldesc.modified.second[1],
+ data->voldesc.modified.hundredth[0],
+ data->voldesc.modified.hundredth[1]);
+ }
+ }
+ else
+ *uuid = NULL;
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+/* Get writing time of filesystem. */
+static grub_err_t
+grub_iso9660_mtime (grub_device_t device, grub_int32_t *timebuf)
+{
+ struct grub_iso9660_data *data;
+ grub_disk_t disk = device->disk;
+ grub_err_t err;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_iso9660_mount (disk);
+ if (!data)
+ {
+ grub_dl_unref (my_mod);
+ return grub_errno;
+ }
+ err = iso9660_to_unixtime (&data->voldesc.modified, timebuf);
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return err;
+}
+
+
+
+
+static struct grub_fs grub_iso9660_fs =
+ {
+ .name = "iso9660",
+ .fs_dir = grub_iso9660_dir,
+ .fs_open = grub_iso9660_open,
+ .fs_read = grub_iso9660_read,
+ .fs_close = grub_iso9660_close,
+ .fs_label = grub_iso9660_label,
+ .fs_uuid = grub_iso9660_uuid,
+ .fs_mtime = grub_iso9660_mtime,
+#ifdef GRUB_UTIL
+ .reserved_first_sector = 1,
+ .blocklist_install = 1,
+#endif
+ .next = 0
+ };
+
+GRUB_MOD_INIT(iso9660)
+{
+ grub_fs_register (&grub_iso9660_fs);
+ my_mod = mod;
+}
+
+GRUB_MOD_FINI(iso9660)
+{
+ grub_fs_unregister (&grub_iso9660_fs);
+}
diff --git a/EDK2/efiffs/org/src/file.c b/EDK2/efiffs/org/src/file.c
new file mode 100644
index 00000000000..66b678025f0
--- /dev/null
+++ b/EDK2/efiffs/org/src/file.c
@@ -0,0 +1,784 @@
+/* file.c - SimpleFileIo Interface */
+/*
+ * Copyright © 2014-2017 Pete Batard
+ * Based on iPXE's efi_driver.c and efi_file.c:
+ * Copyright © 2011,2013 Michael Brown .
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "driver.h"
+
+/**
+ * Get EFI file name (for debugging)
+ *
+ * @v file EFI file
+ * @ret Name Name
+ */
+static const CHAR16 *
+FileName(EFI_GRUB_FILE *File)
+{
+ EFI_STATUS Status;
+ static CHAR16 Path[MAX_PATH];
+
+ Status = Utf8ToUtf16NoAlloc(File->path, Path, sizeof(Path));
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not convert filename to UTF16");
+ return NULL;
+ }
+
+ return Path;
+}
+
+/* Simple hook to populate the timestamp and directory flag when opening a file */
+static INT32
+InfoHook(const CHAR8 *name, const GRUB_DIRHOOK_INFO *Info, VOID *Data)
+{
+ EFI_GRUB_FILE *File = (EFI_GRUB_FILE *) Data;
+
+ /* Look for a specific file */
+ if (strcmpa(name, File->basename) != 0)
+ return 0;
+
+ File->IsDir = (BOOLEAN) (Info->Dir);
+ if (Info->MtimeSet)
+ File->Mtime = Info->Mtime;
+
+ return 0;
+}
+
+/**
+ * Open file
+ *
+ * @v This File handle
+ * @ret new New file handle
+ * @v Name File name
+ * @v Mode File mode
+ * @v Attributes File attributes (for newly-created files)
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileOpen(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New,
+ CHAR16 *Name, UINT64 Mode, UINT64 Attributes)
+{
+ EFI_STATUS Status;
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+ EFI_GRUB_FILE *NewFile;
+
+ // TODO: Use dynamic buffers?
+ char path[MAX_PATH], clean_path[MAX_PATH], *dirname;
+ INTN i, len;
+ BOOLEAN AbsolutePath = (*Name == L'\\');
+
+ PrintInfo(L"Open(" PERCENT_P L"%s, \"%s\")\n", (UINTN) This,
+ IS_ROOT(File)?L" ":L"", Name);
+
+ /* Fail unless opening read-only */
+ if (Mode != EFI_FILE_MODE_READ) {
+ PrintWarning(L"File '%s' can only be opened in read-only mode\n", Name);
+ return EFI_WRITE_PROTECTED;
+ }
+
+ /* Additional failures */
+ if ((StrCmp(Name, L"..") == 0) && IS_ROOT(File)) {
+ PrintInfo(L"Trying to open 's parent\n");
+ return EFI_NOT_FOUND;
+ }
+
+ /* See if we're trying to reopen current (which the EFI Shell insists on doing) */
+ if ((*Name == 0) || (StrCmp(Name, L".") == 0)) {
+ PrintInfo(L" Reopening %s\n", IS_ROOT(File)?L"":FileName(File));
+ File->RefCount++;
+ *New = This;
+ PrintInfo(L" RET: " PERCENT_P L"\n", (UINTN) *New);
+ return EFI_SUCCESS;
+ }
+
+ /* If we have an absolute path, don't bother completing with the parent */
+ if (AbsolutePath) {
+ len = 0;
+ } else {
+ strcpya(path, File->path);
+ len = strlena(path);
+ /* Add delimiter if needed */
+ if ((len == 0) || (path[len-1] != '/'))
+ path[len++] = '/';
+ }
+
+ /* Copy the rest of the path (converted to UTF-8) */
+ Status = Utf16ToUtf8NoAlloc(Name, &path[len], sizeof(path) - len);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not convert path to UTF-8");
+ return Status;
+ }
+ /* Convert the delimiters */
+ for (i = strlena(path) - 1 ; i >= len; i--) {
+ if (path[i] == '\\')
+ path[i] = '/';
+ }
+
+ /* We only want to handle with absolute paths */
+ clean_path[0] = '/';
+ /* Find out if we're dealing with root by removing the junk */
+ CopyPathRelative(&clean_path[1], path, MAX_PATH - 1);
+ if (clean_path[1] == 0) {
+ /* We're dealing with the root */
+ PrintInfo(L" Reopening \n");
+ *New = &File->FileSystem->RootFile->EfiFile;
+ /* Must make sure that DirIndex is reset too (NB: no concurrent access!) */
+ File->FileSystem->RootFile->DirIndex = 0;
+ PrintInfo(L" RET: " PERCENT_P L"\n", (UINTN) *New);
+ return EFI_SUCCESS;
+ }
+
+ // TODO: eventually we should seek for already opened files and increase RefCount
+ /* Allocate and initialise an instance of a file */
+ Status = GrubCreateFile(&NewFile, File->FileSystem);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not instantiate file");
+ return Status;
+ }
+
+ NewFile->path = AllocatePool(strlena(clean_path)+1);
+ if (NewFile->path == NULL) {
+ GrubDestroyFile(NewFile);
+ PrintError(L"Could not instantiate path\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ strcpya(NewFile->path, clean_path);
+
+ /* Isolate the basename and dirname */
+ for (i = strlena(clean_path) - 1; i >= 0; i--) {
+ if (clean_path[i] == '/') {
+ clean_path[i] = 0;
+ break;
+ }
+ }
+ dirname = (i <= 0) ? "/" : clean_path;
+ NewFile->basename = &NewFile->path[i+1];
+
+ /* Find if we're working with a directory and fill the grub timestamp */
+ Status = GrubDir(NewFile, dirname, InfoHook, (VOID *) NewFile);
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_NOT_FOUND)
+ PrintStatusError(Status, L"Could not get file attributes for '%s'", Name);
+ FreePool(NewFile->path);
+ GrubDestroyFile(NewFile);
+ return Status;
+ }
+
+ /* Finally we can call on GRUB open() if it's a regular file */
+ if (!NewFile->IsDir) {
+ Status = GrubOpen(NewFile);
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_NOT_FOUND)
+ PrintStatusError(Status, L"Could not open file '%s'", Name);
+ FreePool(NewFile->path);
+ GrubDestroyFile(NewFile);
+ return Status;
+ }
+ }
+
+ NewFile->RefCount++;
+ *New = &NewFile->EfiFile;
+
+ PrintInfo(L" RET: " PERCENT_P L"\n", (UINTN) *New);
+ return EFI_SUCCESS;
+}
+
+/* Ex version */
+static EFI_STATUS EFIAPI
+FileOpenEx(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New, CHAR16 *Name,
+ UINT64 Mode, UINT64 Attributes, EFI_FILE_IO_TOKEN *Token)
+{
+ return FileOpen(This, New, Name, Mode, Attributes);
+}
+
+
+/**
+ * Close file
+ *
+ * @v This File handle
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileClose(EFI_FILE_HANDLE This)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintInfo(L"Close(" PERCENT_P L"|'%s') %s\n", (UINTN) This, FileName(File),
+ IS_ROOT(File)?L"":L"");
+
+ /* Nothing to do it this is the root */
+ if (IS_ROOT(File))
+ return EFI_SUCCESS;
+
+ if (--File->RefCount == 0) {
+ /* Close the file if it's a regular one */
+ if (!File->IsDir)
+ GrubClose(File);
+ /* NB: basename points into File->path and does not need to be freed */
+ if (File->path != NULL)
+ FreePool(File->path);
+ GrubDestroyFile(File);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Close and delete file
+ *
+ * @v This File handle
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileDelete(EFI_FILE_HANDLE This)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintError(L"Cannot delete '%s'\n", FileName(File));
+
+ /* Close file */
+ FileClose(This);
+
+ /* Warn of failure to delete */
+ return EFI_WARN_DELETE_FAILURE;
+}
+
+/* GRUB uses a callback for each directory entry, whereas EFI uses repeated
+ * firmware generated calls to FileReadDir() to get the info for each entry,
+ * so we have to reconcile the twos. For now, we'll re-issue a call to GRUB
+ * dir(), and run through all the entries (to find the one we
+ * are interested in) multiple times. Maybe later we'll try to optimize this
+ * by building a one-off chained list of entries that we can parse...
+ */
+static INT32
+DirHook(const CHAR8 *name, const GRUB_DIRHOOK_INFO *DirInfo, VOID *Data)
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data;
+ INT64 *Index = (INT64 *) &Info->FileSize;
+ CHAR8 *filename = (CHAR8 *) (UINTN) Info->PhysicalSize;
+ EFI_TIME Time = { 1970, 01, 01, 00, 00, 00, 0, 0, 0, 0, 0};
+
+ // Eliminate '.' or '..'
+ if ((name[0] == '.') && ((name[1] == 0) || ((name[1] == '.') && (name[2] == 0))))
+ return 0;
+
+ /* Ignore any entry that doesn't match our index */
+ if ((*Index)-- != 0)
+ return 0;
+
+ strcpya(filename, name);
+
+ Status = Utf8ToUtf16NoAlloc(filename, Info->FileName, (INTN)(Info->Size - sizeof(EFI_FILE_INFO)));
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_BUFFER_TOO_SMALL)
+ PrintStatusError(Status, L"Could not convert directory entry to UTF-8");
+ return (INT32) Status;
+ }
+ /* The Info struct size already accounts for the extra NUL */
+ Info->Size = sizeof(*Info) + StrLen(Info->FileName) * sizeof(CHAR16);
+
+ // Oh, and of course GRUB uses a 32 bit signed mtime value (seriously, wtf guys?!?)
+ if (DirInfo->MtimeSet)
+ GrubTimeToEfiTime(DirInfo->Mtime, &Time);
+ CopyMem(&Info->CreateTime, &Time, sizeof(Time));
+ CopyMem(&Info->LastAccessTime, &Time, sizeof(Time));
+ CopyMem(&Info->ModificationTime, &Time, sizeof(Time));
+
+ Info->Attribute = EFI_FILE_READ_ONLY;
+ if (DirInfo->Dir)
+ Info->Attribute |= EFI_FILE_DIRECTORY;
+
+ return 0;
+}
+
+/**
+ * Read directory entry
+ *
+ * @v file EFI file
+ * @v Len Length to read
+ * @v Data Data buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS
+FileReadDir(EFI_GRUB_FILE *File, UINTN *Len, VOID *Data)
+{
+ EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data;
+ EFI_STATUS Status;
+ /* We temporarily repurpose the FileSize as a *signed* entry index */
+ INT64 *Index = (INT64 *) &Info->FileSize;
+ /* And PhysicalSize as a pointer to our filename */
+ CHAR8 **basename = (CHAR8 **) &Info->PhysicalSize;
+ CHAR8 path[MAX_PATH];
+ EFI_GRUB_FILE *TmpFile = NULL;
+ INTN len;
+
+ /* Unless we can fit our maximum size, forget it */
+ if (*Len < MINIMUM_INFO_LENGTH) {
+ *Len = MINIMUM_INFO_LENGTH;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ /* Populate our Info template */
+ ZeroMem(Data, *Len);
+ Info->Size = *Len;
+ *Index = File->DirIndex;
+ strcpya(path, File->path);
+ len = strlena(path);
+ if (path[len-1] != '/')
+ path[len++] = '/';
+ *basename = &path[len];
+
+ /* Invoke GRUB's directory listing */
+ Status = GrubDir(File, File->path, DirHook, Data);
+ if (*Index >= 0) {
+ /* No more entries */
+ *Len = 0;
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Directory listing failed");
+ return Status;
+ }
+
+ /* Our Index/FileSize must be reset */
+ Info->FileSize = 0;
+ Info->PhysicalSize = 0;
+
+ /* For regular files, we still need to fill the size */
+ if (!(Info->Attribute & EFI_FILE_DIRECTORY)) {
+ /* Open the file and read its size */
+ Status = GrubCreateFile(&TmpFile, File->FileSystem);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Unable to create temporary file");
+ return Status;
+ }
+ TmpFile->path = path;
+
+ Status = GrubOpen(TmpFile);
+ if (EFI_ERROR(Status)) {
+ // TODO: EFI_NO_MAPPING is returned for links...
+ PrintStatusError(Status, L"Unable to obtain the size of '%s'", Info->FileName);
+ /* Non fatal error */
+ } else {
+ Info->FileSize = GrubGetFileSize(TmpFile);
+ Info->PhysicalSize = GrubGetFileSize(TmpFile);
+ GrubClose(TmpFile);
+ }
+ GrubDestroyFile(TmpFile);
+ }
+
+ *Len = (UINTN) Info->Size;
+ /* Advance to the next entry */
+ File->DirIndex++;
+
+// PrintInfo(L" Entry[%d]: '%s' %s\n", File->DirIndex-1, Info->FileName,
+// (Info->Attribute&EFI_FILE_DIRECTORY)?L"":L"");
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Read from file
+ *
+ * @v This File handle
+ * @v Len Length to read
+ * @v Data Data buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileRead(EFI_FILE_HANDLE This, UINTN *Len, VOID *Data)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintInfo(L"Read(" PERCENT_P L"|'%s', %d) %s\n", (UINTN) This, FileName(File),
+ *Len, File->IsDir?L"":L"");
+
+ /* If this is a directory, then fetch the directory entries */
+ if (File->IsDir)
+ return FileReadDir(File, Len, Data);
+
+ return GrubRead(File, Data, Len);
+}
+
+/* Ex version */
+static EFI_STATUS EFIAPI
+FileReadEx(IN EFI_FILE_PROTOCOL *This, IN OUT EFI_FILE_IO_TOKEN *Token)
+{
+ return FileRead(This, &(Token->BufferSize), Token->Buffer);
+}
+
+/**
+ * Write to file
+ *
+ * @v This File handle
+ * @v Len Length to write
+ * @v Data Data buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileWrite(EFI_FILE_HANDLE This, UINTN *Len, VOID *Data)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintError(L"Cannot write to '%s'\n", FileName(File));
+ return EFI_WRITE_PROTECTED;
+}
+
+/* Ex version */
+static EFI_STATUS EFIAPI
+FileWriteEx(IN EFI_FILE_PROTOCOL *This, IN OUT EFI_FILE_IO_TOKEN *Token)
+{
+ return FileWrite(This, &(Token->BufferSize), Token->Buffer);
+}
+
+/**
+ * Set file position
+ *
+ * @v This File handle
+ * @v Position New file position
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileSetPosition(EFI_FILE_HANDLE This, UINT64 Position)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+ UINT64 FileSize;
+
+ PrintInfo(L"SetPosition(" PERCENT_P L"|'%s', %lld) %s\n", (UINTN) This,
+ FileName(File), Position, (File->IsDir)?L"":L"");
+
+ /* If this is a directory, reset the Index to the start */
+ if (File->IsDir) {
+ if (Position != 0)
+ return EFI_INVALID_PARAMETER;
+ File->DirIndex = 0;
+ return EFI_SUCCESS;
+ }
+
+ /* Fail if we attempt to seek past the end of the file (since
+ * we do not support writes).
+ */
+ FileSize = GrubGetFileSize(File);
+ if (Position > FileSize) {
+ PrintError(L"'%s': Cannot seek to #%llx of %llx\n",
+ FileName(File), Position, FileSize);
+ return EFI_UNSUPPORTED;
+ }
+
+ /* Set position */
+ GrubSetFileOffset(File, Position);
+ PrintDebug(L"'%s': Position set to %llx\n",
+ FileName(File), Position);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Get file position
+ *
+ * @v This File handle
+ * @ret Position New file position
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileGetPosition(EFI_FILE_HANDLE This, UINT64 *Position)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintInfo(L"GetPosition(" PERCENT_P L"|'%s', %lld)\n", (UINTN) This, FileName(File));
+
+ if (File->IsDir)
+ *Position = File->DirIndex;
+ else
+ *Position = GrubGetFileOffset(File);
+ return EFI_SUCCESS;
+}
+
+/**
+ * Get file information
+ *
+ * @v This File handle
+ * @v Type Type of information
+ * @v Len Buffer size
+ * @v Data Buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileGetInfo(EFI_FILE_HANDLE This, EFI_GUID *Type, UINTN *Len, VOID *Data)
+{
+ EFI_STATUS Status;
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+ EFI_FILE_SYSTEM_INFO *FSInfo = (EFI_FILE_SYSTEM_INFO *) Data;
+ EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data;
+ EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *VLInfo = (EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Data;
+ EFI_TIME Time;
+ CHAR8* label;
+ UINTN tmpLen;
+
+ PrintInfo(L"GetInfo(" PERCENT_P L"|'%s', %d) %s\n", (UINTN) This,
+ FileName(File), *Len, File->IsDir?L"":L"");
+
+ /* Determine information to return */
+ if (CompareMem(Type, &gEfiFileInfoGuid, sizeof(*Type)) == 0) {
+
+ /* Fill file information */
+ PrintExtra(L"Get regular file information\n");
+ if (*Len < MINIMUM_INFO_LENGTH) {
+ *Len = MINIMUM_INFO_LENGTH;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ ZeroMem(Data, sizeof(EFI_FILE_INFO));
+
+ Info->Attribute = EFI_FILE_READ_ONLY;
+ GrubTimeToEfiTime(File->Mtime, &Time);
+ CopyMem(&Info->CreateTime, &Time, sizeof(Time));
+ CopyMem(&Info->LastAccessTime, &Time, sizeof(Time));
+ CopyMem(&Info->ModificationTime, &Time, sizeof(Time));
+
+ if (File->IsDir) {
+ Info->Attribute |= EFI_FILE_DIRECTORY;
+ } else {
+ Info->FileSize = GrubGetFileSize(File);
+ Info->PhysicalSize = GrubGetFileSize(File);
+ }
+
+ tmpLen = (UINTN)(Info->Size - sizeof(EFI_FILE_INFO) - 1);
+ Status = Utf8ToUtf16NoAllocUpdateLen(File->basename, Info->FileName, &tmpLen);
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_BUFFER_TOO_SMALL)
+ PrintStatusError(Status, L"Could not convert basename to UTF-16");
+ return Status;
+ }
+
+ /* The Info struct size already accounts for the extra NUL */
+ Info->Size = sizeof(EFI_FILE_INFO) + tmpLen;
+ *Len = (INTN)Info->Size;
+ return EFI_SUCCESS;
+
+ } else if (CompareMem(Type, &gEfiFileSystemInfoGuid, sizeof(*Type)) == 0) {
+
+ /* Get file system information */
+ PrintExtra(L"Get file system information\n");
+ if (*Len < MINIMUM_FS_INFO_LENGTH) {
+ *Len = MINIMUM_FS_INFO_LENGTH;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ ZeroMem(Data, sizeof(EFI_FILE_INFO));
+ FSInfo->Size = *Len;
+ FSInfo->ReadOnly = 1;
+ /* NB: This should really be cluster size, but we don't have access to that */
+ if (File->FileSystem->BlockIo2 != NULL) {
+ FSInfo->BlockSize = File->FileSystem->BlockIo2->Media->BlockSize;
+ } else {
+ FSInfo->BlockSize = File->FileSystem->BlockIo->Media->BlockSize;
+ }
+ if (FSInfo->BlockSize == 0) {
+ PrintWarning(L"Corrected Media BlockSize\n");
+ FSInfo->BlockSize = 512;
+ }
+ if (File->FileSystem->BlockIo2 != NULL) {
+ FSInfo->VolumeSize = (File->FileSystem->BlockIo2->Media->LastBlock + 1) *
+ FSInfo->BlockSize;
+ } else {
+ FSInfo->VolumeSize = (File->FileSystem->BlockIo->Media->LastBlock + 1) *
+ FSInfo->BlockSize;
+ }
+ /* No idea if we can easily get this for GRUB, and the device is RO anyway */
+ FSInfo->FreeSpace = 0;
+
+ Status = GrubLabel(File, &label);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not read disk label");
+ FSInfo->VolumeLabel[0] = 0;
+ *Len = sizeof(EFI_FILE_SYSTEM_INFO);
+ } else {
+ tmpLen = (INTN)(FSInfo->Size - sizeof(EFI_FILE_SYSTEM_INFO) - 1);
+ Status = Utf8ToUtf16NoAllocUpdateLen(label, FSInfo->VolumeLabel, &tmpLen);
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_BUFFER_TOO_SMALL)
+ PrintStatusError(Status, L"Could not convert label to UTF-16");
+ return Status;
+ }
+ FSInfo->Size = sizeof(EFI_FILE_SYSTEM_INFO) - 1 + tmpLen;
+ *Len = (INTN)FSInfo->Size;
+ }
+ return EFI_SUCCESS;
+
+ } else if (CompareMem(Type, &gEfiFileSystemVolumeLabelInfoIdGuid, sizeof(*Type)) == 0) {
+
+ /* Get the volume label */
+ Status = GrubLabel(File, &label);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not read disk label");
+ }
+ else {
+ Status = Utf8ToUtf16NoAllocUpdateLen(label, VLInfo->VolumeLabel, Len);
+ if (EFI_ERROR(Status)) {
+ if (Status != EFI_BUFFER_TOO_SMALL)
+ PrintStatusError(Status, L"Could not convert label to UTF-16");
+ return Status;
+ }
+ }
+ return EFI_SUCCESS;
+
+ } else {
+
+ Print(L"'%s': Cannot get information of type ", FileName(File));
+ PrintGuid(Type);
+ Print(L"\n");
+ return EFI_UNSUPPORTED;
+
+ }
+}
+
+/**
+ * Set file information
+ *
+ * @v This File handle
+ * @v Type Type of information
+ * @v Len Buffer size
+ * @v Data Buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileSetInfo(EFI_FILE_HANDLE This, EFI_GUID *Type, UINTN Len, VOID *Data)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ Print(L"Cannot set information of type ");
+ PrintGuid(Type);
+ Print(L" for file '%s'\n", FileName(File));
+
+ return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * Flush file modified data
+ *
+ * @v This File handle
+ * @v Type Type of information
+ * @v Len Buffer size
+ * @v Data Buffer
+ * @ret Status EFI status code
+ */
+static EFI_STATUS EFIAPI
+FileFlush(EFI_FILE_HANDLE This)
+{
+ EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile);
+
+ PrintInfo(L"Flush(" PERCENT_P L"|'%s')\n", (UINTN) This, FileName(File));
+ return EFI_SUCCESS;
+}
+
+/* Ex version */
+static EFI_STATUS EFIAPI
+FileFlushEx(EFI_FILE_HANDLE This, EFI_FILE_IO_TOKEN *Token)
+{
+ return FileFlush(This);
+}
+
+/**
+ * Open root directory
+ *
+ * @v This EFI simple file system
+ * @ret Root File handle for the root directory
+ * @ret Status EFI status code
+ */
+EFI_STATUS EFIAPI
+FileOpenVolume(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, EFI_FILE_HANDLE *Root)
+{
+ EFI_FS *FSInstance = _CR(This, EFI_FS, FileIoInterface);
+
+ PrintInfo(L"OpenVolume\n");
+ *Root = &FSInstance->RootFile->EfiFile;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Install the EFI simple file system protocol
+ * If successful this call instantiates a new FS#: drive, that is made
+ * available on the next 'map -r'. Note that all this call does is add
+ * the FS protocol. OpenVolume won't be called until a process tries
+ * to access a file or the root directory on the volume.
+ */
+EFI_STATUS
+FSInstall(EFI_FS *This, EFI_HANDLE ControllerHandle)
+{
+ EFI_STATUS Status;
+
+ /* Check if it's a filesystem we can handle */
+ if (!GrubFSProbe(This))
+ return EFI_UNSUPPORTED;
+
+ PrintInfo(L"FSInstall: %s\n", This->DevicePathString);
+
+ /* Initialize the root handle */
+ Status = GrubCreateFile(&This->RootFile, This);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not create root file");
+ return Status;
+ }
+
+ /* Setup the EFI part */
+ This->RootFile->EfiFile.Revision = EFI_FILE_PROTOCOL_REVISION2;
+ This->RootFile->EfiFile.Open = FileOpen;
+ This->RootFile->EfiFile.Close = FileClose;
+ This->RootFile->EfiFile.Delete = FileDelete;
+ This->RootFile->EfiFile.Read = FileRead;
+ This->RootFile->EfiFile.Write = FileWrite;
+ This->RootFile->EfiFile.GetPosition = FileGetPosition;
+ This->RootFile->EfiFile.SetPosition = FileSetPosition;
+ This->RootFile->EfiFile.GetInfo = FileGetInfo;
+ This->RootFile->EfiFile.SetInfo = FileSetInfo;
+ This->RootFile->EfiFile.Flush = FileFlush;
+ This->RootFile->EfiFile.OpenEx = FileOpenEx;
+ This->RootFile->EfiFile.ReadEx = FileReadEx;
+ This->RootFile->EfiFile.WriteEx = FileWriteEx;
+ This->RootFile->EfiFile.FlushEx = FileFlushEx;
+
+ /* Setup the other attributes */
+ This->RootFile->path = "/";
+ This->RootFile->basename = &This->RootFile->path[1];
+ This->RootFile->IsDir = TRUE;
+
+ /* Install the simple file system protocol. */
+ Status = BS->InstallMultipleProtocolInterfaces(&ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid, &This->FileIoInterface,
+ NULL);
+ if (EFI_ERROR(Status)) {
+ PrintStatusError(Status, L"Could not install simple file system protocol");
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/* Uninstall EFI simple file system protocol */
+VOID
+FSUninstall(EFI_FS *This, EFI_HANDLE ControllerHandle)
+{
+ PrintInfo(L"FSUninstall: %s\n", This->DevicePathString);
+
+ BS->UninstallMultipleProtocolInterfaces(ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid, &This->FileIoInterface,
+ NULL);
+}
diff --git a/EDK2/efiffs/org/src/logging.c b/EDK2/efiffs/org/src/logging.c
new file mode 100644
index 00000000000..34ca6538782
--- /dev/null
+++ b/EDK2/efiffs/org/src/logging.c
@@ -0,0 +1,80 @@
+/* logging.c - EFI logging */
+/*
+ * Copyright © 2014-2017 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "driver.h"
+
+/* Not defined in gnu-efi yet */
+#define SHELL_VARIABLE_GUID { \
+ 0x158def5a, 0xf656, 0x419c, { 0xb0, 0x27, 0x7a, 0x31, 0x92, 0xc0, 0x79, 0xd2 } \
+}
+extern EFI_GUID gShellVariableGuid;
+EFI_GUID ShellVariable = SHELL_VARIABLE_GUID;
+
+static UINTN PrintNone(IN CONST CHAR16 *fmt, ... ) { return 0; }
+Print_t PrintError = PrintNone;
+Print_t PrintWarning = PrintNone;
+Print_t PrintInfo = PrintNone;
+Print_t PrintDebug = PrintNone;
+Print_t PrintExtra = PrintNone;
+Print_t* PrintTable[] = { &PrintError, &PrintWarning, &PrintInfo,
+ &PrintDebug, &PrintExtra };
+
+/* Global driver verbosity level */
+#if !defined(DEFAULT_LOGLEVEL)
+#define DEFAULT_LOGLEVEL FS_LOGLEVEL_NONE
+#endif
+UINTN LogLevel = DEFAULT_LOGLEVEL;
+
+/**
+ * Print status
+ *
+ * @v Status EFI status code
+ */
+VOID
+PrintStatus(EFI_STATUS Status)
+{
+#if defined(__MAKEWITH_GNUEFI)
+ CHAR16 StatusString[64];
+ StatusToString(StatusString, Status);
+ // Make sure the Status is unsigned 32 bits
+ Print(L": [%d] %s\n", (Status & 0x7FFFFFFF), StatusString);
+#else
+ Print(L": [%d]\n", (Status & 0x7FFFFFFF));
+#endif
+}
+
+/*
+ * You can control the verbosity of the driver output by setting the shell environment
+ * variable FS_LOGGING to one of the values defined in the FS_LOGLEVEL constants
+ */
+VOID
+SetLogging(VOID)
+{
+ EFI_STATUS Status;
+ CHAR16 LogVar[4];
+ UINTN i, LogVarSize = sizeof(LogVar);
+
+ Status = RT->GetVariable(L"FS_LOGGING", &ShellVariable, NULL, &LogVarSize, LogVar);
+ if (Status == EFI_SUCCESS)
+ LogLevel = Atoi(LogVar);
+
+ for (i=0; i= 0) argv[0][0] = '@';" -i exfat-1.3.0/fuse/main.c
cd exfat-1.3.0
autoreconf --install
@@ -42,6 +42,8 @@ cd ..
rm -rf exfat-1.3.0
unzip exfat-1.3.0.zip
+sed "/printf.*VERSION/a\ if (access(\"/etc/initrd-release\", F_OK) >= 0) argv[0][0] = '@';" -i exfat-1.3.0/fuse/main.c
+
cd exfat-1.3.0
autoreconf --install
diff --git a/FUSEISO/build.sh b/FUSEISO/build.sh
index 17950add328..af510d022c4 100644
--- a/FUSEISO/build.sh
+++ b/FUSEISO/build.sh
@@ -2,8 +2,7 @@
CUR="$PWD"
-#LIBFUSE_DIR=$CUR/LIBFUSE
-LIBFUSE_DIR=../ExFAT/LIBFUSE
+LIBFUSE_DIR=$CUR/LIBFUSE
if uname -a | egrep -q 'x86_64|amd64'; then
name=vtoy_fuse_iso_64
diff --git a/FUSEISO/build_libfuse.sh b/FUSEISO/build_libfuse.sh
index 25ef02a6c4a..64f6d756603 100644
--- a/FUSEISO/build_libfuse.sh
+++ b/FUSEISO/build_libfuse.sh
@@ -15,12 +15,12 @@ rm -rf libfuse
rm -rf $LIBFUSE_DIR
# please download https://gitee.com/mirrors/libfuse/repository/archive/fuse-2.9.9.zip
-if ! [ -e mirrors-libfuse-fuse-2.9.9.zip ]; then
+if ! [ -e ../ExFAT/mirrors-libfuse-fuse-2.9.9.zip ]; then
echo "Please download mirrors-libfuse-fuse-2.9.9.zip first"
exit 1
fi
-unzip mirrors-libfuse-fuse-2.9.9.zip
+unzip ../ExFAT/mirrors-libfuse-fuse-2.9.9.zip
cd libfuse
diff --git a/FUSEISO/vtoy_fuse_iso_32 b/FUSEISO/vtoy_fuse_iso_32
new file mode 100644
index 00000000000..607ce42a9e1
Binary files /dev/null and b/FUSEISO/vtoy_fuse_iso_32 differ
diff --git a/FUSEISO/vtoy_fuse_iso_64 b/FUSEISO/vtoy_fuse_iso_64
new file mode 100644
index 00000000000..ad4ff34050b
Binary files /dev/null and b/FUSEISO/vtoy_fuse_iso_64 differ
diff --git a/GRUB2/grub-2.04/grub-core/Makefile.core.def b/GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.core.def
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/Makefile.core.def
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.core.def
diff --git a/GRUB2/grub-2.04/grub-core/boot/i386/pc/boot.S b/GRUB2/MOD_SRC/grub-2.04/grub-core/boot/i386/pc/boot.S
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/boot/i386/pc/boot.S
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/boot/i386/pc/boot.S
diff --git a/GRUB2/grub-2.04/grub-core/commands/blocklist.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/blocklist.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/commands/blocklist.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/commands/blocklist.c
diff --git a/GRUB2/grub-2.04/grub-core/disk/i386/pc/biosdisk.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
diff --git a/GRUB2/grub-2.04/grub-core/fs/ext2.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ext2.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/fs/ext2.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ext2.c
diff --git a/GRUB2/grub-2.04/grub-core/fs/fat.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/fat.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/fs/fat.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/fs/fat.c
diff --git a/GRUB2/grub-2.04/grub-core/fs/iso9660.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/iso9660.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/fs/iso9660.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/fs/iso9660.c
diff --git a/GRUB2/grub-2.04/grub-core/fs/ntfs.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ntfs.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/fs/ntfs.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ntfs.c
diff --git a/GRUB2/grub-2.04/grub-core/fs/udf.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/udf.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/fs/udf.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/fs/udf.c
diff --git a/GRUB2/grub-2.04/grub-core/fs/xfs.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/xfs.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/fs/xfs.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/fs/xfs.c
diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gfxmenu.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gfxmenu.c
new file mode 100644
index 00000000000..4dc537e7c01
--- /dev/null
+++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gfxmenu.c
@@ -0,0 +1,161 @@
+/* gfxmenu.c - Graphical menu interface controller. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+extern int g_ventoy_menu_refresh;
+
+static grub_gfxmenu_view_t cached_view;
+
+static void
+grub_gfxmenu_viewer_fini (void *data __attribute__ ((unused)))
+{
+}
+
+/* FIXME: Previously 't' changed to text menu is it necessary? */
+static grub_err_t
+grub_gfxmenu_try (int entry, grub_menu_t menu, int nested)
+{
+ int force_refresh = 0;
+ grub_gfxmenu_view_t view = NULL;
+ const char *theme_path;
+ char *full_theme_path = 0;
+ struct grub_menu_viewer *instance;
+ grub_err_t err;
+ struct grub_video_mode_info mode_info;
+
+ theme_path = grub_env_get ("theme");
+ if (! theme_path)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"),
+ "theme");
+
+ err = grub_video_get_info (&mode_info);
+ if (err)
+ return err;
+
+ instance = grub_zalloc (sizeof (*instance));
+ if (!instance)
+ return grub_errno;
+
+ if (theme_path[0] != '/' && theme_path[0] != '(')
+ {
+ const char *prefix;
+ prefix = grub_env_get ("prefix");
+ full_theme_path = grub_xasprintf ("%s/themes/%s",
+ prefix,
+ theme_path);
+ }
+
+ if (g_ventoy_menu_refresh)
+ {
+ g_ventoy_menu_refresh = 0;
+ force_refresh = 1;
+ }
+
+ if (force_refresh ||
+ !cached_view || grub_strcmp (cached_view->theme_path,
+ full_theme_path ? : theme_path) != 0
+ || cached_view->screen.width != mode_info.width
+ || cached_view->screen.height != mode_info.height)
+ {
+ grub_gfxmenu_view_destroy (cached_view);
+ /* Create the view. */
+ cached_view = grub_gfxmenu_view_new (full_theme_path ? : theme_path,
+ mode_info.width,
+ mode_info.height);
+ }
+ grub_free (full_theme_path);
+
+ if (! cached_view)
+ {
+ grub_free (instance);
+ return grub_errno;
+ }
+
+ view = cached_view;
+
+ view->double_repaint = (mode_info.mode_type
+ & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED)
+ && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
+ view->selected = entry;
+ view->menu = menu;
+ view->nested = nested;
+ view->first_timeout = -1;
+
+ grub_video_set_viewport (0, 0, mode_info.width, mode_info.height);
+ if (view->double_repaint)
+ {
+ grub_video_swap_buffers ();
+ grub_video_set_viewport (0, 0, mode_info.width, mode_info.height);
+ }
+
+ grub_gfxmenu_view_draw (view);
+
+ instance->data = view;
+ instance->set_chosen_entry = grub_gfxmenu_set_chosen_entry;
+ instance->fini = grub_gfxmenu_viewer_fini;
+ instance->print_timeout = grub_gfxmenu_print_timeout;
+ instance->clear_timeout = grub_gfxmenu_clear_timeout;
+
+ grub_menu_register_viewer (instance);
+
+ return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT (gfxmenu)
+{
+ struct grub_term_output *term;
+
+ FOR_ACTIVE_TERM_OUTPUTS(term)
+ if (grub_gfxmenu_try_hook && term->fullscreen)
+ {
+ term->fullscreen ();
+ break;
+ }
+
+ grub_gfxmenu_try_hook = grub_gfxmenu_try;
+}
+
+GRUB_MOD_FINI (gfxmenu)
+{
+ grub_gfxmenu_view_destroy (cached_view);
+ grub_gfxmenu_try_hook = NULL;
+}
diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c
new file mode 100644
index 00000000000..e1c1d478d78
--- /dev/null
+++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c
@@ -0,0 +1,295 @@
+/* gui_label.c - GUI component to display a line of text. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern int g_ventoy_memdisk_mode;
+extern int g_ventoy_iso_raw;
+extern int g_ventoy_iso_uefi_drv;
+
+static const char *align_options[] =
+{
+ "left",
+ "center",
+ "right",
+ 0
+};
+
+enum align_mode {
+ align_left,
+ align_center,
+ align_right
+};
+
+struct grub_gui_label
+{
+ struct grub_gui_component comp;
+
+ grub_gui_container_t parent;
+ grub_video_rect_t bounds;
+ char *id;
+ int visible;
+ char *text;
+ char *template;
+ grub_font_t font;
+ grub_video_rgba_color_t color;
+ int value;
+ enum align_mode align;
+};
+
+typedef struct grub_gui_label *grub_gui_label_t;
+
+static void
+label_destroy (void *vself)
+{
+ grub_gui_label_t self = vself;
+ grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self);
+ grub_free (self->text);
+ grub_free (self->template);
+ grub_free (self);
+}
+
+static const char *
+label_get_id (void *vself)
+{
+ grub_gui_label_t self = vself;
+ return self->id;
+}
+
+static int
+label_is_instance (void *vself __attribute__((unused)), const char *type)
+{
+ return grub_strcmp (type, "component") == 0;
+}
+
+static void
+label_paint (void *vself, const grub_video_rect_t *region)
+{
+ grub_gui_label_t self = vself;
+
+ if (! self->visible)
+ return;
+
+ if (!grub_video_have_common_points (region, &self->bounds))
+ return;
+
+ /* Calculate the starting x coordinate. */
+ int left_x;
+ if (self->align == align_left)
+ left_x = 0;
+ else if (self->align == align_center)
+ left_x = (self->bounds.width
+ - grub_font_get_string_width (self->font, self->text)) / 2;
+ else if (self->align == align_right)
+ left_x = (self->bounds.width
+ - grub_font_get_string_width (self->font, self->text));
+ else
+ return; /* Invalid alignment. */
+
+ if (left_x < 0 || left_x > (int) self->bounds.width)
+ left_x = 0;
+
+ grub_video_rect_t vpsave;
+ grub_gui_set_viewport (&self->bounds, &vpsave);
+ grub_font_draw_string (self->text,
+ self->font,
+ grub_video_map_rgba_color (self->color),
+ left_x,
+ grub_font_get_ascent (self->font));
+ grub_gui_restore_viewport (&vpsave);
+}
+
+static void
+label_set_parent (void *vself, grub_gui_container_t parent)
+{
+ grub_gui_label_t self = vself;
+ self->parent = parent;
+}
+
+static grub_gui_container_t
+label_get_parent (void *vself)
+{
+ grub_gui_label_t self = vself;
+ return self->parent;
+}
+
+static void
+label_set_bounds (void *vself, const grub_video_rect_t *bounds)
+{
+ grub_gui_label_t self = vself;
+ self->bounds = *bounds;
+}
+
+static void
+label_get_bounds (void *vself, grub_video_rect_t *bounds)
+{
+ grub_gui_label_t self = vself;
+ *bounds = self->bounds;
+}
+
+static void
+label_get_minimal_size (void *vself, unsigned *width, unsigned *height)
+{
+ grub_gui_label_t self = vself;
+ *width = grub_font_get_string_width (self->font, self->text);
+ *height = (grub_font_get_ascent (self->font)
+ + grub_font_get_descent (self->font));
+}
+
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+
+static void
+label_set_state (void *vself, int visible, int start __attribute__ ((unused)),
+ int current, int end __attribute__ ((unused)))
+{
+ grub_gui_label_t self = vself;
+ self->value = -current;
+ self->visible = visible;
+ grub_free (self->text);
+ self->text = grub_xasprintf (self->template ? : "%d", self->value);
+}
+
+static grub_err_t
+label_set_property (void *vself, const char *name, const char *value)
+{
+ grub_gui_label_t self = vself;
+ if (grub_strcmp (name, "text") == 0)
+ {
+ grub_free (self->text);
+ grub_free (self->template);
+ if (! value)
+ {
+ self->template = NULL;
+ self->text = grub_strdup ("");
+ }
+ else
+ {
+ if (grub_strcmp (value, "@KEYMAP_LONG@") == 0)
+ value = _("Press enter to boot the selected OS, "
+ "`e' to edit the commands before booting "
+ "or `c' for a command-line. ESC to return previous menu.");
+ else if (grub_strcmp (value, "@KEYMAP_MIDDLE@") == 0)
+ value = _("Press enter to boot the selected OS, "
+ "`e' to edit the commands before booting "
+ "or `c' for a command-line.");
+ else if (grub_strcmp (value, "@KEYMAP_SHORT@") == 0)
+ value = _("enter: boot, `e': options, `c': cmd-line");
+ /* FIXME: Add more templates here if needed. */
+
+ else if (grub_strcmp (value, "@VTOY_MEM_DISK@") == 0) {
+ value = g_ventoy_memdisk_mode ? grub_env_get("VTOY_MEM_DISK_STR") : " ";
+ }
+ else if (grub_strcmp (value, "@VTOY_ISO_RAW@") == 0) {
+ value = g_ventoy_iso_raw ? grub_env_get("VTOY_ISO_RAW_STR") : " ";
+ }
+ else if (grub_strcmp (value, "@VTOY_ISO_UEFI_DRV@") == 0) {
+ value = g_ventoy_iso_uefi_drv ? grub_env_get("VTOY_ISO_UEFI_DRV_STR") : " ";
+ }
+ else if (grub_strcmp (value, "@VTOY_HOTKEY_TIP@") == 0) {
+ value = grub_env_get("VTOY_HOTKEY_TIP");
+ if (value == NULL) {
+ value = _(" ");
+ }
+ }
+
+ self->template = grub_strdup (value);
+ self->text = grub_xasprintf (value, self->value);
+ }
+ }
+ else if (grub_strcmp (name, "font") == 0)
+ {
+ self->font = grub_font_get (value);
+ }
+ else if (grub_strcmp (name, "color") == 0)
+ {
+ grub_video_parse_color (value, &self->color);
+ }
+ else if (grub_strcmp (name, "align") == 0)
+ {
+ int i;
+ for (i = 0; align_options[i]; i++)
+ {
+ if (grub_strcmp (align_options[i], value) == 0)
+ {
+ self->align = i; /* Set the alignment mode. */
+ break;
+ }
+ }
+ }
+ else if (grub_strcmp (name, "visible") == 0)
+ {
+ self->visible = grub_strcmp (value, "false") != 0;
+ }
+ else if (grub_strcmp (name, "id") == 0)
+ {
+ grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self);
+ grub_free (self->id);
+ if (value)
+ self->id = grub_strdup (value);
+ else
+ self->id = 0;
+ if (self->id && grub_strcmp (self->id, GRUB_GFXMENU_TIMEOUT_COMPONENT_ID)
+ == 0)
+ grub_gfxmenu_timeout_register ((grub_gui_component_t) self,
+ label_set_state);
+ }
+ return GRUB_ERR_NONE;
+}
+
+#pragma GCC diagnostic error "-Wformat-nonliteral"
+
+static struct grub_gui_component_ops label_ops =
+{
+ .destroy = label_destroy,
+ .get_id = label_get_id,
+ .is_instance = label_is_instance,
+ .paint = label_paint,
+ .set_parent = label_set_parent,
+ .get_parent = label_get_parent,
+ .set_bounds = label_set_bounds,
+ .get_bounds = label_get_bounds,
+ .get_minimal_size = label_get_minimal_size,
+ .set_property = label_set_property
+};
+
+grub_gui_component_t
+grub_gui_label_new (void)
+{
+ grub_gui_label_t label;
+ label = grub_zalloc (sizeof (*label));
+ if (! label)
+ return 0;
+ label->comp.ops = &label_ops;
+ label->visible = 1;
+ label->text = grub_strdup ("");
+ label->font = grub_font_get ("Unknown Regular 16");
+ label->color.red = 0;
+ label->color.green = 0;
+ label->color.blue = 0;
+ label->color.alpha = 255;
+ label->align = align_left;
+ return (grub_gui_component_t) label;
+}
diff --git a/GRUB2/grub-2.04/grub-core/kern/disk.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/disk.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/kern/disk.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/kern/disk.c
diff --git a/GRUB2/grub-2.04/grub-core/kern/efi/efi.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/kern/efi/efi.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c
diff --git a/GRUB2/grub-2.04/grub-core/kern/file.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/file.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/kern/file.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/kern/file.c
diff --git a/GRUB2/grub-2.04/grub-core/kern/fs.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/fs.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/kern/fs.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/kern/fs.c
diff --git a/GRUB2/grub-2.04/grub-core/kern/main.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/main.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/kern/main.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/kern/main.c
diff --git a/GRUB2/grub-2.04/grub-core/lib/cmdline.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/cmdline.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/lib/cmdline.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/lib/cmdline.c
diff --git a/GRUB2/grub-2.04/grub-core/loader/efi/chainloader.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/efi/chainloader.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/loader/efi/chainloader.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/loader/efi/chainloader.c
diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/context.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/context.c
new file mode 100644
index 00000000000..87edd254c44
--- /dev/null
+++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/context.c
@@ -0,0 +1,214 @@
+/* env.c - Environment variables */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct menu_pointer
+{
+ grub_menu_t menu;
+ struct menu_pointer *prev;
+};
+
+static struct menu_pointer initial_menu;
+static struct menu_pointer *current_menu = &initial_menu;
+
+void
+grub_env_unset_menu (void)
+{
+ current_menu->menu = NULL;
+}
+
+grub_menu_t
+grub_env_get_menu (void)
+{
+ return current_menu->menu;
+}
+
+void
+grub_env_set_menu (grub_menu_t nmenu)
+{
+ current_menu->menu = nmenu;
+}
+
+static grub_err_t
+grub_env_new_context (int export_all)
+{
+ struct grub_env_context *context;
+ int i;
+ struct menu_pointer *menu;
+
+ context = grub_zalloc (sizeof (*context));
+ if (! context)
+ return grub_errno;
+ menu = grub_zalloc (sizeof (*menu));
+ if (! menu)
+ {
+ grub_free (context);
+ return grub_errno;
+ }
+
+ context->prev = grub_current_context;
+ grub_current_context = context;
+
+ menu->prev = current_menu;
+ current_menu = menu;
+
+ /* Copy exported variables. */
+ for (i = 0; i < HASHSZ; i++)
+ {
+ struct grub_env_var *var;
+
+ for (var = context->prev->vars[i]; var; var = var->next)
+ if (var->global || export_all)
+ {
+ if (grub_env_set (var->name, var->value) != GRUB_ERR_NONE)
+ {
+ grub_env_context_close ();
+ return grub_errno;
+ }
+ grub_env_export (var->name);
+ grub_register_variable_hook (var->name, var->read_hook, var->write_hook);
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_env_context_open (void)
+{
+ return grub_env_new_context (1);
+}
+
+int grub_extractor_level = 0;
+
+grub_err_t
+grub_env_extractor_open (int source)
+{
+ grub_extractor_level++;
+ return grub_env_new_context (source);
+}
+
+grub_err_t
+grub_env_context_close (void)
+{
+ struct grub_env_context *context;
+ int i;
+ struct menu_pointer *menu;
+
+ if (! grub_current_context->prev)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "cannot close the initial context");
+
+ /* Free the variables associated with this context. */
+ for (i = 0; i < HASHSZ; i++)
+ {
+ struct grub_env_var *p, *q;
+
+ for (p = grub_current_context->vars[i]; p; p = q)
+ {
+ q = p->next;
+ grub_free (p->name);
+ grub_free (p->value);
+ grub_free (p);
+ }
+ }
+
+ /* Restore the previous context. */
+ context = grub_current_context->prev;
+ grub_free (grub_current_context);
+ grub_current_context = context;
+
+ menu = current_menu->prev;
+ if (current_menu->menu)
+ grub_normal_free_menu (current_menu->menu);
+ grub_free (current_menu);
+ current_menu = menu;
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_env_extractor_close (int source)
+{
+ grub_menu_t menu = NULL;
+ grub_menu_entry_t *last;
+ grub_err_t err;
+
+ if (source)
+ {
+ menu = grub_env_get_menu ();
+ grub_env_unset_menu ();
+ }
+ err = grub_env_context_close ();
+
+ if (source && menu)
+ {
+ grub_menu_t menu2;
+ menu2 = grub_env_get_menu ();
+
+ last = &menu2->entry_list;
+ while (*last)
+ last = &(*last)->next;
+
+ *last = menu->entry_list;
+ menu2->size += menu->size;
+ }
+
+ grub_extractor_level--;
+ return err;
+}
+
+static grub_command_t export_cmd;
+
+static grub_err_t
+grub_cmd_export (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ int i;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("one argument expected"));
+
+ for (i = 0; i < argc; i++)
+ grub_env_export (args[i]);
+
+ return 0;
+}
+
+void
+grub_context_init (void)
+{
+ export_cmd = grub_register_command ("export", grub_cmd_export,
+ N_("ENVVAR [ENVVAR] ..."),
+ N_("Export variables."));
+}
+
+void
+grub_context_fini (void)
+{
+ grub_unregister_command (export_cmd);
+}
diff --git a/GRUB2/grub-2.04/grub-core/normal/menu.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/normal/menu.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu.c
diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu_text.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu_text.c
new file mode 100644
index 00000000000..cb1d3d61e4a
--- /dev/null
+++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu_text.c
@@ -0,0 +1,605 @@
+/* menu_text.c - Basic text menu implementation. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static grub_uint8_t grub_color_menu_normal;
+static grub_uint8_t grub_color_menu_highlight;
+
+struct menu_viewer_data
+{
+ int first, offset;
+ struct grub_term_screen_geometry geo;
+ enum {
+ TIMEOUT_UNKNOWN,
+ TIMEOUT_NORMAL,
+ TIMEOUT_TERSE,
+ TIMEOUT_TERSE_NO_MARGIN
+ } timeout_msg;
+ grub_menu_t menu;
+ struct grub_term_output *term;
+};
+
+static inline int
+grub_term_cursor_x (const struct grub_term_screen_geometry *geo)
+{
+ return (geo->first_entry_x + geo->entry_width);
+}
+
+grub_size_t
+grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position,
+ struct grub_term_output *term)
+{
+ grub_ssize_t width = 0;
+
+ while (str < last_position)
+ {
+ struct grub_unicode_glyph glyph;
+ glyph.ncomb = 0;
+ str += grub_unicode_aglomerate_comb (str, last_position - str, &glyph);
+ width += grub_term_getcharwidth (term, &glyph);
+ grub_unicode_destroy_glyph (&glyph);
+ }
+ return width;
+}
+
+static int
+grub_print_message_indented_real (const char *msg, int margin_left,
+ int margin_right,
+ struct grub_term_output *term, int dry_run)
+{
+ grub_uint32_t *unicode_msg;
+ grub_uint32_t *last_position;
+ grub_size_t msg_len = grub_strlen (msg) + 2;
+ int ret = 0;
+
+ unicode_msg = grub_malloc (msg_len * sizeof (grub_uint32_t));
+
+ if (!unicode_msg)
+ return 0;
+
+ msg_len = grub_utf8_to_ucs4 (unicode_msg, msg_len,
+ (grub_uint8_t *) msg, -1, 0);
+
+ last_position = unicode_msg + msg_len;
+ *last_position = 0;
+
+ if (dry_run)
+ ret = grub_ucs4_count_lines (unicode_msg, last_position, margin_left,
+ margin_right, term);
+ else
+ grub_print_ucs4_menu (unicode_msg, last_position, margin_left,
+ margin_right, term, 0, -1, 0, 0);
+
+ grub_free (unicode_msg);
+
+ return ret;
+}
+
+void
+grub_print_message_indented (const char *msg, int margin_left, int margin_right,
+ struct grub_term_output *term)
+{
+ grub_print_message_indented_real (msg, margin_left, margin_right, term, 0);
+}
+
+static void
+draw_border (struct grub_term_output *term, const struct grub_term_screen_geometry *geo)
+{
+ int i;
+
+ grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
+
+ grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
+ geo->first_entry_y - 1 });
+ grub_putcode (GRUB_UNICODE_CORNER_UL, term);
+ for (i = 0; i < geo->entry_width + 1; i++)
+ grub_putcode (GRUB_UNICODE_HLINE, term);
+ grub_putcode (GRUB_UNICODE_CORNER_UR, term);
+
+ for (i = 0; i < geo->num_entries; i++)
+ {
+ grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
+ geo->first_entry_y + i });
+ grub_putcode (GRUB_UNICODE_VLINE, term);
+ grub_term_gotoxy (term,
+ (struct grub_term_coordinate) { geo->first_entry_x + geo->entry_width + 1,
+ geo->first_entry_y + i });
+ grub_putcode (GRUB_UNICODE_VLINE, term);
+ }
+
+ grub_term_gotoxy (term,
+ (struct grub_term_coordinate) { geo->first_entry_x - 1,
+ geo->first_entry_y - 1 + geo->num_entries + 1 });
+ grub_putcode (GRUB_UNICODE_CORNER_LL, term);
+ for (i = 0; i < geo->entry_width + 1; i++)
+ grub_putcode (GRUB_UNICODE_HLINE, term);
+ grub_putcode (GRUB_UNICODE_CORNER_LR, term);
+
+ grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
+
+ grub_term_gotoxy (term,
+ (struct grub_term_coordinate) { geo->first_entry_x - 1,
+ (geo->first_entry_y - 1 + geo->num_entries
+ + GRUB_TERM_MARGIN + 1) });
+}
+
+static int
+print_message (int nested, int edit, struct grub_term_output *term, int dry_run)
+{
+ int ret = 0;
+ grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
+
+ if (edit)
+ {
+ ret += grub_print_message_indented_real (_("Minimum Emacs-like screen editing is \
+supported. TAB lists completions. Press Ctrl-x or F10 to boot, Ctrl-c or F2 for a \
+command-line or ESC to discard edits and return to the GRUB menu."),
+ STANDARD_MARGIN, STANDARD_MARGIN,
+ term, dry_run);
+ }
+ else
+ {
+ char *msg_translated;
+
+ msg_translated = grub_xasprintf (_("Use the %C and %C keys to select which "
+ "entry is highlighted."),
+ GRUB_UNICODE_UPARROW,
+ GRUB_UNICODE_DOWNARROW);
+ if (!msg_translated)
+ return 0;
+ ret += grub_print_message_indented_real (msg_translated, STANDARD_MARGIN,
+ STANDARD_MARGIN, term, dry_run);
+
+ grub_free (msg_translated);
+
+ if (nested)
+ {
+ ret += grub_print_message_indented_real
+ (_("Press enter to boot the selected OS, "
+ "`e' to edit the commands before booting "
+ "or `c' for a command-line. ESC to return previous menu."),
+ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ }
+ else
+ {
+ ret += grub_print_message_indented_real("\n", STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+
+ ret += grub_print_message_indented_real(grub_env_get("VTOY_TEXT_MENU_VER"),
+ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+
+ ret += grub_print_message_indented_real("\n", STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ ret += grub_print_message_indented_real(grub_env_get("VTOY_HOTKEY_TIP"),
+ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ }
+ }
+ return ret;
+}
+
+static void
+print_entry (int y, int highlight, grub_menu_entry_t entry,
+ const struct menu_viewer_data *data)
+{
+ const char *title;
+ grub_size_t title_len;
+ grub_ssize_t len;
+ grub_uint32_t *unicode_title;
+ grub_ssize_t i;
+ grub_uint8_t old_color_normal, old_color_highlight;
+
+ title = entry ? entry->title : "";
+ title_len = grub_strlen (title);
+ unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
+ if (! unicode_title)
+ /* XXX How to show this error? */
+ return;
+
+ len = grub_utf8_to_ucs4 (unicode_title, title_len,
+ (grub_uint8_t *) title, -1, 0);
+ if (len < 0)
+ {
+ /* It is an invalid sequence. */
+ grub_free (unicode_title);
+ return;
+ }
+
+ old_color_normal = grub_term_normal_color;
+ old_color_highlight = grub_term_highlight_color;
+ grub_term_normal_color = grub_color_menu_normal;
+ grub_term_highlight_color = grub_color_menu_highlight;
+ grub_term_setcolorstate (data->term, highlight
+ ? GRUB_TERM_COLOR_HIGHLIGHT
+ : GRUB_TERM_COLOR_NORMAL);
+
+ grub_term_gotoxy (data->term, (struct grub_term_coordinate) {
+ data->geo.first_entry_x, y });
+
+ for (i = 0; i < len; i++)
+ if (unicode_title[i] == '\n' || unicode_title[i] == '\b'
+ || unicode_title[i] == '\r' || unicode_title[i] == '\e')
+ unicode_title[i] = ' ';
+
+ if (data->geo.num_entries > 1)
+ grub_putcode (highlight ? '*' : ' ', data->term);
+
+ grub_print_ucs4_menu (unicode_title,
+ unicode_title + len,
+ 0,
+ data->geo.right_margin,
+ data->term, 0, 1,
+ GRUB_UNICODE_RIGHTARROW, 0);
+
+ grub_term_setcolorstate (data->term, GRUB_TERM_COLOR_NORMAL);
+ grub_term_gotoxy (data->term,
+ (struct grub_term_coordinate) {
+ grub_term_cursor_x (&data->geo), y });
+
+ grub_term_normal_color = old_color_normal;
+ grub_term_highlight_color = old_color_highlight;
+
+ grub_term_setcolorstate (data->term, GRUB_TERM_COLOR_NORMAL);
+ grub_free (unicode_title);
+}
+
+static void
+print_entries (grub_menu_t menu, const struct menu_viewer_data *data)
+{
+ grub_menu_entry_t e;
+ int i;
+
+ grub_term_gotoxy (data->term,
+ (struct grub_term_coordinate) {
+ data->geo.first_entry_x + data->geo.entry_width
+ + data->geo.border + 1,
+ data->geo.first_entry_y });
+
+ if (data->geo.num_entries != 1)
+ {
+ if (data->first)
+ grub_putcode (GRUB_UNICODE_UPARROW, data->term);
+ else
+ grub_putcode (' ', data->term);
+ }
+ e = grub_menu_get_entry (menu, data->first);
+
+ for (i = 0; i < data->geo.num_entries; i++)
+ {
+ print_entry (data->geo.first_entry_y + i, data->offset == i,
+ e, data);
+ if (e)
+ e = e->next;
+ }
+
+ grub_term_gotoxy (data->term,
+ (struct grub_term_coordinate) { data->geo.first_entry_x + data->geo.entry_width
+ + data->geo.border + 1,
+ data->geo.first_entry_y + data->geo.num_entries - 1 });
+ if (data->geo.num_entries == 1)
+ {
+ if (data->first && e)
+ grub_putcode (GRUB_UNICODE_UPDOWNARROW, data->term);
+ else if (data->first)
+ grub_putcode (GRUB_UNICODE_UPARROW, data->term);
+ else if (e)
+ grub_putcode (GRUB_UNICODE_DOWNARROW, data->term);
+ else
+ grub_putcode (' ', data->term);
+ }
+ else
+ {
+ if (e)
+ grub_putcode (GRUB_UNICODE_DOWNARROW, data->term);
+ else
+ grub_putcode (' ', data->term);
+ }
+
+ grub_term_gotoxy (data->term,
+ (struct grub_term_coordinate) { grub_term_cursor_x (&data->geo),
+ data->geo.first_entry_y + data->offset });
+}
+
+/* Initialize the screen. If NESTED is non-zero, assume that this menu
+ is run from another menu or a command-line. If EDIT is non-zero, show
+ a message for the menu entry editor. */
+void
+grub_menu_init_page (int nested, int edit,
+ struct grub_term_screen_geometry *geo,
+ struct grub_term_output *term)
+{
+ grub_uint8_t old_color_normal, old_color_highlight;
+ int msg_num_lines;
+ int bottom_message = 1;
+ int empty_lines = 1;
+ int version_msg = 1;
+
+ geo->border = 1;
+ geo->first_entry_x = 1 /* margin */ + 1 /* border */;
+ geo->entry_width = grub_term_width (term) - 5;
+
+ geo->first_entry_y = 2 /* two empty lines*/
+ + 1 /* GNU GRUB version text */ + 1 /* top border */;
+
+ geo->timeout_lines = 2;
+
+ /* 3 lines for timeout message and bottom margin. 2 lines for the border. */
+ geo->num_entries = grub_term_height (term) - geo->first_entry_y
+ - 1 /* bottom border */
+ - 1 /* empty line before info message*/
+ - geo->timeout_lines /* timeout */
+ - 1 /* empty final line */;
+ msg_num_lines = print_message (nested, edit, term, 1);
+ if (geo->num_entries - msg_num_lines < 3
+ || geo->entry_width < 10)
+ {
+ geo->num_entries += 4;
+ geo->first_entry_y -= 2;
+ empty_lines = 0;
+ geo->first_entry_x -= 1;
+ geo->entry_width += 1;
+ }
+ if (geo->num_entries - msg_num_lines < 3
+ || geo->entry_width < 10)
+ {
+ geo->num_entries += 2;
+ geo->first_entry_y -= 1;
+ geo->first_entry_x -= 1;
+ geo->entry_width += 2;
+ geo->border = 0;
+ }
+
+ if (geo->entry_width <= 0)
+ geo->entry_width = 1;
+
+ if (geo->num_entries - msg_num_lines < 3
+ && geo->timeout_lines == 2)
+ {
+ geo->timeout_lines = 1;
+ geo->num_entries++;
+ }
+
+ if (geo->num_entries - msg_num_lines < 3)
+ {
+ geo->num_entries += 1;
+ geo->first_entry_y -= 1;
+ version_msg = 0;
+ }
+
+ if (geo->num_entries - msg_num_lines >= 2)
+ geo->num_entries -= msg_num_lines;
+ else
+ bottom_message = 0;
+
+ /* By default, use the same colors for the menu. */
+ old_color_normal = grub_term_normal_color;
+ old_color_highlight = grub_term_highlight_color;
+ grub_color_menu_normal = grub_term_normal_color;
+ grub_color_menu_highlight = grub_term_highlight_color;
+
+ /* Then give user a chance to replace them. */
+ grub_parse_color_name_pair (&grub_color_menu_normal,
+ grub_env_get ("menu_color_normal"));
+ grub_parse_color_name_pair (&grub_color_menu_highlight,
+ grub_env_get ("menu_color_highlight"));
+
+ if (version_msg)
+ grub_normal_init_page (term, empty_lines);
+ else
+ grub_term_cls (term);
+
+ grub_term_normal_color = grub_color_menu_normal;
+ grub_term_highlight_color = grub_color_menu_highlight;
+ if (geo->border)
+ draw_border (term, geo);
+ grub_term_normal_color = old_color_normal;
+ grub_term_highlight_color = old_color_highlight;
+ geo->timeout_y = geo->first_entry_y + geo->num_entries
+ + geo->border + empty_lines;
+ if (bottom_message)
+ {
+ grub_term_gotoxy (term,
+ (struct grub_term_coordinate) { GRUB_TERM_MARGIN,
+ geo->timeout_y });
+
+ print_message (nested, edit, term, 0);
+ geo->timeout_y += msg_num_lines;
+ }
+ geo->right_margin = grub_term_width (term)
+ - geo->first_entry_x
+ - geo->entry_width - 1;
+}
+
+static void
+menu_text_print_timeout (int timeout, void *dataptr)
+{
+ struct menu_viewer_data *data = dataptr;
+ char *msg_translated = 0;
+
+ grub_term_gotoxy (data->term,
+ (struct grub_term_coordinate) { 0, data->geo.timeout_y });
+
+ if (data->timeout_msg == TIMEOUT_TERSE
+ || data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN)
+ msg_translated = grub_xasprintf (_("%ds"), timeout);
+ else
+ msg_translated = grub_xasprintf (_("The highlighted entry will be executed automatically in %ds."), timeout);
+ if (!msg_translated)
+ {
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ return;
+ }
+
+ if (data->timeout_msg == TIMEOUT_UNKNOWN)
+ {
+ data->timeout_msg = grub_print_message_indented_real (msg_translated,
+ 3, 1, data->term, 1)
+ <= data->geo.timeout_lines ? TIMEOUT_NORMAL : TIMEOUT_TERSE;
+ if (data->timeout_msg == TIMEOUT_TERSE)
+ {
+ grub_free (msg_translated);
+ msg_translated = grub_xasprintf (_("%ds"), timeout);
+ if (grub_term_width (data->term) < 10)
+ data->timeout_msg = TIMEOUT_TERSE_NO_MARGIN;
+ }
+ }
+
+ grub_print_message_indented (msg_translated,
+ data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN ? 0 : 3,
+ data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN ? 0 : 1,
+ data->term);
+ grub_free (msg_translated);
+
+ grub_term_gotoxy (data->term,
+ (struct grub_term_coordinate) {
+ grub_term_cursor_x (&data->geo),
+ data->geo.first_entry_y + data->offset });
+ grub_term_refresh (data->term);
+}
+
+static void
+menu_text_set_chosen_entry (int entry, void *dataptr)
+{
+ struct menu_viewer_data *data = dataptr;
+ int oldoffset = data->offset;
+ int complete_redraw = 0;
+
+ data->offset = entry - data->first;
+ if (data->offset > data->geo.num_entries - 1)
+ {
+ data->first = entry - (data->geo.num_entries - 1);
+ data->offset = data->geo.num_entries - 1;
+ complete_redraw = 1;
+ }
+ if (data->offset < 0)
+ {
+ data->offset = 0;
+ data->first = entry;
+ complete_redraw = 1;
+ }
+ if (complete_redraw)
+ print_entries (data->menu, data);
+ else
+ {
+ print_entry (data->geo.first_entry_y + oldoffset, 0,
+ grub_menu_get_entry (data->menu, data->first + oldoffset),
+ data);
+ print_entry (data->geo.first_entry_y + data->offset, 1,
+ grub_menu_get_entry (data->menu, data->first + data->offset),
+ data);
+ }
+ grub_term_refresh (data->term);
+}
+
+static void
+menu_text_fini (void *dataptr)
+{
+ struct menu_viewer_data *data = dataptr;
+
+ grub_term_setcursor (data->term, 1);
+ grub_term_cls (data->term);
+ grub_free (data);
+}
+
+static void
+menu_text_clear_timeout (void *dataptr)
+{
+ struct menu_viewer_data *data = dataptr;
+ int i;
+
+ for (i = 0; i < data->geo.timeout_lines;i++)
+ {
+ grub_term_gotoxy (data->term, (struct grub_term_coordinate) {
+ 0, data->geo.timeout_y + i });
+ grub_print_spaces (data->term, grub_term_width (data->term) - 1);
+ }
+ if (data->geo.num_entries <= 5 && !data->geo.border)
+ {
+ grub_term_gotoxy (data->term,
+ (struct grub_term_coordinate) {
+ data->geo.first_entry_x + data->geo.entry_width
+ + data->geo.border + 1,
+ data->geo.first_entry_y + data->geo.num_entries - 1
+ });
+ grub_putcode (' ', data->term);
+
+ data->geo.timeout_lines = 0;
+ data->geo.num_entries++;
+ print_entries (data->menu, data);
+ }
+ grub_term_gotoxy (data->term,
+ (struct grub_term_coordinate) {
+ grub_term_cursor_x (&data->geo),
+ data->geo.first_entry_y + data->offset });
+ grub_term_refresh (data->term);
+}
+
+grub_err_t
+grub_menu_try_text (struct grub_term_output *term,
+ int entry, grub_menu_t menu, int nested)
+{
+ struct menu_viewer_data *data;
+ struct grub_menu_viewer *instance;
+
+ instance = grub_zalloc (sizeof (*instance));
+ if (!instance)
+ return grub_errno;
+
+ data = grub_zalloc (sizeof (*data));
+ if (!data)
+ {
+ grub_free (instance);
+ return grub_errno;
+ }
+
+ data->term = term;
+ instance->data = data;
+ instance->set_chosen_entry = menu_text_set_chosen_entry;
+ instance->print_timeout = menu_text_print_timeout;
+ instance->clear_timeout = menu_text_clear_timeout;
+ instance->fini = menu_text_fini;
+
+ data->menu = menu;
+
+ data->offset = entry;
+ data->first = 0;
+
+ grub_term_setcursor (data->term, 0);
+ grub_menu_init_page (nested, 0, &data->geo, data->term);
+
+ if (data->offset > data->geo.num_entries - 1)
+ {
+ data->first = data->offset - (data->geo.num_entries - 1);
+ data->offset = data->geo.num_entries - 1;
+ }
+
+ print_entries (menu, data);
+ grub_term_refresh (data->term);
+ grub_menu_register_viewer (instance);
+
+ return GRUB_ERR_NONE;
+}
diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/misc.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/misc.c
new file mode 100644
index 00000000000..56629a80002
--- /dev/null
+++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/misc.c
@@ -0,0 +1,194 @@
+/* misc.c - miscellaneous functions */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static const char *grub_human_sizes[3][6] =
+ {
+ /* This algorithm in reality would work only up to (2^64) / 100 B = 81 PiB.
+ Put here all possible suffixes it can produce so no array bounds check
+ is needed.
+ */
+ /* TRANSLATORS: that's the list of binary unit prefixes. */
+ { N_("B"), N_("KiB"), N_("MiB"), N_("GiB"), N_("TiB"), N_("PiB")},
+ /* TRANSLATORS: that's the list of binary unit prefixes. */
+ { "", N_("KB"), N_("MB"), N_("GB"), N_("TB"), N_("PB") },
+ /* TRANSLATORS: that's the list of binary unit prefixes. */
+ { N_("B/s"), N_("KiB/s"), N_("MiB/s"), N_("GiB/s"), N_("TiB/s"), N_("PiB/s"), },
+ };
+
+const char *
+grub_get_human_size (grub_uint64_t size, enum grub_human_size_type type)
+{
+ grub_uint64_t fsize;
+ unsigned units = 0;
+ static char buf[30];
+ const char *umsg;
+
+ if (type != GRUB_HUMAN_SIZE_SPEED)
+ fsize = size * 100ULL;
+ else
+ fsize = size;
+
+ /* Since 2^64 / 1024^5 < 102400, this can give at most 5 iterations.
+ So units <=5, so impossible to go past the end of array.
+ */
+ while (fsize >= 102400)
+ {
+ fsize = (fsize + 512) / 1024;
+ units++;
+ }
+
+ umsg = _(grub_human_sizes[type][units]);
+
+ if (units || type == GRUB_HUMAN_SIZE_SPEED)
+ {
+ grub_uint64_t whole, fraction;
+
+ whole = grub_divmod64 (fsize, 100, &fraction);
+ grub_snprintf (buf, sizeof (buf),
+ "%" PRIuGRUB_UINT64_T
+ ".%02" PRIuGRUB_UINT64_T "%s", whole, fraction,
+ umsg);
+ }
+ else
+ grub_snprintf (buf, sizeof (buf), "%llu%s", (unsigned long long) size,
+ umsg);
+ return buf;
+}
+
+/* Print the information on the device NAME. */
+grub_err_t
+grub_normal_print_device_info (const char *name)
+{
+ grub_device_t dev;
+ char *p;
+
+ p = grub_strchr (name, ',');
+ if (p)
+ {
+ grub_xputs ("\t");
+ grub_printf_ (N_("Partition %s:"), name);
+ grub_xputs (" ");
+ }
+ else
+ {
+ grub_printf_ (N_("Device %s:"), name);
+ grub_xputs (" ");
+ }
+
+ dev = grub_device_open (name);
+ if (! dev)
+ grub_printf ("%s", _("Filesystem cannot be accessed"));
+ else if (dev->disk)
+ {
+ grub_fs_t fs;
+
+ fs = grub_fs_probe (dev);
+ /* Ignore all errors. */
+ grub_errno = 0;
+
+ if (fs)
+ {
+ const char *fsname = fs->name;
+ if (grub_strcmp (fsname, "ext2") == 0)
+ fsname = "ext*";
+ grub_printf_ (N_("Filesystem type %s"), fsname);
+ if (fs->fs_label)
+ {
+ char *label;
+ (fs->fs_label) (dev, &label);
+ if (grub_errno == GRUB_ERR_NONE)
+ {
+ if (label && grub_strlen (label))
+ {
+ grub_xputs (" ");
+ grub_printf_ (N_("- Label `%s'"), label);
+ }
+ grub_free (label);
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+ if (fs->fs_mtime)
+ {
+ grub_int32_t tm;
+ struct grub_datetime datetime;
+ (fs->fs_mtime) (dev, &tm);
+ if (grub_errno == GRUB_ERR_NONE)
+ {
+ grub_unixtime2datetime (tm, &datetime);
+ grub_xputs (" ");
+ /* TRANSLATORS: Arguments are year, month, day, hour, minute,
+ second, day of the week (translated). */
+ grub_printf_ (N_("- Last modification time %d-%02d-%02d "
+ "%02d:%02d:%02d %s"),
+ datetime.year, datetime.month, datetime.day,
+ datetime.hour, datetime.minute, datetime.second,
+ grub_get_weekday_name (&datetime));
+
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+ if (fs->fs_uuid)
+ {
+ char *uuid;
+ (fs->fs_uuid) (dev, &uuid);
+ if (grub_errno == GRUB_ERR_NONE)
+ {
+ if (uuid && grub_strlen (uuid))
+ grub_printf (", UUID %s", uuid);
+ grub_free (uuid);
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+ }
+ else
+ grub_printf ("%s", _("No known filesystem detected"));
+
+ if (dev->disk->partition)
+ grub_printf (_(" - Partition start at %llu%sKiB"),
+ (unsigned long long) (grub_partition_get_start (dev->disk->partition) >> 1),
+ (grub_partition_get_start (dev->disk->partition) & 1) ? ".5" : "" );
+ else
+ grub_printf_ (N_(" - Sector size %uB"), 1 << dev->disk->log_sector_size);
+ if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN)
+ grub_puts_ (N_(" - Total size unknown"));
+ else
+ grub_printf (_(" - Total size %llu%sKiB"),
+ (unsigned long long) (grub_disk_get_size (dev->disk) >> 1),
+ /* TRANSLATORS: Replace dot with appropriate decimal separator for
+ your language. */
+ (grub_disk_get_size (dev->disk) & 1) ? _(".5") : "");
+ }
+
+ if (dev)
+ grub_device_close (dev);
+
+ grub_xputs ("\n");
+ return grub_errno;
+}
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/huffman.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/ventoy/huffman.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.c
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/huffman.h b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.h
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/ventoy/huffman.h
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.h
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/lzx.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/ventoy/lzx.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.c
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/lzx.h b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.h
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/ventoy/lzx.h
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.h
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/ventoy.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
similarity index 99%
rename from GRUB2/grub-2.04/grub-core/ventoy/ventoy.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
index 1978daefb2e..ce77a8c83a3 100644
--- a/GRUB2/grub-2.04/grub-core/ventoy/ventoy.c
+++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
@@ -49,7 +49,7 @@ initrd_info *g_initrd_img_list = NULL;
initrd_info *g_initrd_img_tail = NULL;
int g_initrd_img_count = 0;
int g_valid_initrd_count = 0;
-
+int g_filt_dot_underscore_file = 0;
static grub_file_t g_old_file;
char g_img_swap_tmp_buf[1024];
@@ -618,6 +618,11 @@ static int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
{
grub_size_t i;
+ if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
+ {
+ return 0;
+ }
+
for (i = 0; i < namelen; i++)
{
if (filename[i] == ' ' || filename[i] == '\t')
@@ -938,6 +943,7 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char
grub_device_t dev = NULL;
img_info *cur = NULL;
img_info *tail = NULL;
+ const char *strdata = NULL;
char *device_name = NULL;
char buf[32];
img_iterator_node *node = NULL;
@@ -955,6 +961,12 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char
return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
}
+ strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
+ if (strdata && strdata[0] == '1' && strdata[1] == 0)
+ {
+ g_filt_dot_underscore_file = 1;
+ }
+
device_name = grub_file_get_device_name(args[0]);
if (!device_name)
{
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/ventoy_def.h b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/ventoy/ventoy_def.h
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/ventoy_json.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_json.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/ventoy/ventoy_json.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_json.c
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/ventoy_linux.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/ventoy/ventoy_linux.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/ventoy_plugin.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c
similarity index 89%
rename from GRUB2/grub-2.04/grub-core/ventoy/ventoy_plugin.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c
index 827e142d4d8..82de5130cda 100644
--- a/GRUB2/grub-2.04/grub-core/ventoy/ventoy_plugin.c
+++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c
@@ -40,6 +40,34 @@ GRUB_MOD_LICENSE ("GPLv3+");
static install_template *g_install_template_head = NULL;
+static int ventoy_plugin_control_entry(VTOY_JSON *json, const char *isodisk)
+{
+ VTOY_JSON *pNode = NULL;
+ VTOY_JSON *pChild = NULL;
+
+ (void)isodisk;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ debug("Not array %d\n", json->enDataType);
+ return 0;
+ }
+
+ for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
+ {
+ if (pNode->enDataType == JSON_TYPE_OBJECT)
+ {
+ pChild = pNode->pstChild;
+ if (pChild->enDataType == JSON_TYPE_STRING && pChild->pcName && pChild->unData.pcStrVal)
+ {
+ ventoy_set_env(pChild->pcName, pChild->unData.pcStrVal);
+ }
+ }
+ }
+
+ return 0;
+}
+
static int ventoy_plugin_theme_entry(VTOY_JSON *json, const char *isodisk)
{
const char *value;
@@ -136,6 +164,7 @@ static int ventoy_plugin_auto_install_entry(VTOY_JSON *json, const char *isodisk
static plugin_entry g_plugin_entries[] =
{
+ { "control", ventoy_plugin_control_entry },
{ "theme", ventoy_plugin_theme_entry },
{ "auto_install", ventoy_plugin_auto_install_entry },
};
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/ventoy_windows.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_windows.c
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/ventoy/ventoy_windows.c
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_windows.c
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/wimboot.h b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/wimboot.h
similarity index 100%
rename from GRUB2/grub-2.04/grub-core/ventoy/wimboot.h
rename to GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/wimboot.h
diff --git a/GRUB2/grub-2.04/include/grub/disk.h b/GRUB2/MOD_SRC/grub-2.04/include/grub/disk.h
similarity index 100%
rename from GRUB2/grub-2.04/include/grub/disk.h
rename to GRUB2/MOD_SRC/grub-2.04/include/grub/disk.h
diff --git a/GRUB2/grub-2.04/include/grub/efi/efi.h b/GRUB2/MOD_SRC/grub-2.04/include/grub/efi/efi.h
similarity index 100%
rename from GRUB2/grub-2.04/include/grub/efi/efi.h
rename to GRUB2/MOD_SRC/grub-2.04/include/grub/efi/efi.h
diff --git a/GRUB2/grub-2.04/include/grub/fs.h b/GRUB2/MOD_SRC/grub-2.04/include/grub/fs.h
similarity index 100%
rename from GRUB2/grub-2.04/include/grub/fs.h
rename to GRUB2/MOD_SRC/grub-2.04/include/grub/fs.h
diff --git a/GRUB2/grub-2.04/include/grub/ventoy.h b/GRUB2/MOD_SRC/grub-2.04/include/grub/ventoy.h
similarity index 100%
rename from GRUB2/grub-2.04/include/grub/ventoy.h
rename to GRUB2/MOD_SRC/grub-2.04/include/grub/ventoy.h
diff --git a/GRUB2/MOD_SRC/grub-2.04/install.sh b/GRUB2/MOD_SRC/grub-2.04/install.sh
new file mode 100644
index 00000000000..3baf95f4044
--- /dev/null
+++ b/GRUB2/MOD_SRC/grub-2.04/install.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+VT_DIR=$PWD/../../..
+
+rm -rf $VT_DIR/GRUB2/INSTALL
+rm -rf $VT_DIR/GRUB2/PXE
+mkdir -p $VT_DIR/GRUB2/INSTALL
+mkdir -p $VT_DIR/GRUB2/PXE
+
+make install
+
+PATH=$PATH:$VT_DIR/GRUB2/INSTALL/bin/:$VT_DIR/GRUB2/INSTALL/sbin/
+
+net_modules_legacy="net tftp http"
+all_modules_legacy="date drivemap blocklist ext2 xfs ventoy chain read halt iso9660 linux16 test true sleep reboot echo video_colors video_cirrus video_bochs vga vbe video_fb font video gettext extcmd terminal linux minicmd help configfile tr trig boot biosdisk disk ls tar squash4 password_pbkdf2 all_video png jpeg part_msdos fat exfat ntfs loopback gzio normal udf gfxmenu gfxterm gfxterm_background gfxterm_menu"
+
+net_modules_uefi="efinet net tftp http"
+all_modules_uefi="blocklist ventoy test ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux relocator jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop efi_uga video_bochs video_cirrus video video_fb gfxterm_background gfxterm_menu"
+
+
+if [ "$1" = "uefi" ]; then
+ all_modules="$net_modules_uefi $all_modules_uefi"
+ grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/x86_64-efi" --prefix '(,msdos2)/grub' --output "$VT_DIR/INSTALL/EFI/BOOT/grubx64_real.efi" --format 'x86_64-efi' --compression 'auto' $all_modules_uefi 'fat' 'part_msdos'
+else
+ all_modules="$net_modules_legacy $all_modules_legacy"
+ grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc" --prefix '(,msdos2)/grub' --output "$VT_DIR/INSTALL/grub/i386-pc/core.img" --format 'i386-pc' --compression 'auto' $all_modules_legacy 'fat' 'part_msdos' 'biosdisk'
+fi
+
+grub-mknetdir --modules="$all_modules" --net-directory=$VT_DIR/GRUB2/PXE --subdir=grub2 --locales=en@quot || exit 1
+
+if [ "$1" = "uefi" ]; then
+ rm -f $VT_DIR/GRUB2/NBP/core.efi
+ cp -a $VT_DIR/GRUB2/PXE/grub2/x86_64-efi/core.efi $VT_DIR/GRUB2/NBP/core.efi || exit 1
+
+ rm -f $VT_DIR/INSTALL/grub/x86_64-efi/normal.mod
+ cp -a $VT_DIR/GRUB2/PXE/grub2/x86_64-efi/normal.mod $VT_DIR/INSTALL/grub/x86_64-efi/normal.mod || exit 1
+else
+ rm -f $VT_DIR/GRUB2/NBP/core.0
+ cp -a $VT_DIR/GRUB2/PXE/grub2/i386-pc/core.0 $VT_DIR/GRUB2/NBP/core.0 || exit 1
+
+ rm -f $VT_DIR/INSTALL/grub/i386-pc/boot.img
+ cp -a $VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc/boot.img $VT_DIR/INSTALL/grub/i386-pc/boot.img || exit 1
+fi
diff --git a/GRUB2/README.txt b/GRUB2/README.txt
deleted file mode 100644
index 57f0008d890..00000000000
--- a/GRUB2/README.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-
-========== About Source Code =============
-Ventoy use grub-2.04, so I only put the added and modified source code here.
-
-You can download grub-2.04 source code from this site:
-https://ftp.gnu.org/gnu/grub/
-
-Just merge the code here with the original code of grub-2.04
-
-
-========== Build =============
-./autogen.sh
-./configure
-make
diff --git a/GRUB2/buildgrub.sh b/GRUB2/buildgrub.sh
new file mode 100644
index 00000000000..553a7531247
--- /dev/null
+++ b/GRUB2/buildgrub.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+VT_GRUB_DIR=$PWD
+
+rm -rf INSTALL
+rm -rf SRC
+rm -rf NBP
+rm -rf PXE
+
+mkdir SRC
+mkdir NBP
+mkdir PXE
+
+tar -xvf grub-2.04.tar.xz -C ./SRC/
+
+/bin/cp -a ./MOD_SRC/grub-2.04 ./SRC/
+
+cd ./SRC/grub-2.04
+
+# build for Legacy BIOS
+./autogen.sh
+./configure --prefix=$VT_GRUB_DIR/INSTALL/
+make -j 16
+sh install.sh
+
+# build for UEFI
+make distclean
+./autogen.sh
+./configure --with-platform=efi --prefix=$VT_GRUB_DIR/INSTALL/
+make -j 16
+sh install.sh uefi
+
+
+cd ../../
+
diff --git a/GenUUID/build.sh b/GenUUID/build.sh
new file mode 100644
index 00000000000..65625d66fdc
--- /dev/null
+++ b/GenUUID/build.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+/opt/diet32/bin/diet gcc -Os -m32 vtoy_gen_uuid.c -o vtoy_gen_uuid
+
+if [ -e vtoy_gen_uuid ]; then
+ echo -e '\n############### SUCCESS ###############\n'
+
+ rm -f ../INSTALL/tool/vtoy_gen_uuid
+ cp -a vtoy_gen_uuid ../INSTALL/tool/vtoy_gen_uuid
+else
+ echo -e '\n############### FAILED ################\n'
+ exit 1
+fi
+
diff --git a/GenUUID/vtoy_gen_uuid.c b/GenUUID/vtoy_gen_uuid.c
new file mode 100644
index 00000000000..6e37750f8b6
--- /dev/null
+++ b/GenUUID/vtoy_gen_uuid.c
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * vtoy_gen_uuid.c
+ *
+ * Copyright (c) 2020, longpanda
+ *
+ * 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 the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+int main()
+{
+ int i;
+ int fd;
+ unsigned char uuid[16];
+
+ fd = open("/dev/random", O_RDONLY);
+ if (fd < 0)
+ {
+ srand(time(NULL));
+ for (i = 0; i < 16; i++)
+ {
+ uuid[i] = (unsigned char)(rand());
+ }
+ }
+ else
+ {
+ read(fd, uuid, 16);
+ }
+
+ fwrite(uuid, 1, 16, stdout);
+ return 0;
+}
diff --git a/IMG/mkcpio.sh b/IMG/mkcpio.sh
index a6ac06c83bd..c288ed94d13 100644
--- a/IMG/mkcpio.sh
+++ b/IMG/mkcpio.sh
@@ -2,12 +2,6 @@
VENTOY_PATH=$PWD/../
-if [ -e check.sh ]; then
- if ! sh check.sh; then
- exit 1
- fi
-fi
-
rm -f ventoy.cpio
chmod -R 777 cpio
@@ -22,6 +16,13 @@ ln -s sbin/init linuxrc
cd ventoy
+cp -a $VENTOY_PATH/DMSETUP/dmsetup tool/
+cp -a $VENTOY_PATH/SQUASHFS/unsquashfs_* tool/
+cp -a $VENTOY_PATH/FUSEISO/vtoy_fuse_iso_* tool/
+cp -a $VENTOY_PATH/VtoyTool/vtoytool tool/
+cp -a $VENTOY_PATH/VBLADE/vblade-master/vblade_* tool/
+
+chmod -R 777 ./tool
find ./tool | cpio -o -H newc>tool.cpio
xz tool.cpio
diff --git a/INSTALL/all_in_one.sh b/INSTALL/all_in_one.sh
new file mode 100644
index 00000000000..89484e7c7b9
--- /dev/null
+++ b/INSTALL/all_in_one.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+VTOY_PATH=$PWD/..
+
+cd $VTOY_PATH/DOC
+sh installdietlibc.sh
+
+cd $VTOY_PATH/GRUB2
+sh buildgrub.sh || exit 1
+
+cd $VTOY_PATH/IPXE
+sh buildipxe.sh || exit 1
+
+cd $VTOY_PATH/EDK2
+sh buildedk.sh || exit 1
+
+cd $VTOY_PATH/VtoyTool
+sh build.sh || exit 1
+
+cd $VTOY_PATH/vtoyfat/fat_io_lib
+sh buildlib.sh
+
+cd $VTOY_PATH/vtoyfat
+sh build.sh || exit 1
+
+
+cd $VTOY_PATH/ExFAT
+sh buidlibfuse.sh || exit 1
+sh buidexfat.sh || exit 1
+/bin/cp -a EXFAT/shared/mkexfatfs $VTOY_PATH/INSTALL/tool/mkexfatfs_64
+/bin/cp -a EXFAT/shared/mount.exfat-fuse $VTOY_PATH/INSTALL/tool/mount.exfat-fuse_64
+
+
+cd $VTOY_PATH/FUSEISO
+sh build_libfuse.sh
+sh build.sh
+
+cd $VTOY_PATH/SQUASHFS/SRC
+sh build_lz4.sh
+sh build_lzma.sh
+sh build_lzo.sh
+sh build_zstd.sh
+
+cd $VTOY_PATH/SQUASHFS/squashfs-tools-4.4/squashfs-tools
+sh build.sh
+
+cd $VTOY_PATH/VBLADE/vblade-master
+sh build.sh
+
+cd $VTOY_PATH/Ventoy2Disk/Ventoy2Disk/xz-embedded-20130513/userspace
+make -f ventoy_makefile
+strip --strip-all xzminidec
+rm -f $VTOY_PATH/IMG/cpio/ventoy/tool/xzminidec
+cp -a xzminidec $VTOY_PATH/IMG/cpio/ventoy/tool/xzminidec
+make clean; rm -f *.o
+
+
+
+cd $VTOY_PATH/INSTALL
+sh ventoy_pack.sh || exit 1
+
+echo -e '\n============== SUCCESS ==================\n'
diff --git a/INSTALL/grub/grub.cfg b/INSTALL/grub/grub.cfg
index 763fed82c56..ab18f8d8e7b 100644
--- a/INSTALL/grub/grub.cfg
+++ b/INSTALL/grub/grub.cfg
@@ -38,7 +38,7 @@ function ventoy_power {
function get_os_type {
set vtoy_os=Linux
- for file in "efi/microsoft" "sources/boot.wim" "boot/bcd" "bootmgr.efi" "boot/etfsboot.com"; do
+ for file in "efi/microsoft" "sources/boot.wim" "boot/bcd" "bootmgr.efi" "boot/etfsboot.com" "BOOT/etfsboot.com"; do
if [ -e $1/$file ]; then
set vtoy_os=Windows
break
@@ -453,8 +453,7 @@ function common_menuentry {
#############################################################
#############################################################
-set VENTOY_VERSION="1.0.9Y"
-
+set VENTOY_VERSION="1.0.10"
# Default menu display mode, you can change it as you want.
# 0: List mode
@@ -470,14 +469,6 @@ set VTOY_ISO_UEFI_DRV_STR="UEFI FS"
set VTOY_F2_CMD="ventoy_power"
-if [ $VTOY_DEFAULT_MENU_MODE -eq 0 ]; then
- set VTOY_F3_CMD="vt_dynamic_menu 1 1"
- set VTOY_HOTKEY_TIP="F1:Memdisk F2:Power F3:TreeView"
-else
- set VTOY_F3_CMD="vt_dynamic_menu 1 0"
- set VTOY_HOTKEY_TIP="F1:Memdisk F2:Power F3:ListView"
-fi
-
if [ "$grub_platform" = "pc" ]; then
set VTOY_TEXT_MENU_VER="Ventoy $VENTOY_VERSION BIOS www.ventoy.net"
else
@@ -501,10 +492,21 @@ fi
loadfont ascii
+#Load Plugin
if [ -f $iso_path/ventoy/ventoy.json ]; then
vt_load_plugin $iso_path
fi
+
+if [ $VTOY_DEFAULT_MENU_MODE -eq 0 ]; then
+ set VTOY_F3_CMD="vt_dynamic_menu 1 1"
+ set VTOY_HOTKEY_TIP="F1:Memdisk F2:Power F3:TreeView"
+else
+ set VTOY_F3_CMD="vt_dynamic_menu 1 0"
+ set VTOY_HOTKEY_TIP="F1:Memdisk F2:Power F3:ListView"
+fi
+
+
if [ -n "$vtoy_gfxmode" ]; then
set gfxmode=$vtoy_gfxmode
else
diff --git a/INSTALL/ventoy_pack.sh b/INSTALL/ventoy_pack.sh
new file mode 100644
index 00000000000..8969e4823ce
--- /dev/null
+++ b/INSTALL/ventoy_pack.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+. ./tool/ventoy_lib.sh
+
+GRUB_DIR=../GRUB2/INSTALL
+LANG_DIR=../LANGUAGES
+
+if ! [ -d $GRUB_DIR ]; then
+ echo "$GRUB_DIR not exist"
+ exit 1
+fi
+
+
+cd ../IMG
+sh mkcpio.sh
+cd -
+
+
+LOOP=$(losetup -f)
+
+rm -f img.bin
+dd if=/dev/zero of=img.bin bs=1M count=256 status=none
+
+losetup -P $LOOP img.bin
+
+while ! grep -q 524288 /sys/block/${LOOP#/dev/}/size 2>/dev/null; do
+ echo "wait $LOOP ..."
+ sleep 1
+done
+
+format_ventoy_disk $LOOP
+
+$GRUB_DIR/sbin/grub-bios-setup --skip-fs-probe --directory="./grub/i386-pc" $LOOP
+
+curver=$(get_ventoy_version_from_cfg ./grub/grub.cfg)
+
+tmpmnt=./ventoy-${curver}-mnt
+tmpdir=./ventoy-${curver}
+
+rm -rf $tmpmnt
+mkdir -p $tmpmnt
+
+mount ${LOOP}p2 $tmpmnt
+
+mkdir -p $tmpmnt/grub
+
+# First copy grub.cfg file, to make it locate at front of the part2
+cp -a ./grub/grub.cfg $tmpmnt/grub/
+
+ls -1 ./grub/ | grep -v 'grub\.cfg' | while read line; do
+ cp -a ./grub/$line $tmpmnt/grub/
+done
+
+cp -a ./ventoy $tmpmnt/
+cp -a ./EFI $tmpmnt/
+cp -a ./tool/ENROLL_THIS_KEY_IN_MOKMANAGER.cer $tmpmnt/
+
+
+mkdir -p $tmpmnt/tool
+cp -a ./tool/mount* $tmpmnt/tool/
+
+rm -f $tmpmnt/grub/i386-pc/*
+
+
+umount $tmpmnt && rm -rf $tmpmnt
+
+
+rm -rf $tmpdir
+mkdir -p $tmpdir/boot
+mkdir -p $tmpdir/ventoy
+echo $curver > $tmpdir/ventoy/version
+dd if=$LOOP of=$tmpdir/boot/boot.img bs=1 count=512 status=none
+dd if=$LOOP of=$tmpdir/boot/core.img bs=512 count=2047 skip=1 status=none
+xz --check=crc32 $tmpdir/boot/core.img
+
+cp -a ./tool $tmpdir/
+cp -a Ventoy2Disk.sh $tmpdir/
+
+
+#32MB disk img
+dd status=none if=$LOOP of=$tmpdir/ventoy/ventoy.disk.img bs=512 count=$VENTOY_SECTOR_NUM skip=$part2_start_sector
+xz --check=crc32 $tmpdir/ventoy/ventoy.disk.img
+
+losetup -d $LOOP && rm -f img.bin
+
+rm -f ventoy-${curver}-linux.tar.gz
+
+
+CurDir=$PWD
+cd $tmpdir/tool
+
+for file in $(ls); do
+ if [ "$file" != "xzcat" ] && [ "$file" != "ventoy_lib.sh" ]; then
+ xz --check=crc32 $file
+ fi
+done
+
+cd $CurDir
+tar -czvf ventoy-${curver}-linux.tar.gz $tmpdir
+
+rm -f ventoy-${curver}-windows.zip
+cp -a Ventoy2Disk.exe $tmpdir/
+cp -a $LANG_DIR/languages.ini $tmpdir/ventoy/
+rm -rf $tmpdir/tool
+rm -f $tmpdir/*.sh
+
+
+zip -r ventoy-${curver}-windows.zip $tmpdir/
+
+rm -rf $tmpdir
+
+if [ -e ventoy-${curver}-windows.zip ] && [ -e ventoy-${curver}-linux.tar.gz ]; then
+ echo -e "\n ============= SUCCESS =================\n"
+else
+ echo -e "\n ============= FAILED =================\n"
+ exit 1
+fi
+
+
diff --git a/IPXE/README.txt b/IPXE/README.txt
deleted file mode 100644
index 0eabadd0db8..00000000000
--- a/IPXE/README.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-
-========== About Source Code =============
-1. unpack ipxe_org_code/ipxe-3fe683e.tar.bz2
-2. After decompressing, delete ipxe-3fe683e/src/drivers (whole directory)
-3. Merge left source code with the ipxe-3fe683e directory here
-
-========== Build =============
-make bin/ipxe.iso
diff --git a/IPXE/buildipxe.sh b/IPXE/buildipxe.sh
new file mode 100644
index 00000000000..27bbdee7d1f
--- /dev/null
+++ b/IPXE/buildipxe.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+rm -rf ipxe-3fe683e
+
+tar -xvf ipxe_org_code/ipxe-3fe683e.tar.bz2 -C ./
+
+rm -rf ./ipxe-3fe683e/src/bin
+rm -rf ./ipxe-3fe683e/src/drivers
+
+/bin/cp -a ipxe_mod_code/ipxe-3fe683e ./
+
+cd ipxe-3fe683e/src
+
+sh build.sh
+
+cd ../../
+
diff --git a/IPXE/ipxe-3fe683e/src/arch/x86/core/runtime.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/core/runtime.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/arch/x86/core/runtime.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/core/runtime.c
diff --git a/IPXE/ipxe-3fe683e/src/arch/x86/core/ventoy_vdisk.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/core/ventoy_vdisk.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/arch/x86/core/ventoy_vdisk.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/core/ventoy_vdisk.c
diff --git a/IPXE/ipxe-3fe683e/src/arch/x86/drivers/hyperv/hyperv.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/drivers/hyperv/hyperv.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/arch/x86/drivers/hyperv/hyperv.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/drivers/hyperv/hyperv.c
diff --git a/IPXE/ipxe-3fe683e/src/arch/x86/drivers/xen/hvm.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/drivers/xen/hvm.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/arch/x86/drivers/xen/hvm.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/drivers/xen/hvm.c
diff --git a/IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/hidemem.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/interface/pcbios/hidemem.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/hidemem.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/interface/pcbios/hidemem.c
diff --git a/IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/int13.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/interface/pcbios/int13.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/int13.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/interface/pcbios/int13.c
diff --git a/IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/ventoy_int13.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/interface/pcbios/ventoy_int13.c
similarity index 98%
rename from IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/ventoy_int13.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/interface/pcbios/ventoy_int13.c
index c71f9f63859..4ac03799909 100644
--- a/IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/ventoy_int13.c
+++ b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/interface/pcbios/ventoy_int13.c
@@ -1374,6 +1374,25 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
return -EIO;
}
+ if (catalog.boot.length > 4)
+ {
+ isolinux_boot_info *bootinfo = NULL;
+ bootinfo = (isolinux_boot_info *)(real_to_user(address->segment, address->offset));
+ if (0x7C6CEAFA == bootinfo->isolinux0 && 0x90900000 == bootinfo->isolinux1)
+ {
+ if (bootinfo->BootFileLocation == 0 && bootinfo->PvdLocation == 16 &&
+ (bootinfo->BootFileLen / 2048) < catalog.boot.length && bootinfo->BootFileChecksum > 0)
+ {
+ if (g_debug)
+ {
+ printf("isolinux file location is 0, now fix it to %u ...\n", catalog.boot.start);
+ ventoy_debug_pause();
+ }
+ bootinfo->BootFileLocation = catalog.boot.start;
+ }
+ }
+ }
+
return 0;
}
diff --git a/IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/ventoy_int13.h b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/interface/pcbios/ventoy_int13.h
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/ventoy_int13.h
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/interface/pcbios/ventoy_int13.h
diff --git a/IPXE/ipxe_mod_code/ipxe-3fe683e/src/build.sh b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/build.sh
new file mode 100644
index 00000000000..e8417a2a4a9
--- /dev/null
+++ b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/build.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+build_bios() {
+ rm -f bin/ipxe.iso
+
+ make -e -k -j 8 bin/ipxe.iso BIOS_MODE=BIOS
+
+ if ! [ -e bin/ipxe.iso ]; then
+ echo "Failed"
+ exit 1
+ fi
+
+ mkdir -p ./mnt
+ mount bin/ipxe.iso ./mnt
+
+ rm -f ../../../INSTALL/ventoy/ipxe.krn
+ cp -a ./mnt/ipxe.krn ../../../INSTALL/ventoy/ipxe.krn
+
+ umount ./mnt > /dev/null 2>&1
+ umount ./mnt > /dev/null 2>&1
+ umount ./mnt > /dev/null 2>&1
+
+ rm -rf ./mnt
+
+ echo -e "\n===============SUCCESS===============\n"
+}
+
+
+build_bios
+
+
diff --git a/IPXE/ipxe-3fe683e/src/config/settings.h b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/config/settings.h
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/config/settings.h
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/config/settings.h
diff --git a/IPXE/ipxe-3fe683e/src/core/device.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/core/device.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/core/device.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/core/device.c
diff --git a/IPXE/ipxe-3fe683e/src/core/main.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/core/main.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/core/main.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/core/main.c
diff --git a/IPXE/ipxe-3fe683e/src/core/ventoy_dummy.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/core/ventoy_dummy.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/core/ventoy_dummy.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/core/ventoy_dummy.c
diff --git a/IPXE/ipxe-3fe683e/src/core/vsprintf.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/core/vsprintf.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/core/vsprintf.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/core/vsprintf.c
diff --git a/IPXE/ipxe-3fe683e/src/drivers/net/efi/snp.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/drivers/net/efi/snp.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/drivers/net/efi/snp.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/drivers/net/efi/snp.c
diff --git a/IPXE/ipxe-3fe683e/src/include/ipxe/sanboot.h b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/include/ipxe/sanboot.h
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/include/ipxe/sanboot.h
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/include/ipxe/sanboot.h
diff --git a/IPXE/ipxe-3fe683e/src/include/ventoy.h b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/include/ventoy.h
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/include/ventoy.h
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/include/ventoy.h
diff --git a/IPXE/ipxe-3fe683e/src/interface/efi/efi_pci.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/interface/efi/efi_pci.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/interface/efi/efi_pci.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/interface/efi/efi_pci.c
diff --git a/IPXE/ipxe-3fe683e/src/net/tcp/iscsi.c b/IPXE/ipxe_mod_code/ipxe-3fe683e/src/net/tcp/iscsi.c
similarity index 100%
rename from IPXE/ipxe-3fe683e/src/net/tcp/iscsi.c
rename to IPXE/ipxe_mod_code/ipxe-3fe683e/src/net/tcp/iscsi.c
diff --git a/LANGUAGES/languages.ini b/LANGUAGES/languages.ini
index 688237695d7..29729e08465 100644
Binary files a/LANGUAGES/languages.ini and b/LANGUAGES/languages.ini differ
diff --git a/SQUASHFS/unsquashfs_32 b/SQUASHFS/unsquashfs_32
new file mode 100644
index 00000000000..20e2525dfec
Binary files /dev/null and b/SQUASHFS/unsquashfs_32 differ
diff --git a/SQUASHFS/unsquashfs_64 b/SQUASHFS/unsquashfs_64
new file mode 100644
index 00000000000..d7d201c7ac8
Binary files /dev/null and b/SQUASHFS/unsquashfs_64 differ
diff --git a/Ventoy2Disk/Ventoy2Disk/xz-embedded-20130513/userspace/ventoy_makefile b/Ventoy2Disk/Ventoy2Disk/xz-embedded-20130513/userspace/ventoy_makefile
new file mode 100644
index 00000000000..d4c0697a4fe
--- /dev/null
+++ b/Ventoy2Disk/Ventoy2Disk/xz-embedded-20130513/userspace/ventoy_makefile
@@ -0,0 +1,48 @@
+#
+# Makefile
+#
+# Author: Lasse Collin
+#
+# This file has been put into the public domain.
+# You can do whatever you want with this file.
+#
+
+CC = /opt/diet32/bin/diet gcc -Os -m32 -std=gnu89
+BCJ_CPPFLAGS = -DXZ_DEC_X86 -DXZ_DEC_POWERPC -DXZ_DEC_IA64 \
+ -DXZ_DEC_ARM -DXZ_DEC_ARMTHUMB -DXZ_DEC_SPARC
+CPPFLAGS = -DXZ_USE_CRC64 -DXZ_DEC_ANY_CHECK
+CFLAGS = -ggdb3 -O2 -pedantic -Wall -Wextra
+RM = rm -f
+VPATH = ../linux/include/linux ../linux/lib/xz
+COMMON_SRCS = xz_crc32.c xz_crc64.c xz_dec_stream.c xz_dec_lzma2.c xz_dec_bcj.c
+COMMON_OBJS = $(COMMON_SRCS:.c=.o)
+XZMINIDEC_OBJS = xzminidec.o
+BYTETEST_OBJS = bytetest.o
+BUFTEST_OBJS = buftest.o
+BOOTTEST_OBJS = boottest.o
+XZ_HEADERS = xz.h xz_private.h xz_stream.h xz_lzma2.h xz_config.h
+PROGRAMS = xzminidec bytetest buftest boottest
+
+ALL_CPPFLAGS = -I../linux/include/linux -I. $(BCJ_CPPFLAGS) $(CPPFLAGS)
+
+all: $(PROGRAMS)
+
+%.o: %.c $(XZ_HEADERS)
+ $(CC) $(ALL_CPPFLAGS) $(CFLAGS) -c -o $@ $<
+
+xzminidec: $(COMMON_OBJS) $(XZMINIDEC_OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(COMMON_OBJS) $(XZMINIDEC_OBJS)
+
+bytetest: $(COMMON_OBJS) $(BYTETEST_OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(COMMON_OBJS) $(BYTETEST_OBJS)
+
+buftest: $(COMMON_OBJS) $(BUFTEST_OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(COMMON_OBJS) $(BUFTEST_OBJS)
+
+boottest: $(BOOTTEST_OBJS) $(COMMON_SRCS)
+ $(CC) $(ALL_CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(BOOTTEST_OBJS)
+
+.PHONY: clean
+clean:
+ -$(RM) $(COMMON_OBJS) $(XZMINIDEC_OBJS) $(BUFTEST_OBJS) \
+ $(BOOTTEST_OBJS) $(PROGRAMS)
diff --git a/ZSTD/build.txt b/ZSTD/build.txt
new file mode 100644
index 00000000000..7977794e7c8
--- /dev/null
+++ b/ZSTD/build.txt
@@ -0,0 +1,20 @@
+Build a static linked, small zstdcat tool
+
+======== Source Code ========
+use an old version of zstd
+https://codeload.github.com/facebook/zstd/zip/v1.0.0
+
+======== Build Envrioment ========
+build for 32bit, static linked with dietlibc
+1. install centos 6.10 i386 with CentOS-6.10-i386-bin-DVD1.iso
+2. yum install gcc gettext gettext-devel
+3. install dietc libc (just make && make install)
+4. export PATH=$PATH:/opt/diet/bin
+
+======== Build Step ========
+1. extract zstd source code
+2. cd programs
+3. diet -Os gcc -pipe -nostdinc -falign-loops=32 -I../lib -I../lib/common -I../lib/dictBuilder -I../lib/legacy -O3 -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef -DZSTD_LEGACY_SUPPORT=1 ../lib/decompress/zstd_decompress.c -c -o ../lib/decompress/zstd_decompress.o
+ diet -Os gcc -pipe -nostdinc -I../lib -I../lib/common -I../lib/dictBuilder -I../lib/legacy -O3 -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef -DZSTD_LEGACY_SUPPORT=1 ../lib/decompress/zstd_decompress.o ../lib/decompress/huf_decompress.c ../lib/common/entropy_common.c ../lib/common/fse_decompress.c ../lib/common/xxhash.c ../lib/common/zstd_common.c ../lib/compress/zstd_compress.c ../lib/compress/fse_compress.c ../lib/compress/huf_compress.c ../lib/legacy/zstd_v01.c ../lib/legacy/zstd_v02.c ../lib/legacy/zstd_v03.c ../lib/legacy/zstd_v04.c ../lib/legacy/zstd_v05.c ../lib/legacy/zstd_v06.c ../lib/legacy/zstd_v07.c ../lib/dictBuilder/divsufsort.c ../lib/dictBuilder/zdict.c zstdcli.c fileio.c bench.c datagen.c dibio.c -o zstd
+4. strip --strip-all zstd
+5. rename zstd to zstdcat
diff --git a/ZSTD/zstdcat b/ZSTD/zstdcat
new file mode 100644
index 00000000000..e8657c6b4d4
Binary files /dev/null and b/ZSTD/zstdcat differ
diff --git a/vtoyfat/fat_io_lib/README.txt b/vtoyfat/fat_io_lib/README.txt
deleted file mode 100644
index 5f5111bb1e8..00000000000
--- a/vtoyfat/fat_io_lib/README.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-========= About fat_io_lib =========
-1. Download fat_io_lib source code from http://ultra-embedded.com/releases/fat_io_lib.zip
-2. decompress the code and run buildlib.sh
diff --git a/vtoyfat/fat_io_lib/buildlib.sh b/vtoyfat/fat_io_lib/buildlib.sh
index 11ca235700b..4c9846bbd25 100644
--- a/vtoyfat/fat_io_lib/buildlib.sh
+++ b/vtoyfat/fat_io_lib/buildlib.sh
@@ -1,8 +1,16 @@
#!/bin/sh
+if ! [ -f fat_io_lib.zip ]; then
+ echo "No fat_io_lib.zip found ..."
+ exit 1
+fi
+
+unzip fat_io_lib.zip
+
rm -rf include
rm -rf lib
+
cd release
gcc -O2 -D_FILE_OFFSET_BITS=64 fat*.c -c
ar -rc libfat_io_64.a *.o