diff --git a/DOC/BuildVentoyFromSource.txt b/DOC/BuildVentoyFromSource.txt new file mode 100644 index 00000000..e2550257 --- /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 00000000..ac8350b4 --- /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 3d802235..00000000 --- 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 00000000..bc99afc8 --- /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 00000000..b691cd6d --- /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 00000000..9c17cc96 --- /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 00000000..64d30f7d --- /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 00000000..66b67802 --- /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 00000000..34ca6538 --- /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 17950add..af510d02 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 25ef02a6..64f6d756 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 00000000..607ce42a 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 00000000..ad4ff340 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 00000000..4dc537e7 --- /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 00000000..e1c1d478 --- /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 00000000..87edd254 --- /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 00000000..cb1d3d61 --- /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 00000000..56629a80 --- /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 1978daef..ce77a8c8 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 827e142d..82de5130 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 00000000..3baf95f4 --- /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 57f0008d..00000000 --- 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 00000000..553a7531 --- /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 00000000..65625d66 --- /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 00000000..6e37750f --- /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 a6ac06c8..c288ed94 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 00000000..89484e7c --- /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 763fed82..ab18f8d8 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 00000000..8969e482 --- /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 0eabadd0..00000000 --- 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 00000000..27bbdee7 --- /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 c71f9f63..4ac03799 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 00000000..e8417a2a --- /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 68823769..29729e08 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 00000000..20e2525d 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 00000000..d7d201c7 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 00000000..d4c0697a --- /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 00000000..7977794e --- /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 00000000..e8657c6b 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 5f5111bb..00000000 --- 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 11ca2357..4c9846bb 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