Compare commits

...

28 Commits

Author SHA1 Message Date
longpanda
8cde5a4898 1.0.12 release 2020-05-30 20:13:09 +08:00
longpanda
c8e86938fe 1. Add a new feature to directly boot wim files
2. auto installation plugin update
    1) Expand the configuration, now you can specify more than one auto installation scripts for one ISO file
    2) Add a prompt for the iso with auto installation config, you can choose whether to use the auto installation script and which one to use for this time
3. persistence plugin update
    1) Expand the configuration, now you can specify more than one persistence backend image files for one ISO file
    2) Add a prompt for the iso with persistence config, you can choose whether to use the persistence image and which one to use for this time
4. Move the position of the red Memdisk tip to a more prominent position
5. Add a return parent directory item when in TreeView mode
6. Add a VTOY_DEFAULT_SEARCH_ROOT option in global control plugin to specify the root path of the iso files.
7. Change the style of F2 power menu
8. Fix a bug about Ventoy2Disk.exe can't start when there is a DataRAM Ramdisk in the system.
9. Files with size less than 32KB will be filted by default
10. Fix a bug about wrong file size in TreeView mode with NTFS/XFS
11. Files with space or Non Ascii charactors in name will be shown but with unsupported message when you boot it.
12. Optimization for Ventoy2Disk.sh
13. Optimization for arch linux boot
14. New iso support
2020-05-29 22:57:46 +08:00
Ali Mahdavi
7a0b2d945e Persian language added (#170) 2020-05-29 22:27:06 +08:00
longpanda
5089fda07d Create FUNDING.yml 2020-05-25 15:10:14 +08:00
longpanda
f77ba141fd Update README.md 2020-05-25 12:45:09 +08:00
longpanda
6d1ace0570 dos2unix 2020-05-24 20:45:04 +08:00
longpanda
a2d732c170 update ventoy_pack.sh 2020-05-24 20:43:41 +08:00
longpanda
a54b6f692c Update ventoy_lib.sh 2020-05-24 20:25:47 +08:00
longpanda
73c196a823 Update Ventoy2Disk.sh 2020-05-24 20:24:34 +08:00
longpanda
487ffc6795 update Italian format 2020-05-23 21:33:36 +08:00
longpanda
ad7322cb0a 1.0.11 release 2020-05-23 21:20:32 +08:00
longpanda
ef40780f20 1.0.11 release 2020-05-23 21:19:32 +08:00
Tim Obezuk
f0d59949e5 Fixed typo in README.md (#144) 2020-05-22 09:04:16 +08:00
longpanda
89c1ab55f1 Update ventoy_lib.sh 2020-05-21 16:09:37 +08:00
longpanda
1e4965cb24 Update ventoy_lib.sh 2020-05-21 16:05:07 +08:00
longpanda
ac0f68f90b Update ventoy_lib.sh 2020-05-21 15:59:06 +08:00
longpanda
50aa5d3823 Delete fat_io_lib.zip 2020-05-21 13:05:03 +08:00
longpanda
e80871a31e Add files via upload 2020-05-21 13:03:42 +08:00
longpanda
0997342607 Add files via upload 2020-05-21 12:59:37 +08:00
longpanda
c4a79e68e1 Update build.txt 2020-05-21 12:53:13 +08:00
longpanda
5f60eae6ee Update BuildVentoyFromSource.txt 2020-05-21 12:46:50 +08:00
longpanda
90fa7adc84 Update build_libfuse.sh 2020-05-21 12:46:10 +08:00
longpanda
b0c321dfc8 Update buidlibfuse.sh 2020-05-21 12:45:39 +08:00
longpanda
efa7a942ac Add install and compile instructions in README.md 2020-05-20 22:57:50 +08:00
longpanda
f352003913 DOC/BuildVentoyFromSource.txt 2020-05-20 22:46:16 +08:00
longpanda
2aae096c2a 1. change some directory structure for the build script
2. add build script and document
   see DOC/BuildVentoyFromSource.txt for detail
2020-05-20 22:43:54 +08:00
longpanda
5d0fe69b25 1. change some directory structure for the build script
2. add build script and document
   see DOC/BuildVentoyFromSource.txt for detail
2020-05-20 22:37:26 +08:00
longpanda
965417970b Update PhyDrive.c 2020-05-18 16:40:12 +08:00
137 changed files with 8873 additions and 781 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['https://www.ventoy.net/en/donation.html'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -2,7 +2,8 @@ Build a static linked, small dmsetup tool
======== Source Code ========
use an old version of dmsetup
xxx/centos-vault/5.3/os/SRPMS/device-mapper-1.02.28-2.el5.src.rpm
http://vault.centos.org/5.3/os/SRPMS/device-mapper-1.02.28-2.el5.src.rpm
https://www.fefe.de/dietlibc/dietlibc-0.34.tar.xz
======== Build Envrioment ========
build for 32bit, static linked with dietlibc

View File

@@ -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://codeload.github.com/libfuse/libfuse/zip/fuse-2.9.9 ===> /home/Ventoy-master/ExFAT/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

34
DOC/installdietlibc.sh Normal file
View File

@@ -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 ""

View File

@@ -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

33
EDK2/buildedk.sh Normal file
View File

@@ -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

View File

@@ -413,7 +413,7 @@ EFI_STATUS EFIAPI ventoy_block_io_read
secNum = BufferSize / 2048;
offset = Lba * 2048;
if (offset + BufferSize < g_chain->real_img_size_in_bytes)
if (offset + BufferSize <= g_chain->real_img_size_in_bytes)
{
return ventoy_read_iso_sector(Lba, secNum, Buffer);
}

File diff suppressed because it is too large Load Diff

794
EDK2/efiffs/mod/src/file.c Normal file
View File

@@ -0,0 +1,794 @@
/* file.c - SimpleFileIo Interface */
/*
* Copyright © 2014-2017 Pete Batard <pete@akeo.ie>
* Based on iPXE's efi_driver.c and efi_file.c:
* Copyright © 2011,2013 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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" <ROOT>":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 <ROOT>'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"<ROOT>":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 <ROOT>\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"<ROOT>":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"<DIR>":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"<DIR>":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"<DIR>":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"<DIR>":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);
}

View File

@@ -0,0 +1,86 @@
/* logging.c - EFI logging */
/*
* Copyright © 2014-2017 Pete Batard <pete@akeo.ie>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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<ARRAYSIZE(PrintTable); i++)
*PrintTable[i] = (i < LogLevel)?(Print_t)Print:(Print_t)PrintNone;
PrintExtra(L"LogLevel = %d\n", LogLevel);
}

File diff suppressed because it is too large Load Diff

784
EDK2/efiffs/org/src/file.c Normal file
View File

@@ -0,0 +1,784 @@
/* file.c - SimpleFileIo Interface */
/*
* Copyright © 2014-2017 Pete Batard <pete@akeo.ie>
* Based on iPXE's efi_driver.c and efi_file.c:
* Copyright © 2011,2013 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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" <ROOT>":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 <ROOT>'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"<ROOT>":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 <ROOT>\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"<ROOT>":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"<DIR>":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"<DIR>":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"<DIR>":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"<DIR>":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);
}

View File

@@ -0,0 +1,80 @@
/* logging.c - EFI logging */
/*
* Copyright © 2014-2017 Pete Batard <pete@akeo.ie>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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<ARRAYSIZE(PrintTable); i++)
*PrintTable[i] = (i < LogLevel)?(Print_t)Print:(Print_t)PrintNone;
PrintExtra(L"LogLevel = %d\n", LogLevel);
}

View File

@@ -1,8 +0,0 @@
Please download exfat-1.3.0.zip and mirrors-libfuse-fuse-2.9.9.zip first.
exfat-1.3.0.zip:
https://codeload.github.com/relan/exfat/zip/v1.3.0
mirrors-libfuse-fuse-2.9.9.zip:
https://gitee.com/mirrors/libfuse/repository/archive/fuse-2.9.9.zip

View File

@@ -18,14 +18,14 @@ if ! [ -e LIBFUSE ]; then
./buidlibfuse.sh
fi
rm -f EXFAT/shared/*
rm -f EXFAT/static/*
rm -rf EXFAT
mkdir -p EXFAT/shared
mkdir -p EXFAT/static
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
@@ -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

View File

@@ -5,10 +5,14 @@ CUR="$PWD"
rm -rf libfuse
rm -rf LIBFUSE
unzip mirrors-libfuse-fuse-2.9.9.zip
if [ -e mirrors-libfuse-fuse-2.9.9.zip ]; then
unzip mirrors-libfuse-fuse-2.9.9.zip
cd libfuse
else
unzip libfuse-fuse-2.9.9.zip
cd libfuse-fuse-2.9.9
fi
cd libfuse
./makeconf.sh
./configure --prefix="$CUR/LIBFUSE"

View File

@@ -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

View File

@@ -14,16 +14,21 @@ LIBFUSE_DIR=$CUR/LIBFUSE
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
# please download https://codeload.github.com/libfuse/libfuse/zip/fuse-2.9.9
if [ -e ../ExFAT/mirrors-libfuse-fuse-2.9.9.zip ]; then
rm -rf libfuse
unzip ../ExFAT/mirrors-libfuse-fuse-2.9.9.zip
cd libfuse
elif [ -e ../ExFAT/libfuse-fuse-2.9.9.zip ]; then
rm -rf libfuse-fuse-2.9.9
unzip ../ExFAT/libfuse-fuse-2.9.9.zip
cd libfuse-fuse-2.9.9
else
echo "Please download mirrors-libfuse-fuse-2.9.9.zip first"
exit 1
fi
unzip mirrors-libfuse-fuse-2.9.9.zip
cd libfuse
./makeconf.sh
./configure --prefix="$LIBFUSE_DIR"

BIN
FUSEISO/vtoy_fuse_iso_32 Normal file

Binary file not shown.

BIN
FUSEISO/vtoy_fuse_iso_64 Normal file

Binary file not shown.

View File

@@ -46,6 +46,7 @@
#include <grub/dl.h>
#include <grub/types.h>
#include <grub/fshelp.h>
#include <grub/ventoy.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -339,7 +340,7 @@ struct grub_ext2_data
static grub_dl_t my_mod;
static int g_ventoy_block_count;
/* Check is a = b^x for some x. */
static inline int
@@ -499,6 +500,7 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
start = grub_le_to_cpu16 (ext[i].start_hi);
start = (start << 32) + grub_le_to_cpu32 (ext[i].start);
g_ventoy_block_count = (int)(grub_le_to_cpu16 (ext[i].len) - fileblock);
ret = fileblock + start;
}
}
@@ -1069,8 +1071,46 @@ grub_ext2_mtime (grub_device_t device, grub_int32_t *tm)
}
int grub_ext_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list)
{
int blocksize;
int log2blocksize;
grub_disk_t disk;
grub_disk_addr_t i = 0;
grub_disk_addr_t blockcnt;
grub_disk_addr_t blknr;
grub_fshelp_node_t node = NULL;
disk = file->device->disk;
node = &(((struct grub_ext2_data *)file->data)->diropen);
log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data);
blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS);
blockcnt = (file->size + blocksize - 1) >> (log2blocksize + GRUB_DISK_SECTOR_BITS);
while (i < blockcnt)
{
g_ventoy_block_count = 1;
blknr = grub_ext2_read_block(node, i);
if (blknr == 0)
{
return 0;
}
i += g_ventoy_block_count;
blknr = blknr << log2blocksize;
grub_disk_blocklist_read(chunk_list, blknr, g_ventoy_block_count * blocksize, disk->log_sector_size);
}
for (i = 0; i < chunk_list->cur_chunk; i++)
{
chunk_list->chunk[i].disk_start_sector += part_start;
chunk_list->chunk[i].disk_end_sector += part_start;
}
return 0;
}
static struct grub_fs grub_ext2_fs =
{
.name = "ext2",

View File

@@ -0,0 +1,429 @@
/* fshelp.c -- Filesystem helper functions */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2004,2005,2006,2007,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 <http://www.gnu.org/licenses/>.
*/
#include <grub/err.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/disk.h>
#include <grub/fshelp.h>
#include <grub/dl.h>
#include <grub/i18n.h>
GRUB_MOD_LICENSE ("GPLv3+");
typedef int (*iterate_dir_func) (grub_fshelp_node_t dir,
grub_fshelp_iterate_dir_hook_t hook,
void *data);
typedef grub_err_t (*lookup_file_func) (grub_fshelp_node_t dir,
const char *name,
grub_fshelp_node_t *foundnode,
enum grub_fshelp_filetype *foundtype);
typedef char *(*read_symlink_func) (grub_fshelp_node_t node);
struct stack_element {
struct stack_element *parent;
grub_fshelp_node_t node;
enum grub_fshelp_filetype type;
};
/* Context for grub_fshelp_find_file. */
struct grub_fshelp_find_file_ctx
{
/* Inputs. */
const char *path;
grub_fshelp_node_t rootnode;
/* Global options. */
int symlinknest;
/* Current file being traversed and its parents. */
struct stack_element *currnode;
};
/* Helper for find_file_iter. */
static void
free_node (grub_fshelp_node_t node, struct grub_fshelp_find_file_ctx *ctx)
{
if (node != ctx->rootnode)
grub_free (node);
}
static void
pop_element (struct grub_fshelp_find_file_ctx *ctx)
{
struct stack_element *el;
el = ctx->currnode;
ctx->currnode = el->parent;
free_node (el->node, ctx);
grub_free (el);
}
static void
free_stack (struct grub_fshelp_find_file_ctx *ctx)
{
while (ctx->currnode)
pop_element (ctx);
}
static void
go_up_a_level (struct grub_fshelp_find_file_ctx *ctx)
{
if (!ctx->currnode->parent)
return;
pop_element (ctx);
}
static grub_err_t
push_node (struct grub_fshelp_find_file_ctx *ctx, grub_fshelp_node_t node, enum grub_fshelp_filetype filetype)
{
struct stack_element *nst;
nst = grub_malloc (sizeof (*nst));
if (!nst)
return grub_errno;
nst->node = node;
nst->type = filetype & ~GRUB_FSHELP_CASE_INSENSITIVE;
nst->parent = ctx->currnode;
ctx->currnode = nst;
return GRUB_ERR_NONE;
}
static grub_err_t
go_to_root (struct grub_fshelp_find_file_ctx *ctx)
{
free_stack (ctx);
return push_node (ctx, ctx->rootnode, GRUB_FSHELP_DIR);
}
struct grub_fshelp_find_file_iter_ctx
{
const char *name;
grub_fshelp_node_t *foundnode;
enum grub_fshelp_filetype *foundtype;
};
/* Helper for grub_fshelp_find_file. */
static int
find_file_iter (const char *filename, enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node, void *data)
{
struct grub_fshelp_find_file_iter_ctx *ctx = data;
if (filetype == GRUB_FSHELP_UNKNOWN ||
((filetype & GRUB_FSHELP_CASE_INSENSITIVE)
? grub_strcasecmp (ctx->name, filename)
: grub_strcmp (ctx->name, filename)))
{
grub_free (node);
return 0;
}
/* The node is found, stop iterating over the nodes. */
*ctx->foundnode = node;
*ctx->foundtype = filetype;
return 1;
}
static grub_err_t
directory_find_file (grub_fshelp_node_t node, const char *name, grub_fshelp_node_t *foundnode,
enum grub_fshelp_filetype *foundtype, iterate_dir_func iterate_dir)
{
int found;
struct grub_fshelp_find_file_iter_ctx ctx = {
.foundnode = foundnode,
.foundtype = foundtype,
.name = name
};
found = iterate_dir (node, find_file_iter, &ctx);
if (! found)
{
if (grub_errno)
return grub_errno;
}
return GRUB_ERR_NONE;
}
static grub_err_t
find_file (char *currpath,
iterate_dir_func iterate_dir, lookup_file_func lookup_file,
read_symlink_func read_symlink,
struct grub_fshelp_find_file_ctx *ctx)
{
char *name, *next;
grub_err_t err;
for (name = currpath; ; name = next)
{
char c;
grub_fshelp_node_t foundnode = NULL;
enum grub_fshelp_filetype foundtype = 0;
/* Remove all leading slashes. */
while (*name == '/')
name++;
/* Found the node! */
if (! *name)
return 0;
/* Extract the actual part from the pathname. */
for (next = name; *next && *next != '/'; next++);
/* At this point it is expected that the current node is a
directory, check if this is true. */
if (ctx->currnode->type != GRUB_FSHELP_DIR)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
/* Don't rely on fs providing actual . in the listing. */
if (next - name == 1 && name[0] == '.')
continue;
/* Don't rely on fs providing actual .. in the listing. */
if (next - name == 2 && name[0] == '.' && name[1] == '.')
{
go_up_a_level (ctx);
continue;
}
/* Iterate over the directory. */
c = *next;
*next = '\0';
if (lookup_file)
err = lookup_file (ctx->currnode->node, name, &foundnode, &foundtype);
else
err = directory_find_file (ctx->currnode->node, name, &foundnode, &foundtype, iterate_dir);
*next = c;
if (err)
return err;
if (!foundnode)
break;
push_node (ctx, foundnode, foundtype);
/* Read in the symlink and follow it. */
if (ctx->currnode->type == GRUB_FSHELP_SYMLINK)
{
char *symlink;
/* Test if the symlink does not loop. */
if (++ctx->symlinknest == 8)
return grub_error (GRUB_ERR_SYMLINK_LOOP,
N_("too deep nesting of symlinks"));
symlink = read_symlink (ctx->currnode->node);
if (!symlink)
return grub_errno;
/* The symlink is an absolute path, go back to the root inode. */
if (symlink[0] == '/')
{
err = go_to_root (ctx);
if (err)
return err;
}
else
{
/* Get from symlink to containing directory. */
go_up_a_level (ctx);
}
/* Lookup the node the symlink points to. */
find_file (symlink, iterate_dir, lookup_file, read_symlink, ctx);
grub_free (symlink);
if (grub_errno)
return grub_errno;
}
}
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"),
ctx->path);
}
static grub_err_t
grub_fshelp_find_file_real (const char *path, grub_fshelp_node_t rootnode,
grub_fshelp_node_t *foundnode,
iterate_dir_func iterate_dir,
lookup_file_func lookup_file,
read_symlink_func read_symlink,
enum grub_fshelp_filetype expecttype)
{
struct grub_fshelp_find_file_ctx ctx = {
.path = path,
.rootnode = rootnode,
.symlinknest = 0,
.currnode = 0
};
grub_err_t err;
enum grub_fshelp_filetype foundtype;
char *duppath;
if (!path || path[0] != '/')
{
return grub_error (GRUB_ERR_BAD_FILENAME, N_("invalid file name `%s'"), path);
}
err = go_to_root (&ctx);
if (err)
return err;
duppath = grub_strdup (path);
if (!duppath)
return grub_errno;
err = find_file (duppath, iterate_dir, lookup_file, read_symlink, &ctx);
grub_free (duppath);
if (err)
{
free_stack (&ctx);
return err;
}
*foundnode = ctx.currnode->node;
foundtype = ctx.currnode->type;
/* Avoid the node being freed. */
ctx.currnode->node = 0;
free_stack (&ctx);
/* Check if the node that was found was of the expected type. */
if (expecttype == GRUB_FSHELP_REG && foundtype != expecttype)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
else if (expecttype == GRUB_FSHELP_DIR && foundtype != expecttype)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
return 0;
}
/* Lookup the node PATH. The node ROOTNODE describes the root of the
directory tree. The node found is returned in FOUNDNODE, which is
either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to
iterate over all directory entries in the current node.
READ_SYMLINK is used to read the symlink if a node is a symlink.
EXPECTTYPE is the type node that is expected by the called, an
error is generated if the node is not of the expected type. */
grub_err_t
grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
grub_fshelp_node_t *foundnode,
iterate_dir_func iterate_dir,
read_symlink_func read_symlink,
enum grub_fshelp_filetype expecttype)
{
return grub_fshelp_find_file_real (path, rootnode, foundnode,
iterate_dir, NULL,
read_symlink, expecttype);
}
grub_err_t
grub_fshelp_find_file_lookup (const char *path, grub_fshelp_node_t rootnode,
grub_fshelp_node_t *foundnode,
lookup_file_func lookup_file,
read_symlink_func read_symlink,
enum grub_fshelp_filetype expecttype)
{
return grub_fshelp_find_file_real (path, rootnode, foundnode,
NULL, lookup_file,
read_symlink, expecttype);
}
/* Read LEN bytes from the file NODE on disk DISK into the buffer BUF,
beginning with the block POS. READ_HOOK should be set before
reading a block from the file. READ_HOOK_DATA is passed through as
the DATA argument to READ_HOOK. GET_BLOCK is used to translate
file blocks to disk blocks. The file is FILESIZE bytes big and the
blocks have a size of LOG2BLOCKSIZE (in log2). */
grub_ssize_t
grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node,
grub_disk_read_hook_t read_hook, void *read_hook_data,
grub_off_t pos, grub_size_t len, char *buf,
grub_disk_addr_t (*get_block) (grub_fshelp_node_t node,
grub_disk_addr_t block),
grub_off_t filesize, int log2blocksize,
grub_disk_addr_t blocks_start)
{
grub_disk_addr_t i, blockcnt;
int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS);
if (pos > filesize)
{
grub_error (GRUB_ERR_OUT_OF_RANGE,
N_("attempt to read past the end of file"));
return -1;
}
/* Adjust LEN so it we can't read past the end of the file. */
if (pos + len > filesize)
len = filesize - pos;
blockcnt = ((len + pos) + blocksize - 1) >> (log2blocksize + GRUB_DISK_SECTOR_BITS);
for (i = pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS); i < blockcnt; i++)
{
grub_disk_addr_t blknr;
int blockoff = pos & (blocksize - 1);
int blockend = blocksize;
int skipfirst = 0;
blknr = get_block (node, i);
if (grub_errno)
return -1;
blknr = blknr << log2blocksize;
/* Last block. */
if (i == blockcnt - 1)
{
blockend = (len + pos) & (blocksize - 1);
/* The last portion is exactly blocksize. */
if (! blockend)
blockend = blocksize;
}
/* First block. */
if (i == (pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS)))
{
skipfirst = blockoff;
blockend -= skipfirst;
}
/* If the block number is 0 this block is not stored on disk but
is zero filled instead. */
if (blknr)
{
disk->read_hook = read_hook;
disk->read_hook_data = read_hook_data;
grub_disk_read (disk, blknr + blocks_start, skipfirst,
blockend, buf);
disk->read_hook = 0;
if (grub_errno)
return -1;
}
else if (read_hook != (grub_disk_read_hook_t)grub_disk_blocklist_read)
grub_memset (buf, 0, blockend);
buf += blocksize - skipfirst;
}
return len;
}

View File

@@ -970,8 +970,6 @@ grub_xfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
info.mtime = grub_be_to_cpu32 (node->inode.mtime.sec);
}
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
if (!info.dir)
info.size = node->inode.size;
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/command.h>
#include <grub/video.h>
#include <grub/gfxterm.h>
#include <grub/bitmap.h>
#include <grub/bitmap_scale.h>
#include <grub/term.h>
#include <grub/env.h>
#include <grub/normal.h>
#include <grub/gfxwidgets.h>
#include <grub/menu.h>
#include <grub/menu_viewer.h>
#include <grub/gfxmenu_model.h>
#include <grub/gfxmenu_view.h>
#include <grub/time.h>
#include <grub/env.h>
#include <grub/i18n.h>
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;
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/gui.h>
#include <grub/font.h>
#include <grub/gui_string_util.h>
#include <grub/i18n.h>
#include <grub/color.h>
#include <grub/env.h>
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;
}

View File

@@ -412,16 +412,23 @@ grub_disk_read_small (grub_disk_t disk, grub_disk_addr_t sector,
grub_err_t grub_disk_blocklist_read(void *chunklist, grub_uint64_t sector,
grub_uint64_t size, grub_uint32_t log_sector_size)
{
grub_uint64_t sizeshift;
ventoy_img_chunk *last_chunk = NULL;
ventoy_img_chunk *new_chunk = NULL;
ventoy_img_chunk_list *chunk_list = (ventoy_img_chunk_list *)chunklist;
sizeshift = (size >> log_sector_size);
if (sizeshift == 0)
{
sizeshift = 1;
}
if (chunk_list->cur_chunk == 0)
{
chunk_list->chunk[0].img_start_sector = 0;
chunk_list->chunk[0].img_end_sector = (size >> 11) - 1;
chunk_list->chunk[0].disk_start_sector = sector;
chunk_list->chunk[0].disk_end_sector = sector + (size >> log_sector_size) - 1;
chunk_list->chunk[0].disk_end_sector = sector + sizeshift - 1;
chunk_list->cur_chunk = 1;
return 0;
}
@@ -430,7 +437,7 @@ grub_err_t grub_disk_blocklist_read(void *chunklist, grub_uint64_t sector,
if (last_chunk->disk_end_sector + 1 == sector)
{
last_chunk->img_end_sector += (size >> 11);
last_chunk->disk_end_sector += (size >> log_sector_size);
last_chunk->disk_end_sector += sizeshift;
return 0;
}
@@ -452,7 +459,7 @@ grub_err_t grub_disk_blocklist_read(void *chunklist, grub_uint64_t sector,
new_chunk->img_start_sector = last_chunk->img_end_sector + 1;
new_chunk->img_end_sector = new_chunk->img_start_sector + (size >> 11) - 1;
new_chunk->disk_start_sector = sector;
new_chunk->disk_end_sector = sector + (size >> log_sector_size) - 1;
new_chunk->disk_end_sector = sector + sizeshift - 1;
chunk_list->cur_chunk++;

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#include <grub/env.h>
#include <grub/env_private.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/command.h>
#include <grub/normal.h>
#include <grub/i18n.h>
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);
}

View File

@@ -39,6 +39,8 @@ int g_ventoy_memdisk_mode = 0;
int g_ventoy_iso_raw = 0;
int g_ventoy_iso_uefi_drv = 0;
int g_ventoy_last_entry = 0;
int g_ventoy_suppress_esc = 0;
int g_ventoy_menu_esc = 0;
/* Time to delay after displaying an error message about a default/fallback
entry failing to boot. */
@@ -590,8 +592,10 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
enum timeout_style timeout_style;
default_entry = get_entry_number (menu, "default");
if (g_ventoy_last_entry >= 0 && g_ventoy_last_entry < menu->size) {
if (g_ventoy_suppress_esc)
default_entry = 1;
else if (g_ventoy_last_entry >= 0 && g_ventoy_last_entry < menu->size) {
default_entry = g_ventoy_last_entry;
}
/* If DEFAULT_ENTRY is not within the menu entries, fall back to
@@ -771,12 +775,12 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
case '\r':
// case GRUB_TERM_KEY_RIGHT:
case GRUB_TERM_CTRL | 'f':
menu_fini ();
menu_fini ();
*auto_boot = 0;
return current_entry;
return current_entry;
case GRUB_TERM_ESC:
if (nested)
if (nested && 0 == g_ventoy_suppress_esc)
{
menu_fini ();
return -1;
@@ -950,11 +954,16 @@ show_menu (grub_menu_t menu, int nested, int autobooted)
break;
g_ventoy_last_entry = boot_entry;
if (g_ventoy_menu_esc)
break;
e = grub_menu_get_entry (menu, boot_entry);
if (! e)
continue; /* Menu is empty. */
if (2 == e->argc && e->args && e->args[1] && grub_strncmp(e->args[1], "VTOY_RET", 8) == 0)
break;
grub_cls ();
if (auto_boot)

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#include <grub/normal.h>
#include <grub/term.h>
#include <grub/misc.h>
#include <grub/loader.h>
#include <grub/mm.h>
#include <grub/time.h>
#include <grub/env.h>
#include <grub/menu_viewer.h>
#include <grub/i18n.h>
#include <grub/charset.h>
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;
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#include <grub/normal.h>
#include <grub/disk.h>
#include <grub/fs.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/datetime.h>
#include <grub/term.h>
#include <grub/i18n.h>
#include <grub/partition.h>
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;
}

View File

@@ -33,6 +33,7 @@
#include <grub/datetime.h>
#include <grub/i18n.h>
#include <grub/net.h>
#include <grub/misc.h>
#ifdef GRUB_MACHINE_EFI
#include <grub/efi/efi.h>
#endif
@@ -49,12 +50,15 @@ 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_default_menu_mode = 0;
int g_filt_dot_underscore_file = 0;
static grub_file_t g_old_file;
char g_iso_path[256];
char g_img_swap_tmp_buf[1024];
img_info g_img_swap_tmp;
img_info *g_ventoy_img_list = NULL;
int g_ventoy_img_count = 0;
grub_device_t g_enum_dev = NULL;
@@ -75,6 +79,10 @@ ventoy_guid g_ventoy_guid = VENTOY_GUID;
ventoy_img_chunk_list g_img_chunk_list;
int g_wimboot_enable = 0;
ventoy_img_chunk_list g_wimiso_chunk_list;
char *g_wimiso_path = NULL;
static char *g_tree_script_buf = NULL;
static int g_tree_script_pos = 0;
@@ -127,6 +135,10 @@ static int ventoy_get_fs_type(const char *fs)
{
return ventoy_fs_udf;
}
else if (grub_strncmp(fs, "fat", 3) == 0)
{
return ventoy_fs_fat;
}
return ventoy_fs_max;
}
@@ -337,6 +349,44 @@ static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, cha
return rc;
}
static grub_err_t ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt, int argc, char **args)
{
grub_file_t file;
(void)ctxt;
(void)argc;
(void)args;
g_wimboot_enable = 0;
grub_check_free(g_wimiso_path);
grub_check_free(g_wimiso_chunk_list.chunk);
file = grub_file_open(args[0], VENTOY_FILE_TYPE);
if (!file)
{
return 0;
}
grub_memset(&g_wimiso_chunk_list, 0, sizeof(g_wimiso_chunk_list));
g_wimiso_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
if (NULL == g_wimiso_chunk_list.chunk)
{
return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
}
g_wimiso_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
g_wimiso_chunk_list.cur_chunk = 0;
ventoy_get_block_list(file, &g_wimiso_chunk_list, file->device->disk->partition->start);
g_wimboot_enable = 1;
g_wimiso_path = grub_strdup(args[0]);
grub_file_close(file);
return 0;
}
static grub_err_t ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
{
int rc = 1;
@@ -618,6 +668,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')
@@ -650,6 +705,8 @@ static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirh
static int ventoy_colect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
{
int i = 0;
int type = 0;
int ignore = 0;
grub_size_t len;
img_info *img;
@@ -714,52 +771,89 @@ static int ventoy_colect_img_files(const char *filename, const struct grub_dirho
else
{
debug("Find a file %s\n", filename);
if ((len > 4) && (0 == grub_strcasecmp(filename + len - 4, ".iso")))
if (len <= 4)
{
if (!ventoy_img_name_valid(filename, len))
return 0;
}
if (0 == grub_strcasecmp(filename + len - 4, ".iso"))
{
type = img_type_iso;
}
else if (g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim")))
{
type = img_type_wim;
}
else
{
return 0;
}
if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
{
return 0;
}
img = grub_zalloc(sizeof(img_info));
if (img)
{
img->type = type;
grub_snprintf(img->name, sizeof(img->name), "%s", filename);
for (i = 0; i < (int)len; i++)
{
if (filename[i] == ' ' || filename[i] == '\t' || (0 == grub_isprint(filename[i])))
{
img->name[i] = '*';
img->unsupport = 1;
}
}
grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
img->size = info->size;
if (0 == img->size)
{
img->size = ventoy_grub_get_file_size("%s/%s", g_iso_path, img->path);
}
if (img->size < VTOY_FILT_MIN_FILE_SIZE)
{
debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
grub_free(img);
return 0;
}
img = grub_zalloc(sizeof(img_info));
if (img)
if (g_ventoy_img_list)
{
grub_snprintf(img->name, sizeof(img->name), "%s", filename);
grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, filename);
if (g_ventoy_img_list)
{
tail = *(node->tail);
img->prev = tail;
tail->next = img;
}
else
{
g_ventoy_img_list = img;
}
img->size = info->size;
img->id = g_ventoy_img_count;
img->parent = node;
if (node && NULL == node->firstiso)
{
node->firstiso = img;
}
node->isocnt++;
tmp = node->parent;
while (tmp)
{
tmp->isocnt++;
tmp = tmp->parent;
}
*((img_info **)(node->tail)) = img;
g_ventoy_img_count++;
debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
tail = *(node->tail);
img->prev = tail;
tail->next = img;
}
else
{
g_ventoy_img_list = img;
}
img->id = g_ventoy_img_count;
img->parent = node;
if (node && NULL == node->firstiso)
{
node->firstiso = img;
}
node->isocnt++;
tmp = node->parent;
while (tmp)
{
tmp->isocnt++;
tmp = tmp->parent;
}
*((img_info **)(node->tail)) = img;
g_ventoy_img_count++;
debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
}
}
@@ -902,11 +996,27 @@ static int ventoy_dynamic_tree_menu(img_iterator_node *node)
offset = node->parent->dirlen;
}
if (node != &g_img_iterator_head)
if (node == &g_img_iterator_head)
{
if (g_default_menu_mode == 0)
{
vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
"menuentry \"%-10s [Return to ListView]\" VTOY_RET {\n "
" echo 'return ...' \n"
"}\n", "<--");
}
}
else
{
node->dir[node->dirlen - 1] = 0;
g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos,
"submenu \"%-10s [%s]\" {\n", "DIR", node->dir + offset);
vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
"submenu \"%-10s [%s]\" {\n",
"DIR", node->dir + offset);
vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
"menuentry \"%-10s [../]\" VTOY_RET {\n "
" echo 'return ...' \n"
"}\n", "<--");
}
while ((child = ventoy_get_min_child(node)) != NULL)
@@ -916,16 +1026,19 @@ static int ventoy_dynamic_tree_menu(img_iterator_node *node)
while ((img = ventoy_get_min_iso(node)) != NULL)
{
g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos,
"menuentry \"%-10s %s\" --id=\"VID_%d\" {\n"
" common_menuentry \n"
"}\n",
grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT), img->name, img->id);
vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos,
"menuentry \"%-10s %s%s\" --id=\"VID_%d\" {\n"
" %s_%s \n"
"}\n",
grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT),
img->unsupport ? "[unsupported] " : "", img->name, img->id,
(img->type == img_type_iso) ? "iso" : "wim",
img->unsupport ? "unsupport_menuentry" : "common_menuentry");
}
if (node != &g_img_iterator_head)
{
g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos, "}\n");
vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
}
node->done = 1;
@@ -934,10 +1047,12 @@ static int ventoy_dynamic_tree_menu(img_iterator_node *node)
static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
{
int len;
grub_fs_t fs;
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 +1070,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)
{
@@ -976,14 +1097,37 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char
if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
{
debug("unsupported fs:<%s>\n", fs->name);
ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
goto fail;
}
strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
if (strdata && strdata[0] == '1')
{
g_default_menu_mode = 1;
}
grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
g_img_iterator_head.dirlen = 1;
grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
if (strdata && strdata[0] == '/')
{
len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
if (g_img_iterator_head.dir[len] != '/')
{
g_img_iterator_head.dir[len++] = '/';
}
g_img_iterator_head.dirlen = len;
}
else
{
g_img_iterator_head.dirlen = 1;
grub_strcpy(g_img_iterator_head.dir, "/");
}
g_img_iterator_head.tail = &tail;
grub_strcpy(g_img_iterator_head.dir, "/");
for (node = &g_img_iterator_head; node; node = node->next)
{
@@ -1016,13 +1160,23 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char
}
}
if (g_default_menu_mode == 1)
{
vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
"menuentry \"%s [Return to TreeView]\" VTOY_RET {\n "
" echo 'return ...' \n"
"}\n", "<--");
}
for (cur = g_ventoy_img_list; cur; cur = cur->next)
{
g_list_script_pos += grub_snprintf(g_list_script_buf + g_list_script_pos, VTOY_MAX_SCRIPT_BUF - g_list_script_pos,
"menuentry \"%s\" --id=\"VID_%d\" {\n"
" common_menuentry \n"
vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
"menuentry \"%s%s\" --id=\"VID_%d\" {\n"
" %s_%s \n"
"}\n",
cur->name, cur->id);
cur->unsupport ? "[unsupported] " : "", cur->name, cur->id,
(cur->type == img_type_iso) ? "iso" : "wim",
cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
}
g_list_script_buf[g_list_script_pos] = 0;
@@ -1276,7 +1430,35 @@ void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
return;
}
static int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
{
grub_uint32_t i = 0;
grub_uint64_t total = 0;
ventoy_img_chunk *chunk = NULL;
for (i = 0; i < chunklist->cur_chunk; i++)
{
chunk = chunklist->chunk + i;
if (chunk->disk_start_sector <= start)
{
debug("%u disk start invalid %lu\n", i, (ulong)start);
return 1;
}
total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
}
if (total != ((file->size + 511) / 512))
{
debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
return 1;
}
return 0;
}
int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
{
int fs_type;
grub_uint32_t i = 0;
@@ -1290,6 +1472,10 @@ static int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunkl
{
grub_fat_get_file_chunk(start, file, chunklist);
}
else if (fs_type == ventoy_fs_ext)
{
grub_ext_get_file_chunk(start, file, chunklist);
}
else
{
file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
@@ -1324,7 +1510,9 @@ static int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunkl
static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
{
int rc;
grub_file_t file;
grub_disk_addr_t start;
(void)ctxt;
(void)argc;
@@ -1351,11 +1539,129 @@ static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, ch
g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
g_img_chunk_list.cur_chunk = 0;
ventoy_get_block_list(file, &g_img_chunk_list, file->device->disk->partition->start);
start = file->device->disk->partition->start;
ventoy_get_block_list(file, &g_img_chunk_list, start);
rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
grub_file_close(file);
if (rc)
{
return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
}
grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
{
int i = 0;
int pos = 0;
char *buf = NULL;
char configfile[128];
install_template *node = NULL;
(void)ctxt;
(void)argc;
(void)args;
if (argc < 1)
{
return 0;
}
node = ventoy_plugin_find_install_template(args[0]);
if (!node)
{
return 0;
}
buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
if (!buf)
{
return 0;
}
vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
" echo %s\n}\n", "123");
for (i = 0; i < node->templatenum; i++)
{
vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
" echo 123\n}\n",
node->templatepath[i].path);
}
g_ventoy_menu_esc = 1;
g_ventoy_suppress_esc = 1;
grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
grub_script_execute_sourcecode(configfile);
g_ventoy_menu_esc = 0;
g_ventoy_suppress_esc = 0;
grub_free(buf);
node->cursel = g_ventoy_last_entry - 1;
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
{
int i = 0;
int pos = 0;
char *buf = NULL;
char configfile[128];
persistence_config *node;
(void)ctxt;
(void)argc;
(void)args;
if (argc < 1)
{
return 0;
}
node = ventoy_plugin_find_persistent(args[0]);
if (!node)
{
return 0;
}
buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
if (!buf)
{
return 0;
}
vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
" echo %s\n}\n", "123");
for (i = 0; i < node->backendnum; i++)
{
vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
" echo 123\n}\n",
node->backendpath[i].path);
}
g_ventoy_menu_esc = 1;
g_ventoy_suppress_esc = 1;
grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
grub_script_execute_sourcecode(configfile);
g_ventoy_menu_esc = 0;
g_ventoy_suppress_esc = 0;
grub_free(buf);
node->cursel = g_ventoy_last_entry - 1;
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
@@ -1469,8 +1775,11 @@ static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int arg
chunklist.cur_chunk = 0;
ventoy_get_block_list(file, &chunklist, 0);
grub_file_close(file);
if (0 != ventoy_check_block_list(file, &chunklist, 0))
{
grub_printf("########## UNSUPPORTED ###############\n");
}
grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
@@ -1481,6 +1790,7 @@ static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int arg
}
grub_printf("\n==================================\n");
for (i = 0; i < chunklist.cur_chunk; i++)
{
grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
@@ -1492,6 +1802,7 @@ static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int arg
}
grub_free(chunklist.chunk);
grub_file_close(file);
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
@@ -1554,6 +1865,17 @@ static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int a
return 0;
}
static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
{
(void)ctxt;
(void)argc;
(void)args;
ventoy_plugin_dump_persistence();
return 0;
}
static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
{
(void)ctxt;
@@ -1710,6 +2032,30 @@ static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int a
return 0;
}
grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
{
grub_uint64_t size = 0;
grub_file_t file;
va_list ap;
char fullpath[256] = {0};
va_start (ap, fmt);
grub_vsnprintf(fullpath, 255, fmt, ap);
va_end (ap);
file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
if (!file)
{
debug("grub_file_open failed <%s>\n", fullpath);
grub_errno = 0;
return 0;
}
size = file->size;
grub_file_close(file);
return size;
}
grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
{
va_list ap;
@@ -1794,12 +2140,16 @@ static cmd_para ventoy_cmds[] =
{ "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
{ "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
{ "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
{ "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
{ "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
{ "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
{ "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
{ "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
{ "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
{ "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
{ "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
{ "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
{ "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
{ "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
{ "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
@@ -1818,6 +2168,7 @@ static cmd_para ventoy_cmds[] =
{ "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
{ "vt_windows_locate_wim", ventoy_cmd_wimdows_locate_wim, 0, NULL, "", "", NULL },
{ "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
{ "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
{ "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
{ "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata, 0, NULL, "", "", NULL },

View File

@@ -23,7 +23,10 @@
#define VTOY_MAX_SCRIPT_BUF (4 * 1024 * 1024)
#define VTOY_SIZE_1GB 1073741824
#define VTOY_FILT_MIN_FILE_SIZE 32768
#define VTOY_SIZE_1GB 1073741824
#define VTOY_SIZE_512KB (512 * 1024)
#define JSON_SUCCESS 0
#define JSON_FAILED 1
@@ -62,6 +65,7 @@ typedef struct cmd_para
grub_extcmd_t cmd;
}cmd_para;
#define ventoy_align_2k(value) ((value + 2047) / 2048 * 2048)
#define ventoy_align(value, align) (((value) + ((align) - 1)) & (~((align) - 1)))
#pragma pack(1)
@@ -87,6 +91,7 @@ typedef struct cpio_newc_header
#define cmd_raw_name ctxt->extcmd->cmd->name
#define check_free(p, func) if (p) { func(p); p = NULL; }
#define grub_check_free(p) if (p) { grub_free(p); p = NULL; }
typedef int (*grub_char_check_func)(int c);
#define ventoy_is_decimal(str) ventoy_string_check(str, grub_isdigit)
@@ -120,13 +125,18 @@ typedef struct ventoy_udf_override
#pragma pack()
#define img_type_iso 0
#define img_type_wim 1
typedef struct img_info
{
char path[512];
char name[256];
int id;
int type;
grub_uint64_t size;
int select;
int unsupport;
void *parent;
@@ -186,12 +196,15 @@ extern grub_uint8_t *g_ventoy_runtime_buf;
extern ventoy_guid g_ventoy_guid;
extern ventoy_img_chunk_list g_img_chunk_list;
extern ventoy_img_chunk_list g_wimiso_chunk_list;
extern char *g_wimiso_path;
extern int g_ventoy_debug;
void ventoy_debug(const char *fmt, ...);
#define debug(fmt, ...) if (g_ventoy_debug) ventoy_debug("[VTOY]: "fmt, __VA_ARGS__)
#define vtoy_ssprintf(buf, pos, fmt, ...) \
pos += grub_snprintf(buf + pos, VTOY_MAX_SCRIPT_BUF - pos, fmt, __VA_ARGS__)
#define FLAG_HEADER_RESERVED 0x00000001
#define FLAG_HEADER_COMPRESSION 0x00000002
@@ -422,12 +435,14 @@ grub_err_t ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt, int argc, c
grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args);
int ventoy_cpio_newc_fill_head(void *buf, int filesize, const void *filedata, const char *name);
grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...);
grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...);
int ventoy_is_file_exist(const char *fmt, ...);
int ventoy_fill_data(grub_uint32_t buflen, char *buffer);
grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **args);
grub_err_t ventoy_cmd_wimdows_reset(grub_extcmd_context_t ctxt, int argc, char **args);
grub_err_t ventoy_cmd_wimdows_locate_wim(grub_extcmd_context_t ctxt, int argc, char **args);
grub_err_t ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt, int argc, char **args);
grub_err_t ventoy_cmd_wim_chain_data(grub_extcmd_context_t ctxt, int argc, char **args);
VTOY_JSON *vtoy_json_find_item
(
@@ -552,15 +567,37 @@ typedef struct ventoy_mbr_head
}ventoy_mbr_head;
#pragma pack()
typedef struct file_fullpath
{
char path[256];
}file_fullpath;
typedef struct install_template
{
int pathlen;
char isopath[256];
char templatepath[256];
int cursel;
int templatenum;
file_fullpath *templatepath;
struct install_template *next;
}install_template;
typedef struct persistence_config
{
int pathlen;
char isopath[256];
int cursel;
int backendnum;
file_fullpath *backendpath;
struct persistence_config *next;
}persistence_config;
extern int g_ventoy_menu_esc;
extern int g_ventoy_suppress_esc;
extern int g_ventoy_last_entry;
extern int g_ventoy_memdisk_mode;
extern int g_ventoy_iso_raw;
@@ -568,10 +605,15 @@ extern int g_ventoy_iso_uefi_drv;
int ventoy_cmp_img(img_info *img1, img_info *img2);
void ventoy_swap_img(img_info *img1, img_info *img2);
char * ventoy_plugin_get_install_template(const char *isopath);
char * ventoy_plugin_get_cur_install_template(const char *isopath);
install_template * ventoy_plugin_find_install_template(const char *isopath);
persistence_config * ventoy_plugin_find_persistent(const char *isopath);
void ventoy_plugin_dump_auto_install(void);
int ventoy_fill_windows_rtdata(void *buf, char *isopath);
int ventoy_plugin_get_persistent_chunklist(const char *isopath, int index, ventoy_img_chunk_list *chunk_list);
int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start);
int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start);
void ventoy_plugin_dump_persistence(void);
#endif /* __VENTOY_DEF_H__ */

View File

@@ -686,6 +686,8 @@ static grub_uint32_t ventoy_linux_get_override_chunk_size(void)
static void ventoy_linux_fill_override_data( grub_uint64_t isosize, void *override)
{
initrd_info *node;
grub_uint32_t mod;
grub_uint32_t newlen;
grub_uint64_t sector;
ventoy_override_chunk *cur;
@@ -699,13 +701,20 @@ static void ventoy_linux_fill_override_data( grub_uint64_t isosize, void *ove
continue;
}
newlen = (grub_uint32_t)(node->size + g_ventoy_cpio_size);
mod = newlen % 4;
if (mod > 0)
{
newlen += 4 - mod;
}
if (node->iso_type == 0)
{
ventoy_iso9660_override *dirent = (ventoy_iso9660_override *)node->override_data;
node->override_length = sizeof(ventoy_iso9660_override);
dirent->first_sector = (grub_uint32_t)sector;
dirent->size = (grub_uint32_t)(node->size + g_ventoy_cpio_size);
dirent->size = newlen;
dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
dirent->size_be = grub_swap_bytes32(dirent->size);
@@ -716,7 +725,7 @@ static void ventoy_linux_fill_override_data( grub_uint64_t isosize, void *ove
ventoy_udf_override *udf = (ventoy_udf_override *)node->override_data;
node->override_length = sizeof(ventoy_udf_override);
udf->length = (grub_uint32_t)(node->size + g_ventoy_cpio_size);
udf->length = newlen;
udf->position = (grub_uint32_t)sector - node->udf_start_block;
sector += (udf->length + 2047) / 2048;
@@ -852,8 +861,10 @@ grub_err_t ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt, int argc,
grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args)
{
int rc;
char *template_file = NULL;
char *template_buf = NULL;
char *persistent_buf = NULL;
grub_uint8_t *buf = NULL;
grub_uint32_t mod;
grub_uint32_t headlen;
@@ -861,9 +872,11 @@ grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **arg
grub_uint32_t padlen;
grub_uint32_t img_chunk_size;
grub_uint32_t template_size = 0;
grub_uint32_t persistent_size = 0;
grub_file_t file;
grub_file_t scriptfile;
ventoy_img_chunk_list chunk_list;
(void)ctxt;
(void)argc;
@@ -892,7 +905,14 @@ grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **arg
g_ventoy_cpio_size = 0;
}
template_file = ventoy_plugin_get_install_template(args[1]);
rc = ventoy_plugin_get_persistent_chunklist(args[1], -1, &chunk_list);
if (rc == 0 && chunk_list.cur_chunk > 0 && chunk_list.chunk)
{
persistent_size = chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
persistent_buf = (char *)(chunk_list.chunk);
}
template_file = ventoy_plugin_get_cur_install_template(args[1]);
if (template_file)
{
debug("auto install template: <%s>\n", template_file);
@@ -914,8 +934,12 @@ grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **arg
debug("Failed to open install script %s%s\n", args[2], template_file);
}
}
else
{
debug("auto install script skipped or not configed %s\n", args[1]);
}
g_ventoy_cpio_buf = grub_malloc(file->size + 4096 + template_size + img_chunk_size);
g_ventoy_cpio_buf = grub_malloc(file->size + 4096 + template_size + persistent_size + img_chunk_size);
if (NULL == g_ventoy_cpio_buf)
{
grub_file_close(file);
@@ -943,6 +967,15 @@ grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **arg
buf += headlen + ventoy_align(template_size, 4);
}
if (persistent_size > 0 && persistent_buf)
{
headlen = ventoy_cpio_newc_fill_head(buf, persistent_size, persistent_buf, "ventoy/ventoy_persistent_map");
buf += headlen + ventoy_align(persistent_size, 4);
grub_free(persistent_buf);
persistent_buf = NULL;
}
/* step2: insert os param to cpio */
headlen = ventoy_cpio_newc_fill_head(buf, 0, NULL, "ventoy/ventoy_os_param");
padlen = sizeof(ventoy_os_param);

View File

@@ -0,0 +1,568 @@
/******************************************************************************
* ventoy_plugin.c
*
* Copyright (c) 2020, longpanda <admin@ventoy.net>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/disk.h>
#include <grub/device.h>
#include <grub/term.h>
#include <grub/partition.h>
#include <grub/file.h>
#include <grub/normal.h>
#include <grub/extcmd.h>
#include <grub/datetime.h>
#include <grub/i18n.h>
#include <grub/net.h>
#include <grub/time.h>
#include <grub/ventoy.h>
#include "ventoy_def.h"
GRUB_MOD_LICENSE ("GPLv3+");
static char g_iso_disk_name[128];
static install_template *g_install_template_head = NULL;
static persistence_config *g_persistence_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;
char filepath[256];
value = vtoy_json_get_string_ex(json->pstChild, "file");
if (value)
{
if (value[0] == '/')
{
grub_snprintf(filepath, sizeof(filepath), "%s%s", isodisk, value);
}
else
{
grub_snprintf(filepath, sizeof(filepath), "%s/ventoy/%s", isodisk, value);
}
if (ventoy_is_file_exist(filepath) == 0)
{
debug("Theme file %s does not exist\n", filepath);
return 0;
}
debug("vtoy_theme %s\n", filepath);
grub_env_set("vtoy_theme", filepath);
}
value = vtoy_json_get_string_ex(json->pstChild, "gfxmode");
if (value)
{
debug("vtoy_gfxmode %s\n", value);
grub_env_set("vtoy_gfxmode", value);
}
value = vtoy_json_get_string_ex(json->pstChild, "ventoy_left");
if (value)
{
grub_env_set("VTLE_LFT", value);
}
value = vtoy_json_get_string_ex(json->pstChild, "ventoy_top");
if (value)
{
grub_env_set("VTLE_TOP", value);
}
value = vtoy_json_get_string_ex(json->pstChild, "ventoy_color");
if (value)
{
grub_env_set("VTLE_CLR", value);
}
return 0;
}
static int ventoy_plugin_parse_fullpath
(
VTOY_JSON *json,
const char *isodisk,
const char *key,
file_fullpath **fullpath,
int *pathnum
)
{
int rc = 1;
int count = 0;
VTOY_JSON *node = json;
VTOY_JSON *child = NULL;
file_fullpath *path = NULL;
while (node)
{
if (0 == grub_strcmp(key, node->pcName))
{
break;
}
node = node->pstNext;
}
if (!node)
{
return 1;
}
if (JSON_TYPE_STRING == node->enDataType)
{
debug("%s is string type data\n", node->pcName);
if ((node->unData.pcStrVal[0] != '/') || (!ventoy_is_file_exist("%s%s", isodisk, node->unData.pcStrVal)))
{
debug("%s%s file not found\n", isodisk, node->unData.pcStrVal);
return 1;
}
path = (file_fullpath *)grub_zalloc(sizeof(file_fullpath));
if (path)
{
grub_snprintf(path->path, sizeof(path->path), "%s", node->unData.pcStrVal);
*fullpath = path;
*pathnum = 1;
rc = 0;
}
}
else if (JSON_TYPE_ARRAY == node->enDataType)
{
for (child = node->pstChild; child; child = child->pstNext)
{
if ((JSON_TYPE_STRING != child->enDataType) || (child->unData.pcStrVal[0] != '/'))
{
debug("Invalid data type:%d\n", child->enDataType);
return 1;
}
count++;
}
debug("%s is array type data, count=%d\n", node->pcName, count);
path = (file_fullpath *)grub_zalloc(sizeof(file_fullpath) * count);
if (path)
{
*fullpath = path;
for (count = 0, child = node->pstChild; child; child = child->pstNext)
{
if (ventoy_is_file_exist("%s%s", isodisk, child->unData.pcStrVal))
{
grub_snprintf(path->path, sizeof(path->path), "%s", child->unData.pcStrVal);
path++;
count++;
}
}
*pathnum = count;
rc = 0;
}
}
return rc;
}
static int ventoy_plugin_auto_install_entry(VTOY_JSON *json, const char *isodisk)
{
int pathnum = 0;
const char *iso = NULL;
VTOY_JSON *pNode = NULL;
install_template *node = NULL;
install_template *next = NULL;
file_fullpath *templatepath = NULL;
if (json->enDataType != JSON_TYPE_ARRAY)
{
debug("Not array %d\n", json->enDataType);
return 0;
}
if (g_install_template_head)
{
for (node = g_install_template_head; node; node = next)
{
next = node->next;
grub_check_free(node->templatepath);
grub_free(node);
}
g_install_template_head = NULL;
}
for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
{
iso = vtoy_json_get_string_ex(pNode->pstChild, "image");
if (iso && iso[0] == '/')
{
if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "template", &templatepath, &pathnum))
{
node = grub_zalloc(sizeof(install_template));
if (node)
{
node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso);
node->templatepath = templatepath;
node->templatenum = pathnum;
if (g_install_template_head)
{
node->next = g_install_template_head;
}
g_install_template_head = node;
}
}
}
}
return 0;
}
static int ventoy_plugin_persistence_entry(VTOY_JSON *json, const char *isodisk)
{
int pathnum = 0;
const char *iso = NULL;
VTOY_JSON *pNode = NULL;
persistence_config *node = NULL;
persistence_config *next = NULL;
file_fullpath *backendpath = NULL;
(void)isodisk;
if (json->enDataType != JSON_TYPE_ARRAY)
{
debug("Not array %d\n", json->enDataType);
return 0;
}
if (g_persistence_head)
{
for (node = g_persistence_head; node; node = next)
{
next = node->next;
grub_check_free(node->backendpath);
grub_free(node);
}
g_persistence_head = NULL;
}
for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
{
iso = vtoy_json_get_string_ex(pNode->pstChild, "image");
if (iso && iso[0] == '/')
{
if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "backend", &backendpath, &pathnum))
{
node = grub_zalloc(sizeof(persistence_config));
if (node)
{
node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso);
node->backendpath = backendpath;
node->backendnum = pathnum;
if (g_persistence_head)
{
node->next = g_persistence_head;
}
g_persistence_head = node;
}
}
}
}
return 0;
}
static plugin_entry g_plugin_entries[] =
{
{ "control", ventoy_plugin_control_entry },
{ "theme", ventoy_plugin_theme_entry },
{ "auto_install", ventoy_plugin_auto_install_entry },
{ "persistence", ventoy_plugin_persistence_entry },
};
static int ventoy_parse_plugin_config(VTOY_JSON *json, const char *isodisk)
{
int i;
VTOY_JSON *cur = json;
grub_snprintf(g_iso_disk_name, sizeof(g_iso_disk_name), "%s", isodisk);
while (cur)
{
for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++)
{
if (grub_strcmp(g_plugin_entries[i].key, cur->pcName) == 0)
{
debug("Plugin entry for %s\n", g_plugin_entries[i].key);
g_plugin_entries[i].entryfunc(cur, isodisk);
break;
}
}
cur = cur->pstNext;
}
return 0;
}
grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **args)
{
int ret = 0;
char *buf = NULL;
grub_file_t file;
VTOY_JSON *json = NULL;
(void)ctxt;
(void)argc;
file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/ventoy/ventoy.json", args[0]);
if (!file)
{
return GRUB_ERR_NONE;
}
debug("json configuration file size %d\n", (int)file->size);
buf = grub_malloc(file->size + 1);
if (!buf)
{
grub_file_close(file);
return 1;
}
buf[file->size] = 0;
grub_file_read(file, buf, file->size);
grub_file_close(file);
json = vtoy_json_create();
if (!json)
{
return 1;
}
ret = vtoy_json_parse(json, buf);
if (ret)
{
debug("Failed to parse json string %d\n", ret);
grub_free(buf);
return 1;
}
ventoy_parse_plugin_config(json->pstChild, args[0]);
vtoy_json_destroy(json);
grub_free(buf);
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
void ventoy_plugin_dump_auto_install(void)
{
int i;
install_template *node = NULL;
for (node = g_install_template_head; node; node = node->next)
{
grub_printf("\nIMAGE:<%s>\n", node->isopath);
for (i = 0; i < node->templatenum; i++)
{
grub_printf("SCRIPT %d:<%s>\n", i, node->templatepath[i].path);
}
}
return;
}
void ventoy_plugin_dump_persistence(void)
{
int rc;
int i = 0;
persistence_config *node = NULL;
ventoy_img_chunk_list chunk_list;
for (node = g_persistence_head; node; node = node->next)
{
grub_printf("\nIMAGE:<%s>\n", node->isopath);
for (i = 0; i < node->backendnum; i++)
{
grub_printf("PERSIST %d:<%s>", i, node->backendpath[i].path);
rc = ventoy_plugin_get_persistent_chunklist(node->isopath, i, &chunk_list);
if (rc == 0)
{
grub_printf(" [ SUCCESS ]\n");
grub_free(chunk_list.chunk);
}
else
{
grub_printf(" [ FAILED ]\n");
}
}
}
return;
}
install_template * ventoy_plugin_find_install_template(const char *isopath)
{
install_template *node = NULL;
int len = (int)grub_strlen(isopath);
for (node = g_install_template_head; node; node = node->next)
{
if (node->pathlen == len && grub_strcmp(node->isopath, isopath) == 0)
{
return node;
}
}
return NULL;
}
char * ventoy_plugin_get_cur_install_template(const char *isopath)
{
install_template *node = NULL;
node = ventoy_plugin_find_install_template(isopath);
if ((!node) || (!node->templatepath))
{
return NULL;
}
if (node->cursel < 0 || node->cursel >= node->templatenum)
{
return NULL;
}
return node->templatepath[node->cursel].path;
}
persistence_config * ventoy_plugin_find_persistent(const char *isopath)
{
persistence_config *node = NULL;
int len = (int)grub_strlen(isopath);
for (node = g_persistence_head; node; node = node->next)
{
if ((len == node->pathlen) && (grub_strcmp(node->isopath, isopath) == 0))
{
return node;
}
}
return NULL;
}
int ventoy_plugin_get_persistent_chunklist(const char *isopath, int index, ventoy_img_chunk_list *chunk_list)
{
int rc = 1;
grub_uint64_t start = 0;
grub_file_t file = NULL;
persistence_config *node = NULL;
node = ventoy_plugin_find_persistent(isopath);
if ((!node) || (!node->backendpath))
{
return 1;
}
if (index < 0)
{
index = node->cursel;
}
if (index < 0 || index >= node->backendnum)
{
return 1;
}
file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", g_iso_disk_name, node->backendpath[index].path);
if (!file)
{
debug("Failed to open file %s%s\n", g_iso_disk_name, node->backendpath[index].path);
goto end;
}
grub_memset(chunk_list, 0, sizeof(ventoy_img_chunk_list));
chunk_list->chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
if (NULL == chunk_list->chunk)
{
goto end;
}
chunk_list->max_chunk = DEFAULT_CHUNK_NUM;
chunk_list->cur_chunk = 0;
start = file->device->disk->partition->start;
ventoy_get_block_list(file, chunk_list, start);
if (0 != ventoy_check_block_list(file, chunk_list, start))
{
grub_free(chunk_list->chunk);
chunk_list->chunk = NULL;
goto end;
}
rc = 0;
end:
if (file)
grub_file_close(file);
return rc;
}

View File

@@ -470,7 +470,7 @@ int ventoy_fill_windows_rtdata(void *buf, char *isopath)
return 1;
}
script = ventoy_plugin_get_install_template(pos);
script = ventoy_plugin_get_cur_install_template(pos);
if (script)
{
debug("auto install script <%s>\n", script);
@@ -478,7 +478,7 @@ int ventoy_fill_windows_rtdata(void *buf, char *isopath)
}
else
{
debug("auto install script not found %p\n", pos);
debug("auto install script skipped or not configed %s\n", pos);
}
return 0;
@@ -957,3 +957,214 @@ grub_err_t ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt, int argc, c
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
static grub_uint32_t ventoy_get_wim_iso_offset(const char *filepath)
{
grub_uint32_t imgoffset;
grub_file_t file;
char cmdbuf[128];
grub_snprintf(cmdbuf, sizeof(cmdbuf), "loopback wimiso %s", filepath);
grub_script_execute_sourcecode(cmdbuf);
file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(wimiso)/boot/boot.wim");
if (!file)
{
grub_printf("Failed to open boot.wim file in the image file\n");
return 0;
}
imgoffset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file) + 2;
debug("wimiso wim direct offset: %u\n", imgoffset);
grub_file_close(file);
grub_script_execute_sourcecode("loopback -d wimiso");
return imgoffset;
}
static int ventoy_get_wim_chunklist(const char *filename, ventoy_img_chunk_list *wimchunk, grub_uint64_t *wimsize)
{
grub_file_t wimfile;
wimfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", filename);
if (!wimfile)
{
return 1;
}
grub_memset(wimchunk, 0, sizeof(ventoy_img_chunk_list));
wimchunk->chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
if (NULL == wimchunk->chunk)
{
grub_file_close(wimfile);
return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
}
wimchunk->max_chunk = DEFAULT_CHUNK_NUM;
wimchunk->cur_chunk = 0;
ventoy_get_block_list(wimfile, wimchunk, wimfile->device->disk->partition->start);
*wimsize = wimfile->size;
grub_file_close(wimfile);
return 0;
}
grub_err_t ventoy_cmd_wim_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
{
grub_uint32_t i = 0;
grub_uint32_t imgoffset = 0;
grub_uint32_t size = 0;
grub_uint32_t isosector = 0;
grub_uint64_t wimsize = 0;
grub_uint32_t boot_catlog = 0;
grub_uint32_t img_chunk1_size = 0;
grub_uint32_t img_chunk2_size = 0;
grub_uint32_t override_size = 0;
grub_file_t file;
grub_disk_t disk;
const char *pLastChain = NULL;
ventoy_chain_head *chain;
ventoy_iso9660_override *dirent;
ventoy_img_chunk *chunknode;
ventoy_override_chunk *override;
ventoy_img_chunk_list wimchunk;
char envbuf[128];
(void)ctxt;
(void)argc;
debug("wim chain data begin <%s> ...\n", args[0]);
if (NULL == g_wimiso_chunk_list.chunk || NULL == g_wimiso_path)
{
grub_printf("ventoy not ready\n");
return 1;
}
imgoffset = ventoy_get_wim_iso_offset(g_wimiso_path);
if (imgoffset == 0)
{
grub_printf("image offset not found\n");
return 1;
}
if (0 != ventoy_get_wim_chunklist(args[0], &wimchunk, &wimsize))
{
grub_printf("Failed to get wim chunklist\n");
return 1;
}
file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", g_wimiso_path);
if (!file)
{
return 1;
}
boot_catlog = ventoy_get_iso_boot_catlog(file);
img_chunk1_size = g_wimiso_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
img_chunk2_size = wimchunk.cur_chunk * sizeof(ventoy_img_chunk);
override_size = sizeof(ventoy_override_chunk);
size = sizeof(ventoy_chain_head) + img_chunk1_size + img_chunk2_size + override_size;
pLastChain = grub_env_get("vtoy_chain_mem_addr");
if (pLastChain)
{
chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
if (chain)
{
debug("free last chain memory %p\n", chain);
grub_free(chain);
}
}
chain = grub_malloc(size);
if (!chain)
{
grub_printf("Failed to alloc chain memory size %u\n", size);
grub_file_close(file);
return 1;
}
grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
grub_env_set("vtoy_chain_mem_addr", envbuf);
grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
grub_env_set("vtoy_chain_mem_size", envbuf);
grub_memset(chain, 0, sizeof(ventoy_chain_head));
/* part 1: os parameter */
ventoy_fill_os_param(file, &(chain->os_param));
/* part 2: chain head */
disk = file->device->disk;
chain->disk_drive = disk->id;
chain->disk_sector_size = (1 << disk->log_sector_size);
chain->real_img_size_in_bytes = ventoy_align_2k(file->size) + ventoy_align_2k(wimsize);
chain->virt_img_size_in_bytes = chain->real_img_size_in_bytes;
chain->boot_catalog = boot_catlog;
if (!ventoy_is_efi_os())
{
grub_file_seek(file, boot_catlog * 2048);
grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
}
/* part 3: image chunk */
chain->img_chunk_offset = sizeof(ventoy_chain_head);
chain->img_chunk_num = g_wimiso_chunk_list.cur_chunk + wimchunk.cur_chunk;
grub_memcpy((char *)chain + chain->img_chunk_offset, g_wimiso_chunk_list.chunk, img_chunk1_size);
/* fs cluster size >= 2048, so don't need to proc align */
/* align by 2048 */
chunknode = wimchunk.chunk + wimchunk.cur_chunk - 1;
i = (chunknode->disk_end_sector + 1 - chunknode->disk_start_sector) % 4;
if (i)
{
chunknode->disk_end_sector += 4 - i;
}
isosector = (grub_uint32_t)((file->size + 2047) / 2048);
for (i = 0; i < wimchunk.cur_chunk; i++)
{
chunknode = wimchunk.chunk + i;
chunknode->img_start_sector = isosector;
chunknode->img_end_sector = chunknode->img_start_sector +
((chunknode->disk_end_sector + 1 - chunknode->disk_start_sector) / 4) - 1;
isosector = chunknode->img_end_sector + 1;
}
grub_memcpy((char *)chain + chain->img_chunk_offset + img_chunk1_size, wimchunk.chunk, img_chunk2_size);
/* part 4: override chunk */
chain->override_chunk_offset = chain->img_chunk_offset + img_chunk1_size + img_chunk2_size;
chain->override_chunk_num = 1;
override = (ventoy_override_chunk *)((char *)chain + chain->override_chunk_offset);
override->img_offset = imgoffset;
override->override_size = sizeof(ventoy_iso9660_override);
dirent = (ventoy_iso9660_override *)(override->override_data);
dirent->first_sector = (grub_uint32_t)((file->size + 2047) / 2048);
dirent->size = (grub_uint32_t)(wimsize);
dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
dirent->size_be = grub_swap_bytes32(dirent->size);
debug("imgoffset=%u first_sector=0x%x size=0x%x\n", imgoffset, dirent->first_sector, dirent->size);
if (ventoy_is_efi_os() == 0)
{
ventoy_windows_drive_map(chain);
}
grub_file_close(file);
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}

View File

@@ -35,6 +35,7 @@ typedef enum ventoy_fs_type
ventoy_fs_ext, /* 2: ext2/ext3/ext4 */
ventoy_fs_xfs, /* 3: XFS */
ventoy_fs_udf, /* 4: UDF */
ventoy_fs_fat, /* 5: FAT */
ventoy_fs_max
}ventoy_fs_type;
@@ -224,7 +225,7 @@ typedef struct ventoy_grub_param
#pragma pack()
int grub_ext_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list);
int grub_fat_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list);
grub_uint64_t grub_iso9660_get_last_read_pos(grub_file_t file);
grub_uint64_t grub_iso9660_get_last_file_dirent_pos(grub_file_t file);

View File

@@ -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 lspci pci ext2 xfs ventoy chain read halt iso9660 linux16 test true sleep reboot echo videotest videoinfo videotest_checksum 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

View File

@@ -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

35
GRUB2/buildgrub.sh Normal file
View File

@@ -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 ../../

View File

@@ -1,249 +0,0 @@
/******************************************************************************
* ventoy_plugin.c
*
* Copyright (c) 2020, longpanda <admin@ventoy.net>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/disk.h>
#include <grub/device.h>
#include <grub/term.h>
#include <grub/partition.h>
#include <grub/file.h>
#include <grub/normal.h>
#include <grub/extcmd.h>
#include <grub/datetime.h>
#include <grub/i18n.h>
#include <grub/net.h>
#include <grub/time.h>
#include <grub/ventoy.h>
#include "ventoy_def.h"
GRUB_MOD_LICENSE ("GPLv3+");
static install_template *g_install_template_head = NULL;
static int ventoy_plugin_theme_entry(VTOY_JSON *json, const char *isodisk)
{
const char *value;
char filepath[256];
value = vtoy_json_get_string_ex(json->pstChild, "file");
if (value)
{
if (value[0] == '/')
{
grub_snprintf(filepath, sizeof(filepath), "%s%s", isodisk, value);
}
else
{
grub_snprintf(filepath, sizeof(filepath), "%s/ventoy/%s", isodisk, value);
}
if (ventoy_is_file_exist(filepath) == 0)
{
debug("Theme file %s does not exist\n", filepath);
return 0;
}
debug("vtoy_theme %s\n", filepath);
grub_env_set("vtoy_theme", filepath);
}
value = vtoy_json_get_string_ex(json->pstChild, "gfxmode");
if (value)
{
debug("vtoy_gfxmode %s\n", value);
grub_env_set("vtoy_gfxmode", value);
}
return 0;
}
static int ventoy_plugin_auto_install_entry(VTOY_JSON *json, const char *isodisk)
{
const char *iso = NULL;
const char *script = NULL;
VTOY_JSON *pNode = NULL;
install_template *node = NULL;
install_template *next = NULL;
(void)isodisk;
if (json->enDataType != JSON_TYPE_ARRAY)
{
debug("Not array %d\n", json->enDataType);
return 0;
}
if (g_install_template_head)
{
for (node = g_install_template_head; node; node = next)
{
next = node->next;
grub_free(node);
}
g_install_template_head = NULL;
}
for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
{
iso = vtoy_json_get_string_ex(pNode->pstChild, "image");
if (iso && iso[0] == '/')
{
script = vtoy_json_get_string_ex(pNode->pstChild, "template");
if (script && script[0] == '/')
{
node = grub_zalloc(sizeof(install_template));
if (node)
{
grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso);
grub_snprintf(node->templatepath, sizeof(node->templatepath), "%s", script);
if (g_install_template_head)
{
node->next = g_install_template_head;
}
g_install_template_head = node;
}
}
}
}
return 0;
}
static plugin_entry g_plugin_entries[] =
{
{ "theme", ventoy_plugin_theme_entry },
{ "auto_install", ventoy_plugin_auto_install_entry },
};
static int ventoy_parse_plugin_config(VTOY_JSON *json, const char *isodisk)
{
int i;
VTOY_JSON *cur = json;
while (cur)
{
for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++)
{
if (grub_strcmp(g_plugin_entries[i].key, cur->pcName) == 0)
{
debug("Plugin entry for %s\n", g_plugin_entries[i].key);
g_plugin_entries[i].entryfunc(cur, isodisk);
break;
}
}
cur = cur->pstNext;
}
return 0;
}
grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **args)
{
int ret = 0;
char *buf = NULL;
grub_file_t file;
VTOY_JSON *json = NULL;
(void)ctxt;
(void)argc;
file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/ventoy/ventoy.json", args[0]);
if (!file)
{
return GRUB_ERR_NONE;
}
debug("json configuration file size %d\n", (int)file->size);
buf = grub_malloc(file->size + 1);
if (!buf)
{
grub_file_close(file);
return 1;
}
buf[file->size] = 0;
grub_file_read(file, buf, file->size);
grub_file_close(file);
json = vtoy_json_create();
if (!json)
{
return 1;
}
ret = vtoy_json_parse(json, buf);
if (ret)
{
debug("Failed to parse json string %d\n", ret);
grub_free(buf);
return 1;
}
ventoy_parse_plugin_config(json->pstChild, args[0]);
vtoy_json_destroy(json);
grub_free(buf);
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
void ventoy_plugin_dump_auto_install(void)
{
install_template *node = NULL;
for (node = g_install_template_head; node; node = node->next)
{
grub_printf("IMAGE:<%s>\n", node->isopath);
grub_printf("SCRIPT:<%s>\n\n", node->templatepath);
}
return;
}
char * ventoy_plugin_get_install_template(const char *isopath)
{
install_template *node = NULL;
for (node = g_install_template_head; node; node = node->next)
{
if (grub_strcmp(node->isopath, isopath) == 0)
{
return node->templatepath;
}
}
return NULL;
}

14
GenUUID/build.sh Normal file
View File

@@ -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

50
GenUUID/vtoy_gen_uuid.c Normal file
View File

@@ -0,0 +1,50 @@
/******************************************************************************
* vtoy_gen_uuid.c
*
* Copyright (c) 2020, longpanda <admin@ventoy.net>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
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;
}

View File

@@ -0,0 +1,42 @@
#!/ventoy/busybox/sh
#************************************************************************************
# Copyright (c) 2020, longpanda <admin@ventoy.net>
#
# 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 <http://www.gnu.org/licenses/>.
#
#************************************************************************************
. /ventoy/hook/ventoy-hook-lib.sh
if is_ventoy_hook_finished; then
exit 0
fi
vtdiskname=$(get_ventoy_disk_name)
if [ "$vtdiskname" = "unknown" ]; then
vtlog "ventoy disk not found"
PATH=$VTPATH_OLD
exit 0
fi
ventoy_udev_disk_common_hook "${vtdiskname#/dev/}2" "noreplace"
if ! [ -e $VTOY_DM_PATH ]; then
blkdev_num=$($VTOY_PATH/tool/dmsetup ls | grep ventoy | sed 's/.*(\([0-9][0-9]*\),.*\([0-9][0-9]*\).*/\1 \2/')
mknod -m 0666 $VTOY_DM_PATH b $blkdev_num
fi
# OK finish
set_ventoy_hook_finish

View File

@@ -0,0 +1,27 @@
#!/ventoy/busybox/sh
#************************************************************************************
# Copyright (c) 2020, longpanda <admin@ventoy.net>
#
# 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 <http://www.gnu.org/licenses/>.
#
#************************************************************************************
. $VTOY_PATH/hook/ventoy-os-lib.sh
if ! [ -d /dev ]; then
$BUSYBOX_PATH/mkdir /dev
fi
$SED "1a\export ROOT=/dev/mapper/ventoy" -i /init
$SED "/check_root \$device/i\ $BUSYBOX_PATH/sh $VTOY_PATH/hook/android/ventoy-disk.sh" -i /init

View File

@@ -22,6 +22,10 @@
if $GREP -q '^"$mount_handler"' /init; then
echo 'use mount_handler ...' >> $VTLOG
$SED "/^\"\$mount_handler\"/i\ $BUSYBOX_PATH/sh $VTOY_PATH/hook/arch/ventoy-disk.sh \"\$archisodevice\"" -i /init
if [ -f /hooks/archiso ]; then
$SED '/while ! poll_device "${dev}"/a\ if /ventoy/busybox/sh /ventoy/hook/arch/ventoy-timeout.sh ${dev}; then break; fi' -i /hooks/archiso
fi
else
# some archlinux initramfs doesn't contain device-mapper udev rules file
ARCH_UDEV_DIR=$(ventoy_get_udev_conf_dir)

View File

@@ -0,0 +1,36 @@
#!/ventoy/busybox/sh
#************************************************************************************
# Copyright (c) 2020, longpanda <admin@ventoy.net>
#
# 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 <http://www.gnu.org/licenses/>.
#
#************************************************************************************
. /ventoy/hook/ventoy-hook-lib.sh
vtlog "######### $0 $* ############"
blkdev_num=$($VTOY_PATH/tool/dmsetup ls | grep ventoy | sed 's/.*(\([0-9][0-9]*\),.*\([0-9][0-9]*\).*/\1:\2/')
vtDM=$(ventoy_find_dm_id ${blkdev_num})
if [ -b /dev/$vtDM ]; then
vtlog "ln -s /dev/$vtDM $1"
ln -s /dev/$vtDM "$1"
exit 0
else
vtlog "Device-mapper not found"
exit 1
fi

View File

@@ -25,5 +25,9 @@ fi
$SED -i "/_search_for_boot_device_/a\ $BUSYBOX_PATH/sh $VTOY_PATH/hook/debian/antix-disk.sh" /init
if [ -f $VTOY_PATH/ventoy_persistent_map ]; then
$SED 's#for param in $cmdline#for param in persist_all $cmdline#g' -i /init
fi
# for debug
#$SED -i "/^linuxfs_error/a\exec $VTOY_PATH/busybox/sh" /init

View File

@@ -50,6 +50,3 @@ if [ -f $VTOY_PATH/autoinstall ]; then
fi
fi

View File

@@ -118,5 +118,6 @@ else
fi
fi
# OK finish
set_ventoy_hook_finish

View File

@@ -21,5 +21,11 @@
vtHook=$($CAT $VTOY_PATH/inotifyd-hook-script.txt)
vtlog "... start inotifyd listen $vtHook ..."
$BUSYBOX_PATH/nohup $VTOY_PATH/tool/inotifyd $vtHook /dev:n 2>&- &
vtdisk=$(get_ventoy_disk_name)
if [ "$vtdisk" = "unknown" ]; then
vtlog "... start inotifyd listen $vtHook ..."
$BUSYBOX_PATH/nohup $VTOY_PATH/tool/inotifyd $vtHook /dev:n 2>&- &
else
vtlog "... $vtdisk already exist ..."
$BUSYBOX_PATH/sh $vtHook n /dev "${vtdisk#/dev/}2"
fi

View File

@@ -19,7 +19,7 @@
. $VTOY_PATH/hook/ventoy-os-lib.sh
if [ -d /etc/udev/rules.d ]; then
if [ -d /etc/udev/rules.d ] || [ -d /lib/udev/rules.d ]; then
ventoy_systemd_udevd_work_around
ventoy_add_udev_rule "$VTOY_PATH/hook/default/udev_disk_hook.sh %k noreplace"
else

View File

@@ -42,7 +42,8 @@ if is_inotify_ventoy_part $3; then
fi
vtlog "set anaconda-diskroot ..."
/sbin/initqueue --settled --onetime --name anaconda-diskroot anaconda-diskroot /dev/dm-0
/sbin/anaconda-diskroot /dev/dm-0
#/sbin/initqueue --settled --onetime --name anaconda-diskroot anaconda-diskroot /dev/dm-0
set_ventoy_hook_finish
fi

View File

@@ -27,6 +27,7 @@ blkdev_num=$(dmsetup ls | grep ventoy | sed 's/.*(\([0-9][0-9]*\),.*\([0-9][0-9]
vtDM=$(ventoy_find_dm_id ${blkdev_num})
vtlog "diskroot $vtDM ..."
/sbin/initqueue --settled --onetime --name anaconda-diskroot anaconda-diskroot /dev/$vtDM
/sbin/anaconda-diskroot /dev/dm-0
#/sbin/initqueue --settled --onetime --name anaconda-diskroot anaconda-diskroot /dev/$vtDM
PATH=$VTPATH_OLD

View File

@@ -215,6 +215,29 @@ create_ventoy_device_mapper() {
fi
}
create_persistent_device_mapper() {
vtlog "create_persistent_device_mapper $*"
VT_DM_BIN=$(ventoy_find_bin_path dmsetup)
if [ -z "$VT_DM_BIN" ]; then
vtlog "no dmsetup avaliable, lastly try inbox dmsetup"
VT_DM_BIN=$VTOY_PATH/tool/dmsetup
fi
vtlog "dmsetup avaliable in system $VT_DM_BIN"
if ventoy_check_dm_module "$1"; then
vtlog "device-mapper module check success"
else
vterr "Error: no dm module avaliable"
fi
$VTOY_PATH/tool/vtoydm -p -f $VTOY_PATH/ventoy_persistent_map -d $1 > $VTOY_PATH/persistent_dm_table
$VT_DM_BIN create vtoy_persistent $VTOY_PATH/persistent_dm_table >>$VTLOG 2>&1
}
wait_for_ventoy_dm_disk_label() {
DM=$($BUSYBOX_PATH/readlink $VTOY_DM_PATH)
vtlog "wait_for_ventoy_dm_disk_label $DM ..."
@@ -385,6 +408,30 @@ ventoy_copy_device_mapper() {
fi
}
# create link for device-mapper
ventoy_create_persistent_link() {
blkdev_num=$($VTOY_PATH/tool/dmsetup ls | grep vtoy_persistent | sed 's/.*(\([0-9][0-9]*\),.*\([0-9][0-9]*\).*/\1:\2/')
vtDM=$(ventoy_find_dm_id ${blkdev_num})
if ! [ -d /dev/disk/by-label ]; then
mkdir -p /dev/disk/by-label
fi
VTLABEL=$($BUSYBOX_PATH/blkid /dev/$vtDM | $SED 's/.*LABEL="\([^"]*\)".*/\1/')
if [ -z "$VTLABEL" ]; then
VTLABEL=casper-rw
fi
vtlog "Persistent Label: ##${VTLABEL}##"
if ! [ -e /dev/disk/by-label/$VTLABEL ]; then
vtOldDir=$PWD
cd /dev/disk/by-label
ln -s ../../$vtDM $VTLABEL
cd $vtOldDir
fi
}
ventoy_udev_disk_common_hook() {
VTDISK="${1:0:-1}"
@@ -419,8 +466,14 @@ ventoy_udev_disk_common_hook() {
else
ventoy_copy_device_mapper "/dev/$1"
fi
if [ -f $VTOY_PATH/ventoy_persistent_map ]; then
create_persistent_device_mapper "/dev/$VTDISK"
ventoy_create_persistent_link
fi
}
is_inotify_ventoy_part() {
if echo $1 | grep -q "2$"; then
if ! [ -e /sys/block/$1 ]; then

View File

@@ -184,6 +184,10 @@ ventoy_get_os_type() {
fi
fi
if $GREP -q 'android.x86' /proc/version; then
echo 'android'; return
fi
echo "default"
}
@@ -222,6 +226,11 @@ if [ "$rmproc" = "Y" ]; then
$BUSYBOX_PATH/rm -rf /proc
fi
if [ -f $VTOY_PATH/ventoy_persistent_map ]; then
export PERSISTENT='YES'
export PERSISTENCE='true'
fi
cd /
unset VTOY_PATH VTLOG FIND GREP EGREP CAT AWK SED SLEEP HEAD

View File

@@ -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

View File

@@ -0,0 +1,77 @@
#!/bin/sh
size=1024
fstype=ext4
label=casper-rw
print_usage() {
echo 'Usage: CreatePersistentImg.sh [ -s size ] [ -t fstype ] [ -l LABEL ]'
echo ' OPTION: (optional)'
echo ' -s size in MB, default is 1024'
echo ' -t filesystem type, default is ext4 ext2/ext3/ext4/xfs are supported now'
echo ' -l label, default is casper-rw'
echo ''
}
while [ -n "$1" ]; do
if [ "$1" = "-s" ]; then
shift
size=$1
elif [ "$1" = "-t" ]; then
shift
fstype=$1
elif [ "$1" = "-l" ]; then
shift
label=$1
else
print_usage
exit 1
fi
shift
done
# check label
if [ -z "$label" ]; then
echo "The label can NOT be empty."
exit 1
fi
# check size
if echo $size | grep -q "^[0-9][0-9]*$"; then
if [ $size -le 1 ]; then
echo "Invalid size $size"
exit 1
fi
else
echo "Invalid size $size"
exit 1
fi
# check file system type
# nodiscard must be set for ext2/3/4
# -K must be set for xfs
if echo $fstype | grep -q '^ext[234]$'; then
fsopt='-E nodiscard'
elif [ "$fstype" = "xfs" ]; then
fsopt='-K'
else
echo "unsupported file system $fstype"
exit 1
fi
# 00->ff avoid sparse file
dd if=/dev/zero bs=1M count=$size | tr '\000' '\377' > persistence.img
sync
freeloop=$(losetup -f)
losetup $freeloop persistence.img
mkfs -t $fstype $fsopt -L $label $freeloop
sync
losetup -d $freeloop

Binary file not shown.

Binary file not shown.

View File

@@ -1,25 +1,5 @@
#!/bin/sh
OLDDIR=$PWD
if ! [ -f ./tool/ventoy_lib.sh ]; then
cd ${0%Ventoy2Disk.sh}
fi
. ./tool/ventoy_lib.sh
print_usage() {
echo 'Usage: Ventoy2Disk.sh CMD [ OPTION ] /dev/sdX'
echo ' CMD:'
echo ' -i install ventoy to sdX (fail if disk already installed with ventoy)'
echo ' -u update ventoy in sdX'
echo ' -I force install ventoy to sdX (no matter installed or not)'
echo ''
echo ' OPTION: (optional)'
echo ' -s enable secure boot support (default is disabled)'
echo ''
}
echo ''
echo '***********************************************************'
@@ -28,299 +8,43 @@ echo '* longpanda admin@ventoy.net *'
echo '***********************************************************'
echo ''
vtdebug "############# Ventoy2Disk $0 ################"
OLDDIR=$PWD
while [ -n "$1" ]; do
if [ "$1" = "-i" ]; then
MODE="install"
elif [ "$1" = "-I" ]; then
MODE="install"
FORCE="Y"
elif [ "$1" = "-u" ]; then
MODE="update"
elif [ "$1" = "-s" ]; then
SECUREBOOT="YES"
else
if ! [ -b "$1" ]; then
vterr "$1 is NOT a valid device"
print_usage
cd $OLDDIR
exit 1
fi
DISK=$1
if ! [ -f ./tool/xzcat ]; then
if [ -f ${0%Ventoy2Disk.sh}/tool/xzcat ]; then
cd ${0%Ventoy2Disk.sh}
fi
shift
done
if [ -z "$MODE" ]; then
print_usage
cd $OLDDIR
exit 1
fi
if ! [ -b "$DISK" ]; then
vterr "Disk $DISK does not exist"
cd $OLDDIR
exit 1
fi
if [ -e /sys/class/block/${DISK#/dev/}/start ]; then
vterr "$DISK is a partition, please use the whole disk"
cd $OLDDIR
exit 1
fi
if dd if="$DISK" of=/dev/null bs=1 count=1 >/dev/null 2>&1; then
vtdebug "root permission check ok ..."
else
vterr "Failed to access $DISK, maybe root privilege is needed!"
echo ''
cd $OLDDIR
exit 1
fi
vtdebug "MODE=$MODE FORCE=$FORCE"
if ! [ -f ./boot/boot.img ]; then
if [ -d ./grub ]; then
vterr "Don't run me here, please download the released install package, and run there."
echo "Don't run Ventoy2Disk.sh here, please download the released install package, and run the script in it."
else
vterr "Please run under the right directory!"
echo "Please run under the correct directory!"
fi
exit 1
fi
echo "############# Ventoy2Disk $* ################" >> ./log.txt
#decompress tool
cd tool
chmod +x ./xzcat
for file in $(ls); do
if [ "$file" != "xzcat" ]; then
if [ "$file" != "ventoy_lib.sh" ]; then
./xzcat $file > ${file%.xz}
chmod +x ${file%.xz}
fi
fi
done
cd ../
if ! [ -f ./tool/ash ]; then
cd tool
chmod +x ./xzcat
for file in $(ls *.xz); do
./xzcat $file > ${file%.xz}
chmod +x ${file%.xz}
done
cd ../
if ! check_tool_work_ok; then
vterr "Some tools can not run in current system. Please check log.txt for detail."
cd $OLDDIR
exit 1
fi
grep "^$DISK" /proc/mounts | while read mtline; do
mtpnt=$(echo $mtline | awk '{print $DISK}')
vtdebug "Trying to umount $mtpnt ..."
umount $mtpnt >/dev/null 2>&1
done
if grep "$DISK" /proc/mounts; then
vterr "$DISK is already mounted, please umount it first!"
cd $OLDDIR
exit 1
fi
if [ "$MODE" = "install" ]; then
vtdebug "install ventoy ..."
if ! fdisk -v >/dev/null 2>&1; then
vterr "fdisk is needed by ventoy installation, but is not found in the system."
if ! [ -f ./tool/ash ]; then
echo 'Failed to decompress tools ...'
cd $OLDDIR
exit 1
fi
version=$(get_disk_ventoy_version $DISK)
if [ $? -eq 0 ]; then
if [ -z "$FORCE" ]; then
vtwarn "$DISK already contains a Ventoy with version $version"
vtwarn "Use -u option to do a safe upgrade operation."
vtwarn "OR if you really want to reinstall ventoy to $DISK, please use -I option."
vtwarn ""
cd $OLDDIR
exit 1
fi
fi
disk_sector_num=$(cat /sys/block/${DISK#/dev/}/size)
disk_size_gb=$(expr $disk_sector_num / 2097152)
if [ $disk_sector_num -gt 4294967296 ]; then
vterr "$DISK is over 2TB size, MBR will not work on it."
cd $OLDDIR
exit 1
fi
#Print disk info
echo "Disk : $DISK"
parted -s $DISK p 2>&1 | grep Model
echo "Size : $disk_size_gb GB"
echo ''
vtwarn "Attention:"
vtwarn "You will install Ventoy to $DISK."
vtwarn "All the data on the disk $DISK will be lost!!!"
echo ""
read -p 'Continue? (y/n)' Answer
if [ "$Answer" != "y" ]; then
if [ "$Answer" != "Y" ]; then
exit 0
fi
fi
echo ""
vtwarn "All the data on the disk $DISK will be lost!!!"
read -p 'Double-check. Continue? (y/n)' Answer
if [ "$Answer" != "y" ]; then
if [ "$Answer" != "Y" ]; then
exit 0
fi
fi
if [ $disk_sector_num -le $VENTOY_SECTOR_NUM ]; then
vterr "No enough space in disk $DISK"
exit 1
fi
if ! dd if=/dev/zero of=$DISK bs=1 count=512 status=none conv=fsync; then
vterr "Write data to $DISK failed, please check whether it's in use."
exit 1
fi
format_ventoy_disk $DISK
# format part1
if ventoy_is_linux64; then
cmd=./tool/mkexfatfs_64
else
cmd=./tool/mkexfatfs_32
fi
chmod +x ./tool/*
# DiskSize > 32GB Cluster Size use 128KB
# DiskSize < 32GB Cluster Size use 32KB
if [ $disk_size_gb -gt 32 ]; then
cluster_sectors=256
else
cluster_sectors=64
fi
$cmd -n ventoy -s $cluster_sectors ${DISK}1
chmod +x ./tool/vtoy_gen_uuid
vtinfo "writing data to disk ..."
dd status=none conv=fsync if=./boot/boot.img of=$DISK bs=1 count=446
./tool/xzcat ./boot/core.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=2047 seek=1
./tool/xzcat ./ventoy/ventoy.disk.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=$VENTOY_SECTOR_NUM seek=$part2_start_sector
#disk uuid
./tool/vtoy_gen_uuid | dd status=none conv=fsync of=${DISK} seek=384 bs=1 count=16
#disk signature
./tool/vtoy_gen_uuid | dd status=none conv=fsync of=${DISK} skip=12 seek=440 bs=1 count=4
vtinfo "sync data ..."
sync
vtinfo "esp partition processing ..."
if [ "$SECUREBOOT" != "YES" ]; then
mkdir ./tmp_mnt
vtdebug "mounting part2 ...."
for tt in 1 2 3; do
if mount ${DISK}2 ./tmp_mnt; then
vtdebug "mounting part2 success"
break
fi
sleep 2
done
rm -f ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
rm -f ./tmp_mnt/EFI/BOOT/grubx64.efi
rm -f ./tmp_mnt/EFI/BOOT/MokManager.efi
rm -f ./tmp_mnt/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
mv ./tmp_mnt/EFI/BOOT/grubx64_real.efi ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
umount ./tmp_mnt
rm -rf ./tmp_mnt
fi
echo ""
vtinfo "Install Ventoy to $DISK successfully finished."
echo ""
else
vtdebug "update ventoy ..."
oldver=$(get_disk_ventoy_version $DISK)
if [ $? -ne 0 ]; then
vtwarn "$DISK does not contain ventoy or data corupted"
echo ""
vtwarn "Please use -i option if you want to install ventoy to $DISK"
echo ""
cd $OLDDIR
exit 1
fi
curver=$(cat ./ventoy/version)
vtinfo "Upgrade operation is safe, all the data in the 1st partition (iso files and other) will be unchanged!"
echo ""
read -p "Update Ventoy $oldver ===> $curver Continue? (y/n)" Answer
if [ "$Answer" != "y" ]; then
if [ "$Answer" != "Y" ]; then
cd $OLDDIR
exit 0
fi
fi
PART2=$(get_disk_part_name $DISK 2)
dd status=none conv=fsync if=./boot/boot.img of=$DISK bs=1 count=440
./tool/xzcat ./boot/core.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=2047 seek=1
disk_sector_num=$(cat /sys/block/${DISK#/dev/}/size)
part2_start=$(expr $disk_sector_num - $VENTOY_SECTOR_NUM)
./tool/xzcat ./ventoy/ventoy.disk.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=$VENTOY_SECTOR_NUM seek=$part2_start
sync
if [ "$SECUREBOOT" != "YES" ]; then
mkdir ./tmp_mnt
vtdebug "mounting part2 ...."
for tt in 1 2 3; do
if mount ${DISK}2 ./tmp_mnt; then
vtdebug "mounting part2 success"
break
fi
sleep 2
done
rm -f ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
rm -f ./tmp_mnt/EFI/BOOT/grubx64.efi
rm -f ./tmp_mnt/EFI/BOOT/MokManager.efi
rm -f ./tmp_mnt/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
mv ./tmp_mnt/EFI/BOOT/grubx64_real.efi ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
umount ./tmp_mnt
rm -rf ./tmp_mnt
fi
echo ""
vtinfo "Update Ventoy to $DISK successfully finished."
echo ""
fi
./tool/ash ./tool/VentoyWorker.sh $*
cd $OLDDIR

62
INSTALL/all_in_one.sh Normal file
View File

@@ -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'

View File

@@ -17,28 +17,12 @@
#************************************************************************************
function ventoy_power {
echo '<1> Reboot'
echo '<2> Halt'
echo '<0> Return to menu'
echo -e '\nPlease enter your choice:'
unset vtOpt
read vtOpt
if [ "$vtOpt" = "1" ]; then
echo -e '\n\nSystem is rebooting ... \n'
sleep 1
reboot
elif [ "$vtOpt" = "2" ]; then
echo -e '\n\nSystem is halting ... \n'
sleep 1
halt
fi
configfile ($root)/grub/power.cfg
}
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
@@ -121,6 +105,7 @@ function distro_specify_initrd_file {
fi
}
function distro_specify_initrd_file_phase2 {
if [ -f (loop)/boot/initrd.img ]; then
vt_linux_specify_initrd_file /boot/initrd.img
@@ -132,7 +117,11 @@ function distro_specify_initrd_file_phase2 {
vt_linux_specify_initrd_file /boot/iniramfs.igz
elif [ -f (loop)/initrd-x86_64 ]; then
vt_linux_specify_initrd_file /initrd-x86_64
elif [ -f (loop)/live/initrd.img ]; then
vt_linux_specify_initrd_file /live/initrd.img
elif [ -f (loop)/initrd.img ]; then
vt_linux_specify_initrd_file /initrd.img
fi
}
@@ -236,6 +225,8 @@ function uefi_iso_menu_func {
fi
vt_chosen_img_path chosen_path
vt_select_auto_install ${chosen_path}
vt_select_persistence ${chosen_path}
if vt_is_udf ${1}${chosen_path}; then
set ventoy_fs_probe=udf
@@ -383,6 +374,8 @@ function legacy_iso_menu_func {
fi
vt_chosen_img_path chosen_path
vt_select_auto_install ${chosen_path}
vt_select_persistence ${chosen_path}
if vt_is_udf ${1}${chosen_path}; then
set ventoy_fs_probe=udf
@@ -428,7 +421,7 @@ function legacy_iso_memdisk {
boot
}
function common_menuentry {
function iso_common_menuentry {
if [ "$grub_platform" = "pc" ]; then
if vt_check_mode 0; then
legacy_iso_memdisk $iso_path
@@ -444,6 +437,39 @@ function common_menuentry {
fi
}
function iso_unsupport_menuentry {
echo -e "\n The name of the iso file could NOT contain space or non-ascii characters. \n"
echo -e "\n Will return to main menu after 10 seconds ...\n"
sleep 10
}
function wim_common_menuentry {
vt_chosen_img_path chosen_path
vt_wim_chain_data ${iso_path}${chosen_path}
if [ -n "${vtdebug_flag}" ]; then
sleep 5
fi
if [ -n "$vtoy_chain_mem_addr" ]; then
if [ "$grub_platform" = "pc" ]; then
linux16 $vtoy_path/ipxe.krn ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
else
terminal_output console
chainloader ${vtoy_path}/ventoy_x64.efi env_param=${env_param} isoefi=${LoadIsoEfiDriver} ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
fi
boot
else
echo "chain empty failed"
sleep 5
fi
}
function wim_unsupport_menuentry {
echo -e "\n The name of the wim file could NOT contain space or non-ascii characters. \n"
echo -e "\n Will return to main menu after 10 seconds ...\n"
sleep 10
}
#############################################################
#############################################################
@@ -453,8 +479,7 @@ function common_menuentry {
#############################################################
#############################################################
set VENTOY_VERSION="1.0.9Y"
set VENTOY_VERSION="1.0.12"
# Default menu display mode, you can change it as you want.
# 0: List mode
@@ -464,20 +489,12 @@ set VTOY_DEFAULT_MENU_MODE=0
#disable timeout
unset timeout
set VTOY_MEM_DISK_STR="MEMDISK"
set VTOY_MEM_DISK_STR="[Memdisk]"
set VTOY_ISO_RAW_STR="ISO RAW"
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
@@ -491,20 +508,39 @@ if [ "$vtoy_dev" = "tftp" ]; then
for vtid in 0 1 2 3; do
if [ -d (hd$vtid,2)/ventoy ]; then
set iso_path=(hd$vtid,1)
set vtoy_efi_part=(hd$vtid,2)
break
fi
done
else
set vtoy_path=($root)/ventoy
set iso_path=($vtoy_dev,1)
set vtoy_efi_part=($vtoy_dev,2)
fi
loadfont ascii
#Load Plugin
if [ -f $iso_path/ventoy/ventoy.json ]; then
vt_load_plugin $iso_path
fi
if [ -f $iso_path/ventoy/ventoy_wimboot.img ]; then
vt_load_wimboot $iso_path/ventoy/ventoy_wimboot.img
elif [ -f $vtoy_efi_part/ventoy/ventoy_wimboot.img ]; then
vt_load_wimboot $vtoy_efi_part/ventoy/ventoy_wimboot.img
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
@@ -531,7 +567,14 @@ if [ $ventoy_img_count -gt 0 ]; then
vt_dynamic_menu 0 1
fi
else
menuentry "No ISO files found (Press enter to reboot ...)" {
if [ -n "$VTOY_NO_ISO_TIP" ]; then
NO_ISO_MENU="No ISO files found, $VTOY_NO_ISO_TIP"
elif [ -n "$VTOY_DEFAULT_SEARCH_ROOT" ]; then
NO_ISO_MENU="No ISO files found, please check VTOY_DEFAULT_SEARCH_ROOT"
else
NO_ISO_MENU="No ISO files found"
fi
menuentry "$NO_ISO_MENU (Press enter to reboot ...)" {
echo -e "\n Rebooting ... "
reboot
}

Binary file not shown.

15
INSTALL/grub/power.cfg Normal file
View File

@@ -0,0 +1,15 @@
menuentry Reboot {
echo -e '\n\nSystem is rebooting ... \n'
sleep 1
reboot
}
menuentry Halt {
echo -e '\n\nSystem is halting ... \n'
sleep 1
reboot
}
menuentry 'Return to menu [Esc]' VTOY_RET {
echo 'Return ...'
}

View File

@@ -58,8 +58,8 @@ terminal-box: "terminal_box_*.png"
+ hbox{
left = 90%
top = 5
left = 30%
top = 95%-25
width = 10%
height = 25
+ label {text = "@VTOY_MEM_DISK@" color = "red" align = "left"}

Binary file not shown.

View File

@@ -0,0 +1,315 @@
#!/bin/sh
. ./tool/ventoy_lib.sh
print_usage() {
echo 'Usage: Ventoy2Disk.sh CMD [ OPTION ] /dev/sdX'
echo ' CMD:'
echo ' -i install ventoy to sdX (fail if disk already installed with ventoy)'
echo ' -u update ventoy in sdX'
echo ' -I force install ventoy to sdX (no matter installed or not)'
echo ''
echo ' OPTION: (optional)'
echo ' -s enable secure boot support (default is disabled)'
echo ''
}
while [ -n "$1" ]; do
if [ "$1" = "-i" ]; then
MODE="install"
elif [ "$1" = "-I" ]; then
MODE="install"
FORCE="Y"
elif [ "$1" = "-u" ]; then
MODE="update"
elif [ "$1" = "-s" ]; then
SECUREBOOT="YES"
else
if ! [ -b "$1" ]; then
vterr "$1 is NOT a valid device"
print_usage
exit 1
fi
DISK=$1
fi
shift
done
if [ -z "$MODE" ]; then
print_usage
exit 1
fi
if ! [ -b "$DISK" ]; then
vterr "Disk $DISK does not exist"
exit 1
fi
if [ -e /sys/class/block/${DISK#/dev/}/start ]; then
vterr "$DISK is a partition, please use the whole disk"
exit 1
fi
if dd if="$DISK" of=/dev/null bs=1 count=1 >/dev/null 2>&1; then
vtdebug "root permission check ok ..."
else
vterr "Failed to access $DISK, maybe root privilege is needed!"
echo ''
exit 1
fi
vtdebug "MODE=$MODE FORCE=$FORCE"
if ! check_tool_work_ok; then
vterr "Some tools can not run in current system. Please check log.txt for detail."
exit 1
fi
grep "^$DISK" /proc/mounts | while read mtline; do
mtpnt=$(echo $mtline | awk '{print $2}')
vtdebug "Trying to umount $mtpnt ..."
umount $mtpnt >/dev/null 2>&1
done
if swapon -s | grep -q "^${DISK}[0-9]"; then
swapon -s | grep "^${DISK}[0-9]" | awk '{print $1}' | while read line; do
vtdebug "Trying to swapoff $line ..."
swapoff $line
done
fi
if grep "$DISK" /proc/mounts; then
vterr "$DISK is already mounted, please umount it first!"
exit 1
fi
if swapon -s | grep -q "^${DISK}[0-9]"; then
vterr "$DISK is used as swap, please swapoff it first!"
exit 1
fi
if [ "$MODE" = "install" ]; then
vtdebug "install ventoy ..."
if parted -v > /dev/null 2>&1; then
PARTTOOL='parted'
elif fdisk -v >/dev/null 2>&1; then
PARTTOOL='fdisk'
else
vterr "Both parted and fdisk are not found in the sysstem, Ventoy can't create new partition."
exit 1
fi
version=$(get_disk_ventoy_version $DISK)
if [ $? -eq 0 ]; then
if [ -z "$FORCE" ]; then
vtwarn "$DISK already contains a Ventoy with version $version"
vtwarn "Use -u option to do a safe upgrade operation."
vtwarn "OR if you really want to reinstall ventoy to $DISK, please use -I option."
vtwarn ""
exit 1
fi
fi
disk_sector_num=$(cat /sys/block/${DISK#/dev/}/size)
disk_size_gb=$(expr $disk_sector_num / 2097152)
if [ $disk_sector_num -gt 4294967296 ]; then
vterr "$DISK is over 2TB size, MBR will not work on it."
exit 1
fi
#Print disk info
echo "Disk : $DISK"
parted -s $DISK p 2>&1 | grep Model
echo "Size : $disk_size_gb GB"
echo ''
vtwarn "Attention:"
vtwarn "You will install Ventoy to $DISK."
vtwarn "All the data on the disk $DISK will be lost!!!"
echo ""
read -p 'Continue? (y/n)' Answer
if [ "$Answer" != "y" ]; then
if [ "$Answer" != "Y" ]; then
exit 0
fi
fi
echo ""
vtwarn "All the data on the disk $DISK will be lost!!!"
read -p 'Double-check. Continue? (y/n)' Answer
if [ "$Answer" != "y" ]; then
if [ "$Answer" != "Y" ]; then
exit 0
fi
fi
if [ $disk_sector_num -le $VENTOY_SECTOR_NUM ]; then
vterr "No enough space in disk $DISK"
exit 1
fi
if ! dd if=/dev/zero of=$DISK bs=1 count=512 status=none conv=fsync; then
vterr "Write data to $DISK failed, please check whether it's in use."
exit 1
fi
format_ventoy_disk $DISK $PARTTOOL
# format part1
if ventoy_is_linux64; then
cmd=./tool/mkexfatfs_64
else
cmd=./tool/mkexfatfs_32
fi
chmod +x ./tool/*
# DiskSize > 32GB Cluster Size use 128KB
# DiskSize < 32GB Cluster Size use 32KB
if [ $disk_size_gb -gt 32 ]; then
cluster_sectors=256
else
cluster_sectors=64
fi
$cmd -n ventoy -s $cluster_sectors ${DISK}1
chmod +x ./tool/vtoy_gen_uuid
vtinfo "writing data to disk ..."
dd status=none conv=fsync if=./boot/boot.img of=$DISK bs=1 count=446
./tool/xzcat ./boot/core.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=2047 seek=1
./tool/xzcat ./ventoy/ventoy.disk.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=$VENTOY_SECTOR_NUM seek=$part2_start_sector
#disk uuid
./tool/vtoy_gen_uuid | dd status=none conv=fsync of=${DISK} seek=384 bs=1 count=16
#disk signature
./tool/vtoy_gen_uuid | dd status=none conv=fsync of=${DISK} skip=12 seek=440 bs=1 count=4
vtinfo "sync data ..."
sync
vtinfo "esp partition processing ..."
sleep 1
mtpnt=$(grep "^${DISK}2" /proc/mounts | awk '{print $2}')
if [ -n "$mtpnt" ]; then
umount $mtpnt >/dev/null 2>&1
fi
if [ "$SECUREBOOT" != "YES" ]; then
mkdir ./tmp_mnt
vtdebug "mounting part2 ...."
for tt in 1 2 3; do
if mount ${DISK}2 ./tmp_mnt; then
vtdebug "mounting part2 success"
break
fi
mtpnt=$(grep "^${DISK}2" /proc/mounts | awk '{print $2}')
if [ -n "$mtpnt" ]; then
umount $mtpnt >/dev/null 2>&1
fi
sleep 2
done
rm -f ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
rm -f ./tmp_mnt/EFI/BOOT/grubx64.efi
rm -f ./tmp_mnt/EFI/BOOT/MokManager.efi
rm -f ./tmp_mnt/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
mv ./tmp_mnt/EFI/BOOT/grubx64_real.efi ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
umount ./tmp_mnt
rm -rf ./tmp_mnt
fi
echo ""
vtinfo "Install Ventoy to $DISK successfully finished."
echo ""
else
vtdebug "update ventoy ..."
oldver=$(get_disk_ventoy_version $DISK)
if [ $? -ne 0 ]; then
vtwarn "$DISK does not contain ventoy or data corupted"
echo ""
vtwarn "Please use -i option if you want to install ventoy to $DISK"
echo ""
exit 1
fi
curver=$(cat ./ventoy/version)
vtinfo "Upgrade operation is safe, all the data in the 1st partition (iso files and other) will be unchanged!"
echo ""
read -p "Update Ventoy $oldver ===> $curver Continue? (y/n)" Answer
if [ "$Answer" != "y" ]; then
if [ "$Answer" != "Y" ]; then
exit 0
fi
fi
PART2=$(get_disk_part_name $DISK 2)
dd status=none conv=fsync if=./boot/boot.img of=$DISK bs=1 count=440
PART1_ACTIVE=$(dd if=$DISK bs=1 count=1 skip=446 status=none | ./tool/hexdump -n1 -e '1/1 "%02X"')
PART2_ACTIVE=$(dd if=$DISK bs=1 count=1 skip=462 status=none | ./tool/hexdump -n1 -e '1/1 "%02X"')
vtdebug "PART1_ACTIVE=$PART1_ACTIVE PART2_ACTIVE=$PART2_ACTIVE"
if [ "$PART1_ACTIVE" = "00" ] && [ "$PART2_ACTIVE" = "80" ]; then
vtdebug "change 1st partition active, 2nd partition inactive ..."
echo -en '\x80' | dd of=$DISK conv=fsync bs=1 count=1 seek=446 status=none
echo -en '\x00' | dd of=$DISK conv=fsync bs=1 count=1 seek=462 status=none
fi
./tool/xzcat ./boot/core.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=2047 seek=1
disk_sector_num=$(cat /sys/block/${DISK#/dev/}/size)
part2_start=$(expr $disk_sector_num - $VENTOY_SECTOR_NUM)
./tool/xzcat ./ventoy/ventoy.disk.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=$VENTOY_SECTOR_NUM seek=$part2_start
sync
if [ "$SECUREBOOT" != "YES" ]; then
mkdir ./tmp_mnt
vtdebug "mounting part2 ...."
for tt in 1 2 3; do
if mount ${DISK}2 ./tmp_mnt; then
vtdebug "mounting part2 success"
break
fi
sleep 2
done
rm -f ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
rm -f ./tmp_mnt/EFI/BOOT/grubx64.efi
rm -f ./tmp_mnt/EFI/BOOT/MokManager.efi
rm -f ./tmp_mnt/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
mv ./tmp_mnt/EFI/BOOT/grubx64_real.efi ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
umount ./tmp_mnt
rm -rf ./tmp_mnt
fi
echo ""
vtinfo "Update Ventoy to $DISK successfully finished."
echo ""
fi

BIN
INSTALL/tool/ash Normal file

Binary file not shown.

View File

@@ -22,40 +22,17 @@ ventoy_is_linux64() {
ventoy_false
}
ventoy_is_dash() {
if [ -L /bin/sh ]; then
vtdst=$(readlink /bin/sh)
if [ "$vtdst" = "dash" ]; then
ventoy_true
return
fi
fi
ventoy_false
}
vtinfo() {
if ventoy_is_dash; then
echo "\033[32m$*\033[0m"
else
echo -e "\033[32m$*\033[0m"
fi
echo -e "\033[32m$*\033[0m"
}
vtwarn() {
if ventoy_is_dash; then
echo "\033[33m$*\033[0m"
else
echo -e "\033[33m$*\033[0m"
fi
echo -e "\033[33m$*\033[0m"
}
vterr() {
if ventoy_is_dash; then
echo "\033[31m$*\033[0m"
else
echo -e "\033[31m$*\033[0m"
fi
echo -e "\033[31m$*\033[0m"
}
vtdebug() {
@@ -207,9 +184,11 @@ get_disk_ventoy_version() {
ventoy_false
}
format_ventoy_disk() {
DISK=$1
PARTTOOL=$2
PART1=$(get_disk_part_name $DISK 1)
PART2=$(get_disk_part_name $DISK 2)
sector_num=$(cat /sys/block/${DISK#/dev/}/size)
@@ -219,15 +198,33 @@ format_ventoy_disk() {
export part2_start_sector=$(expr $part1_end_sector + 1)
part2_end_sector=$(expr $sector_num - 1)
vtdebug "part1_start_sector=$part1_start_sector part1_end_sector=$part1_end_sector"
vtdebug "part2_start_sector=$part2_start_sector part2_end_sector=$part2_end_sector"
if [ -e $PART2 ]; then
echo "delete $PART2"
rm -f $PART2
fi
echo ""
echo "Create partitions on $DISK ..."
echo "Create partitions on $DISK by $PARTTOOL ..."
fdisk $DISK >/dev/null 2>&1 <<EOF
if [ "$PARTTOOL" = "parted" ]; then
vtdebug "format disk by parted ..."
parted -a none --script $DISK \
mklabel msdos \
unit s \
mkpart primary ntfs $part1_start_sector $part1_end_sector \
mkpart primary fat16 $part2_start_sector $part2_end_sector \
set 1 boot on \
quit
sync
echo -en '\xEF' | dd of=$DISK conv=fsync bs=1 count=1 seek=466 > /dev/null 2>&1
else
vtdebug "format disk by fdisk ..."
fdisk $DISK >>./log.txt 2>&1 <<EOF
o
n
p
@@ -246,23 +243,40 @@ t
2
ef
a
2
1
w
EOF
echo "Done"
fi
udevadm trigger >/dev/null 2>&1
partprobe >/dev/null 2>&1
sleep 3
echo "Done"
echo 'mkfs on disk partitions ...'
while ! [ -e $PART2 ]; do
echo "wait $PART2 ..."
sleep 1
for i in 1 2 3 4 5 6 7; do
if [ -b $PART2 ]; then
break
else
echo "wait $PART2 ..."
sleep 1
fi
done
echo "create efi fat fs ..."
if ! [ -b $PART2 ]; then
MajorMinor=$(sed "s/:/ /" /sys/class/block/${PART2#/dev/}/dev)
echo "mknod -m 0660 $PART2 b $MajorMinor ..."
mknod -m 0660 $PART2 b $MajorMinor
if ! [ -b $PART1 ]; then
MajorMinor=$(sed "s/:/ /" /sys/class/block/${PART1#/dev/}/dev)
echo "mknod -m 0660 $PART1 b $MajorMinor ..."
mknod -m 0660 $PART1 b $MajorMinor
fi
fi
echo "create efi fat fs $PART2 ..."
for i in 0 1 2 3 4 5 6 7 8 9; do
if mkfs.vfat -F 16 -n EFI $PART2; then
echo 'success'

Binary file not shown.

Binary file not shown.

Binary file not shown.

125
INSTALL/ventoy_pack.sh Normal file
View File

@@ -0,0 +1,125 @@
#!/bin/sh
dos2unix -q ./tool/ventoy_lib.sh
dos2unix -q ./tool/VentoyWorker.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 fdisk
$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/
cp -a CreatePersistentImg.sh $tmpdir/
dos2unix -q $tmpdir/Ventoy2Disk.sh
dos2unix -q $tmpdir/CreatePersistentImg.sh
#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
rm -f log.txt

Some files were not shown because too many files have changed in this diff Show More