--- genext2fs-1.3.orig/genext2fs.c +++ genext2fs-1.3/genext2fs.c @@ -26,6 +26,15 @@ // Bugfix: getcwd values for Solaris xavier.gueguen@col.bsf.alcatel.fr // Bugfix: ANSI scanf for non-GNU C xavier.gueguen@col.bsf.alcatel.fr // 28 Jun 2001 Bugfix: getcwd differs for Solaris/GNU mike@sowbug.com +// 8 Mar 2002 Bugfix: endianness swap of x-indirects +// 23 Mar 2002 Bugfix: test for IFCHR or IFBLK was flawed +// 10 Oct 2002 Added comments,makefile targets, vsundar@ixiacom.com +// endianess swap assert check. +// Copyright (C) 2002 Ixia communications +// 12 Oct 2002 Added support for triple indirection vsundar@ixiacom.com +// Copyright (C) 2002 Ixia communications +// 14 Oct 2002 Added support for groups vsundar@ixiacom.com +// Copyright (C) 2002 Ixia communications // `genext2fs' is a mean to generate an ext2 filesystem @@ -67,6 +76,7 @@ #include #include #include +#include @@ -76,10 +86,14 @@ #define BLOCKSIZE 1024 #define BLOCKS_PER_GROUP 8192 #define BYTES_PER_INODE (8*BLOCKSIZE) +/* Percentage of blocks that are reserved.*/ #define RESERVED_INODES 5/100 // inode block size (why is it != BLOCKSIZE ?!?) +/* The field i_blocks in the ext2 inode stores the number of data blocks + but in terms of 512 bytes. That is what INODE_BLOCKSIZE represents. + INOBLK is the number of such blocks in an actual disk block */ #define INODE_BLOCKSIZE 512 #define INOBLK (BLOCKSIZE / INODE_BLOCKSIZE) @@ -147,6 +161,39 @@ #define OP_HOLES 0x01 // make files with holes +/* Defines for accessing group details */ + +// Number of groups in the filesystem +#define GRP_NBGROUPS(fs) ( ((fs)->sb.s_blocks_count-1)/(fs)->sb.s_blocks_per_group ) + +// Get group block bitmap (bbm) given the group number +#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_block_bitmap) ) + +// Get group inode bitmap (ibm) given the group number +#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_inode_bitmap) ) + +// Given an inode number find the group it belongs to +#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group) + +//Given an inode number get the inode bitmap that covers it +#define GRP_GET_INODE_BITMAP(fs,nod) \ + ( GRP_GET_GROUP_IBM((fs),GRP_GROUP_OF_INODE((fs),(nod))) ) + +//Given an inode number find its offset within the inode bitmap that covers it +#define GRP_IBM_OFFSET(fs,nod) \ + ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb.s_inodes_per_group ) + +// Given a block number find the group it belongs to +#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb.s_blocks_per_group) + +//Given a block number get the block bitmap that covers it +#define GRP_GET_BLOCK_BITMAP(fs,blk) \ + ( GRP_GET_GROUP_BBM((fs),GRP_GROUP_OF_BLOCK((fs),(blk))) ) + +//Given a block number find its offset within the block bitmap that covers it +#define GRP_BBM_OFFSET(fs,blk) \ + ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb.s_blocks_per_group ) + // used types @@ -287,7 +334,6 @@ { groupdescriptor_decl uint32 bg_reserved[3]; - uint32 bg_pad_to_bk[(BLOCKSIZE-32)/sizeof(uint32)]; } groupdescriptor; typedef struct @@ -304,6 +350,32 @@ typedef uint8 block[BLOCKSIZE]; +/* blockwalker fields: + The blockwalker is used to access all the blocks of a file (including + the indirection blocks) through repeated calls to walk_bw. + + bpdir -> index into the inode->i_block[]. Indicates level of indirection. + bnum -> total number of blocks so far accessed. including indirection + blocks. + bpind,bpdind,bptind -> index into indirection blocks. + + bpind, bpdind, bptind do *NOT* index into single, double and triple + indirect blocks resp. as you might expect from their names. Instead + they are in order the 1st, 2nd & 3rd index to be used + + As an example.. + To access data block number 70000: + bpdir: 15 (we are doing triple indirection) + bpind: 0 ( index into the triple indirection block) + bpdind: 16 ( index into the double indirection block) + bptind: 99 ( index into the single indirection block) + 70000 = 12 + 256 + 256*256 + 16*256 + 100 (indexing starts from zero) + + So,for double indirection bpind will index into the double indirection + block and bpdind into the single indirection block. For single indirection + only bpind will be used. +*/ + typedef struct { uint32 bnum; @@ -313,15 +385,14 @@ uint32 bptind; } blockwalker; + +/* Filesystem structure that support groups */ #if BLOCKSIZE == 1024 typedef struct { block zero; // The famous block 0 superblock sb; // The superblock - groupdescriptor gd; // The group desciptor - block bbm; // The block bitmap - block ibm; // The inode bitmap - inode itab[0]; // The inode table + groupdescriptor gd[0]; // The group descriptors } filesystem; #else #error UNHANDLED BLOCKSIZE @@ -416,14 +487,15 @@ // temporary working block inline uint8 * get_workblk(void) { - static block b; + unsigned char* b=calloc(1,BLOCKSIZE); return b; } inline void free_workblk(block b) { + free(b); } -// rounds a quantity up to a blocksize +/* Rounds qty upto a multiple of siz. siz should be a power of 2 */ uint32 rndup(uint32 qty, uint32 siz) { return (qty + (siz - 1)) & ~(siz - 1); @@ -444,7 +516,13 @@ // return a given inode from a filesystem inline inode * get_nod(filesystem *fs, uint32 nod) { - return &fs->itab[nod-1]; + int grp,offset; + inode *itab; + + offset = GRP_IBM_OFFSET(fs,nod); + grp = GRP_GROUP_OF_INODE(fs,nod); + itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table); + return itab+offset-1; } // allocate a given block/inode in the bitmap @@ -479,29 +557,57 @@ } // allocate a block -uint32 alloc_blk(filesystem *fs) +uint32 alloc_blk(filesystem *fs, uint32 nod) { - uint32 bk; - if(!(bk = allocate(fs->bbm, 0))) + uint32 bk=0; + uint32 grp,nbgroups; + + grp = nod/fs->sb.s_inodes_per_group; + nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) / + fs->sb.s_blocks_per_group; + if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) { + for(grp=0;grpgd[grp].bg_block_bitmap),0); + grp--; + } + if (!bk) errexit("couldn't allocate a block (no free space)"); - if(!(fs->gd.bg_free_blocks_count--)) - errexit("group descr. free blocks count == 0 (corrupted fs?)"); + if(!(fs->gd[grp].bg_free_blocks_count--)) + errexit("group descr %d. free blocks count == 0 (corrupted fs?)",grp); if(!(fs->sb.s_free_blocks_count--)) errexit("superblock free blocks count == 0 (corrupted fs?)"); - return bk; + return fs->sb.s_blocks_per_group*grp + bk; } // allocate an inode uint32 alloc_nod(filesystem *fs) { - uint32 nod; - if(!(nod = allocate(fs->ibm, 0))) + uint32 nod=0,best_group=0; + uint32 grp,nbgroups,avefreei; + + nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) / + fs->sb.s_blocks_per_group; + + /* Distribute inodes amongst all the blocks */ + /* For every block group with more than average number of free inodes */ + /* find the one with the most free blocks and allocate node there */ + /* Idea from find_group_dir in fs/ext2/ialloc.c in 2.4.19 kernel */ + /* We do it for all inodes. */ + avefreei = fs->sb.s_free_inodes_count / nbgroups; + for(grp=0;grpgd[grp].bg_free_inodes_count < avefreei) + continue; + if (!best_group || + fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count) + best_group = grp; + } + if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0))) errexit("couldn't allocate an inode (no free inode)"); - if(!(fs->gd.bg_free_inodes_count--)) + if(!(fs->gd[best_group].bg_free_inodes_count--)) errexit("group descr. free blocks count == 0 (corrupted fs?)"); if(!(fs->sb.s_free_inodes_count--)) errexit("superblock free blocks count == 0 (corrupted fs?)"); - return nod; + return fs->sb.s_inodes_per_group*best_group+nod; } // print a bitmap allocation @@ -546,14 +652,14 @@ { bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0]; if(extend) // allocate first block - *bkref = hole ? 0 : alloc_blk(fs); + *bkref = hole ? 0 : alloc_blk(fs,nod); } // direct block else if(bw->bpdir < EXT2_NDIR_BLOCKS) { bkref = &get_nod(fs, nod)->i_block[++bw->bpdir]; if(extend) // allocate block - *bkref = hole ? 0 : alloc_blk(fs); + *bkref = hole ? 0 : alloc_blk(fs,nod); } // first block in indirect block else if(bw->bpdir == EXT2_NDIR_BLOCKS) @@ -562,11 +668,11 @@ bw->bpdir = EXT2_IND_BLOCK; bw->bpind = 0; if(extend) // allocate indirect block - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs); + get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod); b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); bkref = &b[bw->bpind]; if(extend) // allocate first block - *bkref = hole ? 0 : alloc_blk(fs); + *bkref = hole ? 0 : alloc_blk(fs,nod); } // block in indirect block else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1)) @@ -575,7 +681,7 @@ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); bkref = &b[bw->bpind]; if(extend) // allocate block - *bkref = hole ? 0 : alloc_blk(fs); + *bkref = hole ? 0 : alloc_blk(fs,nod); } // first block in first indirect block in first double indirect block else if(bw->bpdir == EXT2_IND_BLOCK) @@ -585,14 +691,14 @@ bw->bpind = 0; bw->bpdind = 0; if(extend) // allocate double indirect block - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs); + get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod); b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); if(extend) // allocate first indirect block - b[bw->bpind] = alloc_blk(fs); + b[bw->bpind] = alloc_blk(fs,nod); b = (uint32*)get_blk(fs, b[bw->bpind]); bkref = &b[bw->bpdind]; if(extend) // allocate first block - *bkref = hole ? 0 : alloc_blk(fs); + *bkref = hole ? 0 : alloc_blk(fs,nod); } // block in indirect block in double indirect block else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1)) @@ -602,7 +708,7 @@ b = (uint32*)get_blk(fs, b[bw->bpind]); bkref = &b[bw->bpdind]; if(extend) // allocate block - *bkref = hole ? 0 : alloc_blk(fs); + *bkref = hole ? 0 : alloc_blk(fs,nod); } // first block in indirect block in double indirect block else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1)) @@ -612,19 +718,99 @@ bw->bpind++; b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); if(extend) // allocate indirect block - b[bw->bpind] = alloc_blk(fs); + b[bw->bpind] = alloc_blk(fs,nod); b = (uint32*)get_blk(fs, b[bw->bpind]); bkref = &b[bw->bpdind]; if(extend) // allocate first block - *bkref = hole ? 0 : alloc_blk(fs); + *bkref = hole ? 0 : alloc_blk(fs,nod); + } + + /* Adding support for triple indirection */ + /* Just starting triple indirection. Allocate the indirection + blocks and the first data block + */ + else if (bw->bpdir == EXT2_DIND_BLOCK) + { + bw->bnum += 3; + bw->bpdir = EXT2_TIND_BLOCK; + bw->bpind = 0; + bw->bpdind = 0; + bw->bptind = 0; + if(extend) // allocate triple indirect block + get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod); + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); + if(extend) // allocate first double indirect block + b[bw->bpind] = alloc_blk(fs,nod); + b = (uint32*)get_blk(fs, b[bw->bpind]); + if(extend) // allocate first indirect block + b[bw->bpdind] = alloc_blk(fs,nod); + b = (uint32*)get_blk(fs, b[bw->bpdind]); + bkref = &b[bw->bptind]; + if(extend) // allocate first data block + *bkref = hole ? 0 : alloc_blk(fs,nod); + } + /* Still processing a single indirect block down the indirection + chain.Allocate a data block for it + */ + else if ( (bw->bpdir == EXT2_TIND_BLOCK) && + (bw->bptind < BLOCKSIZE/4 -1) ) + { + bw->bptind++; + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); + b = (uint32*)get_blk(fs, b[bw->bpind]); + b = (uint32*)get_blk(fs, b[bw->bpdind]); + bkref = &b[bw->bptind]; + if(extend) // allocate data block + *bkref = hole ? 0 : alloc_blk(fs,nod); + } + /* Finished processing a single indirect block. But still in the + same double indirect block. Allocate new single indirect block + for it and a data block + */ + else if ( (bw->bpdir == EXT2_TIND_BLOCK) && + (bw->bpdind < BLOCKSIZE/4 -1) ) + { + bw->bnum++; + bw->bptind = 0; + bw->bpdind++; + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); + b = (uint32*)get_blk(fs, b[bw->bpind]); + if (extend) // allocate single indirect block + b[bw->bpdind] = alloc_blk(fs,nod); + b = (uint32*)get_blk(fs, b[bw->bpdind]); + bkref = &b[bw->bptind]; + if(extend) // allocate first data block + *bkref = hole ? 0 : alloc_blk(fs,nod); + } + /* Finished processing a double indirect block. Allocate the next + double indirect block and the single,data blocks for it + */ + else if ( (bw->bpdir == EXT2_TIND_BLOCK) && + (bw->bpind < BLOCKSIZE/4 - 1) ) + { + bw->bnum += 2; + bw->bpdind = 0; + bw->bptind = 0; + bw->bpind++; + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); + if(extend) // allocate double indirect block + b[bw->bpind] = alloc_blk(fs,nod); + b = (uint32*)get_blk(fs, b[bw->bpind]); + if(extend) // allocate single indirect block + b[bw->bpdind] = alloc_blk(fs,nod); + b = (uint32*)get_blk(fs, b[bw->bpdind]); + bkref = &b[bw->bptind]; + if(extend) // allocate first block + *bkref = hole ? 0 : alloc_blk(fs,nod); } - // I don't do triple indirect - it's such a small filesystem ... else - errexit("file too big ! blocks list for inode %d extends past double indirect blocks!", nod); + errexit("file too big ! blocks list for inode %d extends past triple indirect blocks!", nod); + /* End change for walking triple indirection */ + if(*bkref) { bw->bnum++; - if(!allocated(fs->bbm, *bkref)) + if(!allocated(GRP_GET_BLOCK_BITMAP(fs,*bkref), GRP_BBM_OFFSET(fs,*bkref))) errexit("[block %d of inode %d is unallocated !]", *bkref, nod); } if(extend) @@ -780,7 +966,7 @@ add2dir(fs, parent_nod, nod, name); add2dir(fs, nod, nod, "."); add2dir(fs, nod, parent_nod, ".."); - fs->gd.bg_used_dirs_count++; + fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++; return nod; } @@ -981,44 +1167,98 @@ // endianness swap of x-indirect blocks void swap_goodblocks(filesystem *fs, inode *nod) { - int i; + int i,j,done=0; + uint32 *b,*b2; + int nblk = nod->i_blocks / INOBLK; - if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR))) + if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR)) for(i = 0; i <= EXT2_TIND_BLOCK; i++) nod->i_block[i] = swab32(nod->i_block[i]); if(nblk <= EXT2_IND_BLOCK) return; swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK])); - if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4) + if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4) return; + /* Currently this will fail b'cos the number of blocks as stored + in i_blocks also includes the indirection blocks (see + walk_bw). But this function assumes that i_blocks only + stores the count of data blocks ( Actually according to + "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed) + i_blocks IS supposed to store the count of data blocks). so + with a file of size 268K nblk would be 269.The above check + will be false even though double indirection hasn't been + started.This is benign as 0 means block 0 which has been + zeroed out and therefore points back to itself from any offset + */ + assert(nod->i_block[EXT2_DIND_BLOCK] != 0); for(i = 0; i < BLOCKSIZE/4; i++) - if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i) + if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i ) swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i])); swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK])); if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4) return; - errexit("too big file on the filesystem"); + /* Adding support for triple indirection */ + b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]); + for(i=0;i < BLOCKSIZE/4 && !done ; i++) { + b2 = (uint32*)get_blk(fs,b[i]); + for(j=0; j ( EXT2_IND_BLOCK + BLOCKSIZE/4 + + (BLOCKSIZE/4)*(BLOCKSIZE/4) + + i*(BLOCKSIZE/4)*(BLOCKSIZE/4) + + j*(BLOCKSIZE/4)) ) + swap_block(get_blk(fs,b2[j])); + else { + done = 1; + break; + } + } + swap_block((uint8 *)b2); + } + swap_block((uint8 *)b); + return; } void swap_badblocks(filesystem *fs, inode *nod) { - int i; + int i,j,done=0; + uint32 *b,*b2; + int nblk = nod->i_blocks / INOBLK; - if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR))) + if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR)) for(i = 0; i <= EXT2_TIND_BLOCK; i++) nod->i_block[i] = swab32(nod->i_block[i]); if(nblk <= EXT2_IND_BLOCK) return; swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK])); - if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4) + if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4) return; + /* See comment in swap_goodblocks */ + assert(nod->i_block[EXT2_DIND_BLOCK] != 0); swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK])); for(i = 0; i < BLOCKSIZE/4; i++) - if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i) + if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i ) swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i])); if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4) return; - errexit("too big file on the filesystem"); + /* Adding support for triple indirection */ + b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]); + swap_block((uint8 *)b); + for(i=0;i < BLOCKSIZE/4 && !done ; i++) { + b2 = (uint32*)get_blk(fs,b[i]); + swap_block((uint8 *)b2); + for(j=0; j ( EXT2_IND_BLOCK + BLOCKSIZE/4 + + (BLOCKSIZE/4)*(BLOCKSIZE/4) + + i*(BLOCKSIZE/4)*(BLOCKSIZE/4) + + j*(BLOCKSIZE/4)) ) + swap_block(get_blk(fs,b2[j])); + else { + done = 1; + break; + } + } + } + return; } // endianness swap of the whole filesystem @@ -1045,7 +1285,8 @@ swap_goodblocks(fs, nod); swap_nod(nod); } - swap_gd(&fs->gd); + for(i=0;igd[i])); swap_sb(&fs->sb); } @@ -1053,7 +1294,8 @@ { int i; swap_sb(&fs->sb); - swap_gd(&fs->gd); + for(i=0;igd[i])); for(i = 1; i < fs->sb.s_inodes_count; i++) { inode *nod = get_nod(fs, i); @@ -1084,53 +1326,113 @@ directory *d; uint8 * b; uint32 nod; + uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks, + free_blocks_per_group,nbblocks_per_group; + uint32 gd,itbl,ibmpos,bbmpos,itblpos; + int j; + uint8 *bbm,*ibm; + inode *itab0; if(nbblocks < 16) // totally arbitrary errexit("too small filesystem"); - if(nbblocks >BLOCKS_PER_GROUP) // I build only one group - errexit("too big filesystem"); + + /* nbblocks is the total number of blocks in the system. First + * calculate how much overhead blocks - inode table blocks,bitmap + * blocks,group descriptor blocks etc. - are needed assuming each + * group has BLOCKS_PER_GROUP blocks.Then recalculate nbblocks with + * this figure. Each group has the same number of blocks. So the fs + * has a size atleast the given value but usually rounded off to a i + * higher number. + */ + nbgroups = rndup(nbblocks,BLOCKS_PER_GROUP)/ BLOCKS_PER_GROUP; + nbinodes_per_group = nbinodes/nbgroups +1; + nbinodes_per_group = rndup(nbinodes_per_group, BLOCKSIZE/sizeof(inode)); + if (nbinodes_per_group < 16) + nbinodes_per_group = 16; //minimum number b'cos the first 10 are reserved + overhead_per_group = 3 /*sb,ibm,bbm*/ + + nbinodes_per_group *sizeof(inode)/BLOCKSIZE + + rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE; + free_blocks = nbblocks - overhead_per_group * nbgroups - 1 /*boot block */; + free_blocks_per_group = free_blocks/nbgroups; + if (free_blocks > free_blocks_per_group * nbgroups) + free_blocks_per_group++; + nbblocks_per_group = free_blocks_per_group + overhead_per_group; + if (nbblocks_per_group > BLOCKS_PER_GROUP) { + /* Can this happen ? */ + nbblocks_per_group = BLOCKS_PER_GROUP; + free_blocks_per_group = nbblocks_per_group - overhead_per_group; + } + nbblocks = nbblocks_per_group * nbgroups + 1; + + if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE))) errexit("not enough memory for filesystem"); // create the superblock for an empty filesystem - fs->sb.s_inodes_count = rndup(nbinodes, BLOCKSIZE/sizeof(inode)); + fs->sb.s_inodes_count = nbinodes_per_group * nbgroups; fs->sb.s_blocks_count = nbblocks; fs->sb.s_r_blocks_count = nbresrvd; - fs->sb.s_free_blocks_count = nbblocks; + fs->sb.s_free_blocks_count = free_blocks_per_group*nbgroups; fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1; fs->sb.s_first_data_block = (BLOCKSIZE == 1024); fs->sb.s_log_block_size = BLOCKSIZE >> 11; fs->sb.s_log_frag_size = BLOCKSIZE >> 11; - fs->sb.s_blocks_per_group = BLOCKS_PER_GROUP; - fs->sb.s_frags_per_group = BLOCKS_PER_GROUP; - fs->sb.s_inodes_per_group = fs->sb.s_inodes_count; + fs->sb.s_blocks_per_group = nbblocks_per_group; + fs->sb.s_frags_per_group = nbblocks_per_group; + fs->sb.s_inodes_per_group = nbinodes_per_group; fs->sb.s_magic = EXT2_MAGIC_NUMBER; // set up groupdescriptors - fs->sb.s_free_blocks_count -= 5 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE; - fs->gd.bg_free_blocks_count = fs->sb.s_free_blocks_count; - fs->gd.bg_free_inodes_count = fs->sb.s_free_inodes_count; - fs->gd.bg_used_dirs_count = 1; - fs->gd.bg_block_bitmap = 3; - fs->gd.bg_inode_bitmap = 4; - fs->gd.bg_inode_table = 5; - - // mark non-filesystem blocks and inodes as allocated - for(i = fs->sb.s_blocks_count; i <= BLOCKSIZE * 8; i++) - allocate(fs->bbm, i); - for(i = fs->sb.s_inodes_count + 1; i <= BLOCKSIZE * 8; i++) - allocate(fs->ibm, i); - - // mark system blocsk and inodes as allocated - for(i = 1; i <= 4 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE; i++) - allocate(fs->bbm, i); - for(i = 1; i < EXT2_FIRST_INO; i++) - allocate(fs->ibm, i); + gd = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE; + itbl = nbinodes_per_group*sizeof(inode)/BLOCKSIZE; + for(i = 0,bbmpos=2+gd,ibmpos=3+gd,itblpos =4+gd; + igd[i].bg_free_blocks_count = free_blocks_per_group; + fs->gd[i].bg_free_inodes_count = nbinodes_per_group; + fs->gd[i].bg_used_dirs_count = 0; + fs->gd[i].bg_block_bitmap = bbmpos; + fs->gd[i].bg_inode_bitmap = ibmpos; + fs->gd[i].bg_inode_table = itblpos; + } + + /* Mark non-filesystem blocks and inodes as allocated */ + /* Mark system blocks and inodes as allocated */ + for(i = 0; isb.s_inodes_per_group; + //printf("j: %d\n",j); + bbm = get_blk(fs,fs->gd[i].bg_block_bitmap); + //non-filesystem blocks.*TODO* check the +1 + for(j=fs->sb.s_blocks_per_group + 1; j <= BLOCKSIZE * 8; j++) + allocate(bbm, j); + //system blocks + for(j = 1; j <= 3+gd+itbl; j++) + allocate(bbm, j); + + /* Inode bitmap */ + ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap); + //non-filesystem inodes + for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++) + allocate(ibm, j); + //system inodes + for(j = 1; j < EXT2_FIRST_INO; j++) + allocate(ibm, j); + } // make root inode and directory - fs->itab[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO; - fs->itab[EXT2_ROOT_INO-1].i_size = BLOCKSIZE; - fs->itab[EXT2_ROOT_INO-1].i_links_count = 2; + /* We have groups now. Add the root filesystem in group 0 */ + /* Also increment the directory count for group 0 */ + fs->gd[0].bg_free_inodes_count--; + fs->gd[0].bg_used_dirs_count = 1; + itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table); + itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO; + itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE; + itab0[EXT2_ROOT_INO-1].i_links_count = 2; + b = get_workblk(); d = (directory*)b; d->d_inode = EXT2_ROOT_INO; @@ -1406,7 +1708,7 @@ s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved"; } printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count); - if(!allocated(fs->ibm, nod)) + if(!allocated(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod))) { printf("unallocated\n"); return; @@ -1450,14 +1752,16 @@ printf("%d inodes (%d free)\n", fs->sb.s_inodes_count, fs->sb.s_free_inodes_count); printf("block size = %d, frag size = %d\n", fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024, fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024); printf("%d blocks per group, %d frags per group, %d inodes per group\n", fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group, fs->sb.s_inodes_per_group); - printf("block bitmap: block %d, inode bitmap: block %d, inode table: block %d\n", fs->gd.bg_block_bitmap, fs->gd.bg_inode_bitmap, fs->gd.bg_inode_table); + // *TBD* printf("block bitmap: block %d, inode bitmap: block %d, inode table: block %d\n", fs->gd.bg_block_bitmap, fs->gd.bg_inode_bitmap, fs->gd.bg_inode_table); printf("block bitmap allocation:\n"); - print_bm(fs->bbm, fs->sb.s_blocks_count); + // *TBD* print_bm(fs->bbm, fs->sb.s_blocks_count); printf("inode bitmap allocation:\n"); + /* *TBD* print_bm(fs->ibm, fs->sb.s_inodes_count); for(i=1; i<=fs->sb.s_inodes_count; i++) if(allocated(fs->ibm, i)) print_inode(fs, i); + */ } void dump_fs(filesystem *fs, FILE * fh, int swapit) @@ -1622,7 +1926,7 @@ } if(emptyval) for(i = 1; i < fs->sb.s_blocks_count; i++) - if(!allocated(fs->bbm, i)) + if(!allocated(GRP_GET_BLOCK_BITMAP(fs,i),GRP_BBM_OFFSET(fs,i))) memset(get_blk(fs, i), emptyval, BLOCKSIZE); if(verbose) print_fs(fs); --- genext2fs-1.3.orig/Makefile +++ genext2fs-1.3/Makefile @@ -0,0 +1,26 @@ +all: genext2fs +INSTALL=install +CFLAGS=-Wall -O2 + +install: + $(INSTALL) -d $(DESTDIR)/usr/bin/ + $(INSTALL) -m 755 genext2fs $(DESTDIR)/usr/bin/ + $(INSTALL) -d $(DESTDIR)/usr/share/man/man8/ + $(INSTALL) -m 644 genext2fs.8 $(DESTDIR)/usr/share/man/man8/ + +clean: + -rm genext2fs + rm -rf test ext2.img + +check: all + mkdir -p test + dd if=/dev/zero of=test/zero count=1 + ./genext2fs -b 4096 -d test ext2.img + + md5=`md5sum ext2.img | cut -f 1 -d " "`; \ + if [ "$$md5" != "a736fce6d45ea3631b01fd7b8f623131" ] ; then \ + echo "test failed."; \ + else \ + echo "test succeeded."; \ + fi + --- genext2fs-1.3.orig/genext2fs.8 +++ genext2fs-1.3/genext2fs.8 @@ -0,0 +1,112 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" First parameter, NAME, should be all caps +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection +.\" other parameters are allowed: see man(7), man(1) +.TH GENEXT2FS 8 "July 14, 2001" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +genext2fs \- ext2 filesystem generator for embedded systems +.SH SYNOPSIS +.B genext2fs +.RI [ options ] " image" +.SH DESCRIPTION +\fBgenext2fs\fP generates an ext2 filesystem +as a normal (non-root) user. It doesn't require you to mount +the image file to copy files on it. It doesn't even require +you to be the superuser to make device nodes. +.SH OPTIONS +.TP +.BI -x \ image +Use this image as a starting point +.TP +.BI -d \ directory +Add this directory as source +.TP +.BI -f \ file +Add nodes (e.g. devices) from this spec file +.TP +.BI -b \ blocks +Size in blocks +.TP +.BI -i \ inodes +Number of inodes +.TP +.BI -r \ reserved +Number of reserved blocks +.TP +.BI -g \ path +Generate a block map file for this path +.TP +.BI -e \ value +Fill unallocated blocks with value +.TP +.BI -z +Make files with holes +.TP +.BI -v +Print resulting filesystem structure +.TP +.BI -h +Display help +.TP +.SH EXAMPLES + +.EX +.B + genext2fs -b 1440 -d src /dev/fd0 +.EE + +All files in the +.I src +directory will be written to +.B /dev/fd0 +as a new ext2 filesystem image. You can then mount the floppy as +usual. + +.EX +.B + genext2fs -b 1024 -d src -f dev.txt flashdisk.img +.EE + +This example builds a filesystem from all the files in +.I src +, then device nodes are created based on the contents of the device file +.I dev.txt. +An example device file follows: + +.EX + drwx /dev + crw- 10,190 /dev/lcd + brw- 1,0 /dev/ram0 +.EE + +This device list builds the /dev directory, a character device +node /dev/lcd (major 10, minor 190) and a block device node +/dev/ram0 (major 1, minor 0) +.SH BUGS +\fBgenext2fs\fP has been designed for embedded +systems. As such, it will generate a filesystem for single-user +usage: all files/directories/etc... will belong to UID/GID 0 + +\fBgenext2fs\fP does not support hard links. Hard links present in the input +tree will be represented as separate files in the ext2 image. + +.SH SEE ALSO +.BR mkfs (8), +.BR genromfs (8), +.BR mkisofs (8). +.br +.SH AUTHOR +This manual page was written by David Kimdon , +for the Debian GNU/Linux system (but may be used by others). --- genext2fs-1.3.orig/debian/changelog +++ genext2fs-1.3/debian/changelog @@ -0,0 +1,46 @@ +genext2fs (1.3-5) unstable; urgency=low + + * - Compile with -O2. + - get_workblk() should return zero'd memory. This way we get + nul terminations in the produced image. + - get_workblk() now allocates the block dynamically on the heap. + The previous method of allocating the block as 'static' apparently + results in undefined behavior since get_workblk() is 'inline'. + Thanks to Vincent Sanders for the patch. + (closes: #248987) + + -- David Kimdon Sat, 15 May 2004 19:37:54 +0200 + +genext2fs (1.3-4) unstable; urgency=low + + * Fix assertion failure when there is a 268K file on the + filesystem. Patch thanks to Matt Kraai + (closes: #201277) + + -- David Kimdon Mon, 17 Nov 2003 22:53:15 +0100 + +genext2fs (1.3-3) unstable; urgency=low + + * Update to current upstream cvs + - support triple indirect blocks (removes 8MB limit) + - support for groups. + + -- David Kimdon Sat, 11 Jan 2003 18:45:58 -0800 + +genext2fs (1.3-2) unstable; urgency=low + + * apply fix from upstream cvs that appears to fix endian bug + (closes: #122411) + * mention filesystem size limit in manpage (closes: #122729) + * mention that hard links are not supported in manpage + (closes: #155464) + * add sanity check at the end of the build + + -- David Kimdon Fri, 8 Mar 2002 23:17:36 -0800 + +genext2fs (1.3-1) unstable; urgency=low + + * Initial Release. (closes: #105263) + + -- David Kimdon Sat, 14 Jul 2001 13:24:49 -0700 + --- genext2fs-1.3.orig/debian/rules +++ genext2fs-1.3/debian/rules @@ -0,0 +1,70 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatability version to use. +export DH_COMPAT=2 + +configure: configure-stamp +configure-stamp: + dh_testdir + # Add here commands to configure the package. + # ./configure --prefix=/usr --mandir=/usr/share/man/ + + touch configure-stamp + +build: configure-stamp build-stamp +build-stamp: + dh_testdir + + # Add here commands to compile the package. + $(MAKE) + $(MAKE) check + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + + # Add here commands to clean up after the build process. + -$(MAKE) clean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/genext2fs. + $(MAKE) install DESTDIR=`pwd`/debian/genext2fs + + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installdocs + dh_installchangelogs + dh_link + dh_strip + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure --- genext2fs-1.3.orig/debian/control +++ genext2fs-1.3/debian/control @@ -0,0 +1,19 @@ +Source: genext2fs +Section: admin +Priority: optional +Maintainer: David Kimdon +Build-Depends: debhelper (>> 3.0.0) +Standards-Version: 3.5.2 + +Package: genext2fs +Architecture: any +Depends: ${shlibs:Depends} +Description: ext2 filesystem generator for embedded systems + `genext2fs' is meant to generate an ext2 filesystem + as a normal (non-root) user. It doesn't require you to mount + the image file to copy files on it. It doesn't even require + you to be the superuser to make device nodes. + . + Warning ! `genext2fs' has been designed for embedded + systems. As such, it will generate a filesystem for single-user + usage: all files/directories/etc... will belong to UID/GID 0 --- genext2fs-1.3.orig/debian/copyright +++ genext2fs-1.3/debian/copyright @@ -0,0 +1,15 @@ +This package was debianized by David Kimdon on +Sat, 14 Jul 2001 13:24:49 -0700. + +It was downloaded from http://freshmeat.net/projects/genext2fs/ +Upstream Author(s): Xavier Bestel + +Copyright (C) 2000 Xavier Bestel + +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; version +2 of the License. + +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL file.