1Index: grub-0.97/stage2/fsys_ext2fs.c 2=================================================================== 3--- grub-0.97.orig/stage2/fsys_ext2fs.c 4+++ grub-0.97/stage2/fsys_ext2fs.c 5@@ -41,6 +41,7 @@ typedef __signed__ short __s16; 6 typedef unsigned short __u16; 7 typedef __signed__ int __s32; 8 typedef unsigned int __u32; 9+typedef unsigned long long __u64; 10 11 /* 12 * Constants relative to the data blocks, from ext2_fs.h 13@@ -51,7 +52,7 @@ typedef unsigned int __u32; 14 #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) 15 #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) 16 17-/* include/linux/ext2_fs.h */ 18+/* lib/ext2fs/ext2_fs.h from e2fsprogs */ 19 struct ext2_super_block 20 { 21 __u32 s_inodes_count; /* Inodes count */ 22@@ -61,9 +62,9 @@ struct ext2_super_block 23 __u32 s_free_inodes_count; /* Free inodes count */ 24 __u32 s_first_data_block; /* First Data Block */ 25 __u32 s_log_block_size; /* Block size */ 26- __s32 s_log_frag_size; /* Fragment size */ 27+ __s32 s_obso_log_frag_size; /* Obsoleted Fragment size */ 28 __u32 s_blocks_per_group; /* # Blocks per group */ 29- __u32 s_frags_per_group; /* # Fragments per group */ 30+ __u32 s_obso_frags_per_group; /* Obsoleted Fragments per group */ 31 __u32 s_inodes_per_group; /* # Inodes per group */ 32 __u32 s_mtime; /* Mount time */ 33 __u32 s_wtime; /* Write time */ 34@@ -72,7 +73,7 @@ struct ext2_super_block 35 __u16 s_magic; /* Magic signature */ 36 __u16 s_state; /* File system state */ 37 __u16 s_errors; /* Behaviour when detecting errors */ 38- __u16 s_pad; 39+ __u16 s_minor_rev_level; /* minor revision level */ 40 __u32 s_lastcheck; /* time of last check */ 41 __u32 s_checkinterval; /* max. time between checks */ 42 __u32 s_creator_os; /* OS */ 43@@ -119,15 +120,29 @@ struct ext2_super_block 44 __u32 s_hash_seed[4]; /* HTREE hash seed */ 45 __u8 s_def_hash_version; /* Default hash version to use */ 46 __u8 s_jnl_backup_type; /* Default type of journal backup */ 47- __u16 s_reserved_word_pad; 48+ __u16 s_desc_size; /* size of group descriptor */ 49 __u32 s_default_mount_opts; 50 __u32 s_first_meta_bg; /* First metablock group */ 51 __u32 s_mkfs_time; /* When the filesystem was created */ 52 __u32 s_jnl_blocks[17]; /* Backup of the journal inode */ 53- __u32 s_reserved[172]; /* Padding to the end of the block */ 54- }; 55+ /* 64bit desc support valid if EXT4_FEATURE_INCOMPAT_64BIT */ 56+ __u32 s_blocks_count_hi; /* Blocks count */ 57+ __u32 s_r_blocks_count_hi; /* Reserved blocks count */ 58+ __u32 s_free_blocks_count_hi; /* Free blocks count */ 59+ __u16 s_min_extra_isize; /* All inodes have at least # bytes */ 60+ __u16 s_max_extra_isize; /* New inodes should reverve # bytes */ 61+ __u32 s_flags; /* Miscellaneous flags */ 62+ __u16 s_raid_stride; /* Raid stride */ 63+ __u16 s_mmp_interval; /* # seconds to wait MMP checking */ 64+ __u64 s_mmp_block; /* Block for multi-mount protection */ 65+ __u32 s_raid_stripe_width; /* Blocks on all data disks (N*stride)*/ 66+ __u8 s_log_groups_per_flex;/* FLEX_BG group size*/ 67+ __u8 s_reserved_char_pad; 68+ __u16 s_reserved_pad; 69+ __u32 s_reserved[162]; /* Padding to the end of the block */ 70+}; 71 72-struct ext2_group_desc 73+struct ext4_group_desc 74 { 75 __u32 bg_block_bitmap; /* Blocks bitmap block */ 76 __u32 bg_inode_bitmap; /* Inodes bitmap block */ 77@@ -135,8 +150,18 @@ struct ext2_group_desc 78 __u16 bg_free_blocks_count; /* Free blocks count */ 79 __u16 bg_free_inodes_count; /* Free inodes count */ 80 __u16 bg_used_dirs_count; /* Directories count */ 81- __u16 bg_pad; 82- __u32 bg_reserved[3]; 83+ __u16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ 84+ __u32 bg_reserved[2]; /* Likely block/inode bitmap checksum */ 85+ __u16 bg_itable_unused; /* Unused inodes count */ 86+ __u16 bg_checksum; /* crc16(sb_uuid+group+desc) */ 87+ __u32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ 88+ __u32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ 89+ __u32 bg_inode_table_hi; /* Inodes table block MSB */ 90+ __u16 bg_free_blocks_count_hi;/* Free blocks count MSB */ 91+ __u16 bg_free_inodes_count_hi;/* Free inodes count MSB */ 92+ __u16 bg_used_dirs_count_hi; /* Directories count MSB */ 93+ __u16 bg_itable_unused_hi; /* Unused inodes count MSB */ 94+ __u32 bg_reserved2[3]; 95 }; 96 97 struct ext2_inode 98@@ -174,22 +199,22 @@ struct ext2_inode 99 __u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */ 100 __u32 i_version; /* File version (for NFS) */ 101 __u32 i_file_acl; /* File ACL */ 102- __u32 i_dir_acl; /* Directory ACL */ 103- __u32 i_faddr; /* Fragment address */ 104+ __u32 i_size_high; 105+ __u32 i_obso_faddr; /* Obsoleted fragment address */ 106 union 107 { 108 struct 109 { 110- __u8 l_i_frag; /* Fragment number */ 111- __u8 l_i_fsize; /* Fragment size */ 112- __u16 i_pad1; 113- __u32 l_i_reserved2[2]; 114+ __u16 l_i_blocks_high; /* were l_i_reserved1 */ 115+ __u16 l_i_file_acl_high; 116+ __u16 l_i_uid_high; /* these 2 fields */ 117+ __u16 l_i_gid_high; /* were reserved2[0] */ 118+ __u32 l_i_reserved2; 119 } 120 linux2; 121 struct 122 { 123- __u8 h_i_frag; /* Fragment number */ 124- __u8 h_i_fsize; /* Fragment size */ 125+ __u16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ 126 __u16 h_i_mode_high; 127 __u16 h_i_uid_high; 128 __u16 h_i_gid_high; 129@@ -198,16 +223,36 @@ struct ext2_inode 130 hurd2; 131 struct 132 { 133- __u8 m_i_frag; /* Fragment number */ 134- __u8 m_i_fsize; /* Fragment size */ 135- __u16 m_pad1; 136+ __u16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ 137+ __u16 m_i_file_acl_high; 138 __u32 m_i_reserved2[2]; 139 } 140 masix2; 141 } 142 osd2; /* OS dependent 2 */ 143+ __u16 i_extra_isize; 144+ __u16 i_pad1; 145+ __u32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */ 146+ __u32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */ 147+ __u32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */ 148+ __u32 i_crtime; /* File Creation time */ 149+ __u32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */ 150+ __u32 i_version_hi; /* high 32 bits for 64-bit version */ 151 }; 152 153+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ 154+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 /* grub not supported*/ 155+#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 156+#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 157+ 158+#define EXT4_HAS_INCOMPAT_FEATURE(sb,mask) \ 159+ ( sb->s_feature_incompat & mask ) 160+ 161+#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ 162+#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ 163+ 164+#define EXT4_MIN_DESC_SIZE 32 165+ 166 /* linux/limits.h */ 167 #define NAME_MAX 255 /* # chars in a file name */ 168 169@@ -225,6 +270,57 @@ struct ext2_dir_entry 170 char name[EXT2_NAME_LEN]; /* File name */ 171 }; 172 173+/* linux/ext4_fs_extents.h */ 174+/* This is the extent on-disk structure. 175+ * It's used at the bottom of the tree. 176+ */ 177+struct ext4_extent 178+ { 179+ __u32 ee_block; /* first logical block extent covers */ 180+ __u16 ee_len; /* number of blocks covered by extent */ 181+ __u16 ee_start_hi; /* high 16 bits of physical block */ 182+ __u32 ee_start_lo; /* low 32 bits of physical block */ 183+ }; 184+ 185+/* 186+ * This is index on-disk structure. 187+ * It's used at all the levels except the bottom. 188+ */ 189+struct ext4_extent_idx 190+ { 191+ __u32 ei_block; /* index covers logical blocks from 'block' */ 192+ __u32 ei_leaf_lo; /* pointer to the physical block of the next * 193+ * level. leaf or next index could be there */ 194+ __u16 ei_leaf_hi; /* high 16 bits of physical block */ 195+ __u16 ei_unused; 196+ }; 197+ 198+/* 199+ * Each block (leaves and indexes), even inode-stored has header. 200+ */ 201+struct ext4_extent_header 202+ { 203+ __u16 eh_magic; /* probably will support different formats */ 204+ __u16 eh_entries; /* number of valid entries */ 205+ __u16 eh_max; /* capacity of store in entries */ 206+ __u16 eh_depth; /* has tree real underlying blocks? */ 207+ __u32 eh_generation; /* generation of the tree */ 208+ }; 209+ 210+#define EXT4_EXT_MAGIC (0xf30a) 211+#define EXT_FIRST_EXTENT(__hdr__) \ 212+ ((struct ext4_extent *) (((char *) (__hdr__)) + \ 213+ sizeof(struct ext4_extent_header))) 214+#define EXT_FIRST_INDEX(__hdr__) \ 215+ ((struct ext4_extent_idx *) (((char *) (__hdr__)) + \ 216+ sizeof(struct ext4_extent_header))) 217+#define EXT_LAST_EXTENT(__hdr__) \ 218+ (EXT_FIRST_EXTENT((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1) 219+#define EXT_LAST_INDEX(__hdr__) \ 220+ (EXT_FIRST_INDEX((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1) 221+ 222+ 223+ 224 /* linux/ext2fs.h */ 225 /* 226 * EXT2_DIR_PAD defines the directory entries boundaries 227@@ -271,8 +367,17 @@ struct ext2_dir_entry 228 /* kind of from ext2/super.c */ 229 #define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s)) 230 /* linux/ext2fs.h */ 231+/* sizeof(struct ext2_group_desc) is changed in ext4 232+ * in kernel code, ext2/3 uses sizeof(struct ext2_group_desc) to calculate 233+ * number of desc per block, while ext4 uses superblock->s_desc_size in stead 234+ * superblock->s_desc_size is not available in ext2/3 235+ * */ 236+#define EXT2_DESC_SIZE(s) \ 237+ (EXT4_HAS_INCOMPAT_FEATURE(s,EXT4_FEATURE_INCOMPAT_64BIT)? \ 238+ s->s_desc_size : EXT4_MIN_DESC_SIZE) 239 #define EXT2_DESC_PER_BLOCK(s) \ 240- (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) 241+ (EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s)) 242+ 243 /* linux/stat.h */ 244 #define S_IFMT 00170000 245 #define S_IFLNK 0120000 246@@ -434,6 +539,122 @@ ext2fs_block_map (int logical_block) 247 [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]; 248 } 249 250+/* extent binary search index 251+ * find closest index in the current level extent tree 252+ * kind of from ext4_ext_binsearch_idx in ext4/extents.c 253+ */ 254+static struct ext4_extent_idx* 255+ext4_ext_binsearch_idx(struct ext4_extent_header* eh, int logical_block) 256+{ 257+ struct ext4_extent_idx *r, *l, *m; 258+ l = EXT_FIRST_INDEX(eh) + 1; 259+ r = EXT_LAST_INDEX(eh); 260+ while (l <= r) 261+ { 262+ m = l + (r - l) / 2; 263+ if (logical_block < m->ei_block) 264+ r = m - 1; 265+ else 266+ l = m + 1; 267+ } 268+ return (struct ext4_extent_idx*)(l - 1); 269+} 270+ 271+/* extent binary search 272+ * find closest extent in the leaf level 273+ * kind of from ext4_ext_binsearch in ext4/extents.c 274+ */ 275+static struct ext4_extent* 276+ext4_ext_binsearch(struct ext4_extent_header* eh, int logical_block) 277+{ 278+ struct ext4_extent *r, *l, *m; 279+ l = EXT_FIRST_EXTENT(eh) + 1; 280+ r = EXT_LAST_EXTENT(eh); 281+ while (l <= r) 282+ { 283+ m = l + (r - l) / 2; 284+ if (logical_block < m->ee_block) 285+ r = m - 1; 286+ else 287+ l = m + 1; 288+ } 289+ return (struct ext4_extent*)(l - 1); 290+} 291+ 292+/* Maps extents enabled logical block into physical block via an inode. 293+ * EXT4_HUGE_FILE_FL should be checked before calling this. 294+ */ 295+static int 296+ext4fs_block_map (int logical_block) 297+{ 298+ struct ext4_extent_header *eh; 299+ struct ext4_extent *ex, *extent; 300+ struct ext4_extent_idx *ei, *index; 301+ int depth; 302+ int i; 303+ 304+#ifdef E2DEBUG 305+ unsigned char *i; 306+ for (i = (unsigned char *) INODE; 307+ i < ((unsigned char *) INODE + sizeof (struct ext2_inode)); 308+ i++) 309+ { 310+ printf ("%c", "0123456789abcdef"[*i >> 4]); 311+ printf ("%c", "0123456789abcdef"[*i % 16]); 312+ if (!((i + 1 - (unsigned char *) INODE) % 16)) 313+ { 314+ printf ("\n"); 315+ } 316+ else 317+ { 318+ printf (" "); 319+ } 320+ } 321+ printf ("logical block %d\n", logical_block); 322+#endif /* E2DEBUG */ 323+ eh = (struct ext4_extent_header*)INODE->i_block; 324+ if (eh->eh_magic != EXT4_EXT_MAGIC) 325+ { 326+ errnum = ERR_FSYS_CORRUPT; 327+ return -1; 328+ } 329+ while((depth = eh->eh_depth) != 0) 330+ { /* extent index */ 331+ if (eh->eh_magic != EXT4_EXT_MAGIC) 332+ { 333+ errnum = ERR_FSYS_CORRUPT; 334+ return -1; 335+ } 336+ ei = ext4_ext_binsearch_idx(eh, logical_block); 337+ if (ei->ei_leaf_hi) 338+ {/* 64bit physical block number not supported */ 339+ errnum = ERR_FILELENGTH; 340+ return -1; 341+ } 342+ if (!ext2_rdfsb(ei->ei_leaf_lo, DATABLOCK1)) 343+ { 344+ errnum = ERR_FSYS_CORRUPT; 345+ return -1; 346+ } 347+ eh = (struct ext4_extent_header*)DATABLOCK1; 348+ } 349+ 350+ /* depth==0, we come to the leaf */ 351+ ex = ext4_ext_binsearch(eh, logical_block); 352+ if (ex->ee_start_hi) 353+ {/* 64bit physical block number not supported */ 354+ errnum = ERR_FILELENGTH; 355+ return -1; 356+ } 357+ if ((ex->ee_block + ex->ee_len) < logical_block) 358+ { 359+ errnum = ERR_FSYS_CORRUPT; 360+ return -1; 361+ } 362+ return ex->ee_start_lo + logical_block - ex->ee_block; 363+ 364+} 365+ 366 /* preconditions: all preconds of ext2fs_block_map */ 367 int 368 ext2fs_read (char *buf, int len) 369@@ -468,6 +689,11 @@ ext2fs_read (char *buf, int len) 370 /* find the (logical) block component of our location */ 371 logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); 372 offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1); 373+ /* map extents enabled logical block number to physical fs on-disk block number */ 374+ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS) 375+ && INODE->i_flags & EXT4_EXTENTS_FL) 376+ map = ext4fs_block_map (logical_block); 377+ else 378 map = ext2fs_block_map (logical_block); 379 #ifdef E2DEBUG 380 printf ("map=%d\n", map); 381@@ -552,7 +778,7 @@ ext2fs_dir (char *dirname) 382 int desc; /* index within that group */ 383 int ino_blk; /* fs pointer of the inode's information */ 384 int str_chk = 0; /* used to hold the results of a string compare */ 385- struct ext2_group_desc *gdp; 386+ struct ext4_group_desc *ext4_gdp; 387 struct ext2_inode *raw_inode; /* inode info corresponding to current_ino */ 388 389 char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ 390@@ -598,8 +824,15 @@ ext2fs_dir (char *dirname) 391 { 392 return 0; 393 } 394- gdp = GROUP_DESC; 395- ino_blk = gdp[desc].bg_inode_table + 396+ ext4_gdp = (struct ext4_group_desc *)( (__u8*)GROUP_DESC + 397+ desc * EXT2_DESC_SIZE(SUPERBLOCK)); 398+ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK, EXT4_FEATURE_INCOMPAT_64BIT) 399+ && (! ext4_gdp->bg_inode_table_hi)) 400+ {/* 64bit itable not supported */ 401+ errnum = ERR_FILELENGTH; 402+ return -1; 403+ } 404+ ino_blk = ext4_gdp->bg_inode_table + 405 (((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group)) 406 >> log2 (EXT2_INODES_PER_BLOCK (SUPERBLOCK))); 407 #ifdef E2DEBUG 408@@ -676,7 +909,10 @@ ext2fs_dir (char *dirname) 409 } 410 linkbuf[filemax + len] = '\0'; 411 412- /* Read the symlink data. */ 413+ /* Read the symlink data. 414+ * Slow symlink is extents enabled 415+ * But since grub_read invokes ext2fs_read, nothing to change here 416+ */ 417 if (! ext2_is_fast_symlink ()) 418 { 419 /* Read the necessary blocks, and reset the file pointer. */ 420@@ -687,7 +923,9 @@ ext2fs_dir (char *dirname) 421 } 422 else 423 { 424- /* Copy the data directly from the inode. */ 425+ /* Copy the data directly from the inode. 426+ * Fast symlink is not extents enabled 427+ */ 428 len = filemax; 429 memmove (linkbuf, (char *) INODE->i_block, len); 430 } 431@@ -721,6 +959,13 @@ ext2fs_dir (char *dirname) 432 errnum = ERR_BAD_FILETYPE; 433 return 0; 434 } 435+ /* if file is too large, just stop and report an error*/ 436+ if ( (INODE->i_flags & EXT4_HUGE_FILE_FL) && !(INODE->i_size_high)) 437+ { 438+ /* file too large, stop reading */ 439+ errnum = ERR_FILELENGTH; 440+ return 0; 441+ } 442 443 filemax = (INODE->i_size); 444 return 1; 445@@ -775,17 +1020,28 @@ ext2fs_dir (char *dirname) 446 } 447 448 /* else, find the (logical) block component of our location */ 449+ /* ext4 logical block number the same as ext2/3 */ 450 blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); 451 452 /* we know which logical block of the directory entry we are looking 453 for, now we have to translate that to the physical (fs) block on 454 the disk */ 455+ /* map extents enabled logical block number to physical fs on-disk block number */ 456+ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS) 457+ && INODE->i_flags & EXT4_EXTENTS_FL) 458+ map = ext4fs_block_map (blk); 459+ else 460 map = ext2fs_block_map (blk); 461 #ifdef E2DEBUG 462 printf ("fs block=%d\n", map); 463 #endif /* E2DEBUG */ 464 mapblock2 = -1; 465- if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2)) 466+ if (map < 0) 467+ { 468+ *rest = ch; 469+ return 0; 470+ } 471+ if (!ext2_rdfsb (map, DATABLOCK2)) 472 { 473 errnum = ERR_FSYS_CORRUPT; 474 *rest = ch; 475