diff --git a/GRUB2/grub-2.04/grub-core/disk/i386/pc/biosdisk.c b/GRUB2/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
index ee2ebe9c..a5146ff1 100644
--- a/GRUB2/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
+++ b/GRUB2/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
@@ -374,7 +374,7 @@ static int ventoy_is_mbr_match(ventoy_mbr_head *head)
return 0;
}
- if (head->PartTbl[0].FsFlag != 0x07 || head->PartTbl[0].StartSectorId != 2048) {
+ if (head->PartTbl[0].StartSectorId != 2048) {
return 0;
}
diff --git a/GRUB2/grub-2.04/grub-core/fs/ext2.c b/GRUB2/grub-2.04/grub-core/fs/ext2.c
new file mode 100644
index 00000000..eb0dae5e
--- /dev/null
+++ b/GRUB2/grub-2.04/grub-core/fs/ext2.c
@@ -0,0 +1,1100 @@
+/* ext2.c - Second Extended filesystem */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,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 .
+ */
+
+/* Magic value used to identify an ext2 filesystem. */
+#define EXT2_MAGIC 0xEF53
+/* Amount of indirect blocks in an inode. */
+#define INDIRECT_BLOCKS 12
+
+/* The good old revision and the default inode size. */
+#define EXT2_GOOD_OLD_REVISION 0
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/* Filetype used in directory entry. */
+#define FILETYPE_UNKNOWN 0
+#define FILETYPE_REG 1
+#define FILETYPE_DIRECTORY 2
+#define FILETYPE_SYMLINK 7
+
+/* Filetype information as used in inodes. */
+#define FILETYPE_INO_MASK 0170000
+#define FILETYPE_INO_REG 0100000
+#define FILETYPE_INO_DIRECTORY 0040000
+#define FILETYPE_INO_SYMLINK 0120000
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Log2 size of ext2 block in 512 blocks. */
+#define LOG2_EXT2_BLOCK_SIZE(data) \
+ (grub_le_to_cpu32 (data->sblock.log2_block_size) + 1)
+
+/* Log2 size of ext2 block in bytes. */
+#define LOG2_BLOCK_SIZE(data) \
+ (grub_le_to_cpu32 (data->sblock.log2_block_size) + 10)
+
+/* The size of an ext2 block in bytes. */
+#define EXT2_BLOCK_SIZE(data) (1U << LOG2_BLOCK_SIZE (data))
+
+/* The revision level. */
+#define EXT2_REVISION(data) grub_le_to_cpu32 (data->sblock.revision_level)
+
+/* The inode size. */
+#define EXT2_INODE_SIZE(data) \
+ (data->sblock.revision_level \
+ == grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION) \
+ ? EXT2_GOOD_OLD_INODE_SIZE \
+ : grub_le_to_cpu16 (data->sblock.inode_size))
+
+/* Superblock filesystem feature flags (RW compatible)
+ * A filesystem with any of these enabled can be read and written by a driver
+ * that does not understand them without causing metadata/data corruption. */
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
+#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
+#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
+/* Superblock filesystem feature flags (RO compatible)
+ * A filesystem with any of these enabled can be safely read by a driver that
+ * does not understand them, but should not be written to, usually because
+ * additional metadata is required. */
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
+/* Superblock filesystem feature flags (back-incompatible)
+ * A filesystem with any of these enabled should not be attempted to be read
+ * by a driver that does not understand them, since they usually indicate
+ * metadata format changes that might confuse the reader. */
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Volume is journal device */
+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* Extents used */
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
+#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
+#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
+
+/* The set of back-incompatible features this driver DOES support. Add (OR)
+ * flags here as the related features are implemented into the driver. */
+#define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
+ | EXT4_FEATURE_INCOMPAT_EXTENTS \
+ | EXT4_FEATURE_INCOMPAT_FLEX_BG \
+ | EXT2_FEATURE_INCOMPAT_META_BG \
+ | EXT4_FEATURE_INCOMPAT_64BIT \
+ | EXT4_FEATURE_INCOMPAT_ENCRYPT)
+/* List of rationales for the ignored "incompatible" features:
+ * needs_recovery: Not really back-incompatible - was added as such to forbid
+ * ext2 drivers from mounting an ext3 volume with a dirty
+ * journal because they will ignore the journal, but the next
+ * ext3 driver to mount the volume will find the journal and
+ * replay it, potentially corrupting the metadata written by
+ * the ext2 drivers. Safe to ignore for this RO driver.
+ * mmp: Not really back-incompatible - was added as such to
+ * avoid multiple read-write mounts. Safe to ignore for this
+ * RO driver.
+ */
+#define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \
+ | EXT4_FEATURE_INCOMPAT_MMP)
+
+
+#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
+
+#define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1
+#define EXT3_JOURNAL_COMMIT_BLOCK 2
+#define EXT3_JOURNAL_SUPERBLOCK_V1 3
+#define EXT3_JOURNAL_SUPERBLOCK_V2 4
+#define EXT3_JOURNAL_REVOKE_BLOCK 5
+
+#define EXT3_JOURNAL_FLAG_ESCAPE 1
+#define EXT3_JOURNAL_FLAG_SAME_UUID 2
+#define EXT3_JOURNAL_FLAG_DELETED 4
+#define EXT3_JOURNAL_FLAG_LAST_TAG 8
+
+#define EXT4_ENCRYPT_FLAG 0x800
+#define EXT4_EXTENTS_FLAG 0x80000
+
+/* The ext2 superblock. */
+struct grub_ext2_sblock
+{
+ grub_uint32_t total_inodes;
+ grub_uint32_t total_blocks;
+ grub_uint32_t reserved_blocks;
+ grub_uint32_t free_blocks;
+ grub_uint32_t free_inodes;
+ grub_uint32_t first_data_block;
+ grub_uint32_t log2_block_size;
+ grub_uint32_t log2_fragment_size;
+ grub_uint32_t blocks_per_group;
+ grub_uint32_t fragments_per_group;
+ grub_uint32_t inodes_per_group;
+ grub_uint32_t mtime;
+ grub_uint32_t utime;
+ grub_uint16_t mnt_count;
+ grub_uint16_t max_mnt_count;
+ grub_uint16_t magic;
+ grub_uint16_t fs_state;
+ grub_uint16_t error_handling;
+ grub_uint16_t minor_revision_level;
+ grub_uint32_t lastcheck;
+ grub_uint32_t checkinterval;
+ grub_uint32_t creator_os;
+ grub_uint32_t revision_level;
+ grub_uint16_t uid_reserved;
+ grub_uint16_t gid_reserved;
+ grub_uint32_t first_inode;
+ grub_uint16_t inode_size;
+ grub_uint16_t block_group_number;
+ grub_uint32_t feature_compatibility;
+ grub_uint32_t feature_incompat;
+ grub_uint32_t feature_ro_compat;
+ grub_uint16_t uuid[8];
+ char volume_name[16];
+ char last_mounted_on[64];
+ grub_uint32_t compression_info;
+ grub_uint8_t prealloc_blocks;
+ grub_uint8_t prealloc_dir_blocks;
+ grub_uint16_t reserved_gdt_blocks;
+ grub_uint8_t journal_uuid[16];
+ grub_uint32_t journal_inum;
+ grub_uint32_t journal_dev;
+ grub_uint32_t last_orphan;
+ grub_uint32_t hash_seed[4];
+ grub_uint8_t def_hash_version;
+ grub_uint8_t jnl_backup_type;
+ grub_uint16_t group_desc_size;
+ grub_uint32_t default_mount_opts;
+ grub_uint32_t first_meta_bg;
+ grub_uint32_t mkfs_time;
+ grub_uint32_t jnl_blocks[17];
+};
+
+/* The ext2 blockgroup. */
+struct grub_ext2_block_group
+{
+ grub_uint32_t block_id;
+ grub_uint32_t inode_id;
+ grub_uint32_t inode_table_id;
+ grub_uint16_t free_blocks;
+ grub_uint16_t free_inodes;
+ grub_uint16_t used_dirs;
+ grub_uint16_t pad;
+ grub_uint32_t reserved[3];
+ grub_uint32_t block_id_hi;
+ grub_uint32_t inode_id_hi;
+ grub_uint32_t inode_table_id_hi;
+ grub_uint16_t free_blocks_hi;
+ grub_uint16_t free_inodes_hi;
+ grub_uint16_t used_dirs_hi;
+ grub_uint16_t pad2;
+ grub_uint32_t reserved2[3];
+};
+
+/* The ext2 inode. */
+struct grub_ext2_inode
+{
+ grub_uint16_t mode;
+ grub_uint16_t uid;
+ grub_uint32_t size;
+ grub_uint32_t atime;
+ grub_uint32_t ctime;
+ grub_uint32_t mtime;
+ grub_uint32_t dtime;
+ grub_uint16_t gid;
+ grub_uint16_t nlinks;
+ grub_uint32_t blockcnt; /* Blocks of 512 bytes!! */
+ grub_uint32_t flags;
+ grub_uint32_t osd1;
+ union
+ {
+ struct datablocks
+ {
+ grub_uint32_t dir_blocks[INDIRECT_BLOCKS];
+ grub_uint32_t indir_block;
+ grub_uint32_t double_indir_block;
+ grub_uint32_t triple_indir_block;
+ } blocks;
+ char symlink[60];
+ };
+ grub_uint32_t version;
+ grub_uint32_t acl;
+ grub_uint32_t size_high;
+ grub_uint32_t fragment_addr;
+ grub_uint32_t osd2[3];
+};
+
+/* The header of an ext2 directory entry. */
+struct ext2_dirent
+{
+ grub_uint32_t inode;
+ grub_uint16_t direntlen;
+#define MAX_NAMELEN 255
+ grub_uint8_t namelen;
+ grub_uint8_t filetype;
+};
+
+struct grub_ext3_journal_header
+{
+ grub_uint32_t magic;
+ grub_uint32_t block_type;
+ grub_uint32_t sequence;
+};
+
+struct grub_ext3_journal_revoke_header
+{
+ struct grub_ext3_journal_header header;
+ grub_uint32_t count;
+ grub_uint32_t data[0];
+};
+
+struct grub_ext3_journal_block_tag
+{
+ grub_uint32_t block;
+ grub_uint32_t flags;
+};
+
+struct grub_ext3_journal_sblock
+{
+ struct grub_ext3_journal_header header;
+ grub_uint32_t block_size;
+ grub_uint32_t maxlen;
+ grub_uint32_t first;
+ grub_uint32_t sequence;
+ grub_uint32_t start;
+};
+
+#define EXT4_EXT_MAGIC 0xf30a
+
+struct grub_ext4_extent_header
+{
+ grub_uint16_t magic;
+ grub_uint16_t entries;
+ grub_uint16_t max;
+ grub_uint16_t depth;
+ grub_uint32_t generation;
+};
+
+struct grub_ext4_extent
+{
+ grub_uint32_t block;
+ grub_uint16_t len;
+ grub_uint16_t start_hi;
+ grub_uint32_t start;
+};
+
+struct grub_ext4_extent_idx
+{
+ grub_uint32_t block;
+ grub_uint32_t leaf;
+ grub_uint16_t leaf_hi;
+ grub_uint16_t unused;
+};
+
+struct grub_fshelp_node
+{
+ struct grub_ext2_data *data;
+ struct grub_ext2_inode inode;
+ int ino;
+ int inode_read;
+};
+
+/* Information about a "mounted" ext2 filesystem. */
+struct grub_ext2_data
+{
+ struct grub_ext2_sblock sblock;
+ int log_group_desc_size;
+ grub_disk_t disk;
+ struct grub_ext2_inode *inode;
+ struct grub_fshelp_node diropen;
+};
+
+static grub_dl_t my_mod;
+
+
+
+/* Check is a = b^x for some x. */
+static inline int
+is_power_of (grub_uint64_t a, grub_uint32_t b)
+{
+ grub_uint64_t c;
+ /* Prevent overflow assuming b < 8. */
+ if (a >= (1LL << 60))
+ return 0;
+ for (c = 1; c <= a; c *= b);
+ return (c == a);
+}
+
+
+static inline int
+group_has_super_block (struct grub_ext2_data *data, grub_uint64_t group)
+{
+ if (!(data->sblock.feature_ro_compat
+ & grub_cpu_to_le32_compile_time(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)))
+ return 1;
+ /* Algorithm looked up in Linux source. */
+ if (group <= 1)
+ return 1;
+ /* Even number is never a power of odd number. */
+ if (!(group & 1))
+ return 0;
+ return (is_power_of(group, 7) || is_power_of(group, 5) ||
+ is_power_of(group, 3));
+}
+
+/* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
+ the mounted filesystem DATA. */
+inline static grub_err_t
+grub_ext2_blockgroup (struct grub_ext2_data *data, grub_uint64_t group,
+ struct grub_ext2_block_group *blkgrp)
+{
+ grub_uint64_t full_offset = (group << data->log_group_desc_size);
+ grub_uint64_t block, offset;
+ block = (full_offset >> LOG2_BLOCK_SIZE (data));
+ offset = (full_offset & ((1 << LOG2_BLOCK_SIZE (data)) - 1));
+ if ((data->sblock.feature_incompat
+ & grub_cpu_to_le32_compile_time (EXT2_FEATURE_INCOMPAT_META_BG))
+ && block >= grub_le_to_cpu32(data->sblock.first_meta_bg))
+ {
+ grub_uint64_t first_block_group;
+ /* Find the first block group for which a descriptor
+ is stored in given block. */
+ first_block_group = (block << (LOG2_BLOCK_SIZE (data)
+ - data->log_group_desc_size));
+
+ block = (first_block_group
+ * grub_le_to_cpu32(data->sblock.blocks_per_group));
+
+ if (group_has_super_block (data, first_block_group))
+ block++;
+ }
+ else
+ /* Superblock. */
+ block++;
+ return grub_disk_read (data->disk,
+ ((grub_le_to_cpu32 (data->sblock.first_data_block)
+ + block)
+ << LOG2_EXT2_BLOCK_SIZE (data)), offset,
+ sizeof (struct grub_ext2_block_group), blkgrp);
+}
+
+static struct grub_ext4_extent_header *
+grub_ext4_find_leaf (struct grub_ext2_data *data,
+ struct grub_ext4_extent_header *ext_block,
+ grub_uint32_t fileblock)
+{
+ struct grub_ext4_extent_idx *index;
+ void *buf = NULL;
+
+ while (1)
+ {
+ int i;
+ grub_disk_addr_t block;
+
+ index = (struct grub_ext4_extent_idx *) (ext_block + 1);
+
+ if (ext_block->magic != grub_cpu_to_le16_compile_time (EXT4_EXT_MAGIC))
+ goto fail;
+
+ if (ext_block->depth == 0)
+ return ext_block;
+
+ for (i = 0; i < grub_le_to_cpu16 (ext_block->entries); i++)
+ {
+ if (fileblock < grub_le_to_cpu32(index[i].block))
+ break;
+ }
+
+ if (--i < 0)
+ goto fail;
+
+ block = grub_le_to_cpu16 (index[i].leaf_hi);
+ block = (block << 32) | grub_le_to_cpu32 (index[i].leaf);
+ if (!buf)
+ buf = grub_malloc (EXT2_BLOCK_SIZE(data));
+ if (!buf)
+ goto fail;
+ if (grub_disk_read (data->disk,
+ block << LOG2_EXT2_BLOCK_SIZE (data),
+ 0, EXT2_BLOCK_SIZE(data), buf))
+ goto fail;
+
+ ext_block = buf;
+ }
+ fail:
+ grub_free (buf);
+ return 0;
+}
+
+static grub_disk_addr_t
+grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+{
+ struct grub_ext2_data *data = node->data;
+ struct grub_ext2_inode *inode = &node->inode;
+ unsigned int blksz = EXT2_BLOCK_SIZE (data);
+ grub_disk_addr_t blksz_quarter = blksz / 4;
+ int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
+ int log_perblock = log2_blksz + 9 - 2;
+ grub_uint32_t indir;
+ int shift;
+
+ if (inode->flags & grub_cpu_to_le32_compile_time (EXT4_EXTENTS_FLAG))
+ {
+ struct grub_ext4_extent_header *leaf;
+ struct grub_ext4_extent *ext;
+ int i;
+ grub_disk_addr_t ret;
+
+ leaf = grub_ext4_find_leaf (data, (struct grub_ext4_extent_header *) inode->blocks.dir_blocks, fileblock);
+ if (! leaf)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "invalid extent");
+ return -1;
+ }
+
+ ext = (struct grub_ext4_extent *) (leaf + 1);
+ for (i = 0; i < grub_le_to_cpu16 (leaf->entries); i++)
+ {
+ if (fileblock < grub_le_to_cpu32 (ext[i].block))
+ break;
+ }
+
+ if (--i >= 0)
+ {
+ fileblock -= grub_le_to_cpu32 (ext[i].block);
+ if (fileblock >= grub_le_to_cpu16 (ext[i].len))
+ ret = 0;
+ else
+ {
+ grub_disk_addr_t start;
+
+ start = grub_le_to_cpu16 (ext[i].start_hi);
+ start = (start << 32) + grub_le_to_cpu32 (ext[i].start);
+
+ ret = fileblock + start;
+ }
+ }
+ else
+ {
+ grub_error (GRUB_ERR_BAD_FS, "something wrong with extent");
+ ret = -1;
+ }
+
+ if (leaf != (struct grub_ext4_extent_header *) inode->blocks.dir_blocks)
+ grub_free (leaf);
+
+ return ret;
+ }
+
+ /* Direct blocks. */
+ if (fileblock < INDIRECT_BLOCKS)
+ return grub_le_to_cpu32 (inode->blocks.dir_blocks[fileblock]);
+ fileblock -= INDIRECT_BLOCKS;
+ /* Indirect. */
+ if (fileblock < blksz_quarter)
+ {
+ indir = inode->blocks.indir_block;
+ shift = 0;
+ goto indirect;
+ }
+ fileblock -= blksz_quarter;
+ /* Double indirect. */
+ if (fileblock < blksz_quarter * blksz_quarter)
+ {
+ indir = inode->blocks.double_indir_block;
+ shift = 1;
+ goto indirect;
+ }
+ fileblock -= blksz_quarter * blksz_quarter;
+ /* Triple indirect. */
+ if (fileblock < blksz_quarter * blksz_quarter * (blksz_quarter + 1))
+ {
+ indir = inode->blocks.triple_indir_block;
+ shift = 2;
+ goto indirect;
+ }
+ grub_error (GRUB_ERR_BAD_FS,
+ "ext2fs doesn't support quadruple indirect blocks");
+ return -1;
+
+indirect:
+ do {
+ /* If the indirect block is zero, all child blocks are absent
+ (i.e. filled with zeros.) */
+ if (indir == 0)
+ return 0;
+ if (grub_disk_read (data->disk,
+ ((grub_disk_addr_t) grub_le_to_cpu32 (indir))
+ << log2_blksz,
+ ((fileblock >> (log_perblock * shift))
+ & ((1 << log_perblock) - 1))
+ * sizeof (indir),
+ sizeof (indir), &indir))
+ return -1;
+ } while (shift--);
+
+ return grub_le_to_cpu32 (indir);
+}
+
+/* Read LEN bytes from the file described by DATA starting with byte
+ POS. Return the amount of read bytes in READ. */
+static grub_ssize_t
+grub_ext2_read_file (grub_fshelp_node_t node,
+ grub_disk_read_hook_t read_hook, void *read_hook_data,
+ grub_off_t pos, grub_size_t len, char *buf)
+{
+ return grub_fshelp_read_file (node->data->disk, node,
+ read_hook, read_hook_data,
+ pos, len, buf, grub_ext2_read_block,
+ grub_cpu_to_le32 (node->inode.size)
+ | (((grub_off_t) grub_cpu_to_le32 (node->inode.size_high)) << 32),
+ LOG2_EXT2_BLOCK_SIZE (node->data), 0);
+
+}
+
+
+/* Read the inode INO for the file described by DATA into INODE. */
+static grub_err_t
+grub_ext2_read_inode (struct grub_ext2_data *data,
+ int ino, struct grub_ext2_inode *inode)
+{
+ struct grub_ext2_block_group blkgrp;
+ struct grub_ext2_sblock *sblock = &data->sblock;
+ int inodes_per_block;
+ unsigned int blkno;
+ unsigned int blkoff;
+ grub_disk_addr_t base;
+
+ /* It is easier to calculate if the first inode is 0. */
+ ino--;
+
+ grub_ext2_blockgroup (data,
+ ino / grub_le_to_cpu32 (sblock->inodes_per_group),
+ &blkgrp);
+ if (grub_errno)
+ return grub_errno;
+
+ inodes_per_block = EXT2_BLOCK_SIZE (data) / EXT2_INODE_SIZE (data);
+ blkno = (ino % grub_le_to_cpu32 (sblock->inodes_per_group))
+ / inodes_per_block;
+ blkoff = (ino % grub_le_to_cpu32 (sblock->inodes_per_group))
+ % inodes_per_block;
+
+ base = grub_le_to_cpu32 (blkgrp.inode_table_id);
+ if (data->log_group_desc_size >= 6)
+ base |= (((grub_disk_addr_t) grub_le_to_cpu32 (blkgrp.inode_table_id_hi))
+ << 32);
+
+ /* Read the inode. */
+ if (grub_disk_read (data->disk,
+ ((base + blkno) << LOG2_EXT2_BLOCK_SIZE (data)),
+ EXT2_INODE_SIZE (data) * blkoff,
+ sizeof (struct grub_ext2_inode), inode))
+ return grub_errno;
+
+ return 0;
+}
+
+static struct grub_ext2_data *
+grub_ext2_mount (grub_disk_t disk)
+{
+ struct grub_ext2_data *data;
+
+ data = grub_malloc (sizeof (struct grub_ext2_data));
+ if (!data)
+ return 0;
+
+ /* Read the superblock. */
+ grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_ext2_sblock),
+ &data->sblock);
+ if (grub_errno)
+ goto fail;
+
+ /* Make sure this is an ext2 filesystem. */
+ if (data->sblock.magic != grub_cpu_to_le16_compile_time (EXT2_MAGIC)
+ || grub_le_to_cpu32 (data->sblock.log2_block_size) >= 16
+ || data->sblock.inodes_per_group == 0
+ /* 20 already means 1GiB blocks. We don't want to deal with blocks overflowing int32. */
+ || grub_le_to_cpu32 (data->sblock.log2_block_size) > 20
+ || EXT2_INODE_SIZE (data) == 0
+ || EXT2_BLOCK_SIZE (data) / EXT2_INODE_SIZE (data) == 0)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "not an ext2 filesystem");
+ goto fail;
+ }
+
+ /* Check the FS doesn't have feature bits enabled that we don't support. */
+ if (data->sblock.revision_level != grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION)
+ && (data->sblock.feature_incompat
+ & grub_cpu_to_le32_compile_time (~(EXT2_DRIVER_SUPPORTED_INCOMPAT
+ | EXT2_DRIVER_IGNORED_INCOMPAT))))
+ {
+ grub_error (GRUB_ERR_BAD_FS, "filesystem has unsupported incompatible features");
+ goto fail;
+ }
+
+ if (data->sblock.revision_level != grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION)
+ && (data->sblock.feature_incompat
+ & grub_cpu_to_le32_compile_time (EXT4_FEATURE_INCOMPAT_64BIT))
+ && data->sblock.group_desc_size != 0
+ && ((data->sblock.group_desc_size & (data->sblock.group_desc_size - 1))
+ == 0)
+ && (data->sblock.group_desc_size & grub_cpu_to_le16_compile_time (0x1fe0)))
+ {
+ grub_uint16_t b = grub_le_to_cpu16 (data->sblock.group_desc_size);
+ for (data->log_group_desc_size = 0; b != (1 << data->log_group_desc_size);
+ data->log_group_desc_size++);
+ }
+ else
+ data->log_group_desc_size = 5;
+
+ data->disk = disk;
+
+ data->diropen.data = data;
+ data->diropen.ino = 2;
+ data->diropen.inode_read = 1;
+
+ data->inode = &data->diropen.inode;
+
+ grub_ext2_read_inode (data, 2, data->inode);
+ if (grub_errno)
+ goto fail;
+
+ return data;
+
+ fail:
+ if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
+ grub_error (GRUB_ERR_BAD_FS, "not an ext2 filesystem");
+
+ grub_free (data);
+ return 0;
+}
+
+static char *
+grub_ext2_read_symlink (grub_fshelp_node_t node)
+{
+ char *symlink;
+ struct grub_fshelp_node *diro = node;
+
+ if (! diro->inode_read)
+ {
+ grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
+ if (grub_errno)
+ return 0;
+
+ if (diro->inode.flags & grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG))
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "symlink is encrypted");
+ return 0;
+ }
+ }
+
+ symlink = grub_malloc (grub_le_to_cpu32 (diro->inode.size) + 1);
+ if (! symlink)
+ return 0;
+
+ /* If the filesize of the symlink is bigger than
+ 60 the symlink is stored in a separate block,
+ otherwise it is stored in the inode. */
+ if (grub_le_to_cpu32 (diro->inode.size) <= sizeof (diro->inode.symlink))
+ grub_memcpy (symlink,
+ diro->inode.symlink,
+ grub_le_to_cpu32 (diro->inode.size));
+ else
+ {
+ grub_ext2_read_file (diro, 0, 0, 0,
+ grub_le_to_cpu32 (diro->inode.size),
+ symlink);
+ if (grub_errno)
+ {
+ grub_free (symlink);
+ return 0;
+ }
+ }
+
+ symlink[grub_le_to_cpu32 (diro->inode.size)] = '\0';
+ return symlink;
+}
+
+static int
+grub_ext2_iterate_dir (grub_fshelp_node_t dir,
+ grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
+{
+ unsigned int fpos = 0;
+ struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
+
+ if (! diro->inode_read)
+ {
+ grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
+ if (grub_errno)
+ return 0;
+ }
+
+ if (diro->inode.flags & grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG))
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "directory is encrypted");
+ return 0;
+ }
+
+ /* Search the file. */
+ while (fpos < grub_le_to_cpu32 (diro->inode.size))
+ {
+ struct ext2_dirent dirent;
+
+ grub_ext2_read_file (diro, 0, 0, fpos, sizeof (struct ext2_dirent),
+ (char *) &dirent);
+ if (grub_errno)
+ return 0;
+
+ if (dirent.direntlen == 0)
+ return 0;
+
+ if (dirent.inode != 0 && dirent.namelen != 0)
+ {
+ char filename[MAX_NAMELEN + 1];
+ struct grub_fshelp_node *fdiro;
+ enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
+
+ grub_ext2_read_file (diro, 0, 0, fpos + sizeof (struct ext2_dirent),
+ dirent.namelen, filename);
+ if (grub_errno)
+ return 0;
+
+ fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
+ if (! fdiro)
+ return 0;
+
+ fdiro->data = diro->data;
+ fdiro->ino = grub_le_to_cpu32 (dirent.inode);
+
+ filename[dirent.namelen] = '\0';
+
+ if (dirent.filetype != FILETYPE_UNKNOWN)
+ {
+ fdiro->inode_read = 0;
+
+ if (dirent.filetype == FILETYPE_DIRECTORY)
+ type = GRUB_FSHELP_DIR;
+ else if (dirent.filetype == FILETYPE_SYMLINK)
+ type = GRUB_FSHELP_SYMLINK;
+ else if (dirent.filetype == FILETYPE_REG)
+ type = GRUB_FSHELP_REG;
+ }
+ else
+ {
+ /* The filetype can not be read from the dirent, read
+ the inode to get more information. */
+ grub_ext2_read_inode (diro->data,
+ grub_le_to_cpu32 (dirent.inode),
+ &fdiro->inode);
+ if (grub_errno)
+ {
+ grub_free (fdiro);
+ return 0;
+ }
+
+ fdiro->inode_read = 1;
+
+ if ((grub_le_to_cpu16 (fdiro->inode.mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
+ type = GRUB_FSHELP_DIR;
+ else if ((grub_le_to_cpu16 (fdiro->inode.mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
+ type = GRUB_FSHELP_SYMLINK;
+ else if ((grub_le_to_cpu16 (fdiro->inode.mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
+ type = GRUB_FSHELP_REG;
+ }
+
+ if (hook (filename, type, fdiro, hook_data))
+ return 1;
+ }
+
+ fpos += grub_le_to_cpu16 (dirent.direntlen);
+ }
+
+ return 0;
+}
+
+/* Open a file named NAME and initialize FILE. */
+static grub_err_t
+grub_ext2_open (struct grub_file *file, const char *name)
+{
+ struct grub_ext2_data *data;
+ struct grub_fshelp_node *fdiro = 0;
+ grub_err_t err;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_ext2_mount (file->device->disk);
+ if (! data)
+ {
+ err = grub_errno;
+ goto fail;
+ }
+
+ err = grub_fshelp_find_file (name, &data->diropen, &fdiro,
+ grub_ext2_iterate_dir,
+ grub_ext2_read_symlink, GRUB_FSHELP_REG);
+ if (err)
+ goto fail;
+
+ if (! fdiro->inode_read)
+ {
+ err = grub_ext2_read_inode (data, fdiro->ino, &fdiro->inode);
+ if (err)
+ goto fail;
+ }
+
+ if (fdiro->inode.flags & grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG))
+ {
+ err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "file is encrypted");
+ goto fail;
+ }
+
+ grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_ext2_inode));
+ grub_free (fdiro);
+
+ file->size = grub_le_to_cpu32 (data->inode->size);
+ file->size |= ((grub_off_t) grub_le_to_cpu32 (data->inode->size_high)) << 32;
+ file->data = data;
+ file->offset = 0;
+
+ return 0;
+
+ fail:
+ if (fdiro != &data->diropen)
+ grub_free (fdiro);
+ grub_free (data);
+
+ grub_dl_unref (my_mod);
+
+ return err;
+}
+
+static grub_err_t
+grub_ext2_close (grub_file_t file)
+{
+ grub_free (file->data);
+
+ grub_dl_unref (my_mod);
+
+ return GRUB_ERR_NONE;
+}
+
+/* Read LEN bytes data from FILE into BUF. */
+static grub_ssize_t
+grub_ext2_read (grub_file_t file, char *buf, grub_size_t len)
+{
+ struct grub_ext2_data *data = (struct grub_ext2_data *) file->data;
+
+ return grub_ext2_read_file (&data->diropen,
+ file->read_hook, file->read_hook_data,
+ file->offset, len, buf);
+}
+
+
+/* Context for grub_ext2_dir. */
+struct grub_ext2_dir_ctx
+{
+ grub_fs_dir_hook_t hook;
+ void *hook_data;
+ struct grub_ext2_data *data;
+};
+
+/* Helper for grub_ext2_dir. */
+static int
+grub_ext2_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node, void *data)
+{
+ struct grub_ext2_dir_ctx *ctx = data;
+ struct grub_dirhook_info info;
+
+ grub_memset (&info, 0, sizeof (info));
+ if (! node->inode_read)
+ {
+ grub_ext2_read_inode (ctx->data, node->ino, &node->inode);
+ if (!grub_errno)
+ node->inode_read = 1;
+ grub_errno = GRUB_ERR_NONE;
+ }
+ if (node->inode_read)
+ {
+ info.mtimeset = 1;
+ info.mtime = grub_le_to_cpu32 (node->inode.mtime);
+ }
+
+ info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+ if (!info.dir)
+ info.size = (((grub_off_t) grub_le_to_cpu32 (node->inode.size_high)) << 32) | grub_le_to_cpu32 (node->inode.size);
+ grub_free (node);
+ return ctx->hook (filename, &info, ctx->hook_data);
+}
+
+static grub_err_t
+grub_ext2_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
+ void *hook_data)
+{
+ struct grub_ext2_dir_ctx ctx = {
+ .hook = hook,
+ .hook_data = hook_data
+ };
+ struct grub_fshelp_node *fdiro = 0;
+
+ grub_dl_ref (my_mod);
+
+ ctx.data = grub_ext2_mount (device->disk);
+ if (! ctx.data)
+ goto fail;
+
+ grub_fshelp_find_file (path, &ctx.data->diropen, &fdiro,
+ grub_ext2_iterate_dir, grub_ext2_read_symlink,
+ GRUB_FSHELP_DIR);
+ if (grub_errno)
+ goto fail;
+
+ grub_ext2_iterate_dir (fdiro, grub_ext2_dir_iter, &ctx);
+
+ fail:
+ if (fdiro != &ctx.data->diropen)
+ grub_free (fdiro);
+ grub_free (ctx.data);
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_ext2_label (grub_device_t device, char **label)
+{
+ struct grub_ext2_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_ext2_mount (disk);
+ if (data)
+ *label = grub_strndup (data->sblock.volume_name,
+ sizeof (data->sblock.volume_name));
+ else
+ *label = NULL;
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_ext2_uuid (grub_device_t device, char **uuid)
+{
+ struct grub_ext2_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_ext2_mount (disk);
+ if (data)
+ {
+ *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
+ grub_be_to_cpu16 (data->sblock.uuid[0]),
+ grub_be_to_cpu16 (data->sblock.uuid[1]),
+ grub_be_to_cpu16 (data->sblock.uuid[2]),
+ grub_be_to_cpu16 (data->sblock.uuid[3]),
+ grub_be_to_cpu16 (data->sblock.uuid[4]),
+ grub_be_to_cpu16 (data->sblock.uuid[5]),
+ grub_be_to_cpu16 (data->sblock.uuid[6]),
+ grub_be_to_cpu16 (data->sblock.uuid[7]));
+ }
+ else
+ *uuid = NULL;
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+/* Get mtime. */
+static grub_err_t
+grub_ext2_mtime (grub_device_t device, grub_int32_t *tm)
+{
+ struct grub_ext2_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_ext2_mount (disk);
+ if (!data)
+ *tm = 0;
+ else
+ *tm = grub_le_to_cpu32 (data->sblock.utime);
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+
+}
+
+
+
+static struct grub_fs grub_ext2_fs =
+ {
+ .name = "ext2",
+ .fs_dir = grub_ext2_dir,
+ .fs_open = grub_ext2_open,
+ .fs_read = grub_ext2_read,
+ .fs_close = grub_ext2_close,
+ .fs_label = grub_ext2_label,
+ .fs_uuid = grub_ext2_uuid,
+ .fs_mtime = grub_ext2_mtime,
+#ifdef GRUB_UTIL
+ .reserved_first_sector = 1,
+ .blocklist_install = 1,
+#endif
+ .next = 0
+ };
+
+GRUB_MOD_INIT(ext2)
+{
+ grub_fs_register (&grub_ext2_fs);
+ my_mod = mod;
+}
+
+GRUB_MOD_FINI(ext2)
+{
+ grub_fs_unregister (&grub_ext2_fs);
+}
diff --git a/GRUB2/grub-2.04/grub-core/fs/fat.c b/GRUB2/grub-2.04/grub-core/fs/fat.c
index 6d4ce0d5..439ec410 100644
--- a/GRUB2/grub-2.04/grub-core/fs/fat.c
+++ b/GRUB2/grub-2.04/grub-core/fs/fat.c
@@ -965,10 +965,8 @@ grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
info.dir = !! (ctxt.dir.attr & GRUB_FAT_ATTR_DIRECTORY);
info.case_insensitive = 1;
- #ifdef MODE_EXFAT
if (!info.dir)
info.size = ctxt.dir.file_size;
- #endif
#ifdef MODE_EXFAT
if (!ctxt.dir.have_stream)
@@ -1276,54 +1274,6 @@ GRUB_MOD_FINI(fat)
#ifdef MODE_EXFAT
-static int grub_fat_add_chunk(ventoy_img_chunk_list *chunk_list, grub_uint64_t sector, grub_uint64_t size, grub_uint32_t log_sector_size)
-{
- ventoy_img_chunk *last_chunk;
- ventoy_img_chunk *new_chunk;
-
- if (chunk_list->cur_chunk == 0)
- {
- chunk_list->chunk[0].img_start_sector = 0;
- chunk_list->chunk[0].img_end_sector = (size >> 11) - 1;
- chunk_list->chunk[0].disk_start_sector = sector;
- chunk_list->chunk[0].disk_end_sector = sector + (size >> log_sector_size) - 1;
- chunk_list->cur_chunk = 1;
- return 0;
- }
-
- last_chunk = chunk_list->chunk + chunk_list->cur_chunk - 1;
- if (last_chunk->disk_end_sector + 1 == sector)
- {
- last_chunk->img_end_sector += (size >> 11);
- last_chunk->disk_end_sector += (size >> log_sector_size);
- return 0;
- }
-
- if (chunk_list->cur_chunk == chunk_list->max_chunk)
- {
- new_chunk = grub_realloc(chunk_list->chunk, chunk_list->max_chunk * 2 * sizeof(ventoy_img_chunk));
- if (NULL == new_chunk)
- {
- return -1;
- }
- chunk_list->chunk = new_chunk;
- chunk_list->max_chunk *= 2;
-
- /* issue: update last_chunk */
- last_chunk = chunk_list->chunk + chunk_list->cur_chunk - 1;
- }
-
- new_chunk = chunk_list->chunk + chunk_list->cur_chunk;
- new_chunk->img_start_sector = last_chunk->img_end_sector + 1;
- new_chunk->img_end_sector = new_chunk->img_start_sector + (size >> 11) - 1;
- new_chunk->disk_start_sector = sector;
- new_chunk->disk_end_sector = sector + (size >> log_sector_size) - 1;
-
- chunk_list->cur_chunk++;
-
- return 0;
-}
-
int grub_fat_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list)
{
grub_size_t size;
@@ -1433,7 +1383,7 @@ int grub_fat_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_i
if (size > len)
size = len;
- grub_fat_add_chunk(chunk_list, sector, size, disk->log_sector_size);
+ grub_disk_blocklist_read(chunk_list, sector, size, disk->log_sector_size);
len -= size;
logical_cluster++;
diff --git a/GRUB2/grub-2.04/grub-core/fs/ntfs.c b/GRUB2/grub-2.04/grub-core/fs/ntfs.c
new file mode 100644
index 00000000..e28b82aa
--- /dev/null
+++ b/GRUB2/grub-2.04/grub-core/fs/ntfs.c
@@ -0,0 +1,1239 @@
+/* ntfs.c - NTFS filesystem */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * 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 .
+ */
+
+#define grub_fshelp_node grub_ntfs_file
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_dl_t my_mod;
+
+#define grub_fshelp_node grub_ntfs_file
+
+static inline grub_uint16_t
+u16at (void *ptr, grub_size_t ofs)
+{
+ return grub_le_to_cpu16 (grub_get_unaligned16 ((char *) ptr + ofs));
+}
+
+static inline grub_uint32_t
+u32at (void *ptr, grub_size_t ofs)
+{
+ return grub_le_to_cpu32 (grub_get_unaligned32 ((char *) ptr + ofs));
+}
+
+static inline grub_uint64_t
+u64at (void *ptr, grub_size_t ofs)
+{
+ return grub_le_to_cpu64 (grub_get_unaligned64 ((char *) ptr + ofs));
+}
+
+grub_ntfscomp_func_t grub_ntfscomp_func;
+
+static grub_err_t
+fixup (grub_uint8_t *buf, grub_size_t len, const grub_uint8_t *magic)
+{
+ grub_uint16_t ss;
+ grub_uint8_t *pu;
+ grub_uint16_t us;
+
+ COMPILE_TIME_ASSERT ((1 << GRUB_NTFS_BLK_SHR) == GRUB_DISK_SECTOR_SIZE);
+
+ if (grub_memcmp (buf, magic, 4))
+ return grub_error (GRUB_ERR_BAD_FS, "%s label not found", magic);
+
+ ss = u16at (buf, 6) - 1;
+ if (ss != len)
+ return grub_error (GRUB_ERR_BAD_FS, "size not match");
+ pu = buf + u16at (buf, 4);
+ us = u16at (pu, 0);
+ buf -= 2;
+ while (ss > 0)
+ {
+ buf += GRUB_DISK_SECTOR_SIZE;
+ pu += 2;
+ if (u16at (buf, 0) != us)
+ return grub_error (GRUB_ERR_BAD_FS, "fixup signature not match");
+ buf[0] = pu[0];
+ buf[1] = pu[1];
+ ss--;
+ }
+
+ return 0;
+}
+
+static grub_err_t read_mft (struct grub_ntfs_data *data, grub_uint8_t *buf,
+ grub_uint64_t mftno);
+static grub_err_t read_attr (struct grub_ntfs_attr *at, grub_uint8_t *dest,
+ grub_disk_addr_t ofs, grub_size_t len,
+ int cached,
+ grub_disk_read_hook_t read_hook,
+ void *read_hook_data);
+
+static grub_err_t read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa,
+ grub_uint8_t *dest,
+ grub_disk_addr_t ofs, grub_size_t len,
+ int cached,
+ grub_disk_read_hook_t read_hook,
+ void *read_hook_data);
+
+static void
+init_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft)
+{
+ at->mft = mft;
+ at->flags = (mft == &mft->data->mmft) ? GRUB_NTFS_AF_MMFT : 0;
+ at->attr_nxt = mft->buf + u16at (mft->buf, 0x14);
+ at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL;
+}
+
+static void
+free_attr (struct grub_ntfs_attr *at)
+{
+ grub_free (at->emft_buf);
+ grub_free (at->edat_buf);
+ grub_free (at->sbuf);
+}
+
+static grub_uint8_t *
+find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
+{
+ if (at->flags & GRUB_NTFS_AF_ALST)
+ {
+ retry:
+ while (at->attr_nxt < at->attr_end)
+ {
+ at->attr_cur = at->attr_nxt;
+ at->attr_nxt += u16at (at->attr_cur, 4);
+ if ((*at->attr_cur == attr) || (attr == 0))
+ {
+ grub_uint8_t *new_pos;
+
+ if (at->flags & GRUB_NTFS_AF_MMFT)
+ {
+ if ((grub_disk_read
+ (at->mft->data->disk, u32at (at->attr_cur, 0x10), 0,
+ 512, at->emft_buf))
+ ||
+ (grub_disk_read
+ (at->mft->data->disk, u32at (at->attr_cur, 0x14), 0,
+ 512, at->emft_buf + 512)))
+ return NULL;
+
+ if (fixup (at->emft_buf, at->mft->data->mft_size,
+ (const grub_uint8_t *) "FILE"))
+ return NULL;
+ }
+ else
+ {
+ if (read_mft (at->mft->data, at->emft_buf,
+ u32at (at->attr_cur, 0x10)))
+ return NULL;
+ }
+
+ new_pos = &at->emft_buf[u16at (at->emft_buf, 0x14)];
+ while (*new_pos != 0xFF)
+ {
+ if ((*new_pos == *at->attr_cur)
+ && (u16at (new_pos, 0xE) == u16at (at->attr_cur, 0x18)))
+ {
+ return new_pos;
+ }
+ new_pos += u16at (new_pos, 4);
+ }
+ grub_error (GRUB_ERR_BAD_FS,
+ "can\'t find 0x%X in attribute list",
+ (unsigned char) *at->attr_cur);
+ return NULL;
+ }
+ }
+ return NULL;
+ }
+ at->attr_cur = at->attr_nxt;
+ while (*at->attr_cur != 0xFF)
+ {
+ at->attr_nxt += u16at (at->attr_cur, 4);
+ if (*at->attr_cur == GRUB_NTFS_AT_ATTRIBUTE_LIST)
+ at->attr_end = at->attr_cur;
+ if ((*at->attr_cur == attr) || (attr == 0))
+ return at->attr_cur;
+ at->attr_cur = at->attr_nxt;
+ }
+ if (at->attr_end)
+ {
+ grub_uint8_t *pa;
+
+ at->emft_buf = grub_malloc (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR);
+ if (at->emft_buf == NULL)
+ return NULL;
+
+ pa = at->attr_end;
+ if (pa[8])
+ {
+ grub_uint32_t n;
+
+ n = ((u32at (pa, 0x30) + GRUB_DISK_SECTOR_SIZE - 1)
+ & (~(GRUB_DISK_SECTOR_SIZE - 1)));
+ at->attr_cur = at->attr_end;
+ at->edat_buf = grub_malloc (n);
+ if (!at->edat_buf)
+ return NULL;
+ if (read_data (at, pa, at->edat_buf, 0, n, 0, 0, 0))
+ {
+ grub_error (GRUB_ERR_BAD_FS,
+ "fail to read non-resident attribute list");
+ return NULL;
+ }
+ at->attr_nxt = at->edat_buf;
+ at->attr_end = at->edat_buf + u32at (pa, 0x30);
+ }
+ else
+ {
+ at->attr_nxt = at->attr_end + u16at (pa, 0x14);
+ at->attr_end = at->attr_end + u32at (pa, 4);
+ }
+ at->flags |= GRUB_NTFS_AF_ALST;
+ while (at->attr_nxt < at->attr_end)
+ {
+ if ((*at->attr_nxt == attr) || (attr == 0))
+ break;
+ at->attr_nxt += u16at (at->attr_nxt, 4);
+ }
+ if (at->attr_nxt >= at->attr_end)
+ return NULL;
+
+ if ((at->flags & GRUB_NTFS_AF_MMFT) && (attr == GRUB_NTFS_AT_DATA))
+ {
+ at->flags |= GRUB_NTFS_AF_GPOS;
+ at->attr_cur = at->attr_nxt;
+ pa = at->attr_cur;
+ grub_set_unaligned32 ((char *) pa + 0x10,
+ grub_cpu_to_le32 (at->mft->data->mft_start));
+ grub_set_unaligned32 ((char *) pa + 0x14,
+ grub_cpu_to_le32 (at->mft->data->mft_start
+ + 1));
+ pa = at->attr_nxt + u16at (pa, 4);
+ while (pa < at->attr_end)
+ {
+ if (*pa != attr)
+ break;
+ if (read_attr
+ (at, pa + 0x10,
+ u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR),
+ at->mft->data->mft_size << GRUB_NTFS_BLK_SHR, 0, 0, 0))
+ return NULL;
+ pa += u16at (pa, 4);
+ }
+ at->attr_nxt = at->attr_cur;
+ at->flags &= ~GRUB_NTFS_AF_GPOS;
+ }
+ goto retry;
+ }
+ return NULL;
+}
+
+static grub_uint8_t *
+locate_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft,
+ grub_uint8_t attr)
+{
+ grub_uint8_t *pa;
+
+ init_attr (at, mft);
+ pa = find_attr (at, attr);
+ if (pa == NULL)
+ return NULL;
+ if ((at->flags & GRUB_NTFS_AF_ALST) == 0)
+ {
+ while (1)
+ {
+ pa = find_attr (at, attr);
+ if (pa == NULL)
+ break;
+ if (at->flags & GRUB_NTFS_AF_ALST)
+ return pa;
+ }
+ grub_errno = GRUB_ERR_NONE;
+ free_attr (at);
+ init_attr (at, mft);
+ pa = find_attr (at, attr);
+ }
+ return pa;
+}
+
+static grub_disk_addr_t
+read_run_data (const grub_uint8_t *run, int nn, int sig)
+{
+ grub_uint64_t r = 0;
+
+ if (sig && nn && (run[nn - 1] & 0x80))
+ r = -1;
+
+ grub_memcpy (&r, run, nn);
+
+ return grub_le_to_cpu64 (r);
+}
+
+grub_err_t
+grub_ntfs_read_run_list (struct grub_ntfs_rlst * ctx)
+{
+ grub_uint8_t c1, c2;
+ grub_disk_addr_t val;
+ grub_uint8_t *run;
+
+ run = ctx->cur_run;
+retry:
+ c1 = ((*run) & 0x7);
+ c2 = ((*run) >> 4) & 0x7;
+ run++;
+ if (!c1)
+ {
+ if ((ctx->attr) && (ctx->attr->flags & GRUB_NTFS_AF_ALST))
+ {
+ grub_disk_read_hook_t save_hook;
+
+ save_hook = ctx->comp.disk->read_hook;
+ ctx->comp.disk->read_hook = 0;
+ run = find_attr (ctx->attr, *ctx->attr->attr_cur);
+ ctx->comp.disk->read_hook = save_hook;
+ if (run)
+ {
+ if (run[8] == 0)
+ return grub_error (GRUB_ERR_BAD_FS,
+ "$DATA should be non-resident");
+
+ run += u16at (run, 0x20);
+ ctx->curr_lcn = 0;
+ goto retry;
+ }
+ }
+ return grub_error (GRUB_ERR_BAD_FS, "run list overflown");
+ }
+ ctx->curr_vcn = ctx->next_vcn;
+ ctx->next_vcn += read_run_data (run, c1, 0); /* length of current VCN */
+ run += c1;
+ val = read_run_data (run, c2, 1); /* offset to previous LCN */
+ run += c2;
+ ctx->curr_lcn += val;
+ if (val == 0)
+ ctx->flags |= GRUB_NTFS_RF_BLNK;
+ else
+ ctx->flags &= ~GRUB_NTFS_RF_BLNK;
+ ctx->cur_run = run;
+ return 0;
+}
+
+static grub_disk_addr_t
+grub_ntfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t block)
+{
+ struct grub_ntfs_rlst *ctx;
+
+ ctx = (struct grub_ntfs_rlst *) node;
+ if (block >= ctx->next_vcn)
+ {
+ if (grub_ntfs_read_run_list (ctx))
+ return -1;
+ return ctx->curr_lcn;
+ }
+ else
+ return (ctx->flags & GRUB_NTFS_RF_BLNK) ? 0 : (block -
+ ctx->curr_vcn + ctx->curr_lcn);
+}
+
+static grub_err_t
+read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest,
+ grub_disk_addr_t ofs, grub_size_t len, int cached,
+ grub_disk_read_hook_t read_hook, void *read_hook_data)
+{
+ struct grub_ntfs_rlst cc, *ctx;
+
+ if (len == 0)
+ return 0;
+
+ grub_memset (&cc, 0, sizeof (cc));
+ ctx = &cc;
+ ctx->attr = at;
+ ctx->comp.log_spc = at->mft->data->log_spc;
+ ctx->comp.disk = at->mft->data->disk;
+
+ if (read_hook == grub_file_progress_hook)
+ ctx->file = read_hook_data;
+
+ if (pa[8] == 0)
+ {
+ if (ofs + len > u32at (pa, 0x10))
+ return grub_error (GRUB_ERR_BAD_FS, "read out of range");
+ grub_memcpy (dest, pa + u32at (pa, 0x14) + ofs, len);
+ return 0;
+ }
+
+ ctx->cur_run = pa + u16at (pa, 0x20);
+
+ ctx->next_vcn = u32at (pa, 0x10);
+ ctx->curr_lcn = 0;
+
+ if ((pa[0xC] & GRUB_NTFS_FLAG_COMPRESSED)
+ && !(at->flags & GRUB_NTFS_AF_GPOS))
+ {
+ if (!cached)
+ return grub_error (GRUB_ERR_BAD_FS, "attribute can\'t be compressed");
+
+ return (grub_ntfscomp_func) ? grub_ntfscomp_func (dest, ofs, len, ctx)
+ : grub_error (GRUB_ERR_BAD_FS, N_("module `%s' isn't loaded"),
+ "ntfscomp");
+ }
+
+ ctx->target_vcn = ofs >> (GRUB_NTFS_BLK_SHR + ctx->comp.log_spc);
+ while (ctx->next_vcn <= ctx->target_vcn)
+ {
+ if (grub_ntfs_read_run_list (ctx))
+ return grub_errno;
+ }
+
+ if (at->flags & GRUB_NTFS_AF_GPOS)
+ {
+ grub_disk_addr_t st0, st1;
+ grub_uint64_t m;
+
+ m = (ofs >> GRUB_NTFS_BLK_SHR) & ((1 << ctx->comp.log_spc) - 1);
+
+ st0 =
+ ((ctx->target_vcn - ctx->curr_vcn + ctx->curr_lcn) << ctx->comp.log_spc) + m;
+ st1 = st0 + 1;
+ if (st1 ==
+ (ctx->next_vcn - ctx->curr_vcn + ctx->curr_lcn) << ctx->comp.log_spc)
+ {
+ if (grub_ntfs_read_run_list (ctx))
+ return grub_errno;
+ st1 = ctx->curr_lcn << ctx->comp.log_spc;
+ }
+ grub_set_unaligned32 (dest, grub_cpu_to_le32 (st0));
+ grub_set_unaligned32 (dest + 4, grub_cpu_to_le32 (st1));
+ return 0;
+ }
+
+ grub_fshelp_read_file (ctx->comp.disk, (grub_fshelp_node_t) ctx,
+ read_hook, read_hook_data, ofs, len,
+ (char *) dest,
+ grub_ntfs_read_block, ofs + len,
+ ctx->comp.log_spc, 0);
+ return grub_errno;
+}
+
+static grub_err_t
+read_attr (struct grub_ntfs_attr *at, grub_uint8_t *dest, grub_disk_addr_t ofs,
+ grub_size_t len, int cached,
+ grub_disk_read_hook_t read_hook, void *read_hook_data)
+{
+ grub_uint8_t *save_cur;
+ grub_uint8_t attr;
+ grub_uint8_t *pp;
+ grub_err_t ret;
+
+ save_cur = at->attr_cur;
+ at->attr_nxt = at->attr_cur;
+ attr = *at->attr_nxt;
+ if (at->flags & GRUB_NTFS_AF_ALST)
+ {
+ grub_uint8_t *pa;
+ grub_disk_addr_t vcn;
+
+ /* If compression is possible make sure that we include possible
+ compressed block size. */
+ if (GRUB_NTFS_LOG_COM_SEC >= at->mft->data->log_spc)
+ vcn = ((ofs >> GRUB_NTFS_COM_LOG_LEN)
+ << (GRUB_NTFS_LOG_COM_SEC - at->mft->data->log_spc)) & ~0xFULL;
+ else
+ vcn = ofs >> (at->mft->data->log_spc + GRUB_NTFS_BLK_SHR);
+ pa = at->attr_nxt + u16at (at->attr_nxt, 4);
+ while (pa < at->attr_end)
+ {
+ if (*pa != attr)
+ break;
+ if (u32at (pa, 8) > vcn)
+ break;
+ at->attr_nxt = pa;
+ pa += u16at (pa, 4);
+ }
+ }
+ pp = find_attr (at, attr);
+ if (pp)
+ ret = read_data (at, pp, dest, ofs, len, cached,
+ read_hook, read_hook_data);
+ else
+ ret =
+ (grub_errno) ? grub_errno : grub_error (GRUB_ERR_BAD_FS,
+ "attribute not found");
+ at->attr_cur = save_cur;
+ return ret;
+}
+
+static grub_err_t
+read_mft (struct grub_ntfs_data *data, grub_uint8_t *buf, grub_uint64_t mftno)
+{
+ if (read_attr
+ (&data->mmft.attr, buf, mftno * ((grub_disk_addr_t) data->mft_size << GRUB_NTFS_BLK_SHR),
+ data->mft_size << GRUB_NTFS_BLK_SHR, 0, 0, 0))
+ return grub_error (GRUB_ERR_BAD_FS, "read MFT 0x%llx fails", (unsigned long long) mftno);
+ return fixup (buf, data->mft_size, (const grub_uint8_t *) "FILE");
+}
+
+static grub_err_t
+init_file (struct grub_ntfs_file *mft, grub_uint64_t mftno)
+{
+ unsigned short flag;
+
+ mft->inode_read = 1;
+
+ mft->buf = grub_malloc (mft->data->mft_size << GRUB_NTFS_BLK_SHR);
+ if (mft->buf == NULL)
+ return grub_errno;
+
+ if (read_mft (mft->data, mft->buf, mftno))
+ return grub_errno;
+
+ flag = u16at (mft->buf, 0x16);
+ if ((flag & 1) == 0)
+ return grub_error (GRUB_ERR_BAD_FS, "MFT 0x%llx is not in use",
+ (unsigned long long) mftno);
+
+ if ((flag & 2) == 0)
+ {
+ grub_uint8_t *pa;
+
+ pa = locate_attr (&mft->attr, mft, GRUB_NTFS_AT_DATA);
+ if (pa == NULL)
+ return grub_error (GRUB_ERR_BAD_FS, "no $DATA in MFT 0x%llx",
+ (unsigned long long) mftno);
+
+ if (!pa[8])
+ mft->size = u32at (pa, 0x10);
+ else
+ mft->size = u64at (pa, 0x30);
+
+ if ((mft->attr.flags & GRUB_NTFS_AF_ALST) == 0)
+ mft->attr.attr_end = 0; /* Don't jump to attribute list */
+ }
+ else
+ init_attr (&mft->attr, mft);
+
+ return 0;
+}
+
+static void
+free_file (struct grub_ntfs_file *mft)
+{
+ free_attr (&mft->attr);
+ grub_free (mft->buf);
+}
+
+static char *
+get_utf8 (grub_uint8_t *in, grub_size_t len)
+{
+ grub_uint8_t *buf;
+ grub_uint16_t *tmp;
+ grub_size_t i;
+
+ buf = grub_malloc (len * GRUB_MAX_UTF8_PER_UTF16 + 1);
+ tmp = grub_malloc (len * sizeof (tmp[0]));
+ if (!buf || !tmp)
+ {
+ grub_free (buf);
+ grub_free (tmp);
+ return NULL;
+ }
+ for (i = 0; i < len; i++)
+ tmp[i] = grub_le_to_cpu16 (grub_get_unaligned16 (in + 2 * i));
+ *grub_utf16_to_utf8 (buf, tmp, len) = '\0';
+ grub_free (tmp);
+ return (char *) buf;
+}
+
+static int
+list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos,
+ grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
+{
+ grub_uint8_t *np;
+ int ns;
+
+ while (1)
+ {
+ grub_uint8_t namespace;
+ char *ustr;
+
+ if (pos[0xC] & 2) /* end signature */
+ break;
+
+ np = pos + 0x50;
+ ns = *(np++);
+ namespace = *(np++);
+
+ /*
+ * Ignore files in DOS namespace, as they will reappear as Win32
+ * names.
+ */
+ if ((ns) && (namespace != 2))
+ {
+ enum grub_fshelp_filetype type;
+ struct grub_ntfs_file *fdiro;
+ grub_uint32_t attr;
+
+ attr = u32at (pos, 0x48);
+ if (attr & GRUB_NTFS_ATTR_REPARSE)
+ type = GRUB_FSHELP_SYMLINK;
+ else if (attr & GRUB_NTFS_ATTR_DIRECTORY)
+ type = GRUB_FSHELP_DIR;
+ else
+ type = GRUB_FSHELP_REG;
+
+ fdiro = grub_zalloc (sizeof (struct grub_ntfs_file));
+ if (!fdiro)
+ return 0;
+
+ fdiro->data = diro->data;
+ fdiro->ino = u64at (pos, 0) & 0xffffffffffffULL;
+ fdiro->mtime = u64at (pos, 0x20);
+
+ ustr = get_utf8 (np, ns);
+ if (ustr == NULL)
+ {
+ grub_free (fdiro);
+ return 0;
+ }
+ if (namespace)
+ type |= GRUB_FSHELP_CASE_INSENSITIVE;
+
+ if (hook (ustr, type, fdiro, hook_data))
+ {
+ grub_free (ustr);
+ return 1;
+ }
+
+ grub_free (ustr);
+ }
+ pos += u16at (pos, 8);
+ }
+ return 0;
+}
+
+struct symlink_descriptor
+{
+ grub_uint32_t type;
+ grub_uint32_t total_len;
+ grub_uint16_t off1;
+ grub_uint16_t len1;
+ grub_uint16_t off2;
+ grub_uint16_t len2;
+} GRUB_PACKED;
+
+static char *
+grub_ntfs_read_symlink (grub_fshelp_node_t node)
+{
+ struct grub_ntfs_file *mft;
+ struct symlink_descriptor symdesc;
+ grub_err_t err;
+ grub_uint8_t *buf16;
+ char *buf, *end;
+ grub_size_t len;
+ grub_uint8_t *pa;
+ grub_size_t off;
+
+ mft = (struct grub_ntfs_file *) node;
+
+ mft->buf = grub_malloc (mft->data->mft_size << GRUB_NTFS_BLK_SHR);
+ if (mft->buf == NULL)
+ return NULL;
+
+ if (read_mft (mft->data, mft->buf, mft->ino))
+ return NULL;
+
+ pa = locate_attr (&mft->attr, mft, GRUB_NTFS_AT_SYMLINK);
+ if (pa == NULL)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "no $SYMLINK in MFT 0x%llx",
+ (unsigned long long) mft->ino);
+ return NULL;
+ }
+
+ err = read_attr (&mft->attr, (grub_uint8_t *) &symdesc, 0,
+ sizeof (struct symlink_descriptor), 1, 0, 0);
+ if (err)
+ return NULL;
+
+ switch (grub_cpu_to_le32 (symdesc.type))
+ {
+ case 0xa000000c:
+ off = (sizeof (struct symlink_descriptor) + 4
+ + grub_cpu_to_le32 (symdesc.off1));
+ len = grub_cpu_to_le32 (symdesc.len1);
+ break;
+ case 0xa0000003:
+ off = (sizeof (struct symlink_descriptor)
+ + grub_cpu_to_le32 (symdesc.off1));
+ len = grub_cpu_to_le32 (symdesc.len1);
+ break;
+ default:
+ grub_error (GRUB_ERR_BAD_FS, "symlink type invalid (%x)",
+ grub_cpu_to_le32 (symdesc.type));
+ return NULL;
+ }
+
+ buf16 = grub_malloc (len);
+ if (!buf16)
+ return NULL;
+
+ err = read_attr (&mft->attr, buf16, off, len, 1, 0, 0);
+ if (err)
+ return NULL;
+
+ buf = get_utf8 (buf16, len / 2);
+ if (!buf)
+ {
+ grub_free (buf16);
+ return NULL;
+ }
+ grub_free (buf16);
+
+ for (end = buf; *end; end++)
+ if (*end == '\\')
+ *end = '/';
+
+ /* Split the sequence to avoid GCC thinking that this is a trigraph. */
+ if (grub_memcmp (buf, "/?" "?/", 4) == 0 && buf[5] == ':' && buf[6] == '/'
+ && grub_isalpha (buf[4]))
+ {
+ grub_memmove (buf, buf + 6, end - buf + 1 - 6);
+ end -= 6;
+ }
+ return buf;
+}
+
+static int
+grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
+ grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
+{
+ grub_uint8_t *bitmap;
+ struct grub_ntfs_attr attr, *at;
+ grub_uint8_t *cur_pos, *indx, *bmp;
+ int ret = 0;
+ grub_size_t bitmap_len;
+ struct grub_ntfs_file *mft;
+
+ mft = (struct grub_ntfs_file *) dir;
+
+ if (!mft->inode_read)
+ {
+ if (init_file (mft, mft->ino))
+ return 0;
+ }
+
+ indx = NULL;
+ bmp = NULL;
+
+ at = &attr;
+ init_attr (at, mft);
+ while (1)
+ {
+ cur_pos = find_attr (at, GRUB_NTFS_AT_INDEX_ROOT);
+ if (cur_pos == NULL)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "no $INDEX_ROOT");
+ goto done;
+ }
+
+ /* Resident, Namelen=4, Offset=0x18, Flags=0x00, Name="$I30" */
+ if ((u32at (cur_pos, 8) != 0x180400) ||
+ (u32at (cur_pos, 0x18) != 0x490024) ||
+ (u32at (cur_pos, 0x1C) != 0x300033))
+ continue;
+ cur_pos += u16at (cur_pos, 0x14);
+ if (*cur_pos != 0x30) /* Not filename index */
+ continue;
+ break;
+ }
+
+ cur_pos += 0x10; /* Skip index root */
+ ret = list_file (mft, cur_pos + u16at (cur_pos, 0), hook, hook_data);
+ if (ret)
+ goto done;
+
+ bitmap = NULL;
+ bitmap_len = 0;
+ free_attr (at);
+ init_attr (at, mft);
+ while ((cur_pos = find_attr (at, GRUB_NTFS_AT_BITMAP)) != NULL)
+ {
+ int ofs;
+
+ ofs = cur_pos[0xA];
+ /* Namelen=4, Name="$I30" */
+ if ((cur_pos[9] == 4) &&
+ (u32at (cur_pos, ofs) == 0x490024) &&
+ (u32at (cur_pos, ofs + 4) == 0x300033))
+ {
+ int is_resident = (cur_pos[8] == 0);
+
+ bitmap_len = ((is_resident) ? u32at (cur_pos, 0x10) :
+ u32at (cur_pos, 0x28));
+
+ bmp = grub_malloc (bitmap_len);
+ if (bmp == NULL)
+ goto done;
+
+ if (is_resident)
+ {
+ grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14),
+ bitmap_len);
+ }
+ else
+ {
+ if (read_data (at, cur_pos, bmp, 0, bitmap_len, 0, 0, 0))
+ {
+ grub_error (GRUB_ERR_BAD_FS,
+ "fails to read non-resident $BITMAP");
+ goto done;
+ }
+ bitmap_len = u32at (cur_pos, 0x30);
+ }
+
+ bitmap = bmp;
+ break;
+ }
+ }
+
+ free_attr (at);
+ cur_pos = locate_attr (at, mft, GRUB_NTFS_AT_INDEX_ALLOCATION);
+ while (cur_pos != NULL)
+ {
+ /* Non-resident, Namelen=4, Offset=0x40, Flags=0, Name="$I30" */
+ if ((u32at (cur_pos, 8) == 0x400401) &&
+ (u32at (cur_pos, 0x40) == 0x490024) &&
+ (u32at (cur_pos, 0x44) == 0x300033))
+ break;
+ cur_pos = find_attr (at, GRUB_NTFS_AT_INDEX_ALLOCATION);
+ }
+
+ if ((!cur_pos) && (bitmap))
+ {
+ grub_error (GRUB_ERR_BAD_FS, "$BITMAP without $INDEX_ALLOCATION");
+ goto done;
+ }
+
+ if (bitmap)
+ {
+ grub_disk_addr_t i;
+ grub_uint8_t v;
+
+ indx = grub_malloc (mft->data->idx_size << GRUB_NTFS_BLK_SHR);
+ if (indx == NULL)
+ goto done;
+
+ v = 1;
+ for (i = 0; i < (grub_disk_addr_t)bitmap_len * 8; i++)
+ {
+ if (*bitmap & v)
+ {
+ if ((read_attr
+ (at, indx, i * (mft->data->idx_size << GRUB_NTFS_BLK_SHR),
+ (mft->data->idx_size << GRUB_NTFS_BLK_SHR), 0, 0, 0))
+ || (fixup (indx, mft->data->idx_size,
+ (const grub_uint8_t *) "INDX")))
+ goto done;
+ ret = list_file (mft, &indx[0x18 + u16at (indx, 0x18)],
+ hook, hook_data);
+ if (ret)
+ goto done;
+ }
+ v <<= 1;
+ if (!v)
+ {
+ v = 1;
+ bitmap++;
+ }
+ }
+ }
+
+done:
+ free_attr (at);
+ grub_free (indx);
+ grub_free (bmp);
+
+ return ret;
+}
+
+static struct grub_ntfs_data *
+grub_ntfs_mount (grub_disk_t disk)
+{
+ struct grub_ntfs_bpb bpb;
+ struct grub_ntfs_data *data = 0;
+ grub_uint32_t spc;
+
+ if (!disk)
+ goto fail;
+
+ data = (struct grub_ntfs_data *) grub_zalloc (sizeof (*data));
+ if (!data)
+ goto fail;
+
+ data->disk = disk;
+
+ /* Read the BPB. */
+ if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb))
+ goto fail;
+
+ if (grub_memcmp ((char *) &bpb.oem_name, "NTFS", 4) != 0
+ || bpb.sectors_per_cluster == 0
+ || (bpb.sectors_per_cluster & (bpb.sectors_per_cluster - 1)) != 0
+ || bpb.bytes_per_sector == 0
+ || (bpb.bytes_per_sector & (bpb.bytes_per_sector - 1)) != 0)
+ goto fail;
+
+ spc = (((grub_uint32_t) bpb.sectors_per_cluster
+ * (grub_uint32_t) grub_le_to_cpu16 (bpb.bytes_per_sector))
+ >> GRUB_NTFS_BLK_SHR);
+ if (spc == 0)
+ goto fail;
+
+ for (data->log_spc = 0; (1U << data->log_spc) < spc; data->log_spc++);
+
+ if (bpb.clusters_per_mft > 0)
+ data->mft_size = ((grub_disk_addr_t) bpb.clusters_per_mft) << data->log_spc;
+ else if (-bpb.clusters_per_mft < GRUB_NTFS_BLK_SHR || -bpb.clusters_per_mft >= 31)
+ goto fail;
+ else
+ data->mft_size = 1ULL << (-bpb.clusters_per_mft - GRUB_NTFS_BLK_SHR);
+
+ if (bpb.clusters_per_index > 0)
+ data->idx_size = (((grub_disk_addr_t) bpb.clusters_per_index)
+ << data->log_spc);
+ else if (-bpb.clusters_per_index < GRUB_NTFS_BLK_SHR || -bpb.clusters_per_index >= 31)
+ goto fail;
+ else
+ data->idx_size = 1ULL << (-bpb.clusters_per_index - GRUB_NTFS_BLK_SHR);
+
+ data->mft_start = grub_le_to_cpu64 (bpb.mft_lcn) << data->log_spc;
+
+ if ((data->mft_size > GRUB_NTFS_MAX_MFT) || (data->idx_size > GRUB_NTFS_MAX_IDX))
+ goto fail;
+
+ data->mmft.data = data;
+ data->cmft.data = data;
+
+ data->mmft.buf = grub_malloc (data->mft_size << GRUB_NTFS_BLK_SHR);
+ if (!data->mmft.buf)
+ goto fail;
+
+ if (grub_disk_read
+ (disk, data->mft_start, 0, data->mft_size << GRUB_NTFS_BLK_SHR, data->mmft.buf))
+ goto fail;
+
+ data->uuid = grub_le_to_cpu64 (bpb.num_serial);
+
+ if (fixup (data->mmft.buf, data->mft_size, (const grub_uint8_t *) "FILE"))
+ goto fail;
+
+ if (!locate_attr (&data->mmft.attr, &data->mmft, GRUB_NTFS_AT_DATA))
+ goto fail;
+
+ if (init_file (&data->cmft, GRUB_NTFS_FILE_ROOT))
+ goto fail;
+
+ return data;
+
+fail:
+ grub_error (GRUB_ERR_BAD_FS, "not an ntfs filesystem");
+
+ if (data)
+ {
+ free_file (&data->mmft);
+ free_file (&data->cmft);
+ grub_free (data);
+ }
+ return 0;
+}
+
+/* Context for grub_ntfs_dir. */
+struct grub_ntfs_dir_ctx
+{
+ grub_fs_dir_hook_t hook;
+ void *hook_data;
+};
+
+/* Helper for grub_ntfs_dir. */
+static int
+grub_ntfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node, void *data)
+{
+ struct grub_ntfs_dir_ctx *ctx = data;
+ struct grub_dirhook_info info;
+
+ grub_memset (&info, 0, sizeof (info));
+ info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+ info.mtimeset = 1;
+ info.mtime = grub_divmod64 (node->mtime, 10000000, 0)
+ - 86400ULL * 365 * (1970 - 1601)
+ - 86400ULL * ((1970 - 1601) / 4) + 86400ULL * ((1970 - 1601) / 100);
+ if (!info.dir)
+ info.size = node->size;
+ grub_free (node);
+ return ctx->hook (filename, &info, ctx->hook_data);
+}
+
+static grub_err_t
+grub_ntfs_dir (grub_device_t device, const char *path,
+ grub_fs_dir_hook_t hook, void *hook_data)
+{
+ struct grub_ntfs_dir_ctx ctx = { hook, hook_data };
+ struct grub_ntfs_data *data = 0;
+ struct grub_fshelp_node *fdiro = 0;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_ntfs_mount (device->disk);
+ if (!data)
+ goto fail;
+
+ grub_fshelp_find_file (path, &data->cmft, &fdiro, grub_ntfs_iterate_dir,
+ grub_ntfs_read_symlink, GRUB_FSHELP_DIR);
+
+ if (grub_errno)
+ goto fail;
+
+ grub_ntfs_iterate_dir (fdiro, grub_ntfs_dir_iter, &ctx);
+
+fail:
+ if ((fdiro) && (fdiro != &data->cmft))
+ {
+ free_file (fdiro);
+ grub_free (fdiro);
+ }
+ if (data)
+ {
+ free_file (&data->mmft);
+ free_file (&data->cmft);
+ grub_free (data);
+ }
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_ntfs_open (grub_file_t file, const char *name)
+{
+ struct grub_ntfs_data *data = 0;
+ struct grub_fshelp_node *mft = 0;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_ntfs_mount (file->device->disk);
+ if (!data)
+ goto fail;
+
+ grub_fshelp_find_file (name, &data->cmft, &mft, grub_ntfs_iterate_dir,
+ grub_ntfs_read_symlink, GRUB_FSHELP_REG);
+
+ if (grub_errno)
+ goto fail;
+
+ if (mft != &data->cmft)
+ {
+ free_file (&data->cmft);
+ grub_memcpy (&data->cmft, mft, sizeof (*mft));
+ grub_free (mft);
+ if (!data->cmft.inode_read)
+ {
+ if (init_file (&data->cmft, data->cmft.ino))
+ goto fail;
+ }
+ }
+
+ file->size = data->cmft.size;
+ file->data = data;
+ file->offset = 0;
+
+ return 0;
+
+fail:
+ if (data)
+ {
+ free_file (&data->mmft);
+ free_file (&data->cmft);
+ grub_free (data);
+ }
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+static grub_ssize_t
+grub_ntfs_read (grub_file_t file, char *buf, grub_size_t len)
+{
+ struct grub_ntfs_file *mft;
+
+ mft = &((struct grub_ntfs_data *) file->data)->cmft;
+ if (file->read_hook)
+ mft->attr.save_pos = 1;
+
+ read_attr (&mft->attr, (grub_uint8_t *) buf, file->offset, len, 1,
+ file->read_hook, file->read_hook_data);
+ return (grub_errno) ? -1 : (grub_ssize_t) len;
+}
+
+static grub_err_t
+grub_ntfs_close (grub_file_t file)
+{
+ struct grub_ntfs_data *data;
+
+ data = file->data;
+
+ if (data)
+ {
+ free_file (&data->mmft);
+ free_file (&data->cmft);
+ grub_free (data);
+ }
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_ntfs_label (grub_device_t device, char **label)
+{
+ struct grub_ntfs_data *data = 0;
+ struct grub_fshelp_node *mft = 0;
+ grub_uint8_t *pa;
+
+ grub_dl_ref (my_mod);
+
+ *label = 0;
+
+ data = grub_ntfs_mount (device->disk);
+ if (!data)
+ goto fail;
+
+ grub_fshelp_find_file ("/$Volume", &data->cmft, &mft, grub_ntfs_iterate_dir,
+ 0, GRUB_FSHELP_REG);
+
+ if (grub_errno)
+ goto fail;
+
+ if (!mft->inode_read)
+ {
+ mft->buf = grub_malloc (mft->data->mft_size << GRUB_NTFS_BLK_SHR);
+ if (mft->buf == NULL)
+ goto fail;
+
+ if (read_mft (mft->data, mft->buf, mft->ino))
+ goto fail;
+ }
+
+ init_attr (&mft->attr, mft);
+ pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME);
+ if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10)))
+ {
+ int len;
+
+ len = u32at (pa, 0x10) / 2;
+ pa += u16at (pa, 0x14);
+ *label = get_utf8 (pa, len);
+ }
+
+fail:
+ if ((mft) && (mft != &data->cmft))
+ {
+ free_file (mft);
+ grub_free (mft);
+ }
+ if (data)
+ {
+ free_file (&data->mmft);
+ free_file (&data->cmft);
+ grub_free (data);
+ }
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_ntfs_uuid (grub_device_t device, char **uuid)
+{
+ struct grub_ntfs_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_ntfs_mount (disk);
+ if (data)
+ {
+ char *ptr;
+ *uuid = grub_xasprintf ("%016llx", (unsigned long long) data->uuid);
+ if (*uuid)
+ for (ptr = *uuid; *ptr; ptr++)
+ *ptr = grub_toupper (*ptr);
+ free_file (&data->mmft);
+ free_file (&data->cmft);
+ grub_free (data);
+ }
+ else
+ *uuid = NULL;
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+static struct grub_fs grub_ntfs_fs =
+ {
+ .name = "ntfs",
+ .fs_dir = grub_ntfs_dir,
+ .fs_open = grub_ntfs_open,
+ .fs_read = grub_ntfs_read,
+ .fs_close = grub_ntfs_close,
+ .fs_label = grub_ntfs_label,
+ .fs_uuid = grub_ntfs_uuid,
+#ifdef GRUB_UTIL
+ .reserved_first_sector = 1,
+ .blocklist_install = 1,
+#endif
+ .next = 0
+};
+
+GRUB_MOD_INIT (ntfs)
+{
+ grub_fs_register (&grub_ntfs_fs);
+ my_mod = mod;
+}
+
+GRUB_MOD_FINI (ntfs)
+{
+ grub_fs_unregister (&grub_ntfs_fs);
+}
diff --git a/GRUB2/grub-2.04/grub-core/fs/udf.c b/GRUB2/grub-2.04/grub-core/fs/udf.c
index c5ea54e4..dab046b6 100644
--- a/GRUB2/grub-2.04/grub-core/fs/udf.c
+++ b/GRUB2/grub-2.04/grub-core/fs/udf.c
@@ -1152,6 +1152,8 @@ grub_udf_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
info.mtime -= 60 * tz;
}
+ if (!info.dir)
+ info.size = U64 (node->block.fe.file_size);
grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data);
}
diff --git a/GRUB2/grub-2.04/grub-core/fs/xfs.c b/GRUB2/grub-2.04/grub-core/fs/xfs.c
new file mode 100644
index 00000000..a5c8d938
--- /dev/null
+++ b/GRUB2/grub-2.04/grub-core/fs/xfs.c
@@ -0,0 +1,1164 @@
+/* xfs.c - XFS. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define XFS_INODE_EXTENTS 9
+
+#define XFS_INODE_FORMAT_INO 1
+#define XFS_INODE_FORMAT_EXT 2
+#define XFS_INODE_FORMAT_BTREE 3
+
+/* Superblock version field flags */
+#define XFS_SB_VERSION_NUMBITS 0x000f
+#define XFS_SB_VERSION_ATTRBIT 0x0010
+#define XFS_SB_VERSION_NLINKBIT 0x0020
+#define XFS_SB_VERSION_QUOTABIT 0x0040
+#define XFS_SB_VERSION_ALIGNBIT 0x0080
+#define XFS_SB_VERSION_DALIGNBIT 0x0100
+#define XFS_SB_VERSION_LOGV2BIT 0x0400
+#define XFS_SB_VERSION_SECTORBIT 0x0800
+#define XFS_SB_VERSION_EXTFLGBIT 0x1000
+#define XFS_SB_VERSION_DIRV2BIT 0x2000
+#define XFS_SB_VERSION_MOREBITSBIT 0x8000
+#define XFS_SB_VERSION_BITS_SUPPORTED \
+ (XFS_SB_VERSION_NUMBITS | \
+ XFS_SB_VERSION_ATTRBIT | \
+ XFS_SB_VERSION_NLINKBIT | \
+ XFS_SB_VERSION_QUOTABIT | \
+ XFS_SB_VERSION_ALIGNBIT | \
+ XFS_SB_VERSION_DALIGNBIT | \
+ XFS_SB_VERSION_LOGV2BIT | \
+ XFS_SB_VERSION_SECTORBIT | \
+ XFS_SB_VERSION_EXTFLGBIT | \
+ XFS_SB_VERSION_DIRV2BIT | \
+ XFS_SB_VERSION_MOREBITSBIT)
+
+/* Recognized xfs format versions */
+#define XFS_SB_VERSION_4 4 /* Good old XFS filesystem */
+#define XFS_SB_VERSION_5 5 /* CRC enabled filesystem */
+
+/* features2 field flags */
+#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */
+#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
+#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32-bit project ids */
+#define XFS_SB_VERSION2_FTYPE 0x00000200 /* inode type in dir */
+#define XFS_SB_VERSION2_BITS_SUPPORTED \
+ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
+ XFS_SB_VERSION2_ATTR2BIT | \
+ XFS_SB_VERSION2_PROJID32BIT | \
+ XFS_SB_VERSION2_FTYPE)
+
+/* incompat feature flags */
+#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */
+#define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */
+#define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */
+
+/*
+ * Directory entries with ftype are explicitly handled by GRUB code.
+ *
+ * We do not currently read the inode btrees, so it is safe to read filesystems
+ * with the XFS_SB_FEAT_INCOMPAT_SPINODES feature.
+ *
+ * We do not currently verify metadata UUID, so it is safe to read filesystems
+ * with the XFS_SB_FEAT_INCOMPAT_META_UUID feature.
+ */
+#define XFS_SB_FEAT_INCOMPAT_SUPPORTED \
+ (XFS_SB_FEAT_INCOMPAT_FTYPE | \
+ XFS_SB_FEAT_INCOMPAT_SPINODES | \
+ XFS_SB_FEAT_INCOMPAT_META_UUID)
+
+struct grub_xfs_sblock
+{
+ grub_uint8_t magic[4];
+ grub_uint32_t bsize;
+ grub_uint8_t unused1[24];
+ grub_uint16_t uuid[8];
+ grub_uint8_t unused2[8];
+ grub_uint64_t rootino;
+ grub_uint8_t unused3[20];
+ grub_uint32_t agsize;
+ grub_uint8_t unused4[12];
+ grub_uint16_t version;
+ grub_uint8_t unused5[6];
+ grub_uint8_t label[12];
+ grub_uint8_t log2_bsize;
+ grub_uint8_t log2_sect;
+ grub_uint8_t log2_inode;
+ grub_uint8_t log2_inop;
+ grub_uint8_t log2_agblk;
+ grub_uint8_t unused6[67];
+ grub_uint8_t log2_dirblk;
+ grub_uint8_t unused7[7];
+ grub_uint32_t features2;
+ grub_uint8_t unused8[4];
+ grub_uint32_t sb_features_compat;
+ grub_uint32_t sb_features_ro_compat;
+ grub_uint32_t sb_features_incompat;
+ grub_uint32_t sb_features_log_incompat;
+} GRUB_PACKED;
+
+struct grub_xfs_dir_header
+{
+ grub_uint8_t count;
+ grub_uint8_t largeino;
+ union
+ {
+ grub_uint32_t i4;
+ grub_uint64_t i8;
+ } GRUB_PACKED parent;
+} GRUB_PACKED;
+
+/* Structure for directory entry inlined in the inode */
+struct grub_xfs_dir_entry
+{
+ grub_uint8_t len;
+ grub_uint16_t offset;
+ char name[1];
+ /* Inode number follows, 32 / 64 bits. */
+} GRUB_PACKED;
+
+/* Structure for directory entry in a block */
+struct grub_xfs_dir2_entry
+{
+ grub_uint64_t inode;
+ grub_uint8_t len;
+} GRUB_PACKED;
+
+struct grub_xfs_extent
+{
+ /* This should be a bitfield but bietfields are unportable, so just have
+ a raw array and functions extracting useful info from it.
+ */
+ grub_uint32_t raw[4];
+} GRUB_PACKED;
+
+struct grub_xfs_btree_node
+{
+ grub_uint8_t magic[4];
+ grub_uint16_t level;
+ grub_uint16_t numrecs;
+ grub_uint64_t left;
+ grub_uint64_t right;
+ /* In V5 here follow crc, uuid, etc. */
+ /* Then follow keys and block pointers */
+} GRUB_PACKED;
+
+struct grub_xfs_btree_root
+{
+ grub_uint16_t level;
+ grub_uint16_t numrecs;
+ grub_uint64_t keys[1];
+} GRUB_PACKED;
+
+struct grub_xfs_time
+{
+ grub_uint32_t sec;
+ grub_uint32_t nanosec;
+} GRUB_PACKED;
+
+struct grub_xfs_inode
+{
+ grub_uint8_t magic[2];
+ grub_uint16_t mode;
+ grub_uint8_t version;
+ grub_uint8_t format;
+ grub_uint8_t unused2[26];
+ struct grub_xfs_time atime;
+ struct grub_xfs_time mtime;
+ struct grub_xfs_time ctime;
+ grub_uint64_t size;
+ grub_uint64_t nblocks;
+ grub_uint32_t extsize;
+ grub_uint32_t nextents;
+ grub_uint16_t unused3;
+ grub_uint8_t fork_offset;
+ grub_uint8_t unused4[17];
+} GRUB_PACKED;
+
+#define XFS_V2_INODE_SIZE sizeof(struct grub_xfs_inode)
+#define XFS_V3_INODE_SIZE (XFS_V2_INODE_SIZE + 76)
+
+struct grub_xfs_dirblock_tail
+{
+ grub_uint32_t leaf_count;
+ grub_uint32_t leaf_stale;
+} GRUB_PACKED;
+
+struct grub_fshelp_node
+{
+ struct grub_xfs_data *data;
+ grub_uint64_t ino;
+ int inode_read;
+ struct grub_xfs_inode inode;
+};
+
+struct grub_xfs_data
+{
+ struct grub_xfs_sblock sblock;
+ grub_disk_t disk;
+ int pos;
+ int bsize;
+ grub_uint32_t agsize;
+ unsigned int hasftype:1;
+ unsigned int hascrc:1;
+ struct grub_fshelp_node diropen;
+};
+
+static grub_dl_t my_mod;
+
+
+
+static int grub_xfs_sb_hascrc(struct grub_xfs_data *data)
+{
+ return (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
+ grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5);
+}
+
+static int grub_xfs_sb_hasftype(struct grub_xfs_data *data)
+{
+ if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
+ grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5) &&
+ data->sblock.sb_features_incompat & grub_cpu_to_be32_compile_time(XFS_SB_FEAT_INCOMPAT_FTYPE))
+ return 1;
+ if (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_MOREBITSBIT) &&
+ data->sblock.features2 & grub_cpu_to_be32_compile_time(XFS_SB_VERSION2_FTYPE))
+ return 1;
+ return 0;
+}
+
+static int grub_xfs_sb_valid(struct grub_xfs_data *data)
+{
+ grub_dprintf("xfs", "Validating superblock\n");
+ if (grub_strncmp ((char *) (data->sblock.magic), "XFSB", 4)
+ || data->sblock.log2_bsize < GRUB_DISK_SECTOR_BITS
+ || ((int) data->sblock.log2_bsize
+ + (int) data->sblock.log2_dirblk) >= 27)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "not a XFS filesystem");
+ return 0;
+ }
+ if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
+ grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5))
+ {
+ grub_dprintf("xfs", "XFS v5 superblock detected\n");
+ if (data->sblock.sb_features_incompat &
+ grub_cpu_to_be32_compile_time(~XFS_SB_FEAT_INCOMPAT_SUPPORTED))
+ {
+ grub_error (GRUB_ERR_BAD_FS, "XFS filesystem has unsupported "
+ "incompatible features");
+ return 0;
+ }
+ return 1;
+ }
+ else if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
+ grub_cpu_to_be16_compile_time(XFS_SB_VERSION_4))
+ {
+ grub_dprintf("xfs", "XFS v4 superblock detected\n");
+ if (!(data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_DIRV2BIT)))
+ {
+ grub_error (GRUB_ERR_BAD_FS, "XFS filesystem without V2 directories "
+ "is unsupported");
+ return 0;
+ }
+ if (data->sblock.version & grub_cpu_to_be16_compile_time(~XFS_SB_VERSION_BITS_SUPPORTED) ||
+ (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_MOREBITSBIT) &&
+ data->sblock.features2 & grub_cpu_to_be16_compile_time(~XFS_SB_VERSION2_BITS_SUPPORTED)))
+ {
+ grub_error (GRUB_ERR_BAD_FS, "XFS filesystem has unsupported version "
+ "bits");
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/* Filetype information as used in inodes. */
+#define FILETYPE_INO_MASK 0170000
+#define FILETYPE_INO_REG 0100000
+#define FILETYPE_INO_DIRECTORY 0040000
+#define FILETYPE_INO_SYMLINK 0120000
+
+static inline int
+GRUB_XFS_INO_AGBITS(struct grub_xfs_data *data)
+{
+ return ((data)->sblock.log2_agblk + (data)->sblock.log2_inop);
+}
+
+static inline grub_uint64_t
+GRUB_XFS_INO_INOINAG (struct grub_xfs_data *data,
+ grub_uint64_t ino)
+{
+ return (ino & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1));
+}
+
+static inline grub_uint64_t
+GRUB_XFS_INO_AG (struct grub_xfs_data *data,
+ grub_uint64_t ino)
+{
+ return (ino >> GRUB_XFS_INO_AGBITS (data));
+}
+
+static inline grub_disk_addr_t
+GRUB_XFS_FSB_TO_BLOCK (struct grub_xfs_data *data, grub_disk_addr_t fsb)
+{
+ return ((fsb >> data->sblock.log2_agblk) * data->agsize
+ + (fsb & ((1LL << data->sblock.log2_agblk) - 1)));
+}
+
+static inline grub_uint64_t
+GRUB_XFS_EXTENT_OFFSET (struct grub_xfs_extent *exts, int ex)
+{
+ return ((grub_be_to_cpu32 (exts[ex].raw[0]) & ~(1 << 31)) << 23
+ | grub_be_to_cpu32 (exts[ex].raw[1]) >> 9);
+}
+
+static inline grub_uint64_t
+GRUB_XFS_EXTENT_BLOCK (struct grub_xfs_extent *exts, int ex)
+{
+ return ((grub_uint64_t) (grub_be_to_cpu32 (exts[ex].raw[1])
+ & (0x1ff)) << 43
+ | (grub_uint64_t) grub_be_to_cpu32 (exts[ex].raw[2]) << 11
+ | grub_be_to_cpu32 (exts[ex].raw[3]) >> 21);
+}
+
+static inline grub_uint64_t
+GRUB_XFS_EXTENT_SIZE (struct grub_xfs_extent *exts, int ex)
+{
+ return (grub_be_to_cpu32 (exts[ex].raw[3]) & ((1 << 21) - 1));
+}
+
+
+static inline grub_uint64_t
+grub_xfs_inode_block (struct grub_xfs_data *data,
+ grub_uint64_t ino)
+{
+ long long int inoinag = GRUB_XFS_INO_INOINAG (data, ino);
+ long long ag = GRUB_XFS_INO_AG (data, ino);
+ long long block;
+
+ block = (inoinag >> data->sblock.log2_inop) + ag * data->agsize;
+ block <<= (data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS);
+ return block;
+}
+
+
+static inline int
+grub_xfs_inode_offset (struct grub_xfs_data *data,
+ grub_uint64_t ino)
+{
+ int inoag = GRUB_XFS_INO_INOINAG (data, ino);
+ return ((inoag & ((1 << data->sblock.log2_inop) - 1)) <<
+ data->sblock.log2_inode);
+}
+
+static inline grub_size_t
+grub_xfs_inode_size(struct grub_xfs_data *data)
+{
+ return (grub_size_t)1 << data->sblock.log2_inode;
+}
+
+/*
+ * Returns size occupied by XFS inode stored in memory - we store struct
+ * grub_fshelp_node there but on disk inode size may be actually larger than
+ * struct grub_xfs_inode so we need to account for that so that we can read
+ * from disk directly into in-memory structure.
+ */
+static inline grub_size_t
+grub_xfs_fshelp_size(struct grub_xfs_data *data)
+{
+ return sizeof (struct grub_fshelp_node) - sizeof (struct grub_xfs_inode)
+ + grub_xfs_inode_size(data);
+}
+
+/* This should return void * but XFS code is error-prone with alignment, so
+ return char to retain cast-align.
+ */
+static char *
+grub_xfs_inode_data(struct grub_xfs_inode *inode)
+{
+ if (inode->version <= 2)
+ return ((char *)inode) + XFS_V2_INODE_SIZE;
+ return ((char *)inode) + XFS_V3_INODE_SIZE;
+}
+
+static struct grub_xfs_dir_entry *
+grub_xfs_inline_de(struct grub_xfs_dir_header *head)
+{
+ /*
+ With small inode numbers the header is 4 bytes smaller because of
+ smaller parent pointer
+ */
+ return (struct grub_xfs_dir_entry *)
+ (((char *) head) + sizeof(struct grub_xfs_dir_header) -
+ (head->largeino ? 0 : sizeof(grub_uint32_t)));
+}
+
+static grub_uint8_t *
+grub_xfs_inline_de_inopos(struct grub_xfs_data *data,
+ struct grub_xfs_dir_entry *de)
+{
+ return ((grub_uint8_t *)(de + 1)) + de->len - 1 + (data->hasftype ? 1 : 0);
+}
+
+static struct grub_xfs_dir_entry *
+grub_xfs_inline_next_de(struct grub_xfs_data *data,
+ struct grub_xfs_dir_header *head,
+ struct grub_xfs_dir_entry *de)
+{
+ char *p = (char *)de + sizeof(struct grub_xfs_dir_entry) - 1 + de->len;
+
+ p += head->largeino ? sizeof(grub_uint64_t) : sizeof(grub_uint32_t);
+ if (data->hasftype)
+ p++;
+
+ return (struct grub_xfs_dir_entry *)p;
+}
+
+static struct grub_xfs_dirblock_tail *
+grub_xfs_dir_tail(struct grub_xfs_data *data, void *dirblock)
+{
+ int dirblksize = 1 << (data->sblock.log2_bsize + data->sblock.log2_dirblk);
+
+ return (struct grub_xfs_dirblock_tail *)
+ ((char *)dirblock + dirblksize - sizeof (struct grub_xfs_dirblock_tail));
+}
+
+static struct grub_xfs_dir2_entry *
+grub_xfs_first_de(struct grub_xfs_data *data, void *dirblock)
+{
+ if (data->hascrc)
+ return (struct grub_xfs_dir2_entry *)((char *)dirblock + 64);
+ return (struct grub_xfs_dir2_entry *)((char *)dirblock + 16);
+}
+
+static struct grub_xfs_dir2_entry *
+grub_xfs_next_de(struct grub_xfs_data *data, struct grub_xfs_dir2_entry *de)
+{
+ int size = sizeof (struct grub_xfs_dir2_entry) + de->len + 2 /* Tag */;
+
+ if (data->hasftype)
+ size++; /* File type */
+ return (struct grub_xfs_dir2_entry *)(((char *)de) + ALIGN_UP(size, 8));
+}
+
+/* This should return void * but XFS code is error-prone with alignment, so
+ return char to retain cast-align.
+ */
+static char *
+grub_xfs_btree_keys(struct grub_xfs_data *data,
+ struct grub_xfs_btree_node *leaf)
+{
+ char *keys = (char *)(leaf + 1);
+
+ if (data->hascrc)
+ keys += 48; /* skip crc, uuid, ... */
+ return keys;
+}
+
+static grub_err_t
+grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino,
+ struct grub_xfs_inode *inode)
+{
+ grub_uint64_t block = grub_xfs_inode_block (data, ino);
+ int offset = grub_xfs_inode_offset (data, ino);
+
+ grub_dprintf("xfs", "Reading inode (%"PRIuGRUB_UINT64_T") - %"PRIuGRUB_UINT64_T", %d\n",
+ ino, block, offset);
+ /* Read the inode. */
+ if (grub_disk_read (data->disk, block, offset, grub_xfs_inode_size(data),
+ inode))
+ return grub_errno;
+
+ if (grub_strncmp ((char *) inode->magic, "IN", 2))
+ return grub_error (GRUB_ERR_BAD_FS, "not a correct XFS inode");
+
+ return 0;
+}
+
+static grub_uint64_t
+get_fsb (const void *keys, int idx)
+{
+ const char *p = (const char *) keys + sizeof(grub_uint64_t) * idx;
+ return grub_be_to_cpu64 (grub_get_unaligned64 (p));
+}
+
+static grub_disk_addr_t
+grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+{
+ struct grub_xfs_btree_node *leaf = 0;
+ int ex, nrec;
+ struct grub_xfs_extent *exts;
+ grub_uint64_t ret = 0;
+
+ if (node->inode.format == XFS_INODE_FORMAT_BTREE)
+ {
+ struct grub_xfs_btree_root *root;
+ const char *keys;
+ int recoffset;
+
+ leaf = grub_malloc (node->data->bsize);
+ if (leaf == 0)
+ return 0;
+
+ root = (struct grub_xfs_btree_root *) grub_xfs_inode_data(&node->inode);
+ nrec = grub_be_to_cpu16 (root->numrecs);
+ keys = (char *) &root->keys[0];
+ if (node->inode.fork_offset)
+ recoffset = (node->inode.fork_offset - 1) / 2;
+ else
+ recoffset = (grub_xfs_inode_size(node->data)
+ - ((char *) keys - (char *) &node->inode))
+ / (2 * sizeof (grub_uint64_t));
+ do
+ {
+ int i;
+
+ for (i = 0; i < nrec; i++)
+ {
+ if (fileblock < get_fsb(keys, i))
+ break;
+ }
+
+ /* Sparse block. */
+ if (i == 0)
+ {
+ grub_free (leaf);
+ return 0;
+ }
+
+ if (grub_disk_read (node->data->disk,
+ GRUB_XFS_FSB_TO_BLOCK (node->data, get_fsb (keys, i - 1 + recoffset)) << (node->data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS),
+ 0, node->data->bsize, leaf))
+ return 0;
+
+ if ((!node->data->hascrc &&
+ grub_strncmp ((char *) leaf->magic, "BMAP", 4)) ||
+ (node->data->hascrc &&
+ grub_strncmp ((char *) leaf->magic, "BMA3", 4)))
+ {
+ grub_free (leaf);
+ grub_error (GRUB_ERR_BAD_FS, "not a correct XFS BMAP node");
+ return 0;
+ }
+
+ nrec = grub_be_to_cpu16 (leaf->numrecs);
+ keys = grub_xfs_btree_keys(node->data, leaf);
+ recoffset = ((node->data->bsize - ((char *) keys
+ - (char *) leaf))
+ / (2 * sizeof (grub_uint64_t)));
+ }
+ while (leaf->level);
+ exts = (struct grub_xfs_extent *) keys;
+ }
+ else if (node->inode.format == XFS_INODE_FORMAT_EXT)
+ {
+ nrec = grub_be_to_cpu32 (node->inode.nextents);
+ exts = (struct grub_xfs_extent *) grub_xfs_inode_data(&node->inode);
+ }
+ else
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "XFS does not support inode format %d yet",
+ node->inode.format);
+ return 0;
+ }
+
+ /* Iterate over each extent to figure out which extent has
+ the block we are looking for. */
+ for (ex = 0; ex < nrec; ex++)
+ {
+ grub_uint64_t start = GRUB_XFS_EXTENT_BLOCK (exts, ex);
+ grub_uint64_t offset = GRUB_XFS_EXTENT_OFFSET (exts, ex);
+ grub_uint64_t size = GRUB_XFS_EXTENT_SIZE (exts, ex);
+
+ /* Sparse block. */
+ if (fileblock < offset)
+ break;
+ else if (fileblock < offset + size)
+ {
+ ret = (fileblock - offset + start);
+ break;
+ }
+ }
+
+ grub_free (leaf);
+
+ return GRUB_XFS_FSB_TO_BLOCK(node->data, ret);
+}
+
+
+/* Read LEN bytes from the file described by DATA starting with byte
+ POS. Return the amount of read bytes in READ. */
+static grub_ssize_t
+grub_xfs_read_file (grub_fshelp_node_t node,
+ grub_disk_read_hook_t read_hook, void *read_hook_data,
+ grub_off_t pos, grub_size_t len, char *buf, grub_uint32_t header_size)
+{
+ return grub_fshelp_read_file (node->data->disk, node,
+ read_hook, read_hook_data,
+ pos, len, buf, grub_xfs_read_block,
+ grub_be_to_cpu64 (node->inode.size) + header_size,
+ node->data->sblock.log2_bsize
+ - GRUB_DISK_SECTOR_BITS, 0);
+}
+
+
+static char *
+grub_xfs_read_symlink (grub_fshelp_node_t node)
+{
+ grub_ssize_t size = grub_be_to_cpu64 (node->inode.size);
+
+ if (size < 0)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "invalid symlink");
+ return 0;
+ }
+
+ switch (node->inode.format)
+ {
+ case XFS_INODE_FORMAT_INO:
+ return grub_strndup (grub_xfs_inode_data(&node->inode), size);
+
+ case XFS_INODE_FORMAT_EXT:
+ {
+ char *symlink;
+ grub_ssize_t numread;
+ int off = 0;
+
+ if (node->data->hascrc)
+ off = 56;
+
+ symlink = grub_malloc (size + 1);
+ if (!symlink)
+ return 0;
+
+ node->inode.size = grub_be_to_cpu64 (size + off);
+ numread = grub_xfs_read_file (node, 0, 0, off, size, symlink, off);
+ if (numread != size)
+ {
+ grub_free (symlink);
+ return 0;
+ }
+ symlink[size] = '\0';
+ return symlink;
+ }
+ }
+
+ return 0;
+}
+
+
+static enum grub_fshelp_filetype
+grub_xfs_mode_to_filetype (grub_uint16_t mode)
+{
+ if ((grub_be_to_cpu16 (mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
+ return GRUB_FSHELP_DIR;
+ else if ((grub_be_to_cpu16 (mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
+ return GRUB_FSHELP_SYMLINK;
+ else if ((grub_be_to_cpu16 (mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
+ return GRUB_FSHELP_REG;
+ return GRUB_FSHELP_UNKNOWN;
+}
+
+
+/* Context for grub_xfs_iterate_dir. */
+struct grub_xfs_iterate_dir_ctx
+{
+ grub_fshelp_iterate_dir_hook_t hook;
+ void *hook_data;
+ struct grub_fshelp_node *diro;
+};
+
+/* Helper for grub_xfs_iterate_dir. */
+static int iterate_dir_call_hook (grub_uint64_t ino, const char *filename,
+ struct grub_xfs_iterate_dir_ctx *ctx)
+{
+ struct grub_fshelp_node *fdiro;
+ grub_err_t err;
+
+ fdiro = grub_malloc (grub_xfs_fshelp_size(ctx->diro->data) + 1);
+ if (!fdiro)
+ {
+ grub_print_error ();
+ return 0;
+ }
+
+ /* The inode should be read, otherwise the filetype can
+ not be determined. */
+ fdiro->ino = ino;
+ fdiro->inode_read = 1;
+ fdiro->data = ctx->diro->data;
+ err = grub_xfs_read_inode (ctx->diro->data, ino, &fdiro->inode);
+ if (err)
+ {
+ grub_print_error ();
+ return 0;
+ }
+
+ return ctx->hook (filename, grub_xfs_mode_to_filetype (fdiro->inode.mode),
+ fdiro, ctx->hook_data);
+}
+
+static int
+grub_xfs_iterate_dir (grub_fshelp_node_t dir,
+ grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
+{
+ struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
+ struct grub_xfs_iterate_dir_ctx ctx = {
+ .hook = hook,
+ .hook_data = hook_data,
+ .diro = diro
+ };
+
+ switch (diro->inode.format)
+ {
+ case XFS_INODE_FORMAT_INO:
+ {
+ struct grub_xfs_dir_header *head = (struct grub_xfs_dir_header *) grub_xfs_inode_data(&diro->inode);
+ struct grub_xfs_dir_entry *de = grub_xfs_inline_de(head);
+ int smallino = !head->largeino;
+ int i;
+ grub_uint64_t parent;
+
+ /* If small inode numbers are used to pack the direntry, the
+ parent inode number is small too. */
+ if (smallino)
+ parent = grub_be_to_cpu32 (head->parent.i4);
+ else
+ parent = grub_be_to_cpu64 (head->parent.i8);
+
+ /* Synthesize the direntries for `.' and `..'. */
+ if (iterate_dir_call_hook (diro->ino, ".", &ctx))
+ return 1;
+
+ if (iterate_dir_call_hook (parent, "..", &ctx))
+ return 1;
+
+ for (i = 0; i < head->count; i++)
+ {
+ grub_uint64_t ino;
+ grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de);
+ grub_uint8_t c;
+
+ /* inopos might be unaligned. */
+ if (smallino)
+ ino = (((grub_uint32_t) inopos[0]) << 24)
+ | (((grub_uint32_t) inopos[1]) << 16)
+ | (((grub_uint32_t) inopos[2]) << 8)
+ | (((grub_uint32_t) inopos[3]) << 0);
+ else
+ ino = (((grub_uint64_t) inopos[0]) << 56)
+ | (((grub_uint64_t) inopos[1]) << 48)
+ | (((grub_uint64_t) inopos[2]) << 40)
+ | (((grub_uint64_t) inopos[3]) << 32)
+ | (((grub_uint64_t) inopos[4]) << 24)
+ | (((grub_uint64_t) inopos[5]) << 16)
+ | (((grub_uint64_t) inopos[6]) << 8)
+ | (((grub_uint64_t) inopos[7]) << 0);
+
+ c = de->name[de->len];
+ de->name[de->len] = '\0';
+ if (iterate_dir_call_hook (ino, de->name, &ctx))
+ {
+ de->name[de->len] = c;
+ return 1;
+ }
+ de->name[de->len] = c;
+
+ de = grub_xfs_inline_next_de(dir->data, head, de);
+ }
+ break;
+ }
+
+ case XFS_INODE_FORMAT_BTREE:
+ case XFS_INODE_FORMAT_EXT:
+ {
+ grub_ssize_t numread;
+ char *dirblock;
+ grub_uint64_t blk;
+ int dirblk_size, dirblk_log2;
+
+ dirblk_log2 = (dir->data->sblock.log2_bsize
+ + dir->data->sblock.log2_dirblk);
+ dirblk_size = 1 << dirblk_log2;
+
+ dirblock = grub_malloc (dirblk_size);
+ if (! dirblock)
+ return 0;
+
+ /* Iterate over every block the directory has. */
+ for (blk = 0;
+ blk < (grub_be_to_cpu64 (dir->inode.size)
+ >> dirblk_log2);
+ blk++)
+ {
+ struct grub_xfs_dir2_entry *direntry =
+ grub_xfs_first_de(dir->data, dirblock);
+ int entries;
+ struct grub_xfs_dirblock_tail *tail =
+ grub_xfs_dir_tail(dir->data, dirblock);
+
+ numread = grub_xfs_read_file (dir, 0, 0,
+ blk << dirblk_log2,
+ dirblk_size, dirblock, 0);
+ if (numread != dirblk_size)
+ return 0;
+
+ entries = (grub_be_to_cpu32 (tail->leaf_count)
+ - grub_be_to_cpu32 (tail->leaf_stale));
+
+ if (!entries)
+ continue;
+
+ /* Iterate over all entries within this block. */
+ while ((char *)direntry < (char *)tail)
+ {
+ grub_uint8_t *freetag;
+ char *filename;
+
+ freetag = (grub_uint8_t *) direntry;
+
+ if (grub_get_unaligned16 (freetag) == 0XFFFF)
+ {
+ grub_uint8_t *skip = (freetag + sizeof (grub_uint16_t));
+
+ /* This entry is not used, go to the next one. */
+ direntry = (struct grub_xfs_dir2_entry *)
+ (((char *)direntry) +
+ grub_be_to_cpu16 (grub_get_unaligned16 (skip)));
+
+ continue;
+ }
+
+ filename = (char *)(direntry + 1);
+ /* The byte after the filename is for the filetype, padding, or
+ tag, which is not used by GRUB. So it can be overwritten. */
+ filename[direntry->len] = '\0';
+
+ if (iterate_dir_call_hook (grub_be_to_cpu64(direntry->inode),
+ filename, &ctx))
+ {
+ grub_free (dirblock);
+ return 1;
+ }
+
+ /* Check if last direntry in this block is
+ reached. */
+ entries--;
+ if (!entries)
+ break;
+
+ /* Select the next directory entry. */
+ direntry = grub_xfs_next_de(dir->data, direntry);
+ }
+ }
+ grub_free (dirblock);
+ break;
+ }
+
+ default:
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "XFS does not support inode format %d yet",
+ diro->inode.format);
+ }
+ return 0;
+}
+
+
+static struct grub_xfs_data *
+grub_xfs_mount (grub_disk_t disk)
+{
+ struct grub_xfs_data *data = 0;
+
+ data = grub_zalloc (sizeof (struct grub_xfs_data));
+ if (!data)
+ return 0;
+
+ grub_dprintf("xfs", "Reading sb\n");
+ /* Read the superblock. */
+ if (grub_disk_read (disk, 0, 0,
+ sizeof (struct grub_xfs_sblock), &data->sblock))
+ goto fail;
+
+ if (!grub_xfs_sb_valid(data))
+ goto fail;
+
+ data = grub_realloc (data,
+ sizeof (struct grub_xfs_data)
+ - sizeof (struct grub_xfs_inode)
+ + grub_xfs_inode_size(data) + 1);
+
+ if (! data)
+ goto fail;
+
+ data->diropen.data = data;
+ data->diropen.ino = grub_be_to_cpu64(data->sblock.rootino);
+ data->diropen.inode_read = 1;
+ data->bsize = grub_be_to_cpu32 (data->sblock.bsize);
+ data->agsize = grub_be_to_cpu32 (data->sblock.agsize);
+ data->hasftype = grub_xfs_sb_hasftype(data);
+ data->hascrc = grub_xfs_sb_hascrc(data);
+
+ data->disk = disk;
+ data->pos = 0;
+ grub_dprintf("xfs", "Reading root ino %"PRIuGRUB_UINT64_T"\n",
+ grub_cpu_to_be64(data->sblock.rootino));
+
+ grub_xfs_read_inode (data, data->diropen.ino, &data->diropen.inode);
+
+ return data;
+ fail:
+
+ if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
+ grub_error (GRUB_ERR_BAD_FS, "not an XFS filesystem");
+
+ grub_free (data);
+
+ return 0;
+}
+
+
+/* Context for grub_xfs_dir. */
+struct grub_xfs_dir_ctx
+{
+ grub_fs_dir_hook_t hook;
+ void *hook_data;
+};
+
+/* Helper for grub_xfs_dir. */
+static int
+grub_xfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node, void *data)
+{
+ struct grub_xfs_dir_ctx *ctx = data;
+ struct grub_dirhook_info info;
+
+ grub_memset (&info, 0, sizeof (info));
+ if (node->inode_read)
+ {
+ info.mtimeset = 1;
+ info.mtime = grub_be_to_cpu32 (node->inode.mtime.sec);
+ }
+ info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+ if (!info.dir)
+ info.size = node->inode.size;
+ grub_free (node);
+ return ctx->hook (filename, &info, ctx->hook_data);
+}
+
+static grub_err_t
+grub_xfs_dir (grub_device_t device, const char *path,
+ grub_fs_dir_hook_t hook, void *hook_data)
+{
+ struct grub_xfs_dir_ctx ctx = { hook, hook_data };
+ struct grub_xfs_data *data = 0;
+ struct grub_fshelp_node *fdiro = 0;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_xfs_mount (device->disk);
+ if (!data)
+ goto mount_fail;
+
+ grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_xfs_iterate_dir,
+ grub_xfs_read_symlink, GRUB_FSHELP_DIR);
+ if (grub_errno)
+ goto fail;
+
+ grub_xfs_iterate_dir (fdiro, grub_xfs_dir_iter, &ctx);
+
+ fail:
+ if (fdiro != &data->diropen)
+ grub_free (fdiro);
+ grub_free (data);
+
+ mount_fail:
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+
+/* Open a file named NAME and initialize FILE. */
+static grub_err_t
+grub_xfs_open (struct grub_file *file, const char *name)
+{
+ struct grub_xfs_data *data;
+ struct grub_fshelp_node *fdiro = 0;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_xfs_mount (file->device->disk);
+ if (!data)
+ goto mount_fail;
+
+ grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_xfs_iterate_dir,
+ grub_xfs_read_symlink, GRUB_FSHELP_REG);
+ if (grub_errno)
+ goto fail;
+
+ if (!fdiro->inode_read)
+ {
+ grub_xfs_read_inode (data, fdiro->ino, &fdiro->inode);
+ if (grub_errno)
+ goto fail;
+ }
+
+ if (fdiro != &data->diropen)
+ {
+ grub_memcpy (&data->diropen, fdiro, grub_xfs_fshelp_size(data));
+ grub_free (fdiro);
+ }
+
+ file->size = grub_be_to_cpu64 (data->diropen.inode.size);
+ file->data = data;
+ file->offset = 0;
+
+ return 0;
+
+ fail:
+ if (fdiro != &data->diropen)
+ grub_free (fdiro);
+ grub_free (data);
+
+ mount_fail:
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+
+static grub_ssize_t
+grub_xfs_read (grub_file_t file, char *buf, grub_size_t len)
+{
+ struct grub_xfs_data *data =
+ (struct grub_xfs_data *) file->data;
+
+ return grub_xfs_read_file (&data->diropen,
+ file->read_hook, file->read_hook_data,
+ file->offset, len, buf, 0);
+}
+
+
+static grub_err_t
+grub_xfs_close (grub_file_t file)
+{
+ grub_free (file->data);
+
+ grub_dl_unref (my_mod);
+
+ return GRUB_ERR_NONE;
+}
+
+
+static grub_err_t
+grub_xfs_label (grub_device_t device, char **label)
+{
+ struct grub_xfs_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_xfs_mount (disk);
+ if (data)
+ *label = grub_strndup ((char *) (data->sblock.label), 12);
+ else
+ *label = 0;
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_xfs_uuid (grub_device_t device, char **uuid)
+{
+ struct grub_xfs_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_xfs_mount (disk);
+ if (data)
+ {
+ *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
+ grub_be_to_cpu16 (data->sblock.uuid[0]),
+ grub_be_to_cpu16 (data->sblock.uuid[1]),
+ grub_be_to_cpu16 (data->sblock.uuid[2]),
+ grub_be_to_cpu16 (data->sblock.uuid[3]),
+ grub_be_to_cpu16 (data->sblock.uuid[4]),
+ grub_be_to_cpu16 (data->sblock.uuid[5]),
+ grub_be_to_cpu16 (data->sblock.uuid[6]),
+ grub_be_to_cpu16 (data->sblock.uuid[7]));
+ }
+ else
+ *uuid = NULL;
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+
+
+static struct grub_fs grub_xfs_fs =
+ {
+ .name = "xfs",
+ .fs_dir = grub_xfs_dir,
+ .fs_open = grub_xfs_open,
+ .fs_read = grub_xfs_read,
+ .fs_close = grub_xfs_close,
+ .fs_label = grub_xfs_label,
+ .fs_uuid = grub_xfs_uuid,
+#ifdef GRUB_UTIL
+ .reserved_first_sector = 0,
+ .blocklist_install = 1,
+#endif
+ .next = 0
+ };
+
+GRUB_MOD_INIT(xfs)
+{
+ grub_fs_register (&grub_xfs_fs);
+ my_mod = mod;
+}
+
+GRUB_MOD_FINI(xfs)
+{
+ grub_fs_unregister (&grub_xfs_fs);
+}
diff --git a/GRUB2/grub-2.04/grub-core/kern/disk.c b/GRUB2/grub-2.04/grub-core/kern/disk.c
new file mode 100644
index 00000000..e5c6f208
--- /dev/null
+++ b/GRUB2/grub-2.04/grub-core/kern/disk.c
@@ -0,0 +1,600 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define GRUB_CACHE_TIMEOUT 2
+
+/* The last time the disk was used. */
+static grub_uint64_t grub_last_time = 0;
+
+struct grub_disk_cache grub_disk_cache_table[GRUB_DISK_CACHE_NUM];
+
+void (*grub_disk_firmware_fini) (void);
+int grub_disk_firmware_is_tainted;
+
+#if DISK_CACHE_STATS
+static unsigned long grub_disk_cache_hits;
+static unsigned long grub_disk_cache_misses;
+
+void
+grub_disk_cache_get_performance (unsigned long *hits, unsigned long *misses)
+{
+ *hits = grub_disk_cache_hits;
+ *misses = grub_disk_cache_misses;
+}
+#endif
+
+grub_err_t (*grub_disk_write_weak) (grub_disk_t disk,
+ grub_disk_addr_t sector,
+ grub_off_t offset,
+ grub_size_t size,
+ const void *buf);
+#include "disk_common.c"
+
+void
+grub_disk_cache_invalidate_all (void)
+{
+ unsigned i;
+
+ for (i = 0; i < GRUB_DISK_CACHE_NUM; i++)
+ {
+ struct grub_disk_cache *cache = grub_disk_cache_table + i;
+
+ if (cache->data && ! cache->lock)
+ {
+ grub_free (cache->data);
+ cache->data = 0;
+ }
+ }
+}
+
+static char *
+grub_disk_cache_fetch (unsigned long dev_id, unsigned long disk_id,
+ grub_disk_addr_t sector)
+{
+ struct grub_disk_cache *cache;
+ unsigned cache_index;
+
+ cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+ cache = grub_disk_cache_table + cache_index;
+
+ if (cache->dev_id == dev_id && cache->disk_id == disk_id
+ && cache->sector == sector)
+ {
+ cache->lock = 1;
+#if DISK_CACHE_STATS
+ grub_disk_cache_hits++;
+#endif
+ return cache->data;
+ }
+
+#if DISK_CACHE_STATS
+ grub_disk_cache_misses++;
+#endif
+
+ return 0;
+}
+
+static void
+grub_disk_cache_unlock (unsigned long dev_id, unsigned long disk_id,
+ grub_disk_addr_t sector)
+{
+ struct grub_disk_cache *cache;
+ unsigned cache_index;
+
+ cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+ cache = grub_disk_cache_table + cache_index;
+
+ if (cache->dev_id == dev_id && cache->disk_id == disk_id
+ && cache->sector == sector)
+ cache->lock = 0;
+}
+
+static grub_err_t
+grub_disk_cache_store (unsigned long dev_id, unsigned long disk_id,
+ grub_disk_addr_t sector, const char *data)
+{
+ unsigned cache_index;
+ struct grub_disk_cache *cache;
+
+ cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+ cache = grub_disk_cache_table + cache_index;
+
+ cache->lock = 1;
+ grub_free (cache->data);
+ cache->data = 0;
+ cache->lock = 0;
+
+ cache->data = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
+ if (! cache->data)
+ return grub_errno;
+
+ grub_memcpy (cache->data, data,
+ GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
+ cache->dev_id = dev_id;
+ cache->disk_id = disk_id;
+ cache->sector = sector;
+
+ return GRUB_ERR_NONE;
+}
+
+
+
+grub_disk_dev_t grub_disk_dev_list;
+
+void
+grub_disk_dev_register (grub_disk_dev_t dev)
+{
+ dev->next = grub_disk_dev_list;
+ grub_disk_dev_list = dev;
+}
+
+void
+grub_disk_dev_unregister (grub_disk_dev_t dev)
+{
+ grub_disk_dev_t *p, q;
+
+ for (p = &grub_disk_dev_list, q = *p; q; p = &(q->next), q = q->next)
+ if (q == dev)
+ {
+ *p = q->next;
+ break;
+ }
+}
+
+/* Return the location of the first ',', if any, which is not
+ escaped by a '\'. */
+static const char *
+find_part_sep (const char *name)
+{
+ const char *p = name;
+ char c;
+
+ while ((c = *p++) != '\0')
+ {
+ if (c == '\\' && *p == ',')
+ p++;
+ else if (c == ',')
+ return p - 1;
+ }
+ return NULL;
+}
+
+grub_disk_t
+grub_disk_open (const char *name)
+{
+ const char *p;
+ grub_disk_t disk;
+ grub_disk_dev_t dev;
+ char *raw = (char *) name;
+ grub_uint64_t current_time;
+
+ grub_dprintf ("disk", "Opening `%s'...\n", name);
+
+ disk = (grub_disk_t) grub_zalloc (sizeof (*disk));
+ if (! disk)
+ return 0;
+ disk->log_sector_size = GRUB_DISK_SECTOR_BITS;
+ /* Default 1MiB of maximum agglomerate. */
+ disk->max_agglomerate = 1048576 >> (GRUB_DISK_SECTOR_BITS
+ + GRUB_DISK_CACHE_BITS);
+
+ p = find_part_sep (name);
+ if (p)
+ {
+ grub_size_t len = p - name;
+
+ raw = grub_malloc (len + 1);
+ if (! raw)
+ goto fail;
+
+ grub_memcpy (raw, name, len);
+ raw[len] = '\0';
+ disk->name = grub_strdup (raw);
+ }
+ else
+ disk->name = grub_strdup (name);
+ if (! disk->name)
+ goto fail;
+
+ for (dev = grub_disk_dev_list; dev; dev = dev->next)
+ {
+ if ((dev->disk_open) (raw, disk) == GRUB_ERR_NONE)
+ break;
+ else if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
+ grub_errno = GRUB_ERR_NONE;
+ else
+ goto fail;
+ }
+
+ if (! dev)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
+ name);
+ goto fail;
+ }
+ if (disk->log_sector_size > GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS
+ || disk->log_sector_size < GRUB_DISK_SECTOR_BITS)
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "sector sizes of %d bytes aren't supported yet",
+ (1 << disk->log_sector_size));
+ goto fail;
+ }
+
+ disk->dev = dev;
+
+ if (p)
+ {
+ disk->partition = grub_partition_probe (disk, p + 1);
+ if (! disk->partition)
+ {
+ /* TRANSLATORS: It means that the specified partition e.g.
+ hd0,msdos1=/dev/sda1 doesn't exist. */
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("no such partition"));
+ goto fail;
+ }
+ }
+
+ /* The cache will be invalidated about 2 seconds after a device was
+ closed. */
+ current_time = grub_get_time_ms ();
+
+ if (current_time > (grub_last_time
+ + GRUB_CACHE_TIMEOUT * 1000))
+ grub_disk_cache_invalidate_all ();
+
+ grub_last_time = current_time;
+
+ fail:
+
+ if (raw && raw != name)
+ grub_free (raw);
+
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_error_push ();
+ grub_dprintf ("disk", "Opening `%s' failed.\n", name);
+ grub_error_pop ();
+
+ grub_disk_close (disk);
+ return 0;
+ }
+
+ return disk;
+}
+
+void
+grub_disk_close (grub_disk_t disk)
+{
+ grub_partition_t part;
+ grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
+
+ if (disk->dev && disk->dev->disk_close)
+ (disk->dev->disk_close) (disk);
+
+ /* Reset the timer. */
+ grub_last_time = grub_get_time_ms ();
+
+ while (disk->partition)
+ {
+ part = disk->partition->parent;
+ grub_free (disk->partition);
+ disk->partition = part;
+ }
+ grub_free ((void *) disk->name);
+ grub_free (disk);
+}
+
+/* Small read (less than cache size and not pass across cache unit boundaries).
+ sector is already adjusted and is divisible by cache unit size.
+ */
+static grub_err_t
+grub_disk_read_small_real (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_off_t offset, grub_size_t size, void *buf)
+{
+ char *data;
+ char *tmp_buf;
+
+ /* Fetch the cache. */
+ data = grub_disk_cache_fetch (disk->dev->id, disk->id, sector);
+ if (data)
+ {
+ /* Just copy it! */
+ grub_memcpy (buf, data + offset, size);
+ grub_disk_cache_unlock (disk->dev->id, disk->id, sector);
+ return GRUB_ERR_NONE;
+ }
+
+ /* Allocate a temporary buffer. */
+ tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
+ if (! tmp_buf)
+ return grub_errno;
+
+ /* Otherwise read data from the disk actually. */
+ if (disk->total_sectors == GRUB_DISK_SIZE_UNKNOWN
+ || sector + GRUB_DISK_CACHE_SIZE
+ < (disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)))
+ {
+ grub_err_t err;
+ err = (disk->dev->disk_read) (disk, transform_sector (disk, sector),
+ 1U << (GRUB_DISK_CACHE_BITS
+ + GRUB_DISK_SECTOR_BITS
+ - disk->log_sector_size), tmp_buf);
+ if (!err)
+ {
+ /* Copy it and store it in the disk cache. */
+ grub_memcpy (buf, tmp_buf + offset, size);
+ grub_disk_cache_store (disk->dev->id, disk->id,
+ sector, tmp_buf);
+ grub_free (tmp_buf);
+ return GRUB_ERR_NONE;
+ }
+ }
+
+ grub_free (tmp_buf);
+ grub_errno = GRUB_ERR_NONE;
+
+ {
+ /* Uggh... Failed. Instead, just read necessary data. */
+ unsigned num;
+ grub_disk_addr_t aligned_sector;
+
+ sector += (offset >> GRUB_DISK_SECTOR_BITS);
+ offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1);
+ aligned_sector = (sector & ~((1ULL << (disk->log_sector_size
+ - GRUB_DISK_SECTOR_BITS))
+ - 1));
+ offset += ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS);
+ num = ((size + offset + (1ULL << (disk->log_sector_size))
+ - 1) >> (disk->log_sector_size));
+
+ tmp_buf = grub_malloc (num << disk->log_sector_size);
+ if (!tmp_buf)
+ return grub_errno;
+
+ if ((disk->dev->disk_read) (disk, transform_sector (disk, aligned_sector),
+ num, tmp_buf))
+ {
+ grub_error_push ();
+ grub_dprintf ("disk", "%s read failed\n", disk->name);
+ grub_error_pop ();
+ grub_free (tmp_buf);
+ return grub_errno;
+ }
+ grub_memcpy (buf, tmp_buf + offset, size);
+ grub_free (tmp_buf);
+ return GRUB_ERR_NONE;
+ }
+}
+
+static grub_err_t
+grub_disk_read_small (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_off_t offset, grub_size_t size, void *buf)
+{
+ grub_err_t err;
+
+ err = grub_disk_read_small_real (disk, sector, offset, size, buf);
+ if (err)
+ return err;
+ if (disk->read_hook)
+ (disk->read_hook) (sector + (offset >> GRUB_DISK_SECTOR_BITS),
+ offset & (GRUB_DISK_SECTOR_SIZE - 1),
+ size, disk->read_hook_data);
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t grub_disk_blocklist_read(void *chunklist, grub_uint64_t sector,
+ grub_uint64_t size, grub_uint32_t log_sector_size)
+{
+ ventoy_img_chunk *last_chunk = NULL;
+ ventoy_img_chunk *new_chunk = NULL;
+ ventoy_img_chunk_list *chunk_list = (ventoy_img_chunk_list *)chunklist;
+
+ if (chunk_list->cur_chunk == 0)
+ {
+ chunk_list->chunk[0].img_start_sector = 0;
+ chunk_list->chunk[0].img_end_sector = (size >> 11) - 1;
+ chunk_list->chunk[0].disk_start_sector = sector;
+ chunk_list->chunk[0].disk_end_sector = sector + (size >> log_sector_size) - 1;
+ chunk_list->cur_chunk = 1;
+ return 0;
+ }
+
+ last_chunk = chunk_list->chunk + chunk_list->cur_chunk - 1;
+ if (last_chunk->disk_end_sector + 1 == sector)
+ {
+ last_chunk->img_end_sector += (size >> 11);
+ last_chunk->disk_end_sector += (size >> log_sector_size);
+ return 0;
+ }
+
+ if (chunk_list->cur_chunk == chunk_list->max_chunk)
+ {
+ new_chunk = grub_realloc(chunk_list->chunk, chunk_list->max_chunk * 2 * sizeof(ventoy_img_chunk));
+ if (NULL == new_chunk)
+ {
+ return -1;
+ }
+ chunk_list->chunk = new_chunk;
+ chunk_list->max_chunk *= 2;
+
+ /* issue: update last_chunk */
+ last_chunk = chunk_list->chunk + chunk_list->cur_chunk - 1;
+ }
+
+ new_chunk = chunk_list->chunk + chunk_list->cur_chunk;
+ new_chunk->img_start_sector = last_chunk->img_end_sector + 1;
+ new_chunk->img_end_sector = new_chunk->img_start_sector + (size >> 11) - 1;
+ new_chunk->disk_start_sector = sector;
+ new_chunk->disk_end_sector = sector + (size >> log_sector_size) - 1;
+
+ chunk_list->cur_chunk++;
+
+ return 0;
+}
+
+/* Read data from the disk. */
+grub_err_t
+grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_off_t offset, grub_size_t size, void *buf)
+{
+ if (disk->read_hook == (grub_disk_read_hook_t)grub_disk_blocklist_read)
+ {
+ return grub_disk_blocklist_read((ventoy_img_chunk_list *)disk->read_hook_data, sector, size, disk->log_sector_size);
+ }
+
+ /* First of all, check if the region is within the disk. */
+ if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE)
+ {
+ grub_error_push ();
+ grub_dprintf ("disk", "Read out of range: sector 0x%llx (%s).\n",
+ (unsigned long long) sector, grub_errmsg);
+ grub_error_pop ();
+ return grub_errno;
+ }
+
+ /* First read until first cache boundary. */
+ if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1)))
+ {
+ grub_disk_addr_t start_sector;
+ grub_size_t pos;
+ grub_err_t err;
+ grub_size_t len;
+
+ start_sector = sector & ~((grub_disk_addr_t) GRUB_DISK_CACHE_SIZE - 1);
+ pos = (sector - start_sector) << GRUB_DISK_SECTOR_BITS;
+ len = ((GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS)
+ - pos - offset);
+ if (len > size)
+ len = size;
+ err = grub_disk_read_small (disk, start_sector,
+ offset + pos, len, buf);
+ if (err)
+ return err;
+ buf = (char *) buf + len;
+ size -= len;
+ offset += len;
+ sector += (offset >> GRUB_DISK_SECTOR_BITS);
+ offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1);
+ }
+
+ /* Until SIZE is zero... */
+ while (size >= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS))
+ {
+ char *data = NULL;
+ grub_disk_addr_t agglomerate;
+ grub_err_t err;
+
+ /* agglomerate read until we find a first cached entry. */
+ for (agglomerate = 0; agglomerate
+ < (size >> (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS))
+ && agglomerate < disk->max_agglomerate;
+ agglomerate++)
+ {
+ data = grub_disk_cache_fetch (disk->dev->id, disk->id,
+ sector + (agglomerate
+ << GRUB_DISK_CACHE_BITS));
+ if (data)
+ break;
+ }
+
+ if (data)
+ {
+ grub_memcpy ((char *) buf
+ + (agglomerate << (GRUB_DISK_CACHE_BITS
+ + GRUB_DISK_SECTOR_BITS)),
+ data, GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS);
+ grub_disk_cache_unlock (disk->dev->id, disk->id,
+ sector + (agglomerate
+ << GRUB_DISK_CACHE_BITS));
+ }
+
+ if (agglomerate)
+ {
+ grub_disk_addr_t i;
+
+ err = (disk->dev->disk_read) (disk, transform_sector (disk, sector),
+ agglomerate << (GRUB_DISK_CACHE_BITS
+ + GRUB_DISK_SECTOR_BITS
+ - disk->log_sector_size),
+ buf);
+ if (err)
+ return err;
+
+ for (i = 0; i < agglomerate; i ++)
+ grub_disk_cache_store (disk->dev->id, disk->id,
+ sector + (i << GRUB_DISK_CACHE_BITS),
+ (char *) buf
+ + (i << (GRUB_DISK_CACHE_BITS
+ + GRUB_DISK_SECTOR_BITS)));
+
+
+ if (disk->read_hook)
+ (disk->read_hook) (sector, 0, agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS),
+ disk->read_hook_data);
+
+ sector += agglomerate << GRUB_DISK_CACHE_BITS;
+ size -= agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS);
+ buf = (char *) buf
+ + (agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS));
+ }
+
+ if (data)
+ {
+ if (disk->read_hook)
+ (disk->read_hook) (sector, 0, (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS),
+ disk->read_hook_data);
+ sector += GRUB_DISK_CACHE_SIZE;
+ buf = (char *) buf + (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS);
+ size -= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS);
+ }
+ }
+
+ /* And now read the last part. */
+ if (size)
+ {
+ grub_err_t err;
+ err = grub_disk_read_small (disk, sector, 0, size, buf);
+ if (err)
+ return err;
+ }
+
+ return grub_errno;
+}
+
+grub_uint64_t
+grub_disk_get_size (grub_disk_t disk)
+{
+ if (disk->partition)
+ return grub_partition_get_len (disk->partition);
+ else if (disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN)
+ return disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
+ else
+ return GRUB_DISK_SIZE_UNKNOWN;
+}
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/ventoy.c b/GRUB2/grub-2.04/grub-core/ventoy/ventoy.c
index 459464d1..1978daef 100644
--- a/GRUB2/grub-2.04/grub-core/ventoy/ventoy.c
+++ b/GRUB2/grub-2.04/grub-core/ventoy/ventoy.c
@@ -37,6 +37,7 @@
#include
#endif
#include
+#include
#include
#include "ventoy_def.h"
@@ -100,6 +101,36 @@ int ventoy_is_efi_os(void)
return g_efi_os;
}
+static int ventoy_get_fs_type(const char *fs)
+{
+ if (NULL == fs)
+ {
+ return ventoy_fs_max;
+ }
+ else if (grub_strncmp(fs, "exfat", 5) == 0)
+ {
+ return ventoy_fs_exfat;
+ }
+ else if (grub_strncmp(fs, "ntfs", 4) == 0)
+ {
+ return ventoy_fs_ntfs;
+ }
+ else if (grub_strncmp(fs, "ext", 3) == 0)
+ {
+ return ventoy_fs_ext;
+ }
+ else if (grub_strncmp(fs, "xfs", 3) == 0)
+ {
+ return ventoy_fs_xfs;
+ }
+ else if (grub_strncmp(fs, "udf", 3) == 0)
+ {
+ return ventoy_fs_udf;
+ }
+
+ return ventoy_fs_max;
+}
+
static int ventoy_string_check(const char *str, grub_char_check_func check)
{
if (!str)
@@ -942,6 +973,12 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char
goto fail;
}
+ if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
+ {
+ debug("unsupported fs:<%s>\n", fs->name);
+ goto fail;
+ }
+
grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
g_img_iterator_head.dirlen = 1;
@@ -1212,19 +1249,7 @@ void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size);
param->vtoy_disk_part_id = disk->partition->number + 1;
-
- if (grub_strcmp(file->fs->name, "exfat") == 0)
- {
- param->vtoy_disk_part_type = 0;
- }
- else if (grub_strcmp(file->fs->name, "ntfs") == 0)
- {
- param->vtoy_disk_part_type = 1;
- }
- else
- {
- param->vtoy_disk_part_type = 0xFFFF;
- }
+ param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name);
pos = grub_strstr(file->name, "/");
if (!pos)
@@ -1251,6 +1276,52 @@ void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
return;
}
+static int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
+{
+ int fs_type;
+ grub_uint32_t i = 0;
+ grub_uint32_t sector = 0;
+ grub_uint32_t count = 0;
+ grub_off_t size = 0;
+ grub_off_t read = 0;
+
+ fs_type = ventoy_get_fs_type(file->fs->name);
+ if (fs_type == ventoy_fs_exfat)
+ {
+ grub_fat_get_file_chunk(start, file, chunklist);
+ }
+ else
+ {
+ file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
+ file->read_hook_data = chunklist;
+
+ for (size = file->size; size > 0; size -= read)
+ {
+ read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size;
+ grub_file_read(file, NULL, read);
+ }
+
+ for (i = 0; start > 0 && i < chunklist->cur_chunk; i++)
+ {
+ chunklist->chunk[i].disk_start_sector += start;
+ chunklist->chunk[i].disk_end_sector += start;
+ }
+
+ if (ventoy_fs_udf == fs_type)
+ {
+ for (i = 0; i < chunklist->cur_chunk; i++)
+ {
+ count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2;
+ chunklist->chunk[i].img_start_sector = sector;
+ chunklist->chunk[i].img_end_sector = sector + count - 1;
+ sector += count;
+ }
+ }
+ }
+
+ return 0;
+}
+
static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
{
grub_file_t file;
@@ -1280,8 +1351,7 @@ static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, ch
g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
g_img_chunk_list.cur_chunk = 0;
- debug("get fat file chunk part start:%llu\n", (unsigned long long)file->device->disk->partition->start);
- grub_fat_get_file_chunk(file->device->disk->partition->start, file, &g_img_chunk_list);
+ ventoy_get_block_list(file, &g_img_chunk_list, file->device->disk->partition->start);
grub_file_close(file);
@@ -1311,6 +1381,121 @@ static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int arg
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
+#ifdef GRUB_MACHINE_EFI
+static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+ return 0;
+}
+#else
+static grub_err_t ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ int rc = 0;
+ ulong chain_len = 0;
+ char *chain_data = NULL;
+ char *relocator_addr = NULL;
+ grub_relocator_chunk_t ch;
+ struct grub_relocator *relocator = NULL;
+ char envbuf[64] = { 0 };
+
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ if (argc != 2)
+ {
+ return 1;
+ }
+
+ chain_data = (char *)grub_strtoul(args[0], NULL, 16);
+ chain_len = grub_strtoul(args[1], NULL, 10);
+
+ relocator = grub_relocator_new ();
+ if (!relocator)
+ {
+ debug("grub_relocator_new failed %p %lu\n", chain_data, chain_len);
+ return 1;
+ }
+
+ rc = grub_relocator_alloc_chunk_addr (relocator, &ch,
+ 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
+ chain_len);
+ if (rc)
+ {
+ debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc, chain_data, chain_len);
+ grub_relocator_unload (relocator);
+ return 1;
+ }
+
+ relocator_addr = get_virtual_current_address(ch);
+
+ grub_memcpy(relocator_addr, chain_data, chain_len);
+
+ grub_relocator_unload (relocator);
+
+ grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)relocator_addr);
+ grub_env_set("vtoy_chain_relocator_addr", envbuf);
+
+ VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+#endif
+
+static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ grub_uint32_t i;
+ grub_file_t file;
+ ventoy_img_chunk_list chunklist;
+
+ (void)ctxt;
+ (void)argc;
+
+ file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
+ if (!file)
+ {
+ return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
+ }
+
+ /* get image chunk data */
+ grub_memset(&chunklist, 0, sizeof(chunklist));
+ chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
+ if (NULL == chunklist.chunk)
+ {
+ return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
+ }
+
+ chunklist.max_chunk = DEFAULT_CHUNK_NUM;
+ chunklist.cur_chunk = 0;
+
+ ventoy_get_block_list(file, &chunklist, 0);
+
+ grub_file_close(file);
+
+ grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
+
+ for (i = 0; i < chunklist.cur_chunk; i++)
+ {
+ grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector,
+ (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector));
+ }
+
+ grub_printf("\n==================================\n");
+ for (i = 0; i < chunklist.cur_chunk; i++)
+ {
+ grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
+ (ulonglong)chunklist.chunk[i].img_start_sector,
+ (ulonglong)chunklist.chunk[i].img_end_sector,
+ (ulonglong)chunklist.chunk[i].disk_start_sector,
+ (ulonglong)chunklist.chunk[i].disk_end_sector
+ );
+ }
+
+ grub_free(chunklist.chunk);
+
+ VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+
static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
{
int i;
@@ -1412,7 +1597,7 @@ static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc,
if (argc != 2)
{
- debug("Invlaid argc %d\n", argc);
+ debug("Invalid argc %d\n", argc);
return 0;
}
@@ -1635,6 +1820,8 @@ static cmd_para ventoy_cmds[] =
{ "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
{ "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
+ { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata, 0, NULL, "", "", NULL },
+ { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL },
{ "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/ventoy_def.h b/GRUB2/grub-2.04/grub-core/ventoy/ventoy_def.h
index 085fd1e8..c0456236 100644
--- a/GRUB2/grub-2.04/grub-core/ventoy/ventoy_def.h
+++ b/GRUB2/grub-2.04/grub-core/ventoy/ventoy_def.h
@@ -23,6 +23,8 @@
#define VTOY_MAX_SCRIPT_BUF (4 * 1024 * 1024)
+#define VTOY_SIZE_1GB 1073741824
+
#define JSON_SUCCESS 0
#define JSON_FAILED 1
#define JSON_NOT_FOUND 2
diff --git a/GRUB2/grub-2.04/grub-core/ventoy/ventoy_windows.c b/GRUB2/grub-2.04/grub-core/ventoy/ventoy_windows.c
index e2b4eed9..529d3086 100644
--- a/GRUB2/grub-2.04/grub-core/ventoy/ventoy_windows.c
+++ b/GRUB2/grub-2.04/grub-core/ventoy/ventoy_windows.c
@@ -401,7 +401,7 @@ static int ventoy_update_all_hash(void *meta_data, wim_directory_entry *dir)
return 0;
}
- if (dir->len == 0)
+ if (dir->len < sizeof(wim_directory_entry))
{
return 0;
}
@@ -420,7 +420,7 @@ static int ventoy_update_all_hash(void *meta_data, wim_directory_entry *dir)
}
dir = (wim_directory_entry *)((char *)dir + dir->len);
- } while (dir->len);
+ } while (dir->len >= sizeof(wim_directory_entry));
return 0;
}
@@ -957,4 +957,3 @@ grub_err_t ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt, int argc, c
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
-
diff --git a/GRUB2/grub-2.04/include/grub/disk.h b/GRUB2/grub-2.04/include/grub/disk.h
new file mode 100644
index 00000000..ef4e55c1
--- /dev/null
+++ b/GRUB2/grub-2.04/include/grub/disk.h
@@ -0,0 +1,265 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,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 .
+ */
+
+#ifndef GRUB_DISK_HEADER
+#define GRUB_DISK_HEADER 1
+
+#include
+
+#include
+#include
+#include
+#include
+/* For NULL. */
+#include
+
+/* These are used to set a device id. When you add a new disk device,
+ you must define a new id for it here. */
+enum grub_disk_dev_id
+ {
+ GRUB_DISK_DEVICE_BIOSDISK_ID,
+ GRUB_DISK_DEVICE_OFDISK_ID,
+ GRUB_DISK_DEVICE_LOOPBACK_ID,
+ GRUB_DISK_DEVICE_EFIDISK_ID,
+ GRUB_DISK_DEVICE_DISKFILTER_ID,
+ GRUB_DISK_DEVICE_HOST_ID,
+ GRUB_DISK_DEVICE_ATA_ID,
+ GRUB_DISK_DEVICE_MEMDISK_ID,
+ GRUB_DISK_DEVICE_NAND_ID,
+ GRUB_DISK_DEVICE_SCSI_ID,
+ GRUB_DISK_DEVICE_CRYPTODISK_ID,
+ GRUB_DISK_DEVICE_ARCDISK_ID,
+ GRUB_DISK_DEVICE_HOSTDISK_ID,
+ GRUB_DISK_DEVICE_PROCFS_ID,
+ GRUB_DISK_DEVICE_CBFSDISK_ID,
+ GRUB_DISK_DEVICE_UBOOTDISK_ID,
+ GRUB_DISK_DEVICE_XEN,
+ GRUB_DISK_DEVICE_OBDISK_ID,
+ };
+
+struct grub_disk;
+#ifdef GRUB_UTIL
+struct grub_disk_memberlist;
+#endif
+
+typedef enum
+ {
+ GRUB_DISK_PULL_NONE,
+ GRUB_DISK_PULL_REMOVABLE,
+ GRUB_DISK_PULL_RESCAN,
+ GRUB_DISK_PULL_MAX
+ } grub_disk_pull_t;
+
+typedef int (*grub_disk_dev_iterate_hook_t) (const char *name, void *data);
+
+/* Disk device. */
+struct grub_disk_dev
+{
+ /* The device name. */
+ const char *name;
+
+ /* The device id used by the cache manager. */
+ enum grub_disk_dev_id id;
+
+ /* Call HOOK with each device name, until HOOK returns non-zero. */
+ int (*disk_iterate) (grub_disk_dev_iterate_hook_t hook, void *hook_data,
+ grub_disk_pull_t pull);
+
+ /* Open the device named NAME, and set up DISK. */
+ grub_err_t (*disk_open) (const char *name, struct grub_disk *disk);
+
+ /* Close the disk DISK. */
+ void (*disk_close) (struct grub_disk *disk);
+
+ /* Read SIZE sectors from the sector SECTOR of the disk DISK into BUF. */
+ grub_err_t (*disk_read) (struct grub_disk *disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf);
+
+ /* Write SIZE sectors from BUF into the sector SECTOR of the disk DISK. */
+ grub_err_t (*disk_write) (struct grub_disk *disk, grub_disk_addr_t sector,
+ grub_size_t size, const char *buf);
+
+#ifdef GRUB_UTIL
+ struct grub_disk_memberlist *(*disk_memberlist) (struct grub_disk *disk);
+ const char * (*disk_raidname) (struct grub_disk *disk);
+#endif
+
+ /* The next disk device. */
+ struct grub_disk_dev *next;
+};
+typedef struct grub_disk_dev *grub_disk_dev_t;
+
+extern grub_disk_dev_t EXPORT_VAR (grub_disk_dev_list);
+
+struct grub_partition;
+
+typedef void (*grub_disk_read_hook_t) (grub_disk_addr_t sector,
+ unsigned offset, unsigned length,
+ void *data);
+
+/* Disk. */
+struct grub_disk
+{
+ /* The disk name. */
+ const char *name;
+
+ /* The underlying disk device. */
+ grub_disk_dev_t dev;
+
+ /* The total number of sectors. */
+ grub_uint64_t total_sectors;
+
+ /* Logarithm of sector size. */
+ unsigned int log_sector_size;
+
+ /* Maximum number of sectors read divided by GRUB_DISK_CACHE_SIZE. */
+ unsigned int max_agglomerate;
+
+ /* The id used by the disk cache manager. */
+ unsigned long id;
+
+ /* The partition information. This is machine-specific. */
+ struct grub_partition *partition;
+
+ /* Called when a sector was read. OFFSET is between 0 and
+ the sector size minus 1, and LENGTH is between 0 and the sector size. */
+ grub_disk_read_hook_t read_hook;
+
+ /* Caller-specific data passed to the read hook. */
+ void *read_hook_data;
+
+ /* Device-specific data. */
+ void *data;
+};
+typedef struct grub_disk *grub_disk_t;
+
+#ifdef GRUB_UTIL
+struct grub_disk_memberlist
+{
+ grub_disk_t disk;
+ struct grub_disk_memberlist *next;
+};
+typedef struct grub_disk_memberlist *grub_disk_memberlist_t;
+#endif
+
+/* The sector size. */
+#define GRUB_DISK_SECTOR_SIZE 0x200
+#define GRUB_DISK_SECTOR_BITS 9
+
+/* The maximum number of disk caches. */
+#define GRUB_DISK_CACHE_NUM 1021
+
+/* The size of a disk cache in 512B units. Must be at least as big as the
+ largest supported sector size, currently 16K. */
+#define GRUB_DISK_CACHE_BITS 6
+#define GRUB_DISK_CACHE_SIZE (1 << GRUB_DISK_CACHE_BITS)
+
+#define GRUB_DISK_MAX_MAX_AGGLOMERATE ((1 << (30 - GRUB_DISK_CACHE_BITS - GRUB_DISK_SECTOR_BITS)) - 1)
+
+/* Return value of grub_disk_get_size() in case disk size is unknown. */
+#define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL
+
+/* This is called from the memory manager. */
+void grub_disk_cache_invalidate_all (void);
+
+void EXPORT_FUNC(grub_disk_dev_register) (grub_disk_dev_t dev);
+void EXPORT_FUNC(grub_disk_dev_unregister) (grub_disk_dev_t dev);
+static inline int
+grub_disk_dev_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data)
+{
+ grub_disk_dev_t p;
+ grub_disk_pull_t pull;
+
+ for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
+ for (p = grub_disk_dev_list; p; p = p->next)
+ if (p->disk_iterate && (p->disk_iterate) (hook, hook_data, pull))
+ return 1;
+
+ return 0;
+}
+
+grub_disk_t EXPORT_FUNC(grub_disk_open) (const char *name);
+void EXPORT_FUNC(grub_disk_close) (grub_disk_t disk);
+grub_err_t EXPORT_FUNC(grub_disk_blocklist_read)(void *chunklist, grub_uint64_t sector,
+ grub_uint64_t size, grub_uint32_t log_sector_size);
+
+grub_err_t EXPORT_FUNC(grub_disk_read) (grub_disk_t disk,
+ grub_disk_addr_t sector,
+ grub_off_t offset,
+ grub_size_t size,
+ void *buf);
+grub_err_t grub_disk_write (grub_disk_t disk,
+ grub_disk_addr_t sector,
+ grub_off_t offset,
+ grub_size_t size,
+ const void *buf);
+extern grub_err_t (*EXPORT_VAR(grub_disk_write_weak)) (grub_disk_t disk,
+ grub_disk_addr_t sector,
+ grub_off_t offset,
+ grub_size_t size,
+ const void *buf);
+
+
+grub_uint64_t EXPORT_FUNC(grub_disk_get_size) (grub_disk_t disk);
+
+#if DISK_CACHE_STATS
+void
+EXPORT_FUNC(grub_disk_cache_get_performance) (unsigned long *hits, unsigned long *misses);
+#endif
+
+extern void (* EXPORT_VAR(grub_disk_firmware_fini)) (void);
+extern int EXPORT_VAR(grub_disk_firmware_is_tainted);
+
+static inline void
+grub_stop_disk_firmware (void)
+{
+ /* To prevent two drivers operating on the same disks. */
+ grub_disk_firmware_is_tainted = 1;
+ if (grub_disk_firmware_fini)
+ {
+ grub_disk_firmware_fini ();
+ grub_disk_firmware_fini = NULL;
+ }
+}
+
+/* Disk cache. */
+struct grub_disk_cache
+{
+ enum grub_disk_dev_id dev_id;
+ unsigned long disk_id;
+ grub_disk_addr_t sector;
+ char *data;
+ int lock;
+};
+
+extern struct grub_disk_cache EXPORT_VAR(grub_disk_cache_table)[GRUB_DISK_CACHE_NUM];
+
+#if defined (GRUB_UTIL)
+void grub_lvm_init (void);
+void grub_ldm_init (void);
+void grub_mdraid09_init (void);
+void grub_mdraid1x_init (void);
+void grub_diskfilter_init (void);
+void grub_lvm_fini (void);
+void grub_ldm_fini (void);
+void grub_mdraid09_fini (void);
+void grub_mdraid1x_fini (void);
+void grub_diskfilter_fini (void);
+#endif
+
+#endif /* ! GRUB_DISK_HEADER */
diff --git a/GRUB2/grub-2.04/include/grub/ventoy.h b/GRUB2/grub-2.04/include/grub/ventoy.h
index 4f3de665..205ba1d1 100644
--- a/GRUB2/grub-2.04/include/grub/ventoy.h
+++ b/GRUB2/grub-2.04/include/grub/ventoy.h
@@ -28,6 +28,17 @@
#define VENTOY_GUID { 0x77772020, 0x2e77, 0x6576, { 0x6e, 0x74, 0x6f, 0x79, 0x2e, 0x6e, 0x65, 0x74 }}
+typedef enum ventoy_fs_type
+{
+ ventoy_fs_exfat = 0, /* 0: exfat */
+ ventoy_fs_ntfs, /* 1: NTFS */
+ ventoy_fs_ext, /* 2: ext2/ext3/ext4 */
+ ventoy_fs_xfs, /* 3: XFS */
+ ventoy_fs_udf, /* 4: UDF */
+
+ ventoy_fs_max
+}ventoy_fs_type;
+
#pragma pack(1)
typedef struct ventoy_guid
diff --git a/INSTALL/EFI/BOOT/grubx64_real.efi b/INSTALL/EFI/BOOT/grubx64_real.efi
index 9d9ce3b9..e0624c0c 100644
Binary files a/INSTALL/EFI/BOOT/grubx64_real.efi and b/INSTALL/EFI/BOOT/grubx64_real.efi differ
diff --git a/INSTALL/Ventoy2Disk.exe b/INSTALL/Ventoy2Disk.exe
index 441c04c7..38cbf07e 100644
Binary files a/INSTALL/Ventoy2Disk.exe and b/INSTALL/Ventoy2Disk.exe differ
diff --git a/INSTALL/Ventoy2Disk.sh b/INSTALL/Ventoy2Disk.sh
index 29e30710..64322178 100644
--- a/INSTALL/Ventoy2Disk.sh
+++ b/INSTALL/Ventoy2Disk.sh
@@ -9,12 +9,16 @@ fi
. ./tool/ventoy_lib.sh
print_usage() {
- echo 'Usage: VentoyInstaller.sh OPTION /dev/sdX'
- echo ' OPTION:'
+ echo 'Usage: Ventoy2Disk.sh CMD [ OPTION ] /dev/sdX'
+ echo ' CMD:'
echo ' -i install ventoy to sdX (fail if disk already installed with ventoy)'
echo ' -u update ventoy in sdX'
echo ' -I force install ventoy to sdX (no matter installed or not)'
echo ''
+ echo ' OPTION: (optional)'
+ echo ' -s enable secure boot support (default is disabled)'
+ echo ''
+
}
echo ''
@@ -38,6 +42,7 @@ while [ -n "$1" ]; do
SECUREBOOT="YES"
else
if ! [ -b "$1" ]; then
+ vterr "$1 is NOT a valid device"
print_usage
cd $OLDDIR
exit 1
@@ -54,13 +59,25 @@ if [ -z "$MODE" ]; then
exit 1
fi
-if [ -z "$SUDO_USER" ]; then
- if [ "$USER" != "root" ]; then
- vterr "EUID is $EUID root permission is required."
- echo ''
- cd $OLDDIR
- exit 1
- fi
+if ! [ -b "$DISK" ]; then
+ vterr "Disk $DISK does not exist"
+ cd $OLDDIR
+ exit 1
+fi
+
+if [ -e /sys/class/block/${DISK#/dev/}/start ]; then
+ vterr "$DISK is a partition, please use the whole disk"
+ cd $OLDDIR
+ exit 1
+fi
+
+if dd if="$DISK" of=/dev/null bs=1 count=1 >/dev/null 2>&1; then
+ vtdebug "root permission check ok ..."
+else
+ vterr "Failed to access $DISK, maybe root privilege is needed!"
+ echo ''
+ cd $OLDDIR
+ exit 1
fi
vtdebug "MODE=$MODE FORCE=$FORCE"
@@ -93,20 +110,6 @@ if ! check_tool_work_ok; then
exit 1
fi
-
-if ! [ -b "$DISK" ]; then
- vterr "Disk $DISK does not exist"
- cd $OLDDIR
- exit 1
-fi
-
-
-if [ -e /sys/class/block/${DISK#/dev/}/start ]; then
- vterr "$DISK is a partition, please use the whole disk"
- cd $OLDDIR
- exit 1
-fi
-
grep "^$DISK" /proc/mounts | while read mtline; do
mtpnt=$(echo $mtline | awk '{print $DISK}')
vtdebug "Trying to umount $mtpnt ..."
@@ -242,6 +245,7 @@ if [ "$MODE" = "install" ]; then
rm -f ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
rm -f ./tmp_mnt/EFI/BOOT/grubx64.efi
rm -f ./tmp_mnt/EFI/BOOT/MokManager.efi
+ rm -f ./tmp_mnt/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
mv ./tmp_mnt/EFI/BOOT/grubx64_real.efi ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
umount ./tmp_mnt
@@ -305,6 +309,7 @@ else
rm -f ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
rm -f ./tmp_mnt/EFI/BOOT/grubx64.efi
rm -f ./tmp_mnt/EFI/BOOT/MokManager.efi
+ rm -f ./tmp_mnt/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
mv ./tmp_mnt/EFI/BOOT/grubx64_real.efi ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
umount ./tmp_mnt
diff --git a/INSTALL/grub/grub.cfg b/INSTALL/grub/grub.cfg
index da81008a..763fed82 100644
--- a/INSTALL/grub/grub.cfg
+++ b/INSTALL/grub/grub.cfg
@@ -50,6 +50,21 @@ function get_os_type {
fi
}
+function vt_check_pe {
+ unset VT_PE_SUPPORT
+
+ if [ -f $1/HBCD_PE.ini ]; then
+ set ventoy_compatible=YES
+ set VT_PE_SUPPORT=YES
+ elif [ -f $1/easyu.flg ]; then
+ set VT_PE_SUPPORT=YES
+ elif [ -f $1/USM.ICO ]; then
+ set VT_PE_SUPPORT=YES
+ elif [ -d $1/USM_TOOL ]; then
+ set VT_PE_SUPPORT=YES
+ fi
+}
+
function locate_initrd {
vt_linux_locate_initrd
@@ -62,7 +77,8 @@ function locate_initrd {
function find_wim_file {
unset ventoy_wim_file
- for file in "sources/boot.wim" "sources/BOOT.WIM" "Sources/Win10PEx64.WIM" "boot/BOOT.WIM" "winpe_x64.wim"; do
+ for file in "sources/boot.wim" "sources/BOOT.WIM" "Sources/Win10PEx64.WIM" "boot/BOOT.WIM" \
+ "winpe_x64.wim" "boot/10pex64.wim" "BOOT/USM1PE6L.WIM" "BOOT/USM1PE6F.WIM"; do
if [ -e $1/$file ]; then
set ventoy_wim_file=$1/$file
break
@@ -114,6 +130,8 @@ function distro_specify_initrd_file_phase2 {
vt_linux_specify_initrd_file /isolinux/initramfs
elif [ -f (loop)/boot/iniramfs.igz ]; then
vt_linux_specify_initrd_file /boot/iniramfs.igz
+ elif [ -f (loop)/initrd-x86_64 ]; then
+ vt_linux_specify_initrd_file /initrd-x86_64
fi
}
@@ -248,10 +266,11 @@ function uefi_iso_menu_func {
vt_img_sector ${1}${chosen_path}
if [ "$vtoy_os" = "Windows" ]; then
- if [ "$ventoy_fs_probe" = "iso9660" ]; then
- set ventoy_compatible=YES
- elif [ -f (loop)/HBCD_PE.ini ]; then
- set ventoy_compatible=YES
+ vt_check_pe (loop)
+ if [ "$VT_PE_SUPPORT" != "YES" ]; then
+ if [ "$ventoy_fs_probe" = "iso9660" ]; then
+ set ventoy_compatible=YES
+ fi
fi
uefi_windows_menu_func $1 ${chosen_path}
@@ -293,8 +312,7 @@ function legacy_windows_menu_func {
fi
if [ -n "$vtoy_chain_mem_addr" ]; then
- linux16 $vtoy_path/ipxe.krn ${vtdebug_flag} ibft
- initrd16 mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
+ linux16 $vtoy_path/ipxe.krn ${vtdebug_flag} ibft mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
boot
else
echo "chain empty failed"
@@ -349,9 +367,8 @@ function legacy_linux_menu_func {
sleep 5
fi
- if [ -n "$vtoy_chain_mem_addr" ]; then
- linux16 $vtoy_path/ipxe.krn ${vtdebug_flag}
- initrd16 mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
+ if [ -n "$vtoy_chain_mem_addr" ]; then
+ linux16 $vtoy_path/ipxe.krn ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
boot
else
echo "chain empty failed"
@@ -389,10 +406,11 @@ function legacy_iso_menu_func {
vt_img_sector ${1}${chosen_path}
if [ "$vtoy_os" = "Windows" ]; then
- if [ "$ventoy_fs_probe" = "iso9660" ]; then
- set ventoy_compatible=YES
- elif [ -f (loop)/HBCD_PE.ini ]; then
- set ventoy_compatible=YES
+ vt_check_pe (loop)
+ if [ "$VT_PE_SUPPORT" != "YES" ]; then
+ if [ "$ventoy_fs_probe" = "iso9660" ]; then
+ set ventoy_compatible=YES
+ fi
fi
legacy_windows_menu_func $1 ${chosen_path}
@@ -435,7 +453,7 @@ function common_menuentry {
#############################################################
#############################################################
-set VENTOY_VERSION="1.0.09"
+set VENTOY_VERSION="1.0.9Y"
# Default menu display mode, you can change it as you want.
diff --git a/INSTALL/grub/i386-pc/core.img b/INSTALL/grub/i386-pc/core.img
index a9464bc9..4874c6a0 100644
Binary files a/INSTALL/grub/i386-pc/core.img and b/INSTALL/grub/i386-pc/core.img differ
diff --git a/INSTALL/tool/ventoy_lib.sh b/INSTALL/tool/ventoy_lib.sh
index 3562927c..86317c78 100644
--- a/INSTALL/tool/ventoy_lib.sh
+++ b/INSTALL/tool/ventoy_lib.sh
@@ -14,16 +14,6 @@ ventoy_true() {
}
ventoy_is_linux64() {
- if [ -e /lib64 ]; then
- ventoy_true
- return
- fi
-
- if [ -e /usr/lib64 ]; then
- ventoy_true
- return
- fi
-
if uname -a | egrep -q 'x86_64|amd64'; then
ventoy_true
return
@@ -165,12 +155,12 @@ is_disk_contains_ventoy() {
return
fi
- PART1_TYPE=$(dd if=$DISK bs=1 count=1 skip=450 status=none | ./tool/hexdump -n1 -e '1/1 "%02X"')
- if [ "$PART1_TYPE" != "07" ]; then
- vtdebug "part1 type is $PART2_TYPE not 07"
- ventoy_false
- return
- fi
+ # PART1_TYPE=$(dd if=$DISK bs=1 count=1 skip=450 status=none | ./tool/hexdump -n1 -e '1/1 "%02X"')
+ # if [ "$PART1_TYPE" != "07" ]; then
+ # vtdebug "part1 type is $PART2_TYPE not 07"
+ # ventoy_false
+ # return
+ # fi
if [ -e /sys/class/block/${PART1#/dev/}/start ]; then
PART1_START=$(cat /sys/class/block/${PART1#/dev/}/start)
diff --git a/INSTALL/ventoy/ipxe.krn b/INSTALL/ventoy/ipxe.krn
index 5c0fa256..d5ae13ed 100644
Binary files a/INSTALL/ventoy/ipxe.krn and b/INSTALL/ventoy/ipxe.krn differ
diff --git a/INSTALL/ventoy/ventoy.cpio b/INSTALL/ventoy/ventoy.cpio
index dd750ec0..4b2dd150 100644
Binary files a/INSTALL/ventoy/ventoy.cpio and b/INSTALL/ventoy/ventoy.cpio differ
diff --git a/IPXE/ipxe-3fe683e/src/arch/x86/core/runtime.c b/IPXE/ipxe-3fe683e/src/arch/x86/core/runtime.c
index ed15de50..049f14be 100644
--- a/IPXE/ipxe-3fe683e/src/arch/x86/core/runtime.c
+++ b/IPXE/ipxe-3fe683e/src/arch/x86/core/runtime.c
@@ -117,6 +117,10 @@ static void cmdline_strip ( char *cmdline, const char *cruft ) {
*/
static int cmdline_init ( void ) {
userptr_t cmdline_user;
+ userptr_t chainaddr;
+ char *pos1;
+ char *pos2;
+ int chainlen;
char *cmdline;
size_t len;
int rc;
@@ -129,6 +133,23 @@ static int cmdline_init ( void ) {
cmdline_user = phys_to_user ( cmdline_phys );
len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ );
+ pos1 = strstr((char *)cmdline_user, "mem:");
+ if (pos1)
+ {
+ pos2 = strstr(pos1, ":size:");
+ if (pos2)
+ {
+ *pos2 = 0;
+ chainaddr = phys_to_user(strtoul(pos1 + 4 + 2, NULL, 16)); // skip 0x prefix in hex number
+ chainlen = (int)strtoul(pos2 + 6, NULL, 10);
+ *pos2 = ':';
+
+ g_initrd_addr = (void *)umalloc(chainlen);
+ g_initrd_len = chainlen;
+ memcpy_user((userptr_t)g_initrd_addr, 0, chainaddr, 0, chainlen);
+ }
+ }
+
/* Allocate and copy command line */
cmdline_copy = malloc ( len );
if ( ! cmdline_copy ) {
@@ -137,6 +158,9 @@ static int cmdline_init ( void ) {
rc = -ENOMEM;
goto err_alloc_cmdline_copy;
}
+
+ g_cmdline_copy = cmdline_copy;
+
cmdline = cmdline_copy;
copy_from_user ( cmdline, cmdline_user, 0, len );
DBGC ( colour, "RUNTIME found command line \"%s\" at %08x\n",
@@ -221,11 +245,6 @@ static int initrd_init ( void ) {
memcpy_user ( image->data, 0, phys_to_user ( initrd_phys ), 0,
initrd_len );
- g_initrd_addr = (void *)image->data;
- g_initrd_len = image->len;
- g_cmdline_copy = cmdline_copy;
-
-
/* Mark initrd as consumed */
initrd_phys = 0;
diff --git a/IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/hidemem.c b/IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/hidemem.c
index a8085afd..1a3022c5 100644
--- a/IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/hidemem.c
+++ b/IPXE/ipxe-3fe683e/src/arch/x86/interface/pcbios/hidemem.c
@@ -126,11 +126,8 @@ void hide_umalloc ( physaddr_t start, physaddr_t end ) {
*
*/
void hide_textdata ( void ) {
-/* Deleted by longpanda */
-#if 0
hide_region ( &hidemem_textdata, virt_to_phys ( _textdata ),
virt_to_phys ( _etextdata ) );
-#endif
}
/**
diff --git a/LANGUAGES/languages.ini b/LANGUAGES/languages.ini
index f520df2e..68823769 100644
Binary files a/LANGUAGES/languages.ini and b/LANGUAGES/languages.ini differ
diff --git a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c
index a3dfb776..0a84ce2f 100644
--- a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c
+++ b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c
@@ -130,8 +130,7 @@ static BOOL IsVentoyPhyDrive(int PhyDrive, UINT64 SizeBytes)
PartStartSector = 2048;
PartSectorCount = (UINT32)((SizeBytes - VENTOY_EFI_PART_SIZE - SIZE_1MB) / 512);
- if (MBR.PartTbl[0].FsFlag != 0x07 ||
- MBR.PartTbl[0].StartSectorId != PartStartSector ||
+ if (MBR.PartTbl[0].StartSectorId != PartStartSector ||
MBR.PartTbl[0].SectorCount != PartSectorCount)
{
Log("Part1 not match %u %u", PartStartSector, PartSectorCount);
diff --git a/VtoyTool/vtoydump.c b/VtoyTool/vtoydump.c
index fd557cf9..e494598a 100644
--- a/VtoyTool/vtoydump.c
+++ b/VtoyTool/vtoydump.c
@@ -43,6 +43,17 @@ typedef unsigned char uint8_t;
#define VENTOY_GUID { 0x77772020, 0x2e77, 0x6576, { 0x6e, 0x74, 0x6f, 0x79, 0x2e, 0x6e, 0x65, 0x74 }}
+typedef enum ventoy_fs_type
+{
+ ventoy_fs_exfat = 0, /* 0: exfat */
+ ventoy_fs_ntfs, /* 1: NTFS */
+ ventoy_fs_ext, /* 2: ext2/ext3/ext4 */
+ ventoy_fs_xfs, /* 3: XFS */
+ ventoy_fs_udf, /* 4: UDF */
+
+ ventoy_fs_max
+}ventoy_fs_type;
+
#pragma pack(1)
typedef struct ventoy_guid
@@ -130,6 +141,11 @@ static int verbose = 0;
static ventoy_guid vtoy_guid = VENTOY_GUID;
+static const char *g_ventoy_fs[ventoy_fs_max] =
+{
+ "exfat", "ntfs", "ext*", "xfs", "udf"
+};
+
static int vtoy_check_os_param(ventoy_os_param *param)
{
uint32_t i;
@@ -410,14 +426,10 @@ static int vtoy_print_os_param(ventoy_os_param *param, char *diskname)
cnt = vtoy_find_disk_by_guid(param->vtoy_disk_guid, diskname);
debug("find 0 disk by size, try with guid cnt=%d...\n", cnt);
}
-
- if (param->vtoy_disk_part_type == 0)
+
+ if (param->vtoy_disk_part_type < ventoy_fs_max)
{
- fs = "exfat";
- }
- else if (param->vtoy_disk_part_type == 0)
- {
- fs = "ntfs";
+ fs = g_ventoy_fs[param->vtoy_disk_part_type];
}
else
{
diff --git a/VtoyTool/vtoytool/00/vtoytool_32 b/VtoyTool/vtoytool/00/vtoytool_32
index d2a0c363..1f9773b2 100644
Binary files a/VtoyTool/vtoytool/00/vtoytool_32 and b/VtoyTool/vtoytool/00/vtoytool_32 differ
diff --git a/VtoyTool/vtoytool/00/vtoytool_64 b/VtoyTool/vtoytool/00/vtoytool_64
index bb9d703f..03cfc6eb 100644
Binary files a/VtoyTool/vtoytool/00/vtoytool_64 and b/VtoyTool/vtoytool/00/vtoytool_64 differ