Upstream-Status: inappropriate From fbcbbba3b65402bd43a9e36593d544ff3451620e Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 3 Jun 2011 21:09:25 -0500 Subject: [PATCH 12/19] Add rev 1 support, large file support, and rework holes Add support for individual files larger than 2GB, which requires some rev 1 filesystem support. Also, since we have a non-overly filesystem structure, rework the OP_HOLES hack and just put that flag in the filesystem structure. This avoid having to mess around with the reserved bytes (which changed with rev 1 support). --- genext2fs.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 56 insertions(+), 13 deletions(-) diff --git a/genext2fs.c b/genext2fs.c index 8a7f589..e420bba 100644 --- a/genext2fs.c +++ b/genext2fs.c @@ -233,10 +233,6 @@ struct stats { #define FM_IWOTH 0000002 // write #define FM_IXOTH 0000001 // execute -// options - -#define OP_HOLES 0x01 // make files with holes - /* Defines for accessing group details */ // Number of groups in the filesystem @@ -485,7 +481,22 @@ is_blk_empty(uint8 *b) udecl32(s_creator_os) /* Indicator of which OS created the filesystem */ \ udecl32(s_rev_level) /* The revision level of the filesystem */ \ udecl16(s_def_resuid) /* The default uid for reserved blocks */ \ - udecl16(s_def_resgid) /* The default gid for reserved blocks */ + udecl16(s_def_resgid) /* The default gid for reserved blocks */ \ + /* rev 1 version fields start here */ \ + udecl32(s_first_ino) /* First non-reserved inode */ \ + udecl16(s_inode_size) /* size of inode structure */ \ + udecl16(s_block_group_nr) /* block group # of this superblock */ \ + udecl32(s_feature_compat) /* compatible feature set */ \ + udecl32(s_feature_incompat) /* incompatible feature set */ \ + udecl32(s_feature_ro_compat) /* readonly-compatible feature set */ \ + utdecl8(s_uuid,16) /* 128-bit uuid for volume */ \ + utdecl8(s_volume_name,16) /* volume name */ \ + utdecl8(s_last_mounted,64) /* directory where last mounted */ \ + udecl32(s_algorithm_usage_bitmap) /* For compression */ + +#define EXT2_GOOD_OLD_FIRST_INO 11 +#define EXT2_GOOD_OLD_INODE_SIZE 128 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 #define groupdescriptor_decl \ udecl32(bg_block_bitmap) /* Block number of the block bitmap */ \ @@ -525,6 +536,7 @@ is_blk_empty(uint8 *b) #define decl8(x) int8 x; #define udecl8(x) uint8 x; +#define utdecl8(x,n) uint8 x[n]; #define decl16(x) int16 x; #define udecl16(x) uint16 x; #define decl32(x) int32 x; @@ -534,7 +546,7 @@ is_blk_empty(uint8 *b) typedef struct { superblock_decl - uint32 s_reserved[235]; // Reserved + uint32 s_reserved[205]; // Reserved } superblock; typedef struct @@ -616,6 +628,8 @@ typedef struct int32 hdlink_cnt; struct hdlinks_s hdlinks; + int holes; + listcache blks; listcache inodes; listcache blkmaps; @@ -628,6 +642,7 @@ typedef struct #undef decl8 #undef udecl8 +#undef utdecl8 #undef decl16 #undef udecl16 #undef decl32 @@ -636,6 +651,7 @@ typedef struct #define decl8(x) #define udecl8(x) +#define utdecl8(x,n) #define decl16(x) this->x = swab16(this->x); #define udecl16(x) this->x = swab16(this->x); #define decl32(x) this->x = swab32(this->x); @@ -700,6 +716,7 @@ swap_block(block b) #undef decl8 #undef udecl8 +#undef utdecl8 #undef decl16 #undef udecl16 #undef decl32 @@ -1695,7 +1712,7 @@ extend_inode_blk(filesystem *fs, inode_pos *ipos, block b, int amount) for (pos = 0; amount; pos += BLOCKSIZE) { - int hole = ((fs->sb->s_reserved[200] & OP_HOLES) && is_blk_empty(b + pos)); + int hole = (fs->holes && is_blk_empty(b + pos)); bk = walk_bw(fs, ipos->nod, &ipos->bw, &amount, hole); if (bk == WALK_END) @@ -1912,6 +1929,14 @@ mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint return nod; } +static void +fs_upgrade_rev1_largefile(filesystem *fs) +{ + fs->sb->s_rev_level = 1; + fs->sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; + fs->sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; +} + #define COPY_BLOCKS 16 #define CB_SIZE (COPY_BLOCKS * BLOCKSIZE) @@ -1926,11 +1951,16 @@ mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, off_ size_t readbytes; inode_pos ipos; - b = malloc(CB_SIZE); if (!b) error_msg_and_die("mkfile_fs: out of memory"); inode_pos_init(fs, &ipos, nod, INODE_POS_TRUNCATE, NULL); + if (size > 0x7fffffff) { + if (fs->sb->s_rev_level < 1) + fs_upgrade_rev1_largefile(fs); + fs->sb->s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_LARGE_FILE; + } + node->i_dir_acl = size >> 32; node->i_size = size; while (size) { readbytes = fread(b, 1, CB_SIZE, f); @@ -2269,6 +2299,8 @@ swap_gds(filesystem *fs) // Copy size blocks from src to dst, putting holes in the output // file (if possible) if the input block is all zeros. +// Copy size blocks from src to dst, putting holes in the output +// file (if possible) if the input block is all zeros. static void copy_file(filesystem *fs, FILE *dst, FILE *src, size_t size) { @@ -2284,7 +2316,7 @@ copy_file(filesystem *fs, FILE *dst, FILE *src, size_t size) while (size > 0) { if (fread(b, BLOCKSIZE, 1, src) != 1) perror_msg_and_die("copy failed on read"); - if ((dst != stdout) && is_blk_empty(b)) { + if ((dst != stdout) && fs->holes && is_blk_empty(b)) { /* Empty block, just skip it */ if (fseek(dst, BLOCKSIZE, SEEK_CUR)) perror_msg_and_die("fseek"); @@ -2537,8 +2569,7 @@ init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, fs->sb->s_max_mnt_count = 20; // options for me - if(holes) - fs->sb->s_reserved[200] |= OP_HOLES; + fs->holes = holes; return fs; } @@ -2571,8 +2602,21 @@ load_fs(FILE * fh, int swapit, char *fname) perror_msg_and_die("fread filesystem image superblock"); if(swapit) swap_sb(fs->sb); - if(fs->sb->s_rev_level || (fs->sb->s_magic != EXT2_MAGIC_NUMBER)) + if((fs->sb->s_rev_level > 1) || (fs->sb->s_magic != EXT2_MAGIC_NUMBER)) error_msg_and_die("not a suitable ext2 filesystem"); + if (fs->sb->s_rev_level > 0) { + if (fs->sb->s_first_ino != EXT2_GOOD_OLD_FIRST_INO) + error_msg_and_die("First inode incompatible"); + if (fs->sb->s_inode_size != EXT2_GOOD_OLD_INODE_SIZE) + error_msg_and_die("inode size incompatible"); + if (fs->sb->s_feature_compat) + error_msg_and_die("Unsupported compat features"); + if (fs->sb->s_feature_incompat) + error_msg_and_die("Unsupported incompat features"); + if (fs->sb->s_feature_ro_compat + & ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE) + error_msg_and_die("Unsupported ro compat features"); + } fs->nheadblocks = (((GRP_NBGROUPS(fs) * sizeof(groupdescriptor)) + sizeof(superblock) + (BLOCKSIZE - 1)) / BLOCKSIZE); @@ -2893,7 +2937,6 @@ finish_fs(filesystem *fs) error_msg_and_die("entry mismatch on blockmap cache flush"); if (cache_flush(&fs->blks)) error_msg_and_die("entry mismatch on block cache flush"); - fs->sb->s_reserved[200] = 0; if(fs->swapit) { swap_sb(fs->sb); swap_gds(fs); -- 1.7.4.1