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