mirror of https://github.com/ventoy/Ventoy.git
1. change some directory structure for the build script
2. add build script and document see DOC/BuildVentoyFromSource.txt for detail
This commit is contained in:
parent
965417970b
commit
2aae096c2a
|
@ -0,0 +1,203 @@
|
|||
|
||||
==========================================
|
||||
1. Compile Enviroment
|
||||
==========================================
|
||||
My build envrioment is CentOS 7.8 x86_64. So here I first explain how to create the build environment from scratch.
|
||||
Because Ventoy is based on many open source projects, so the envrioment is important. I suggest you test it on a virtual machine first.
|
||||
|
||||
1.1 Install CentOS 7.8
|
||||
I use CentOS-7-x86_64-Everything-2003.iso and select Minimal install
|
||||
|
||||
1.2 Install Packages
|
||||
yum install \
|
||||
libXpm net-tools bzip2 wget vim gcc gcc-c++ samba dos2unix glibc-devel glibc.i686 glibc-devel.i686 \
|
||||
mpfr.i686 mpfr-devel.i686 zlib.i686 rsync autogen autoconf automake libtool gettext* bison binutils \
|
||||
flex device-mapper-devel SDL libpciaccess libusb freetype freetype-devel gnu-free-* qemu-* virt-* \
|
||||
libvirt* vte* NetworkManager-bluetooth brlapi fuse-devel dejavu* gnu-efi* pesign shim \
|
||||
iscsi-initiator-utils grub2-tools zip nasm acpica-tools glibc-static zlib-static
|
||||
|
||||
|
||||
|
||||
==========================================
|
||||
2. Download Source Code
|
||||
==========================================
|
||||
2.1 Download Ventoy source code from github and decompress it.
|
||||
Next I assume that you have unzipped the code into the /home directory (check /home/Ventoy-master/README.md file for the directory level).
|
||||
|
||||
2.2 Download third-part source code
|
||||
|
||||
https://www.fefe.de/dietlibc/dietlibc-0.34.tar.xz ===> /home/Ventoy-master/DOC/dietlibc-0.34.tar.xz
|
||||
https://ftp.gnu.org/gnu/grub/grub-2.04.tar.xz ===> /home/Ventoy-master/GRUB2/grub-2.04.tar.xz
|
||||
https://codeload.github.com/tianocore/edk2/zip/edk2-stable201911 ===> /home/Ventoy-master/EDK2/edk2-edk2-stable201911.zip
|
||||
https://codeload.github.com/relan/exfat/zip/v1.3.0 ===> /home/Ventoy-master/ExFAT/exfat-1.3.0.zip
|
||||
https://gitee.com/mirrors/libfuse/repository/archive/fuse-2.9.9.zip ===> /home/Ventoy-master/ExFAT/mirrors-libfuse-fuse-2.9.9.zip
|
||||
http://ultra-embedded.com/releases/fat_io_lib.zip ===> /home/Ventoy-master/vtoyfat/fat_io_lib/fat_io_lib.zip
|
||||
|
||||
|
||||
|
||||
==========================================
|
||||
3. All in one script
|
||||
==========================================
|
||||
I have made the whole build process in all_in_one.sh, you can run this script to build and pack ventoy.
|
||||
If you want to compile a certain part separately, you can continue to refer to the later chapters of this text.
|
||||
|
||||
cd /home/Ventoy-master/INSTALL
|
||||
sh all_in_one.sh
|
||||
|
||||
It should be noted that, some part of Ventoy has 32bit&64bit version (like 4.9 4.10 4.11 follows)
|
||||
all_in_one.sh only build 64bit version of them, if you want to rebuild the 32bit verison. You should create a 32bit CentOS environment and build them.
|
||||
Fortunately these parts are few modified, you only need to build once or you can directly use the binary I have built.
|
||||
|
||||
Besides, after a fully compile and pack, you can only build the part you modified (for example grub2) and run ventoy_pack.sh to generate the package.
|
||||
|
||||
|
||||
|
||||
==========================================
|
||||
4. Build every part of Ventoy
|
||||
==========================================
|
||||
4.1 == Build grub2 ==
|
||||
cd /home/Ventoy-master/GRUB2
|
||||
sh buildgrub.sh
|
||||
|
||||
4.2 == Build ipxe.krn ==
|
||||
cd /home/Ventoy-master/IPXE
|
||||
sh buildipxe.sh
|
||||
|
||||
4.3 == Build Ventoy2Disk.exe ==
|
||||
Ventoy2Disk.exe is the installer in Windows platform. And it must be built in Windows with Microsoft Visual Studio (2013+).
|
||||
Open /home/Ventoy-master/Ventoy2Disk/Ventoy2Disk.sln with Visual Studio and build it.
|
||||
|
||||
4.4 == Build vtoyjump64.exe/vtoyjump32.exe ==
|
||||
vtoyjump64.exe/vtoyjump32.exe is used to mount iso file in windows PE. You should install Microsoft Visual Studio (2013+) to build it.
|
||||
Open /home/Ventoy-master/vtoyjump/vtoyjump.sln with Visual Studio and build it (64&32).
|
||||
|
||||
4.5 == Build dmsetup ==
|
||||
Please refer to DMSETUP/build.txt
|
||||
|
||||
4.6 == Build ventoy_x64.efi ==
|
||||
cd /home/Ventoy-master/EDK2
|
||||
sh buildedk.sh
|
||||
|
||||
4.7 == Build VtoyTool ==
|
||||
cd /home/Ventoy-master/VtoyTool
|
||||
sh build.sh
|
||||
|
||||
4.8 == Build vtoyfat ==
|
||||
cd /home/Ventoy-master/vtoyfat/fat_io_lib
|
||||
sh buildlib.sh
|
||||
cd /home/Ventoy-master/vtoyfat
|
||||
sh build.sh
|
||||
|
||||
4.9 == Build exfat-util ==
|
||||
cd /home/Ventoy-master/ExFAT
|
||||
sh buidlibfuse.sh
|
||||
sh buidexfat.sh
|
||||
|
||||
After that, copy EXFAT/shared/mkexfatfs ===> /home/Ventoy-master/INSTALL/tool/mkexfatfs_64
|
||||
After that, copy EXFAT/shared/mount.exfat-fuse ===> /home/Ventoy-master/INSTALL/tool/mount.exfat-fuse_64
|
||||
|
||||
Use the same build step to build exfat-util 32bit in a 32bit CentOS system and get mkexfatfs_32 and mount.exfat-fuse_32
|
||||
|
||||
4.10 == Build vtoy_fuse_iso_64/vtoy_fuse_iso_32 ==
|
||||
cd /home/Ventoy-master/FUSEISO
|
||||
sh build_libfuse.sh
|
||||
sh build.sh
|
||||
|
||||
Use the same build step to build in a 32bit CentOS system and get vtoy_fuse_iso_32
|
||||
|
||||
4.11 == Build unsquashfs_64/unsquashfs_32 ==
|
||||
cd /home/Ventoy-master/SQUASHFS/SRC
|
||||
sh build_lz4.sh
|
||||
sh build_lzma.sh
|
||||
sh build_lzo.sh
|
||||
sh build_zstd.sh
|
||||
|
||||
cd /home/Ventoy-master/SQUASHFS/squashfs-tools-4.4/squashfs-tools
|
||||
sh build.sh
|
||||
|
||||
Use the same build step to build in a 32bit CentOS system and get unsquashfs_32
|
||||
|
||||
4.12 == Build vblade_64/vblade_32 ==
|
||||
cd /home/Ventoy-master/VBLADE/vblade-master
|
||||
sh build.sh
|
||||
|
||||
4.13 == Build zstdcat ==
|
||||
Please refer to ZSTD/build.txt
|
||||
|
||||
4.14 == Build vtoy_gen_uuid ==
|
||||
cd /home/Ventoy-master/GenUUID
|
||||
sh build.sh
|
||||
|
||||
4.15 == Build xzminidec ==
|
||||
cd /home/Ventoy-master/xz-embedded-20130513/userspace
|
||||
make -f ventoy_makefile
|
||||
strip --strip-all xzminidec
|
||||
|
||||
4.16 == Build iso9660_x64.efi ==
|
||||
This efi driver is from https://github.com/pbatard/efifs
|
||||
Follow all the build instructions in this project. I modified 3 files (the original and modified source are at /home/Ventoy-master/EDK2/efiffs)
|
||||
|
||||
|
||||
|
||||
==========================================
|
||||
5. Binaries
|
||||
==========================================
|
||||
There some binaries in Ventoy install package. These files are downloaded from other open source project's website, such as busybox.
|
||||
Here is the list of the binaries, their SHA-256 and the download urls:
|
||||
|
||||
5.1 IMG/cpio/ventoy/tool/lz4cat
|
||||
https://create.stephan-brumme.com/smallz4 smallz4cat-x32-v1.4
|
||||
SHA-256: 13d293ddeedb469f51da41167f79b2cbdb904e681716f6e6191b233dbb162438
|
||||
|
||||
5.2 IMG/cpio/ventoy/tool/ar
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686 busybox_AR
|
||||
SHA-256: f29b7d81a983c0c85d22496f4a833c18f2528a1b666eb7d47c93084c1ed66ae0
|
||||
|
||||
5.3 IMG/cpio/ventoy/tool/inotifyd
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686 busybox_INOTIFYD
|
||||
SHA-256: 3532162a8695e91a1ed9ddea28b2cb22259a90e93d5d9c4a517b6c36842c686f
|
||||
|
||||
5.4 IMG/cpio/ventoy/busybox/tmpsh
|
||||
https://busybox.net/downloads/binaries/1.27.1-i686 busybox_ASH
|
||||
SHA-256: 44a6274bca580c2758ffc173fc76d18bb855b1fe8dcf70efd9ee75cbd57dee97
|
||||
|
||||
5.5 IMG/cpio/ventoy/busybox/tmpxz
|
||||
https://busybox.net/downloads/binaries/1.27.1-i686 busybox_XZ
|
||||
SHA-256: f6cdb6293680424c29b89bde0685ca27f455166c9b302cd6082ef90681456291
|
||||
|
||||
5.6 INSTALL/tool/xzcat
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686/ busybox_XZCAT
|
||||
SHA-256: 7399db642c2beaf52a16ab5264ffc55cfd1ff5699a524f63e5d48edf84e20f44
|
||||
|
||||
5.7 INSTALL/tool/hexdump
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686/ busybox_HEXDUMP
|
||||
SHA-256: cde08b6a2cf5ad914f05203e18e3f7c2ed6060a63604e3d75536f19b55e8e0af
|
||||
|
||||
5.8 imdisk
|
||||
download http://www.ltr-data.se/files/imdiskinst.exe and extract it by 7zip.
|
||||
|
||||
INSTALL/ventoy/imdisk/64/imdisk.sys --> sys/amd64/imdisk.sys SHA-256: 6702202220268787e361f5a82dae53362c8e6c6dcd240bb01b44dd77ae0788da
|
||||
INSTALL/ventoy/imdisk/64/imdisk.exe --> cli/amd64/imdisk.exe SHA-256: 9759175380af836869443e5f21ce2e33022125d154bc6b3d1c04dc36b190de04
|
||||
INSTALL/ventoy/imdisk/64/imdisk.cpl --> cpl/amd64/imdisk.cpl SHA-256: aea2ebbea2b073c947263744962af8a3eab025ff4c9d825c543e380e738a4c99
|
||||
|
||||
INSTALL/ventoy/imdisk/32/imdisk.sys --> sys/i386/imdisk.sys SHA-256: a94caec2f71a924d6a914c093ad4b905d7cfdea3f515ed48aaa8c3950b2dc191
|
||||
INSTALL/ventoy/imdisk/32/imdisk.exe --> cli/i386/imdisk.exe SHA-256: 33b53858e2139704cf603b115a3e5e1dfd4daeaaed4d3e03c633f2df3b55dbaa
|
||||
INSTALL/ventoy/imdisk/32/imdisk.cpl --> cpl/i386/imdisk.cpl SHA-256: b781d3e2d286ac8bf548f44e50cbbb3fe78203296e41e4d2e73b407668f88f2d
|
||||
|
||||
5.9 INSTALL/ventoy/memdisk
|
||||
https://mirrors.edge.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.gz
|
||||
decompress it and memdisk is at syslinux-6.03/bios/memdisk/memdisk
|
||||
SHA-256: 3f6cd656b8a14109cd3f906fee2dd2e75418f983a5e1bfdb64f44f7765588cbb
|
||||
|
||||
|
||||
5.10 UEFIinSecureBoot
|
||||
https://github.com/ValdikSS/Super-UEFIinSecureBoot-Disk/releases Super-UEFIinSecureBoot-Disk_minimal_v3.zip
|
||||
unzip it and get Super-UEFIinSecureBoot-Disk_minimal.img, extract the img by 7zip.
|
||||
|
||||
INSTALL/EFI/BOOT/BOOTX64.EFI --> EFI/BOOT/BOOTX64.EFI SHA-256: 475552c7476ad45e42344eee8b30d44c264d200ac2468428aa86fc8795fb6e34
|
||||
INSTALL/EFI/BOOT/grubx64.efi --> EFI/BOOT/grubx64.efi SHA-256: 25d858157349dc52fa70f3cdf5c62fe1e0bae37ddfc3a6b6528af9a3c745775f
|
||||
INSTALL/EFI/BOOT/MokManager.efi --> EFI/BOOT/MokManager.efi SHA-256: 3bf1f46cee0832355c7dd1dba880dea9bcaa78cc44375a1559d43bc9db18933b
|
||||
|
||||
|
||||
|
||||
|
|
@ -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 ""
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
|
@ -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
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,12 +15,12 @@ rm -rf libfuse
|
|||
rm -rf $LIBFUSE_DIR
|
||||
|
||||
# please download https://gitee.com/mirrors/libfuse/repository/archive/fuse-2.9.9.zip
|
||||
if ! [ -e mirrors-libfuse-fuse-2.9.9.zip ]; then
|
||||
if ! [ -e ../ExFAT/mirrors-libfuse-fuse-2.9.9.zip ]; then
|
||||
echo "Please download mirrors-libfuse-fuse-2.9.9.zip first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
unzip mirrors-libfuse-fuse-2.9.9.zip
|
||||
unzip ../ExFAT/mirrors-libfuse-fuse-2.9.9.zip
|
||||
|
||||
|
||||
cd libfuse
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -49,7 +49,7 @@ initrd_info *g_initrd_img_list = NULL;
|
|||
initrd_info *g_initrd_img_tail = NULL;
|
||||
int g_initrd_img_count = 0;
|
||||
int g_valid_initrd_count = 0;
|
||||
|
||||
int g_filt_dot_underscore_file = 0;
|
||||
static grub_file_t g_old_file;
|
||||
|
||||
char g_img_swap_tmp_buf[1024];
|
||||
|
@ -618,6 +618,11 @@ static int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
|
|||
{
|
||||
grub_size_t i;
|
||||
|
||||
if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < namelen; i++)
|
||||
{
|
||||
if (filename[i] == ' ' || filename[i] == '\t')
|
||||
|
@ -938,6 +943,7 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char
|
|||
grub_device_t dev = NULL;
|
||||
img_info *cur = NULL;
|
||||
img_info *tail = NULL;
|
||||
const char *strdata = NULL;
|
||||
char *device_name = NULL;
|
||||
char buf[32];
|
||||
img_iterator_node *node = NULL;
|
||||
|
@ -955,6 +961,12 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char
|
|||
return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list");
|
||||
}
|
||||
|
||||
strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
|
||||
if (strdata && strdata[0] == '1' && strdata[1] == 0)
|
||||
{
|
||||
g_filt_dot_underscore_file = 1;
|
||||
}
|
||||
|
||||
device_name = grub_file_get_device_name(args[0]);
|
||||
if (!device_name)
|
||||
{
|
|
@ -40,6 +40,34 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
|||
|
||||
static install_template *g_install_template_head = NULL;
|
||||
|
||||
static int ventoy_plugin_control_entry(VTOY_JSON *json, const char *isodisk)
|
||||
{
|
||||
VTOY_JSON *pNode = NULL;
|
||||
VTOY_JSON *pChild = NULL;
|
||||
|
||||
(void)isodisk;
|
||||
|
||||
if (json->enDataType != JSON_TYPE_ARRAY)
|
||||
{
|
||||
debug("Not array %d\n", json->enDataType);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
|
||||
{
|
||||
if (pNode->enDataType == JSON_TYPE_OBJECT)
|
||||
{
|
||||
pChild = pNode->pstChild;
|
||||
if (pChild->enDataType == JSON_TYPE_STRING && pChild->pcName && pChild->unData.pcStrVal)
|
||||
{
|
||||
ventoy_set_env(pChild->pcName, pChild->unData.pcStrVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ventoy_plugin_theme_entry(VTOY_JSON *json, const char *isodisk)
|
||||
{
|
||||
const char *value;
|
||||
|
@ -136,6 +164,7 @@ static int ventoy_plugin_auto_install_entry(VTOY_JSON *json, const char *isodisk
|
|||
|
||||
static plugin_entry g_plugin_entries[] =
|
||||
{
|
||||
{ "control", ventoy_plugin_control_entry },
|
||||
{ "theme", ventoy_plugin_theme_entry },
|
||||
{ "auto_install", ventoy_plugin_auto_install_entry },
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
#!/bin/bash
|
||||
|
||||
VT_DIR=$PWD/../../..
|
||||
|
||||
rm -rf $VT_DIR/GRUB2/INSTALL
|
||||
rm -rf $VT_DIR/GRUB2/PXE
|
||||
mkdir -p $VT_DIR/GRUB2/INSTALL
|
||||
mkdir -p $VT_DIR/GRUB2/PXE
|
||||
|
||||
make install
|
||||
|
||||
PATH=$PATH:$VT_DIR/GRUB2/INSTALL/bin/:$VT_DIR/GRUB2/INSTALL/sbin/
|
||||
|
||||
net_modules_legacy="net tftp http"
|
||||
all_modules_legacy="date drivemap blocklist ext2 xfs ventoy chain read halt iso9660 linux16 test true sleep reboot echo video_colors video_cirrus video_bochs vga vbe video_fb font video gettext extcmd terminal linux minicmd help configfile tr trig boot biosdisk disk ls tar squash4 password_pbkdf2 all_video png jpeg part_msdos fat exfat ntfs loopback gzio normal udf gfxmenu gfxterm gfxterm_background gfxterm_menu"
|
||||
|
||||
net_modules_uefi="efinet net tftp http"
|
||||
all_modules_uefi="blocklist ventoy test ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux relocator jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop efi_uga video_bochs video_cirrus video video_fb gfxterm_background gfxterm_menu"
|
||||
|
||||
|
||||
if [ "$1" = "uefi" ]; then
|
||||
all_modules="$net_modules_uefi $all_modules_uefi"
|
||||
grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/x86_64-efi" --prefix '(,msdos2)/grub' --output "$VT_DIR/INSTALL/EFI/BOOT/grubx64_real.efi" --format 'x86_64-efi' --compression 'auto' $all_modules_uefi 'fat' 'part_msdos'
|
||||
else
|
||||
all_modules="$net_modules_legacy $all_modules_legacy"
|
||||
grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc" --prefix '(,msdos2)/grub' --output "$VT_DIR/INSTALL/grub/i386-pc/core.img" --format 'i386-pc' --compression 'auto' $all_modules_legacy 'fat' 'part_msdos' 'biosdisk'
|
||||
fi
|
||||
|
||||
grub-mknetdir --modules="$all_modules" --net-directory=$VT_DIR/GRUB2/PXE --subdir=grub2 --locales=en@quot || exit 1
|
||||
|
||||
if [ "$1" = "uefi" ]; then
|
||||
rm -f $VT_DIR/GRUB2/NBP/core.efi
|
||||
cp -a $VT_DIR/GRUB2/PXE/grub2/x86_64-efi/core.efi $VT_DIR/GRUB2/NBP/core.efi || exit 1
|
||||
|
||||
rm -f $VT_DIR/INSTALL/grub/x86_64-efi/normal.mod
|
||||
cp -a $VT_DIR/GRUB2/PXE/grub2/x86_64-efi/normal.mod $VT_DIR/INSTALL/grub/x86_64-efi/normal.mod || exit 1
|
||||
else
|
||||
rm -f $VT_DIR/GRUB2/NBP/core.0
|
||||
cp -a $VT_DIR/GRUB2/PXE/grub2/i386-pc/core.0 $VT_DIR/GRUB2/NBP/core.0 || exit 1
|
||||
|
||||
rm -f $VT_DIR/INSTALL/grub/i386-pc/boot.img
|
||||
cp -a $VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc/boot.img $VT_DIR/INSTALL/grub/i386-pc/boot.img || exit 1
|
||||
fi
|
|
@ -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
|
|
@ -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 ../../
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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'
|
|
@ -38,7 +38,7 @@ function ventoy_power {
|
|||
|
||||
function get_os_type {
|
||||
set vtoy_os=Linux
|
||||
for file in "efi/microsoft" "sources/boot.wim" "boot/bcd" "bootmgr.efi" "boot/etfsboot.com"; do
|
||||
for file in "efi/microsoft" "sources/boot.wim" "boot/bcd" "bootmgr.efi" "boot/etfsboot.com" "BOOT/etfsboot.com"; do
|
||||
if [ -e $1/$file ]; then
|
||||
set vtoy_os=Windows
|
||||
break
|
||||
|
@ -453,8 +453,7 @@ function common_menuentry {
|
|||
#############################################################
|
||||
#############################################################
|
||||
|
||||
set VENTOY_VERSION="1.0.9Y"
|
||||
|
||||
set VENTOY_VERSION="1.0.10"
|
||||
|
||||
# Default menu display mode, you can change it as you want.
|
||||
# 0: List mode
|
||||
|
@ -470,14 +469,6 @@ set VTOY_ISO_UEFI_DRV_STR="UEFI FS"
|
|||
|
||||
set VTOY_F2_CMD="ventoy_power"
|
||||
|
||||
if [ $VTOY_DEFAULT_MENU_MODE -eq 0 ]; then
|
||||
set VTOY_F3_CMD="vt_dynamic_menu 1 1"
|
||||
set VTOY_HOTKEY_TIP="F1:Memdisk F2:Power F3:TreeView"
|
||||
else
|
||||
set VTOY_F3_CMD="vt_dynamic_menu 1 0"
|
||||
set VTOY_HOTKEY_TIP="F1:Memdisk F2:Power F3:ListView"
|
||||
fi
|
||||
|
||||
if [ "$grub_platform" = "pc" ]; then
|
||||
set VTOY_TEXT_MENU_VER="Ventoy $VENTOY_VERSION BIOS www.ventoy.net"
|
||||
else
|
||||
|
@ -501,10 +492,21 @@ fi
|
|||
|
||||
loadfont ascii
|
||||
|
||||
#Load Plugin
|
||||
if [ -f $iso_path/ventoy/ventoy.json ]; then
|
||||
vt_load_plugin $iso_path
|
||||
fi
|
||||
|
||||
|
||||
if [ $VTOY_DEFAULT_MENU_MODE -eq 0 ]; then
|
||||
set VTOY_F3_CMD="vt_dynamic_menu 1 1"
|
||||
set VTOY_HOTKEY_TIP="F1:Memdisk F2:Power F3:TreeView"
|
||||
else
|
||||
set VTOY_F3_CMD="vt_dynamic_menu 1 0"
|
||||
set VTOY_HOTKEY_TIP="F1:Memdisk F2:Power F3:ListView"
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "$vtoy_gfxmode" ]; then
|
||||
set gfxmode=$vtoy_gfxmode
|
||||
else
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
#!/bin/sh
|
||||
|
||||
. ./tool/ventoy_lib.sh
|
||||
|
||||
GRUB_DIR=../GRUB2/INSTALL
|
||||
LANG_DIR=../LANGUAGES
|
||||
|
||||
if ! [ -d $GRUB_DIR ]; then
|
||||
echo "$GRUB_DIR not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
cd ../IMG
|
||||
sh mkcpio.sh
|
||||
cd -
|
||||
|
||||
|
||||
LOOP=$(losetup -f)
|
||||
|
||||
rm -f img.bin
|
||||
dd if=/dev/zero of=img.bin bs=1M count=256 status=none
|
||||
|
||||
losetup -P $LOOP img.bin
|
||||
|
||||
while ! grep -q 524288 /sys/block/${LOOP#/dev/}/size 2>/dev/null; do
|
||||
echo "wait $LOOP ..."
|
||||
sleep 1
|
||||
done
|
||||
|
||||
format_ventoy_disk $LOOP
|
||||
|
||||
$GRUB_DIR/sbin/grub-bios-setup --skip-fs-probe --directory="./grub/i386-pc" $LOOP
|
||||
|
||||
curver=$(get_ventoy_version_from_cfg ./grub/grub.cfg)
|
||||
|
||||
tmpmnt=./ventoy-${curver}-mnt
|
||||
tmpdir=./ventoy-${curver}
|
||||
|
||||
rm -rf $tmpmnt
|
||||
mkdir -p $tmpmnt
|
||||
|
||||
mount ${LOOP}p2 $tmpmnt
|
||||
|
||||
mkdir -p $tmpmnt/grub
|
||||
|
||||
# First copy grub.cfg file, to make it locate at front of the part2
|
||||
cp -a ./grub/grub.cfg $tmpmnt/grub/
|
||||
|
||||
ls -1 ./grub/ | grep -v 'grub\.cfg' | while read line; do
|
||||
cp -a ./grub/$line $tmpmnt/grub/
|
||||
done
|
||||
|
||||
cp -a ./ventoy $tmpmnt/
|
||||
cp -a ./EFI $tmpmnt/
|
||||
cp -a ./tool/ENROLL_THIS_KEY_IN_MOKMANAGER.cer $tmpmnt/
|
||||
|
||||
|
||||
mkdir -p $tmpmnt/tool
|
||||
cp -a ./tool/mount* $tmpmnt/tool/
|
||||
|
||||
rm -f $tmpmnt/grub/i386-pc/*
|
||||
|
||||
|
||||
umount $tmpmnt && rm -rf $tmpmnt
|
||||
|
||||
|
||||
rm -rf $tmpdir
|
||||
mkdir -p $tmpdir/boot
|
||||
mkdir -p $tmpdir/ventoy
|
||||
echo $curver > $tmpdir/ventoy/version
|
||||
dd if=$LOOP of=$tmpdir/boot/boot.img bs=1 count=512 status=none
|
||||
dd if=$LOOP of=$tmpdir/boot/core.img bs=512 count=2047 skip=1 status=none
|
||||
xz --check=crc32 $tmpdir/boot/core.img
|
||||
|
||||
cp -a ./tool $tmpdir/
|
||||
cp -a Ventoy2Disk.sh $tmpdir/
|
||||
|
||||
|
||||
#32MB disk img
|
||||
dd status=none if=$LOOP of=$tmpdir/ventoy/ventoy.disk.img bs=512 count=$VENTOY_SECTOR_NUM skip=$part2_start_sector
|
||||
xz --check=crc32 $tmpdir/ventoy/ventoy.disk.img
|
||||
|
||||
losetup -d $LOOP && rm -f img.bin
|
||||
|
||||
rm -f ventoy-${curver}-linux.tar.gz
|
||||
|
||||
|
||||
CurDir=$PWD
|
||||
cd $tmpdir/tool
|
||||
|
||||
for file in $(ls); do
|
||||
if [ "$file" != "xzcat" ] && [ "$file" != "ventoy_lib.sh" ]; then
|
||||
xz --check=crc32 $file
|
||||
fi
|
||||
done
|
||||
|
||||
cd $CurDir
|
||||
tar -czvf ventoy-${curver}-linux.tar.gz $tmpdir
|
||||
|
||||
rm -f ventoy-${curver}-windows.zip
|
||||
cp -a Ventoy2Disk.exe $tmpdir/
|
||||
cp -a $LANG_DIR/languages.ini $tmpdir/ventoy/
|
||||
rm -rf $tmpdir/tool
|
||||
rm -f $tmpdir/*.sh
|
||||
|
||||
|
||||
zip -r ventoy-${curver}-windows.zip $tmpdir/
|
||||
|
||||
rm -rf $tmpdir
|
||||
|
||||
if [ -e ventoy-${curver}-windows.zip ] && [ -e ventoy-${curver}-linux.tar.gz ]; then
|
||||
echo -e "\n ============= SUCCESS =================\n"
|
||||
else
|
||||
echo -e "\n ============= FAILED =================\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
========== About Source Code =============
|
||||
1. unpack ipxe_org_code/ipxe-3fe683e.tar.bz2
|
||||
2. After decompressing, delete ipxe-3fe683e/src/drivers (whole directory)
|
||||
3. Merge left source code with the ipxe-3fe683e directory here
|
||||
|
||||
========== Build =============
|
||||
make bin/ipxe.iso
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
rm -rf ipxe-3fe683e
|
||||
|
||||
tar -xvf ipxe_org_code/ipxe-3fe683e.tar.bz2 -C ./
|
||||
|
||||
rm -rf ./ipxe-3fe683e/src/bin
|
||||
rm -rf ./ipxe-3fe683e/src/drivers
|
||||
|
||||
/bin/cp -a ipxe_mod_code/ipxe-3fe683e ./
|
||||
|
||||
cd ipxe-3fe683e/src
|
||||
|
||||
sh build.sh
|
||||
|
||||
cd ../../
|
||||
|
|
@ -1374,6 +1374,25 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (catalog.boot.length > 4)
|
||||
{
|
||||
isolinux_boot_info *bootinfo = NULL;
|
||||
bootinfo = (isolinux_boot_info *)(real_to_user(address->segment, address->offset));
|
||||
if (0x7C6CEAFA == bootinfo->isolinux0 && 0x90900000 == bootinfo->isolinux1)
|
||||
{
|
||||
if (bootinfo->BootFileLocation == 0 && bootinfo->PvdLocation == 16 &&
|
||||
(bootinfo->BootFileLen / 2048) < catalog.boot.length && bootinfo->BootFileChecksum > 0)
|
||||
{
|
||||
if (g_debug)
|
||||
{
|
||||
printf("isolinux file location is 0, now fix it to %u ...\n", catalog.boot.start);
|
||||
ventoy_debug_pause();
|
||||
}
|
||||
bootinfo->BootFileLocation = catalog.boot.start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#!/bin/bash
|
||||
|
||||
build_bios() {
|
||||
rm -f bin/ipxe.iso
|
||||
|
||||
make -e -k -j 8 bin/ipxe.iso BIOS_MODE=BIOS
|
||||
|
||||
if ! [ -e bin/ipxe.iso ]; then
|
||||
echo "Failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p ./mnt
|
||||
mount bin/ipxe.iso ./mnt
|
||||
|
||||
rm -f ../../../INSTALL/ventoy/ipxe.krn
|
||||
cp -a ./mnt/ipxe.krn ../../../INSTALL/ventoy/ipxe.krn
|
||||
|
||||
umount ./mnt > /dev/null 2>&1
|
||||
umount ./mnt > /dev/null 2>&1
|
||||
umount ./mnt > /dev/null 2>&1
|
||||
|
||||
rm -rf ./mnt
|
||||
|
||||
echo -e "\n===============SUCCESS===============\n"
|
||||
}
|
||||
|
||||
|
||||
build_bios
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,48 @@
|
|||
#
|
||||
# Makefile
|
||||
#
|
||||
# Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
#
|
||||
# This file has been put into the public domain.
|
||||
# You can do whatever you want with this file.
|
||||
#
|
||||
|
||||
CC = /opt/diet32/bin/diet gcc -Os -m32 -std=gnu89
|
||||
BCJ_CPPFLAGS = -DXZ_DEC_X86 -DXZ_DEC_POWERPC -DXZ_DEC_IA64 \
|
||||
-DXZ_DEC_ARM -DXZ_DEC_ARMTHUMB -DXZ_DEC_SPARC
|
||||
CPPFLAGS = -DXZ_USE_CRC64 -DXZ_DEC_ANY_CHECK
|
||||
CFLAGS = -ggdb3 -O2 -pedantic -Wall -Wextra
|
||||
RM = rm -f
|
||||
VPATH = ../linux/include/linux ../linux/lib/xz
|
||||
COMMON_SRCS = xz_crc32.c xz_crc64.c xz_dec_stream.c xz_dec_lzma2.c xz_dec_bcj.c
|
||||
COMMON_OBJS = $(COMMON_SRCS:.c=.o)
|
||||
XZMINIDEC_OBJS = xzminidec.o
|
||||
BYTETEST_OBJS = bytetest.o
|
||||
BUFTEST_OBJS = buftest.o
|
||||
BOOTTEST_OBJS = boottest.o
|
||||
XZ_HEADERS = xz.h xz_private.h xz_stream.h xz_lzma2.h xz_config.h
|
||||
PROGRAMS = xzminidec bytetest buftest boottest
|
||||
|
||||
ALL_CPPFLAGS = -I../linux/include/linux -I. $(BCJ_CPPFLAGS) $(CPPFLAGS)
|
||||
|
||||
all: $(PROGRAMS)
|
||||
|
||||
%.o: %.c $(XZ_HEADERS)
|
||||
$(CC) $(ALL_CPPFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
xzminidec: $(COMMON_OBJS) $(XZMINIDEC_OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(COMMON_OBJS) $(XZMINIDEC_OBJS)
|
||||
|
||||
bytetest: $(COMMON_OBJS) $(BYTETEST_OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(COMMON_OBJS) $(BYTETEST_OBJS)
|
||||
|
||||
buftest: $(COMMON_OBJS) $(BUFTEST_OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(COMMON_OBJS) $(BUFTEST_OBJS)
|
||||
|
||||
boottest: $(BOOTTEST_OBJS) $(COMMON_SRCS)
|
||||
$(CC) $(ALL_CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(BOOTTEST_OBJS)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-$(RM) $(COMMON_OBJS) $(XZMINIDEC_OBJS) $(BUFTEST_OBJS) \
|
||||
$(BOOTTEST_OBJS) $(PROGRAMS)
|
|
@ -0,0 +1,20 @@
|
|||
Build a static linked, small zstdcat tool
|
||||
|
||||
======== Source Code ========
|
||||
use an old version of zstd
|
||||
https://codeload.github.com/facebook/zstd/zip/v1.0.0
|
||||
|
||||
======== Build Envrioment ========
|
||||
build for 32bit, static linked with dietlibc
|
||||
1. install centos 6.10 i386 with CentOS-6.10-i386-bin-DVD1.iso
|
||||
2. yum install gcc gettext gettext-devel
|
||||
3. install dietc libc (just make && make install)
|
||||
4. export PATH=$PATH:/opt/diet/bin
|
||||
|
||||
======== Build Step ========
|
||||
1. extract zstd source code
|
||||
2. cd programs
|
||||
3. diet -Os gcc -pipe -nostdinc -falign-loops=32 -I../lib -I../lib/common -I../lib/dictBuilder -I../lib/legacy -O3 -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef -DZSTD_LEGACY_SUPPORT=1 ../lib/decompress/zstd_decompress.c -c -o ../lib/decompress/zstd_decompress.o
|
||||
diet -Os gcc -pipe -nostdinc -I../lib -I../lib/common -I../lib/dictBuilder -I../lib/legacy -O3 -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef -DZSTD_LEGACY_SUPPORT=1 ../lib/decompress/zstd_decompress.o ../lib/decompress/huf_decompress.c ../lib/common/entropy_common.c ../lib/common/fse_decompress.c ../lib/common/xxhash.c ../lib/common/zstd_common.c ../lib/compress/zstd_compress.c ../lib/compress/fse_compress.c ../lib/compress/huf_compress.c ../lib/legacy/zstd_v01.c ../lib/legacy/zstd_v02.c ../lib/legacy/zstd_v03.c ../lib/legacy/zstd_v04.c ../lib/legacy/zstd_v05.c ../lib/legacy/zstd_v06.c ../lib/legacy/zstd_v07.c ../lib/dictBuilder/divsufsort.c ../lib/dictBuilder/zdict.c zstdcli.c fileio.c bench.c datagen.c dibio.c -o zstd
|
||||
4. strip --strip-all zstd
|
||||
5. rename zstd to zstdcat
|
Binary file not shown.
|
@ -1,3 +0,0 @@
|
|||
========= About fat_io_lib =========
|
||||
1. Download fat_io_lib source code from http://ultra-embedded.com/releases/fat_io_lib.zip
|
||||
2. decompress the code and run buildlib.sh
|
|
@ -1,8 +1,16 @@
|
|||
#!/bin/sh
|
||||
|
||||
if ! [ -f fat_io_lib.zip ]; then
|
||||
echo "No fat_io_lib.zip found ..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
unzip fat_io_lib.zip
|
||||
|
||||
rm -rf include
|
||||
rm -rf lib
|
||||
|
||||
|
||||
cd release
|
||||
gcc -O2 -D_FILE_OFFSET_BITS=64 fat*.c -c
|
||||
ar -rc libfat_io_64.a *.o
|
||||
|
|
Loading…
Reference in New Issue