# HG changeset patch # User Pascal Bellard # Date 1519895487 -3600 # Node ID 0c1ad897a405d50b18d240ba6cbb1bfe338cd46a # Parent ccdba9b27403907015dc6408e63f449dcc137e16 grub: add ext4 patch diff -r ccdba9b27403 -r 0c1ad897a405 grub/receipt --- a/grub/receipt Mon Feb 26 19:03:16 2018 +0100 +++ b/grub/receipt Thu Mar 01 10:11:27 2018 +0100 @@ -16,7 +16,6 @@ # Rules to configure and make the package. compile_rules() { - cd $src for i in $stuff/*.diff ; do [ -f $(basename $i) ] && continue patch -p1 < $i @@ -46,4 +45,3 @@ # Example config file (menu.lst). cp $stuff/example-menu.lst $fs/boot/grub } - diff -r ccdba9b27403 -r 0c1ad897a405 grub/stuff/ext3_256byte_inode+ext4.diff --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/grub/stuff/ext3_256byte_inode+ext4.diff Thu Mar 01 10:11:27 2018 +0100 @@ -0,0 +1,935 @@ +--- grub-0.97/stage2/fsys_ext2fs.c ++++ grub-0.97/stage2/fsys_ext2fs.c +@@ -17,6 +17,19 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + ++/* ++ * The patch about "ext3 with 256-byte inode size" was made by ++ * Stefan Lippers-Hollmann for Debian in 2008-01-30. ++ * Thank Barton for submittal of this patch. ++ * ---- Tinybit, 2008-06-24 ++ */ ++ ++/* ++ * The ext4 patch comes from Gentoo. ++ * Thank kraml for direction to this patch. ++ * ---- Tinybit, 2009-02-11 ++ */ ++ + #ifdef FSYS_EXT2FS + + #include "shared.h" +@@ -41,6 +54,7 @@ + typedef unsigned short __u16; + typedef __signed__ int __s32; + typedef unsigned int __u32; ++typedef unsigned long long __u64; + + /* + * Constants relative to the data blocks, from ext2_fs.h +@@ -61,9 +75,9 @@ + __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ +- __s32 s_log_frag_size; /* Fragment size */ ++ __s32 s_obso_log_frag_size; /* Obsoleted Fragment size */ + __u32 s_blocks_per_group; /* # Blocks per group */ +- __u32 s_frags_per_group; /* # Fragments per group */ ++ __u32 s_obso_frags_per_group; /* Obsoleted Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ + __u32 s_wtime; /* Write time */ +@@ -72,13 +86,14 @@ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ +- __u16 s_pad; ++ __u16 s_minor_rev_level; /* minor revision level */ + __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ + __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ ++ //__u32 s_reserved[235]; /* Padding to the end of the block */ + /* + * These fields are for EXT2_DYNAMIC_REV superblocks only. + * +@@ -98,16 +113,16 @@ + __u32 s_feature_compat; /* compatible feature set */ + __u32 s_feature_incompat; /* incompatible feature set */ + __u32 s_feature_ro_compat; /* readonly-compatible feature set */ +- __u8 s_uuid[16]; /* 128-bit uuid for volume */ +- char s_volume_name[16]; /* volume name */ +- char s_last_mounted[64]; /* directory where last mounted */ +- __u32 s_algorithm_usage_bitmap; /* For compression */ ++ __u8 s_uuid[16]; /* 128-bit uuid for volume */ ++ char s_volume_name[16]; /* volume name */ ++ char s_last_mounted[64]; /* directory where last mounted */ ++ __u32 s_algorithm_usage_bitmap; /* For compression */ + /* +- * Performance hints. Directory preallocation should only ++ * Performance hints. Directory preallocation should only + * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on. + */ +- __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ +- __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ ++ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ ++ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_reserved_gdt_blocks;/* Per group table for online growth */ + /* + * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set. +@@ -117,17 +132,17 @@ + __u32 s_journal_dev; /* device number of journal file */ + __u32 s_last_orphan; /* start of list of inodes to delete */ + __u32 s_hash_seed[4]; /* HTREE hash seed */ +- __u8 s_def_hash_version; /* Default hash version to use */ +- __u8 s_jnl_backup_type; /* Default type of journal backup */ +- __u16 s_reserved_word_pad; ++ __u8 s_def_hash_version; /* Default hash version to use */ ++ __u8 s_jnl_backup_type; /* Default type of journal backup */ ++ __u16 s_desc_size; /* size of group descriptor */ + __u32 s_default_mount_opts; + __u32 s_first_meta_bg; /* First metablock group */ + __u32 s_mkfs_time; /* When the filesystem was created */ +- __u32 s_jnl_blocks[17]; /* Backup of the journal inode */ ++ __u32 s_jnl_blocks[17]; /* Backup of the journal inode */ + __u32 s_reserved[172]; /* Padding to the end of the block */ + }; + +-struct ext2_group_desc ++struct ext4_group_desc + { + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ +@@ -135,8 +150,18 @@ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ +- __u16 bg_pad; +- __u32 bg_reserved[3]; ++ __u16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ ++ __u32 bg_reserved[2]; /* Likely block/inode bitmap checksum */ ++ __u16 bg_itable_unused; /* Unused inodes count */ ++ __u16 bg_checksum; /* crc16(sb_uuid+group+desc) */ ++ __u32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ ++ __u32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ ++ __u32 bg_inode_table_hi; /* Inodes table block MSB */ ++ __u16 bg_free_blocks_count_hi;/* Free blocks count MSB */ ++ __u16 bg_free_inodes_count_hi;/* Free inodes count MSB */ ++ __u16 bg_used_dirs_count_hi; /* Directories count MSB */ ++ __u16 bg_itable_unused_hi; /* Unused inodes count MSB */ ++ __u32 bg_reserved2[3]; + }; + + struct ext2_inode +@@ -174,22 +199,22 @@ + __u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */ + __u32 i_version; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ +- __u32 i_dir_acl; /* Directory ACL */ +- __u32 i_faddr; /* Fragment address */ ++ __u32 i_size_high; ++ __u32 i_obso_faddr; /* Obsoleted fragment address */ + union + { + struct + { +- __u8 l_i_frag; /* Fragment number */ +- __u8 l_i_fsize; /* Fragment size */ +- __u16 i_pad1; +- __u32 l_i_reserved2[2]; ++ __u16 l_i_blocks_high; /* were l_i_reserved1 */ ++ __u16 l_i_file_acl_high; ++ __u16 l_i_uid_high; /* these 2 fields */ ++ __u16 l_i_gid_high; /* were reserved2[0] */ ++ __u32 l_i_reserved2; + } + linux2; + struct + { +- __u8 h_i_frag; /* Fragment number */ +- __u8 h_i_fsize; /* Fragment size */ ++ __u16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; +@@ -198,16 +223,36 @@ + hurd2; + struct + { +- __u8 m_i_frag; /* Fragment number */ +- __u8 m_i_fsize; /* Fragment size */ +- __u16 m_pad1; ++ __u16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ ++ __u16 m_i_file_acl_high; + __u32 m_i_reserved2[2]; + } + masix2; + } + osd2; /* OS dependent 2 */ ++ __u16 i_extra_isize; ++ __u16 i_pad1; ++ __u32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */ ++ __u32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */ ++ __u32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */ ++ __u32 i_crtime; /* File Creation time */ ++ __u32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */ ++ __u32 i_version_hi; /* high 32 bits for 64-bit version */ + }; + ++#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ ++#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 /* grub not supported*/ ++#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 ++#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 ++ ++#define EXT4_HAS_INCOMPAT_FEATURE(sb,mask) \ ++ ( sb->s_feature_incompat & mask ) ++ ++#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ ++#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ ++ ++#define EXT4_MIN_DESC_SIZE 32 ++ + /* linux/limits.h */ + #define NAME_MAX 255 /* # chars in a file name */ + +@@ -225,6 +270,57 @@ + char name[EXT2_NAME_LEN]; /* File name */ + }; + ++/* linux/ext4_fs_extents.h */ ++/* This is the extent on-disk structure. ++ * It's used at the bottom of the tree. ++ */ ++struct ext4_extent ++ { ++ __u32 ee_block; /* first logical block extent covers */ ++ __u16 ee_len; /* number of blocks covered by extent */ ++ __u16 ee_start_hi; /* high 16 bits of physical block */ ++ __u32 ee_start_lo; /* low 32 bits of physical block */ ++ }; ++ ++/* ++ * This is index on-disk structure. ++ * It's used at all the levels except the bottom. ++ */ ++struct ext4_extent_idx ++ { ++ __u32 ei_block; /* index covers logical blocks from 'block' */ ++ __u32 ei_leaf_lo; /* pointer to the physical block of the next * ++ * level. leaf or next index could be there */ ++ __u16 ei_leaf_hi; /* high 16 bits of physical block */ ++ __u16 ei_unused; ++ }; ++ ++/* ++ * Each block (leaves and indexes), even inode-stored has header. ++ */ ++struct ext4_extent_header ++ { ++ __u16 eh_magic; /* probably will support different formats */ ++ __u16 eh_entries; /* number of valid entries */ ++ __u16 eh_max; /* capacity of store in entries */ ++ __u16 eh_depth; /* has tree real underlying blocks? */ ++ __u32 eh_generation; /* generation of the tree */ ++ }; ++ ++#define EXT4_EXT_MAGIC (0xf30a) ++#define EXT_FIRST_EXTENT(__hdr__) \ ++ ((struct ext4_extent *) (((char *) (__hdr__)) + \ ++ sizeof(struct ext4_extent_header))) ++#define EXT_FIRST_INDEX(__hdr__) \ ++ ((struct ext4_extent_idx *) (((char *) (__hdr__)) + \ ++ sizeof(struct ext4_extent_header))) ++#define EXT_LAST_EXTENT(__hdr__) \ ++ (EXT_FIRST_EXTENT((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1) ++#define EXT_LAST_INDEX(__hdr__) \ ++ (EXT_FIRST_INDEX((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1) ++ ++ ++ + /* linux/ext2fs.h */ + /* + * EXT2_DIR_PAD defines the directory entries boundaries +@@ -238,7 +334,7 @@ + + + /* ext2/super.c */ +-#define log2(n) ffz(~(n)) ++//#define log2(n) ffz(~(n)) + + #define EXT2_SUPER_MAGIC 0xEF53 /* include/linux/ext2_fs.h */ + #define EXT2_ROOT_INO 2 /* include/linux/ext2_fs.h */ +@@ -247,11 +343,12 @@ + + /* made up, these are pointers into FSYS_BUF */ + /* read once, always stays there: */ ++#define NAME_BUF ((char *)(FSYS_BUF)) /* 512 bytes */ + #define SUPERBLOCK \ +- ((struct ext2_super_block *)(FSYS_BUF)) ++ ((struct ext2_super_block *)((FSYS_BUF)+512)) /* 1024 bytes */ + #define GROUP_DESC \ + ((struct ext2_group_desc *) \ +- ((int)SUPERBLOCK + sizeof(struct ext2_super_block))) ++ ((int)SUPERBLOCK + sizeof(struct ext2_super_block))) /* 32 bytes */ + #define INODE \ + ((struct ext2_inode *)((int)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK))) + #define DATABLOCK1 \ +@@ -261,14 +358,19 @@ + + /* linux/ext2_fs.h */ + #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) +-#define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s))) ++#define EXT2_ADDR_PER_BLOCK_BITS(s) (log2_tmp(EXT2_ADDR_PER_BLOCK(s))) + ++/* Revision levels */ + #define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ + #define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ +-#define EXT2_GOOD_OLD_INODE_SIZE 128 +-#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ +- EXT2_GOOD_OLD_INODE_SIZE : \ +- (s)->s_inode_size) ++ ++#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV ++#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV ++ ++#define EXT2_GOOD_OLD_INODE_SIZE 128 ++ ++#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size) ++//#define EXT2_INODE_SIZE(s) (SUPERBLOCK->s_inode_size) + #define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s)) + + /* linux/ext2_fs.h */ +@@ -276,8 +378,17 @@ + /* kind of from ext2/super.c */ + #define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s)) + /* linux/ext2fs.h */ ++/* sizeof(struct ext2_group_desc) is changed in ext4 ++ * in kernel code, ext2/3 uses sizeof(struct ext2_group_desc) to calculate ++ * number of desc per block, while ext4 uses superblock->s_desc_size in stead ++ * superblock->s_desc_size is not available in ext2/3 ++ * */ ++#define EXT2_DESC_SIZE(s) \ ++ (EXT4_HAS_INCOMPAT_FEATURE(s,EXT4_FEATURE_INCOMPAT_64BIT)? \ ++ s->s_desc_size : EXT4_MIN_DESC_SIZE) + #define EXT2_DESC_PER_BLOCK(s) \ +- (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) ++ (EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s)) ++ + /* linux/stat.h */ + #define S_IFMT 00170000 + #define S_IFLNK 0120000 +@@ -287,38 +398,82 @@ + #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) + #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) + ++#ifndef GRUB_UTIL ++static char *linkbuf = (char *)(FSYS_BUF - PATH_MAX); /* buffer for following symbolic links */ ++#else ++static char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ ++#endif ++ + /* include/asm-i386/bitops.h */ + /* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +-static __inline__ unsigned long +-ffz (unsigned long word) +-{ +- __asm__ ("bsfl %1,%0" +-: "=r" (word) +-: "r" (~word)); +- return word; +-} ++//static __inline__ unsigned long ++//ffz (unsigned long word) ++//{ ++// __asm__ ("bsfl %1,%0" ++//: "=r" (word) ++//: "r" (~word)); ++// return word; ++//} + + /* check filesystem types and read superblock into memory buffer */ + int + ext2fs_mount (void) + { +- int retval = 1; ++// if (((current_drive & 0x80) || (current_slice != 0)) ++// && (current_slice != PC_SLICE_TYPE_EXT2FS) ++// && (current_slice != PC_SLICE_TYPE_LINUX_RAID) ++// && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS)) ++// && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))) ++// return 0; ++ ++ if ((unsigned long)part_length < (SBLOCK + (sizeof(struct ext2_super_block) / DEV_BSIZE))) ++ return 0; + +- if ((((current_drive & 0x80) || (current_slice != 0)) +- && (current_slice != PC_SLICE_TYPE_EXT2FS) +- && (current_slice != PC_SLICE_TYPE_LINUX_RAID) +- && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS)) +- && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))) +- || part_length < (SBLOCK + (sizeof (struct ext2_super_block) / DEV_BSIZE)) +- || !devread (SBLOCK, 0, sizeof (struct ext2_super_block), +- (char *) SUPERBLOCK) +- || SUPERBLOCK->s_magic != EXT2_SUPER_MAGIC) +- retval = 0; ++ if (!devread(SBLOCK, 0, sizeof(struct ext2_super_block), (char *)SUPERBLOCK, 0xedde0d90)) ++ return 0; + +- return retval; ++ if (SUPERBLOCK->s_magic != EXT2_SUPER_MAGIC) ++ return 0; ++ ++ if (SUPERBLOCK->s_inodes_count == 0) ++ return 0; ++ ++ if (SUPERBLOCK->s_blocks_count == 0) ++ return 0; ++ ++ if (SUPERBLOCK->s_blocks_per_group == 0) ++ return 0; ++ ++ if (SUPERBLOCK->s_inodes_per_group == 0) ++ return 0; ++ ++ if (SUPERBLOCK->s_first_data_block > 1) /* 1 for 1K block, 0 otherwise */ ++ return 0; ++ ++ if (SUPERBLOCK->s_log_block_size > 4) /* max size of block is 16K. 0 for 1K */ ++ return 0; ++ ++ if (SUPERBLOCK->s_first_data_block) ++ { ++ if (SUPERBLOCK->s_log_block_size) ++ return 0; ++ } else { ++ if (SUPERBLOCK->s_log_block_size == 0) ++ return 0; ++ } ++ ++ if (SUPERBLOCK->s_rev_level) ++ { ++ if (SUPERBLOCK->s_inode_size == 0) ++ return 0; ++ if (EXT2_BLOCK_SIZE(SUPERBLOCK) % (SUPERBLOCK->s_inode_size)) ++ return 0; ++ } ++ ++ return 1; + } + + /* Takes a file system block number and reads it into BUFFER. */ +@@ -329,7 +484,7 @@ + printf ("fsblock %d buffer %d\n", fsblock, buffer); + #endif /* E2DEBUG */ + return devread (fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0, +- EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer); ++ EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer, 0xedde0d90); + } + + /* from +@@ -338,7 +493,7 @@ + /* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into + a physical block (the location in the file system) via an inode. */ + static int +-ext2fs_block_map (int logical_block) ++ext2fs_block_map (unsigned long logical_block) + { + + #ifdef E2DEBUG +@@ -412,13 +567,16 @@ + /* else */ + mapblock2 = -1; + logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)); ++ + if (mapblock1 != 3 + && !ext2_rdfsb (INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1)) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } ++ + mapblock1 = 3; ++ + if (!ext2_rdfsb (((__u32 *) DATABLOCK1) + [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) + * 2)], +@@ -427,7 +585,8 @@ + errnum = ERR_FSYS_CORRUPT; + return -1; + } +- if (!ext2_rdfsb (((__u32 *) DATABLOCK2) ++ ++ if (! ext2_rdfsb (((__u32 *) DATABLOCK2) + [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)) + & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)], + DATABLOCK2)) +@@ -435,30 +594,148 @@ + errnum = ERR_FSYS_CORRUPT; + return -1; + } +- return ((__u32 *) DATABLOCK2) +- [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]; ++ ++ return ((__u32 *) DATABLOCK2)[logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]; + } + ++/* extent binary search index ++ * find closest index in the current level extent tree ++ * kind of from ext4_ext_binsearch_idx in ext4/extents.c ++ */ ++static struct ext4_extent_idx* ++ext4_ext_binsearch_idx(struct ext4_extent_header* eh, int logical_block) ++{ ++ struct ext4_extent_idx *r, *l, *m; ++ l = EXT_FIRST_INDEX(eh) + 1; ++ r = EXT_LAST_INDEX(eh); ++ while (l <= r) ++ { ++ m = l + (r - l) / 2; ++ if (logical_block < m->ei_block) ++ r = m - 1; ++ else ++ l = m + 1; ++ } ++ return (struct ext4_extent_idx*)(l - 1); ++} ++ ++/* extent binary search ++ * find closest extent in the leaf level ++ * kind of from ext4_ext_binsearch in ext4/extents.c ++ */ ++static struct ext4_extent* ++ext4_ext_binsearch(struct ext4_extent_header* eh, int logical_block) ++{ ++ struct ext4_extent *r, *l, *m; ++ l = EXT_FIRST_EXTENT(eh) + 1; ++ r = EXT_LAST_EXTENT(eh); ++ while (l <= r) ++ { ++ m = l + (r - l) / 2; ++ if (logical_block < m->ee_block) ++ r = m - 1; ++ else ++ l = m + 1; ++ } ++ return (struct ext4_extent*)(l - 1); ++} ++ ++/* Maps extents enabled logical block into physical block via an inode. ++ * EXT4_HUGE_FILE_FL should be checked before calling this. ++ */ ++static int ++ext4fs_block_map (int logical_block) ++{ ++ struct ext4_extent_header *eh; ++ struct ext4_extent *ex;//, *extent; ++ struct ext4_extent_idx *ei;//, *index; ++ int depth; ++ //int i; ++ ++#ifdef E2DEBUG ++ unsigned char *i; ++ for (i = (unsigned char *) INODE; ++ i < ((unsigned char *) INODE + sizeof (struct ext2_inode)); ++ i++) ++ { ++ printf ("%c", "0123456789abcdef"[*i >> 4]); ++ printf ("%c", "0123456789abcdef"[*i % 16]); ++ if (!((i + 1 - (unsigned char *) INODE) % 16)) ++ { ++ printf ("\n"); ++ } ++ else ++ { ++ printf (" "); ++ } ++ } ++ printf ("logical block %d\n", logical_block); ++#endif /* E2DEBUG */ ++ eh = (struct ext4_extent_header*)INODE->i_block; ++ if (eh->eh_magic != EXT4_EXT_MAGIC) ++ { ++ errnum = ERR_FSYS_CORRUPT; ++ return -1; ++ } ++ while((depth = eh->eh_depth) != 0) ++ { /* extent index */ ++ if (eh->eh_magic != EXT4_EXT_MAGIC) ++ { ++ errnum = ERR_FSYS_CORRUPT; ++ return -1; ++ } ++ ei = ext4_ext_binsearch_idx(eh, logical_block); ++ if (ei->ei_leaf_hi) ++ {/* 64bit physical block number not supported */ ++ errnum = ERR_FILELENGTH; ++ return -1; ++ } ++ if (!ext2_rdfsb(ei->ei_leaf_lo, DATABLOCK1)) ++ { ++ errnum = ERR_FSYS_CORRUPT; ++ return -1; ++ } ++ eh = (struct ext4_extent_header*)DATABLOCK1; ++ } ++ ++ /* depth==0, we come to the leaf */ ++ ex = ext4_ext_binsearch(eh, logical_block); ++ if (ex->ee_start_hi) ++ {/* 64bit physical block number not supported */ ++ errnum = ERR_FILELENGTH; ++ return -1; ++ } ++ if ((ex->ee_block + ex->ee_len) < logical_block) ++ { ++ errnum = ERR_FSYS_CORRUPT; ++ return -1; ++ } ++ return ex->ee_start_lo + logical_block - ex->ee_block; ++ ++} ++ + /* preconditions: all preconds of ext2fs_block_map */ +-int +-ext2fs_read (char *buf, int len) ++unsigned long ++ext2fs_read (char *buf, unsigned long len, unsigned long write) + { +- int logical_block; +- int offset; ++ unsigned long logical_block; ++ unsigned long offset; ++ unsigned long ret = 0; ++ unsigned long size = 0; + int map; +- int ret = 0; +- int size = 0; + + #ifdef E2DEBUG + static char hexdigit[] = "0123456789abcdef"; + unsigned char *i; ++ + for (i = (unsigned char *) INODE; + i < ((unsigned char *) INODE + sizeof (struct ext2_inode)); + i++) + { + printf ("%c", hexdigit[*i >> 4]); + printf ("%c", hexdigit[*i % 16]); +- if (!((i + 1 - (unsigned char *) INODE) % 16)) ++ ++ if (! ((i + 1 - (unsigned char *) INODE) % 16)) + { + printf ("\n"); + } +@@ -469,41 +746,53 @@ + } + #endif /* E2DEBUG */ + while (len > 0) +- { ++ { + /* find the (logical) block component of our location */ + logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); + offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1); ++ ++ /* map extents enabled logical block number to physical fs on-dick block number */ ++ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS) ++ && INODE->i_flags & EXT4_EXTENTS_FL) ++ map = ext4fs_block_map (logical_block); ++ else + map = ext2fs_block_map (logical_block); ++ + #ifdef E2DEBUG + printf ("map=%d\n", map); + #endif /* E2DEBUG */ ++ + if (map < 0) +- break; ++ break; + + size = EXT2_BLOCK_SIZE (SUPERBLOCK); + size -= offset; ++ + if (size > len) +- size = len; ++ size = len; + +- if (map == 0) { +- memset ((char *) buf, 0, size); ++ if (map == 0) ++ { ++ if (buf) ++ memset ((char *) buf, 0, size); + } else { +- disk_read_func = disk_read_hook; ++ disk_read_func = disk_read_hook; + +- devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), +- offset, size, buf); ++ devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), ++ offset, size, buf, write); + +- disk_read_func = NULL; ++ disk_read_func = NULL; + } + +- buf += size; +- len -= size; ++ if (buf) ++ buf += size; ++ len -= size; /* len always >= 0 */ + filepos += size; + ret += size; +- } ++ } + + if (errnum) +- ret = 0; ++ ret = 0; + + return ret; + } +@@ -557,10 +846,10 @@ + int desc; /* index within that group */ + int ino_blk; /* fs pointer of the inode's information */ + int str_chk = 0; /* used to hold the results of a string compare */ +- struct ext2_group_desc *gdp; ++ struct ext4_group_desc *ext4_gdp; + struct ext2_inode *raw_inode; /* inode info corresponding to current_ino */ + +- char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ ++//char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ + int link_count = 0; + + char *rest; +@@ -590,7 +879,7 @@ + + /* look up an inode */ + group_id = (current_ino - 1) / (SUPERBLOCK->s_inodes_per_group); +- group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK)); ++ group_desc = group_id >> log2_tmp (EXT2_DESC_PER_BLOCK (SUPERBLOCK)); + desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1); + #ifdef E2DEBUG + printf ("ipg=%d, dpb=%d\n", SUPERBLOCK->s_inodes_per_group, +@@ -603,10 +892,17 @@ + { + return 0; + } +- gdp = GROUP_DESC; +- ino_blk = gdp[desc].bg_inode_table + ++ ext4_gdp = (struct ext4_group_desc *)( (__u8*)GROUP_DESC + ++ desc * EXT2_DESC_SIZE(SUPERBLOCK)); ++ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK, EXT4_FEATURE_INCOMPAT_64BIT) ++ && (! ext4_gdp->bg_inode_table_hi)) ++ {/* 64bit itable not supported */ ++ errnum = ERR_FILELENGTH; ++ return -1; ++ } ++ ino_blk = ext4_gdp->bg_inode_table + + (((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group)) +- >> log2 (EXT2_INODES_PER_BLOCK (SUPERBLOCK))); ++ >> log2_tmp (EXT2_INODES_PER_BLOCK (SUPERBLOCK))); + #ifdef E2DEBUG + printf ("inode table fsblock=%d\n", ino_blk); + #endif /* E2DEBUG */ +@@ -620,10 +916,10 @@ + + raw_inode = (struct ext2_inode *)((char *)INODE + + ((current_ino - 1) & (EXT2_INODES_PER_BLOCK (SUPERBLOCK) - 1)) * +- EXT2_INODE_SIZE (SUPERBLOCK)); ++ EXT2_INODE_SIZE (SUPERBLOCK)); + #ifdef E2DEBUG + printf ("ipb=%d, sizeof(inode)=%d\n", +- EXT2_INODES_PER_BLOCK (SUPERBLOCK), EXT2_INODE_SIZE (SUPERBLOCK)); ++ EXT2_INODES_PER_BLOCK (SUPERBLOCK), EXT2_INODE_SIZE (SUPERBLOCK)); + printf ("inode=%x, raw_inode=%x\n", INODE, raw_inode); + printf ("offset into inode table block=%d\n", (int) raw_inode - (int) INODE); + for (i = (unsigned char *) INODE; i <= (unsigned char *) raw_inode; +@@ -661,13 +957,22 @@ + } + + /* Find out how long our remaining name is. */ +- len = 0; +- while (dirname[len] && !isspace (dirname[len])) +- len++; ++ //len = 0; ++ //while (dirname[len] && !isspace (dirname[len])) ++ // len++; ++ for (len = 0; (ch = dirname[len]) && !isspace (ch); len++) ++ { ++ if (ch == '\\') ++ { ++ len++; ++ if (! (ch = dirname[len])) ++ break; ++ } ++ } + + /* Get the symlink size. */ + filemax = (INODE->i_size); +- if (filemax + len > sizeof (linkbuf) - 2) ++ if (filemax + len > PATH_MAX - 2) + { + errnum = ERR_FILELENGTH; + return 0; +@@ -681,18 +986,23 @@ + } + linkbuf[filemax + len] = '\0'; + +- /* Read the symlink data. */ ++ /* Read the symlink data. ++ * Slow symlink is extents enabled ++ * But since grub_read invokes ext2fs_read, nothing to change here ++ * */ + if (! ext2_is_fast_symlink ()) + { + /* Read the necessary blocks, and reset the file pointer. */ +- len = grub_read (linkbuf, filemax); ++ len = grub_read (linkbuf, filemax, 0xedde0d90); + filepos = 0; + if (!len) + return 0; + } + else + { +- /* Copy the data directly from the inode. */ ++ /* Copy the data directly from the inode. ++ * Fast symlink is not extents enabled ++ * */ + len = filemax; + memmove (linkbuf, (char *) INODE->i_block, len); + } +@@ -726,6 +1036,13 @@ + errnum = ERR_BAD_FILETYPE; + return 0; + } ++ /* if file is too large, just stop and report an error*/ ++ if ( (INODE->i_flags & EXT4_HUGE_FILE_FL) && !(INODE->i_size_high)) ++ { ++ /* file too large, stop reading */ ++ errnum = ERR_FILELENGTH; ++ return 0; ++ } + + filemax = (INODE->i_size); + return 1; +@@ -746,8 +1063,17 @@ + } + + /* skip to next slash or end of filename (space) */ +- for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; +- rest++); ++// for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; ++// rest++); ++ for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++) ++ { ++ if (ch == '\\') ++ { ++ rest++; ++ if (! (ch = *rest)) ++ break; ++ } ++ } + + /* look through this directory and find the next filename component */ + /* invariant: rest points to slash after the next filename component */ +@@ -765,32 +1091,45 @@ + give up */ + if (loc >= INODE->i_size) + { ++# ifndef STAGE1_5 + if (print_possibilities < 0) + { + # if 0 + putchar ('\n'); + # endif ++ return 1; + } +- else +- { +- errnum = ERR_FILE_NOT_FOUND; +- *rest = ch; +- } +- return (print_possibilities < 0); ++# endif /* STAGE1_5 */ ++ ++ errnum = ERR_FILE_NOT_FOUND; ++ *rest = ch; ++ ++ return 0; + } + + /* else, find the (logical) block component of our location */ ++ /* ext4 logical block number the same as ext2/3 */ + blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); + + /* we know which logical block of the directory entry we are looking + for, now we have to translate that to the physical (fs) block on + the disk */ ++ /* map extents enabled logical block number to physical fs on-dick block number */ ++ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS) ++ && INODE->i_flags & EXT4_EXTENTS_FL) ++ map = ext4fs_block_map (blk); ++ else + map = ext2fs_block_map (blk); + #ifdef E2DEBUG + printf ("fs block=%d\n", map); + #endif /* E2DEBUG */ + mapblock2 = -1; +- if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2)) ++ if (map < 0) ++ { ++ *rest = ch; ++ return 0; ++ } ++ if (!ext2_rdfsb (map, DATABLOCK2)) + { + errnum = ERR_FSYS_CORRUPT; + *rest = ch; +@@ -811,22 +1150,36 @@ + + if (dp->inode) + { +- int saved_c = dp->name[dp->name_len]; ++ //int saved_c = dp->name[dp->name_len]; ++ int j, k; ++ char ch1; ++ char *tmp_name= NAME_BUF; /* EXT2_NAME_LEN is 255, so 512 byte buffer is needed. */ + +- dp->name[dp->name_len] = 0; +- str_chk = substring (dirname, dp->name); ++ /* copy dp->name to tmp_name, and quote the spaces with a '\\' */ ++ for (j = 0, k = 0; j < dp->name_len; j++) ++ { ++ if (! (ch1 = dp->name[j])) ++ break; ++ if (ch1 == ' ') ++ tmp_name[k++] = '\\'; ++ tmp_name[k++] = ch1; ++ } ++ tmp_name[k] = 0; + ++ //dp->name[dp->name_len] = 0; ++ str_chk = substring (dirname, tmp_name, 0); ++ + # ifndef STAGE1_5 + if (print_possibilities && ch != '/' + && (!*dirname || str_chk <= 0)) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; +- print_a_completion (dp->name); ++ print_a_completion (tmp_name); + } + # endif + +- dp->name[dp->name_len] = saved_c; ++ //dp->name[dp->name_len] = saved_c; + } + + } diff -r ccdba9b27403 -r 0c1ad897a405 grub/stuff/ext3_256byte_inode.diff --- a/grub/stuff/ext3_256byte_inode.diff Mon Feb 26 19:03:16 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ - -Patch from Red Hat. See #463236, #463123 (and #491076 for the reviewed version) - -diff -ur grub-0.97/stage2/fsys_ext2fs.c grub-0.97.new/stage2/fsys_ext2fs.c ---- grub-0.97/stage2/fsys_ext2fs.c 2008-07-23 01:18:18.000000000 +0200 -+++ grub-0.97.new/stage2/fsys_ext2fs.c 2008-07-25 14:33:29.000000000 +0200 -@@ -79,7 +79,52 @@ - __u32 s_rev_level; /* Revision level */ - __u16 s_def_resuid; /* Default uid for reserved blocks */ - __u16 s_def_resgid; /* Default gid for reserved blocks */ -- __u32 s_reserved[235]; /* Padding to the end of the block */ -+ /* -+ * These fields are for EXT2_DYNAMIC_REV superblocks only. -+ * -+ * Note: the difference between the compatible feature set and -+ * the incompatible feature set is that if there is a bit set -+ * in the incompatible feature set that the kernel doesn't -+ * know about, it should refuse to mount the filesystem. -+ * -+ * e2fsck's requirements are more strict; if it doesn't know -+ * about a feature in either the compatible or incompatible -+ * feature set, it must abort and not try to meddle with -+ * things it doesn't understand... -+ */ -+ __u32 s_first_ino; /* First non-reserved inode */ -+ __u16 s_inode_size; /* size of inode structure */ -+ __u16 s_block_group_nr; /* block group # of this superblock */ -+ __u32 s_feature_compat; /* compatible feature set */ -+ __u32 s_feature_incompat; /* incompatible feature set */ -+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */ -+ __u8 s_uuid[16]; /* 128-bit uuid for volume */ -+ char s_volume_name[16]; /* volume name */ -+ char s_last_mounted[64]; /* directory where last mounted */ -+ __u32 s_algorithm_usage_bitmap; /* For compression */ -+ /* -+ * Performance hints. Directory preallocation should only -+ * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on. -+ */ -+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ -+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ -+ __u16 s_reserved_gdt_blocks;/* Per group table for online growth */ -+ /* -+ * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set. -+ */ -+ __u8 s_journal_uuid[16]; /* uuid of journal superblock */ -+ __u32 s_journal_inum; /* inode number of journal file */ -+ __u32 s_journal_dev; /* device number of journal file */ -+ __u32 s_last_orphan; /* start of list of inodes to delete */ -+ __u32 s_hash_seed[4]; /* HTREE hash seed */ -+ __u8 s_def_hash_version; /* Default hash version to use */ -+ __u8 s_jnl_backup_type; /* Default type of journal backup */ -+ __u16 s_reserved_word_pad; -+ __u32 s_default_mount_opts; -+ __u32 s_first_meta_bg; /* First metablock group */ -+ __u32 s_mkfs_time; /* When the filesystem was created */ -+ __u32 s_jnl_blocks[17]; /* Backup of the journal inode */ -+ __u32 s_reserved[172]; /* Padding to the end of the block */ - }; - - struct ext2_group_desc -@@ -218,6 +263,14 @@ - #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) - #define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s))) - -+#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ -+#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ -+#define EXT2_GOOD_OLD_INODE_SIZE 128 -+#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ -+ EXT2_GOOD_OLD_INODE_SIZE : \ -+ (s)->s_inode_size) -+#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s)) -+ - /* linux/ext2_fs.h */ - #define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) - /* kind of from ext2/super.c */ -@@ -553,7 +606,7 @@ - gdp = GROUP_DESC; - ino_blk = gdp[desc].bg_inode_table + - (((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group)) -- >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode))); -+ >> log2 (EXT2_INODES_PER_BLOCK (SUPERBLOCK))); - #ifdef E2DEBUG - printf ("inode table fsblock=%d\n", ino_blk); - #endif /* E2DEBUG */ -@@ -565,13 +618,12 @@ - /* reset indirect blocks! */ - mapblock2 = mapblock1 = -1; - -- raw_inode = INODE + -- ((current_ino - 1) -- & (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode) - 1)); -+ raw_inode = (struct ext2_inode *)((char *)INODE + -+ ((current_ino - 1) & (EXT2_INODES_PER_BLOCK (SUPERBLOCK) - 1)) * -+ EXT2_INODE_SIZE (SUPERBLOCK)); - #ifdef E2DEBUG - printf ("ipb=%d, sizeof(inode)=%d\n", -- (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)), -- sizeof (struct ext2_inode)); -+ EXT2_INODES_PER_BLOCK (SUPERBLOCK), EXT2_INODE_SIZE (SUPERBLOCK)); - printf ("inode=%x, raw_inode=%x\n", INODE, raw_inode); - printf ("offset into inode table block=%d\n", (int) raw_inode - (int) INODE); - for (i = (unsigned char *) INODE; i <= (unsigned char *) raw_inode;