1 [PATCH] update genext2fs.c to CVS rev 1.118
3 See http://genext2fs.cvs.sourceforge.net/viewvc/genext2fs/genext2fs/genext2fs.c?view=log
6 Numerous bugfixes, large file and filesystem support, rev 1 filesystems,
7 volume id support, block size, ..
9 Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
12 genext2fs.c | 1870 ++++++++++++++++++++++++++++++++++++++++++------------------
14 3 files changed, 1527 insertions(+), 549 deletions(-)
16 Index: genext2fs-1.4.1/genext2fs.c
17 ===================================================================
18 --- genext2fs-1.4.1.orig/genext2fs.c
19 +++ genext2fs-1.4.1/genext2fs.c
21 // along with -q, -P, -U
25 + * Allow fseeko/off_t to be 64-bit offsets to allow filesystems and
26 + * individual files >2GB.
28 +#define _FILE_OFFSET_BITS 64
37 -# define NAMLEN(dirent) strlen((dirent)->d_name)
39 # define dirent direct
40 -# define NAMLEN(dirent) (dirent)->d_namlen
42 # include <sys/ndir.h>
51 unsigned long nblocks;
52 unsigned long ninodes;
57 -#define BLOCKSIZE 1024
58 +static int blocksize = 1024;
60 +#define SUPERBLOCK_OFFSET 1024
61 +#define SUPERBLOCK_SIZE 1024
63 +#define BLOCKSIZE blocksize
64 #define BLOCKS_PER_GROUP 8192
65 #define INODES_PER_GROUP 8192
66 /* Percentage of blocks that are reserved.*/
67 #define RESERVED_BLOCKS 5/100
68 #define MAX_RESERVED_BLOCKS 25/100
70 +/* The default value for s_creator_os. */
71 +#if defined(__linux__) && defined(EXT2_OS_LINUX)
72 +#define CREATOR_OS EXT2_OS_LINUX
73 +#define CREATOR_OS_NAME "linux"
75 +#if defined(__GNU__) && defined(EXT2_OS_HURD)
76 +#define CREATOR_OS EXT2_OS_HURD
77 +#define CREATOR_OS_NAME "hurd"
79 +#if defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD)
80 +#define CREATOR_OS EXT2_OS_FREEBSD
81 +#define CREATOR_OS_NAME "freebsd"
83 +#if defined(LITES) && defined(EXT2_OS_LITES)
84 +#define CREATOR_OS EXT2_OS_LITES
85 +#define CREATOR_OS_NAME "lites"
87 +#define CREATOR_OS EXT2_OS_LINUX /* by default */
88 +#define CREATOR_OS_NAME "linux"
89 +#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
90 +#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
91 +#endif /* defined(__GNU__) && defined(EXT2_OS_HURD) */
92 +#endif /* defined(__linux__) && defined(EXT2_OS_LINUX) */
95 // inode block size (why is it != BLOCKSIZE ?!?)
96 /* The field i_blocks in the ext2 inode stores the number of data blocks
98 #define EXT2_TIND_BLOCK 14 // triple indirect block
99 #define EXT2_INIT_BLOCK 0xFFFFFFFF // just initialized (not really a block address)
101 +// codes for operating systems
103 +#define EXT2_OS_LINUX 0
104 +#define EXT2_OS_HURD 1
105 +#define EXT2_OS_MASIX 2
106 +#define EXT2_OS_FREEBSD 3
107 +#define EXT2_OS_LITES 4
109 // end of a block walk
111 #define WALK_END 0xFFFFFFFE
112 @@ -227,44 +270,46 @@
113 #define FM_IWOTH 0000002 // write
114 #define FM_IXOTH 0000001 // execute
118 -#define OP_HOLES 0x01 // make files with holes
120 /* Defines for accessing group details */
122 // Number of groups in the filesystem
123 #define GRP_NBGROUPS(fs) \
124 - (((fs)->sb.s_blocks_count - fs->sb.s_first_data_block + \
125 - (fs)->sb.s_blocks_per_group - 1) / (fs)->sb.s_blocks_per_group)
126 + (((fs)->sb->s_blocks_count - fs->sb->s_first_data_block + \
127 + (fs)->sb->s_blocks_per_group - 1) / (fs)->sb->s_blocks_per_group)
129 // Get group block bitmap (bbm) given the group number
130 -#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_block_bitmap) )
131 +#define GRP_GET_GROUP_BBM(fs,grp,bi) (get_blk((fs),(grp)->bg_block_bitmap,(bi)))
132 +#define GRP_PUT_GROUP_BBM(bi) ( put_blk((bi)) )
134 // Get group inode bitmap (ibm) given the group number
135 -#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_inode_bitmap) )
137 +#define GRP_GET_GROUP_IBM(fs,grp,bi) (get_blk((fs), (grp)->bg_inode_bitmap,(bi)))
138 +#define GRP_PUT_GROUP_IBM(bi) ( put_blk((bi)) )
140 // Given an inode number find the group it belongs to
141 -#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group)
142 +#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb->s_inodes_per_group)
144 //Given an inode number get the inode bitmap that covers it
145 -#define GRP_GET_INODE_BITMAP(fs,nod) \
146 - ( GRP_GET_GROUP_IBM((fs),GRP_GROUP_OF_INODE((fs),(nod))) )
147 +#define GRP_GET_INODE_BITMAP(fs,nod,bi,gi) \
148 + ( GRP_GET_GROUP_IBM((fs),get_gd(fs,GRP_GROUP_OF_INODE((fs),(nod)),gi),bi) )
149 +#define GRP_PUT_INODE_BITMAP(bi,gi) \
150 + ( GRP_PUT_GROUP_IBM((bi)),put_gd((gi)) )
152 //Given an inode number find its offset within the inode bitmap that covers it
153 #define GRP_IBM_OFFSET(fs,nod) \
154 - ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb.s_inodes_per_group )
155 + ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb->s_inodes_per_group )
157 // Given a block number find the group it belongs to
158 -#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb.s_blocks_per_group)
159 +#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb->s_blocks_per_group)
161 -//Given a block number get the block bitmap that covers it
162 -#define GRP_GET_BLOCK_BITMAP(fs,blk) \
163 - ( GRP_GET_GROUP_BBM((fs),GRP_GROUP_OF_BLOCK((fs),(blk))) )
164 +//Given a block number get/put the block bitmap that covers it
165 +#define GRP_GET_BLOCK_BITMAP(fs,blk,bi,gi) \
166 + ( GRP_GET_GROUP_BBM((fs),get_gd(fs,GRP_GROUP_OF_BLOCK((fs),(blk)),(gi)),(bi)) )
167 +#define GRP_PUT_BLOCK_BITMAP(bi,gi) \
168 + ( GRP_PUT_GROUP_BBM((bi)),put_gd((gi)) )
170 //Given a block number find its offset within the block bitmap that covers it
171 #define GRP_BBM_OFFSET(fs,blk) \
172 - ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb.s_blocks_per_group )
173 + ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb->s_blocks_per_group )
178 // older solaris. Note that this is still not very portable, in that
179 // the return value cannot be trusted.
181 -#if SCANF_CAN_MALLOC
182 +#if 0 // SCANF_CAN_MALLOC
183 +// C99 define "a" for floating point, so you can have runtime surprise
184 +// according the library versions
185 # define SCANF_PREFIX "a"
186 # define SCANF_STRING(s) (&s)
189 ((val<<8)&0xFF0000) | (val<<24));
193 +is_blk_empty(uint8 *b)
196 + uint32 *v = (uint32 *) b;
198 + for(i = 0; i < BLOCKSIZE / 4; i++)
204 // on-disk structures
205 // this trick makes me declare things only once
207 udecl32(s_creator_os) /* Indicator of which OS created the filesystem */ \
208 udecl32(s_rev_level) /* The revision level of the filesystem */ \
209 udecl16(s_def_resuid) /* The default uid for reserved blocks */ \
210 - udecl16(s_def_resgid) /* The default gid for reserved blocks */
211 + udecl16(s_def_resgid) /* The default gid for reserved blocks */ \
212 + /* rev 1 version fields start here */ \
213 + udecl32(s_first_ino) /* First non-reserved inode */ \
214 + udecl16(s_inode_size) /* size of inode structure */ \
215 + udecl16(s_block_group_nr) /* block group # of this superblock */ \
216 + udecl32(s_feature_compat) /* compatible feature set */ \
217 + udecl32(s_feature_incompat) /* incompatible feature set */ \
218 + udecl32(s_feature_ro_compat) /* readonly-compatible feature set */ \
219 + utdecl8(s_uuid,16) /* 128-bit uuid for volume */ \
220 + utdecl8(s_volume_name,16) /* volume name */ \
221 + utdecl8(s_last_mounted,64) /* directory where last mounted */ \
222 + udecl32(s_algorithm_usage_bitmap) /* For compression */
224 +#define EXT2_GOOD_OLD_FIRST_INO 11
225 +#define EXT2_GOOD_OLD_INODE_SIZE 128
226 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
228 #define groupdescriptor_decl \
229 udecl32(bg_block_bitmap) /* Block number of the block bitmap */ \
232 #define decl8(x) int8 x;
233 #define udecl8(x) uint8 x;
234 +#define utdecl8(x,n) uint8 x[n];
235 #define decl16(x) int16 x;
236 #define udecl16(x) uint16 x;
237 #define decl32(x) int32 x;
242 - uint32 s_reserved[235]; // Reserved
243 + uint32 s_reserved[205]; // Reserved
254 -typedef uint8 block[BLOCKSIZE];
255 +typedef uint8 *block;
257 /* blockwalker fields:
258 The blockwalker is used to access all the blocks of a file (including
259 @@ -567,23 +640,41 @@
263 +#define HDLINK_CNT 16
273 + struct hdlink_s *hdl;
276 /* Filesystem structure that support groups */
277 -#if BLOCKSIZE == 1024
280 - block zero; // The famous block 0
281 - superblock sb; // The superblock
282 - groupdescriptor gd[0]; // The group descriptors
287 + struct hdlinks_s hdlinks;
297 -#error UNHANDLED BLOCKSIZE
300 // now the endianness swap
308 @@ -592,28 +683,13 @@
312 +#define utdecl8(x,n)
313 #define decl16(x) this->x = swab16(this->x);
314 #define udecl16(x) this->x = swab16(this->x);
315 #define decl32(x) this->x = swab32(this->x);
316 #define udecl32(x) this->x = swab32(this->x);
317 #define utdecl32(x,n) { int i; for(i=0; i<n; i++) this->x[i] = swab32(this->x[i]); }
319 -#define HDLINK_CNT 16
320 -static int32 hdlink_cnt = HDLINK_CNT;
330 - struct hdlink_s *hdl;
333 -static struct hdlinks_s hdlinks;
336 swap_sb(superblock *sb)
348 + // block and character inodes store the major and minor in the
349 + // i_block, so we need to unswap to get those. Also, if it's
350 + // zero iblocks, put the data back like it belongs.
351 + nblk = nod->i_blocks / INOBLK;
352 + if ((nod->i_size && !nblk)
353 + || ((nod->i_mode & FM_IFBLK) == FM_IFBLK)
354 + || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
357 + for(i = 0; i <= EXT2_TIND_BLOCK; i++)
358 + nod->i_block[i] = swab32(nod->i_block[i]);
371 @@ -770,15 +862,15 @@
375 -is_hardlink(ino_t inode)
376 +is_hardlink(filesystem *fs, ino_t inode)
380 - for(i = 0; i < hdlinks.count; i++) {
381 - if(hdlinks.hdl[i].src_inode == inode)
382 + for(i = 0; i < fs->hdlinks.count; i++) {
383 + if(fs->hdlinks.hdl[i].src_inode == inode)
390 // printf helper macro
394 unsigned char* b=calloc(1,BLOCKSIZE);
396 + error_msg_and_die("get_workblk() failed, out of memory");
400 @@ -811,24 +905,464 @@
401 return b[(item-1) / 8] & (1 << ((item-1) % 8));
404 -// return a given block from a filesystem
405 +// Used by get_blk/put_blk to hold information about a block owned
417 +#define MAX_FREE_CACHE_BLOCKS 100
420 +blk_elem_val(cache_link *elem)
422 + blk_info *bi = container_of(elem, blk_info, link);
427 +blk_freed(cache_link *elem)
429 + blk_info *bi = container_of(elem, blk_info, link);
431 + if (fseeko(bi->fs->f, ((off_t) bi->blk) * BLOCKSIZE, SEEK_SET))
432 + perror_msg_and_die("fseek");
433 + if (fwrite(bi->b, BLOCKSIZE, 1, bi->fs->f) != 1)
434 + perror_msg_and_die("get_blk: write");
439 +// Return a given block from a filesystem. Make sure to call
440 +// put_blk when you are done with it.
441 static inline uint8 *
442 -get_blk(filesystem *fs, uint32 blk)
443 +get_blk(filesystem *fs, uint32 blk, blk_info **rbi)
445 - return (uint8*)fs + blk*BLOCKSIZE;
449 + if (blk >= fs->sb->s_blocks_count)
450 + error_msg_and_die("Internal error, block out of range");
452 + curr = cache_find(&fs->blks, blk);
454 + bi = container_of(curr, blk_info, link);
459 + bi = malloc(sizeof(*bi));
461 + error_msg_and_die("get_blk: out of memory");
465 + bi->b = malloc(BLOCKSIZE);
467 + error_msg_and_die("get_blk: out of memory");
468 + cache_add(&fs->blks, &bi->link);
469 + if (fseeko(fs->f, ((off_t) blk) * BLOCKSIZE, SEEK_SET))
470 + perror_msg_and_die("fseek");
471 + if (fread(bi->b, BLOCKSIZE, 1, fs->f) != 1) {
473 + perror_msg_and_die("fread");
474 + memset(bi->b, 0, BLOCKSIZE);
482 // return a given inode from a filesystem
483 -static inline inode *
484 -get_nod(filesystem *fs, uint32 nod)
486 +put_blk(blk_info *bi)
488 + if (bi->usecount == 0)
489 + error_msg_and_die("Internal error: put_blk usecount zero");
491 + if (bi->usecount == 0)
492 + /* Free happens in the cache code */
493 + cache_item_set_unused(&bi->fs->blks, &bi->link);
504 + groupdescriptor *gd;
508 +#define MAX_FREE_CACHE_GDS 100
511 +gd_elem_val(cache_link *elem)
513 + gd_info *gi = container_of(elem, gd_info, link);
518 +gd_freed(cache_link *elem)
520 + gd_info *gi = container_of(elem, gd_info, link);
522 + if (gi->fs->swapit)
528 +#define GDS_START ((SUPERBLOCK_OFFSET + SUPERBLOCK_SIZE + BLOCKSIZE - 1) / BLOCKSIZE)
529 +#define GDS_PER_BLOCK (BLOCKSIZE / sizeof(groupdescriptor))
530 +// the group descriptors are aligned on the block size
531 +static inline groupdescriptor *
532 +get_gd(filesystem *fs, uint32 no, gd_info **rgi)
539 + curr = cache_find(&fs->gds, no);
541 + gi = container_of(curr, gd_info, link);
546 + gi = malloc(sizeof(*gi));
548 + error_msg_and_die("get_gd: out of memory");
552 + gdblk = GDS_START + (no / GDS_PER_BLOCK);
553 + offset = no % GDS_PER_BLOCK;
554 + gi->gd = ((groupdescriptor *) get_blk(fs, gdblk, &gi->bi)) + offset;
555 + cache_add(&fs->gds, &gi->link);
567 + if (gi->usecount == 0)
568 + error_msg_and_die("Internal error: put_gd usecount zero");
571 + if (gi->usecount == 0)
572 + /* Free happens in the cache code */
573 + cache_item_set_unused(&gi->fs->gds, &gi->link);
576 +// Used by get_blkmap/put_blkmap to hold information about an block map
577 +// owned by the user.
589 +#define MAX_FREE_CACHE_BLOCKMAPS 100
592 +blkmap_elem_val(cache_link *elem)
594 + blkmap_info *bmi = container_of(elem, blkmap_info, link);
599 +blkmap_freed(cache_link *elem)
601 + blkmap_info *bmi = container_of(elem, blkmap_info, link);
603 + if (bmi->fs->swapit)
604 + swap_block(bmi->b);
609 +// Return a given block map from a filesystem. Make sure to call
610 +// put_blkmap when you are done with it.
611 +static inline uint32 *
612 +get_blkmap(filesystem *fs, uint32 blk, blkmap_info **rbmi)
617 + curr = cache_find(&fs->blkmaps, blk);
619 + bmi = container_of(curr, blkmap_info, link);
624 + bmi = malloc(sizeof(*bmi));
626 + error_msg_and_die("get_blkmap: out of memory");
629 + bmi->b = get_blk(fs, blk, &bmi->bi);
631 + cache_add(&fs->blkmaps, &bmi->link);
634 + swap_block(bmi->b);
637 + return (uint32 *) bmi->b;
641 +put_blkmap(blkmap_info *bmi)
643 + if (bmi->usecount == 0)
644 + error_msg_and_die("Internal error: put_blkmap usecount zero");
647 + if (bmi->usecount == 0)
648 + /* Free happens in the cache code */
649 + cache_item_set_unused(&bmi->fs->blkmaps, &bmi->link);
652 +// Used by get_nod/put_nod to hold information about an inode owned
666 +#define MAX_FREE_CACHE_INODES 100
669 +inode_elem_val(cache_link *elem)
671 + nod_info *ni = container_of(elem, nod_info, link);
676 +inode_freed(cache_link *elem)
678 + nod_info *ni = container_of(elem, nod_info, link);
680 + if (ni->fs->swapit)
681 + swap_nod(ni->itab);
686 +#define INODES_PER_BLOCK (BLOCKSIZE / sizeof(inode))
688 - offset = GRP_IBM_OFFSET(fs,nod);
689 +// return a given inode from a filesystem
690 +static inline inode *
691 +get_nod(filesystem *fs, uint32 nod, nod_info **rni)
693 + uint32 grp, boffset, offset;
695 + groupdescriptor *gd;
699 + curr = cache_find(&fs->inodes, nod);
701 + ni = container_of(curr, nod_info, link);
706 + ni = malloc(sizeof(*ni));
708 + error_msg_and_die("get_nod: out of memory");
712 + cache_add(&fs->inodes, &ni->link);
714 + offset = GRP_IBM_OFFSET(fs,nod) - 1;
715 + boffset = offset / INODES_PER_BLOCK;
716 + offset %= INODES_PER_BLOCK;
717 grp = GRP_GROUP_OF_INODE(fs,nod);
718 - itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table);
719 - return itab+offset-1;
720 + gd = get_gd(fs, grp, &gi);
721 + ni->b = get_blk(fs, gd->bg_inode_table + boffset, &ni->bi);
722 + ni->itab = ((inode *) ni->b) + offset;
724 + swap_nod(ni->itab);
732 +put_nod(nod_info *ni)
734 + if (ni->usecount == 0)
735 + error_msg_and_die("Internal error: put_nod usecount zero");
738 + if (ni->usecount == 0)
739 + /* Free happens in the cache code */
740 + cache_item_set_unused(&ni->fs->inodes, &ni->link);
743 +// Used to hold state information while walking a directory inode.
754 +// Start a directory walk on the given inode. You must pass in a
755 +// dirwalker structure, then use that dirwalker for future operations.
756 +// Call put_dir when you are done walking the directory.
757 +static inline directory *
758 +get_dir(filesystem *fs, uint32 nod, dirwalker *dw)
761 + dw->b = get_blk(fs, nod, &dw->bi);
763 + dw->last_d = (directory *) dw->b;
765 + memcpy(&dw->d, dw->last_d, sizeof(directory));
771 +// Move to the next directory.
772 +static inline directory *
773 +next_dir(dirwalker *dw)
775 + directory *next_d = (directory *)((int8*)dw->last_d + dw->d.d_rec_len);
777 + if (dw->fs->swapit)
779 + memcpy(dw->last_d, &dw->d, sizeof(directory));
781 + if (((int8 *) next_d) >= ((int8 *) dw->b + BLOCKSIZE))
784 + dw->last_d = next_d;
785 + memcpy(&dw->d, next_d, sizeof(directory));
786 + if (dw->fs->swapit)
791 +// Call then when you are done with the directory walk.
793 +put_dir(dirwalker *dw)
795 + if (dw->fs->swapit)
797 + memcpy(dw->last_d, &dw->d, sizeof(directory));
800 + free_workblk(dw->b);
805 +// Create a new directory block with the given inode as it's destination
806 +// and append it to the current dirwalker.
808 +new_dir(filesystem *fs, uint32 dnod, const char *name, int nlen, dirwalker *dw)
813 + dw->b = get_workblk();
815 + dw->last_d = (directory *) dw->b;
818 + d->d_rec_len = BLOCKSIZE;
819 + d->d_name_len = nlen;
820 + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
824 +// Shrink the current directory entry, make a new one with the free
825 +// space, and return the new directory entry (making it current).
826 +static inline directory *
827 +shrink_dir(dirwalker *dw, uint32 nod, const char *name, int nlen)
829 + int reclen, preclen;
830 + directory *d = &dw->d;
832 + reclen = d->d_rec_len;
833 + d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4);
834 + preclen = d->d_rec_len;
836 + if (dw->fs->swapit)
838 + memcpy(dw->last_d, &dw->d, sizeof(directory));
840 + dw->last_d = (directory *) (((int8 *) dw->last_d) + preclen);
841 + d->d_rec_len = reclen;
843 + d->d_name_len = nlen;
844 + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
849 +// Return the current block the directory is walking
850 +static inline uint8 *
851 +dir_data(dirwalker *dw)
856 +// Return the pointer to the name for the current directory
857 +static inline char *
858 +dir_name(dirwalker *dw)
860 + return ((char *) dw->last_d) + sizeof(directory);
863 +// Set the name for the current directory. Note that this doesn't
864 +// verify that there is space for the directory name, you must do
867 +dir_set_name(dirwalker *dw, const char *name, int nlen)
869 + dw->d.d_name_len = nlen;
870 + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
873 // allocate a given block/inode in the bitmap
874 @@ -870,21 +1404,34 @@
879 + groupdescriptor *gd;
882 grp = GRP_GROUP_OF_INODE(fs,nod);
883 nbgroups = GRP_NBGROUPS(fs);
884 - if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) {
885 - for(grp=0;grp<nbgroups && !bk;grp++)
886 - bk=allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap),0);
887 + gd = get_gd(fs, grp, &gi);
888 + bk = allocate(GRP_GET_GROUP_BBM(fs, gd, &bi), 0);
889 + GRP_PUT_GROUP_BBM(bi);
892 + for (grp=0; grp<nbgroups && !bk; grp++) {
893 + gd = get_gd(fs, grp, &gi);
894 + bk = allocate(GRP_GET_GROUP_BBM(fs, gd, &bi), 0);
895 + GRP_PUT_GROUP_BBM(bi);
901 error_msg_and_die("couldn't allocate a block (no free space)");
902 - if(!(fs->gd[grp].bg_free_blocks_count--))
903 + gd = get_gd(fs, grp, &gi);
904 + if(!(gd->bg_free_blocks_count--))
905 error_msg_and_die("group descr %d. free blocks count == 0 (corrupted fs?)",grp);
906 - if(!(fs->sb.s_free_blocks_count--))
908 + if(!(fs->sb->s_free_blocks_count--))
909 error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
910 - return fs->sb.s_blocks_per_group*grp + bk;
911 + return fs->sb->s_first_data_block + fs->sb->s_blocks_per_group*grp + (bk-1);
915 @@ -892,12 +1439,18 @@
916 free_blk(filesystem *fs, uint32 bk)
920 - grp = bk / fs->sb.s_blocks_per_group;
921 - bk %= fs->sb.s_blocks_per_group;
922 - deallocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), bk);
923 - fs->gd[grp].bg_free_blocks_count++;
924 - fs->sb.s_free_blocks_count++;
927 + groupdescriptor *gd;
929 + grp = bk / fs->sb->s_blocks_per_group;
930 + bk %= fs->sb->s_blocks_per_group;
931 + gd = get_gd(fs, grp, &gi);
932 + deallocate(GRP_GET_GROUP_BBM(fs, gd, &bi), bk);
933 + GRP_PUT_GROUP_BBM(bi);
934 + gd->bg_free_blocks_count++;
936 + fs->sb->s_free_blocks_count++;
942 uint32 nod,best_group=0;
943 uint32 grp,nbgroups,avefreei;
945 + gd_info *gi, *bestgi;
946 + groupdescriptor *gd, *bestgd;
948 nbgroups = GRP_NBGROUPS(fs);
950 @@ -914,22 +1470,32 @@
951 /* find the one with the most free blocks and allocate node there */
952 /* Idea from find_group_dir in fs/ext2/ialloc.c in 2.4.19 kernel */
953 /* We do it for all inodes. */
954 - avefreei = fs->sb.s_free_inodes_count / nbgroups;
955 + avefreei = fs->sb->s_free_inodes_count / nbgroups;
956 + bestgd = get_gd(fs, best_group, &bestgi);
957 for(grp=0; grp<nbgroups; grp++) {
958 - if (fs->gd[grp].bg_free_inodes_count < avefreei ||
959 - fs->gd[grp].bg_free_inodes_count == 0)
960 + gd = get_gd(fs, grp, &gi);
961 + if (gd->bg_free_inodes_count < avefreei ||
962 + gd->bg_free_inodes_count == 0) {
966 - fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count)
968 + if (!best_group || gd->bg_free_blocks_count > bestgd->bg_free_blocks_count) {
976 - if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0)))
977 + if (!(nod = allocate(GRP_GET_GROUP_IBM(fs, bestgd, &bi), 0)))
978 error_msg_and_die("couldn't allocate an inode (no free inode)");
979 - if(!(fs->gd[best_group].bg_free_inodes_count--))
980 + GRP_PUT_GROUP_IBM(bi);
981 + if(!(bestgd->bg_free_inodes_count--))
982 error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
983 - if(!(fs->sb.s_free_inodes_count--))
985 + if(!(fs->sb->s_free_inodes_count--))
986 error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
987 - return fs->sb.s_inodes_per_group*best_group+nod;
988 + return fs->sb->s_inodes_per_group*best_group+nod;
991 // print a bitmap allocation
992 @@ -962,30 +1528,40 @@
993 // used after being freed, so once you start
994 // freeing blocks don't stop until the end of
995 // the file. moreover, i_blocks isn't updated.
996 -// in fact, don't do that, just use extend_blk
997 // if hole!=0, create a hole in the file
999 walk_bw(filesystem *fs, uint32 nod, blockwalker *bw, int32 *create, uint32 hole)
1003 + blkmap_info *bmi1 = NULL, *bmi2 = NULL, *bmi3 = NULL;
1005 int extend = 0, reduce = 0;
1010 if(create && (*create) < 0)
1012 - if(bw->bnum >= get_nod(fs, nod)->i_blocks / INOBLK)
1013 + inod = get_nod(fs, nod, &ni);
1014 + if(bw->bnum >= inod->i_blocks / INOBLK)
1016 if(create && (*create) > 0)
1028 + iblk = inod->i_block;
1029 // first direct block
1030 if(bw->bpdir == EXT2_INIT_BLOCK)
1032 - bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0];
1033 + bkref = &iblk[bw->bpdir = 0];
1034 if(extend) // allocate first block
1035 *bkref = hole ? 0 : alloc_blk(fs,nod);
1036 if(reduce) // free first block
1037 @@ -994,7 +1570,7 @@
1039 else if(bw->bpdir < EXT2_NDIR_BLOCKS)
1041 - bkref = &get_nod(fs, nod)->i_block[++bw->bpdir];
1042 + bkref = &iblk[++bw->bpdir];
1043 if(extend) // allocate block
1044 *bkref = hole ? 0 : alloc_blk(fs,nod);
1045 if(reduce) // free block
1046 @@ -1007,10 +1583,10 @@
1047 bw->bpdir = EXT2_IND_BLOCK;
1049 if(extend) // allocate indirect block
1050 - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
1051 + iblk[bw->bpdir] = alloc_blk(fs,nod);
1052 if(reduce) // free indirect block
1053 - free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1054 - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1055 + free_blk(fs, iblk[bw->bpdir]);
1056 + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
1057 bkref = &b[bw->bpind];
1058 if(extend) // allocate first block
1059 *bkref = hole ? 0 : alloc_blk(fs,nod);
1060 @@ -1021,7 +1597,7 @@
1061 else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
1064 - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1065 + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
1066 bkref = &b[bw->bpind];
1067 if(extend) // allocate block
1068 *bkref = hole ? 0 : alloc_blk(fs,nod);
1069 @@ -1036,15 +1612,15 @@
1072 if(extend) // allocate double indirect block
1073 - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
1074 + iblk[bw->bpdir] = alloc_blk(fs,nod);
1075 if(reduce) // free double indirect block
1076 - free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1077 - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1078 + free_blk(fs, iblk[bw->bpdir]);
1079 + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
1080 if(extend) // allocate first indirect block
1081 b[bw->bpind] = alloc_blk(fs,nod);
1082 if(reduce) // free firstindirect block
1083 free_blk(fs, b[bw->bpind]);
1084 - b = (uint32*)get_blk(fs, b[bw->bpind]);
1085 + b = get_blkmap(fs, b[bw->bpind], &bmi2);
1086 bkref = &b[bw->bpdind];
1087 if(extend) // allocate first block
1088 *bkref = hole ? 0 : alloc_blk(fs,nod);
1089 @@ -1055,8 +1631,8 @@
1090 else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1))
1093 - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1094 - b = (uint32*)get_blk(fs, b[bw->bpind]);
1095 + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
1096 + b = get_blkmap(fs, b[bw->bpind], &bmi2);
1097 bkref = &b[bw->bpdind];
1098 if(extend) // allocate block
1099 *bkref = hole ? 0 : alloc_blk(fs,nod);
1100 @@ -1069,12 +1645,12 @@
1104 - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1105 + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
1106 if(extend) // allocate indirect block
1107 b[bw->bpind] = alloc_blk(fs,nod);
1108 if(reduce) // free indirect block
1109 free_blk(fs, b[bw->bpind]);
1110 - b = (uint32*)get_blk(fs, b[bw->bpind]);
1111 + b = get_blkmap(fs, b[bw->bpind], &bmi2);
1112 bkref = &b[bw->bpdind];
1113 if(extend) // allocate first block
1114 *bkref = hole ? 0 : alloc_blk(fs,nod);
1115 @@ -1094,20 +1670,20 @@
1118 if(extend) // allocate triple indirect block
1119 - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
1120 + iblk[bw->bpdir] = alloc_blk(fs,nod);
1121 if(reduce) // free triple indirect block
1122 - free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1123 - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1124 + free_blk(fs, iblk[bw->bpdir]);
1125 + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
1126 if(extend) // allocate first double indirect block
1127 b[bw->bpind] = alloc_blk(fs,nod);
1128 if(reduce) // free first double indirect block
1129 free_blk(fs, b[bw->bpind]);
1130 - b = (uint32*)get_blk(fs, b[bw->bpind]);
1131 + b = get_blkmap(fs, b[bw->bpind], &bmi2);
1132 if(extend) // allocate first indirect block
1133 b[bw->bpdind] = alloc_blk(fs,nod);
1134 if(reduce) // free first indirect block
1135 free_blk(fs, b[bw->bpind]);
1136 - b = (uint32*)get_blk(fs, b[bw->bpdind]);
1137 + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
1138 bkref = &b[bw->bptind];
1139 if(extend) // allocate first data block
1140 *bkref = hole ? 0 : alloc_blk(fs,nod);
1141 @@ -1121,9 +1697,9 @@
1142 (bw->bptind < BLOCKSIZE/4 -1) )
1145 - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1146 - b = (uint32*)get_blk(fs, b[bw->bpind]);
1147 - b = (uint32*)get_blk(fs, b[bw->bpdind]);
1148 + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
1149 + b = get_blkmap(fs, b[bw->bpind], &bmi2);
1150 + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
1151 bkref = &b[bw->bptind];
1152 if(extend) // allocate data block
1153 *bkref = hole ? 0 : alloc_blk(fs,nod);
1154 @@ -1140,13 +1716,13 @@
1158 - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1159 - b = (uint32*)get_blk(fs, b[bw->bpind]);
1160 + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
1161 + b = get_blkmap(fs, b[bw->bpind], &bmi2);
1162 if(extend) // allocate single indirect block
1163 b[bw->bpdind] = alloc_blk(fs,nod);
1164 if(reduce) // free indirect block
1165 free_blk(fs, b[bw->bpind]);
1166 - b = (uint32*)get_blk(fs, b[bw->bpdind]);
1167 + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
1168 bkref = &b[bw->bptind];
1169 if(extend) // allocate first data block
1170 *bkref = hole ? 0 : alloc_blk(fs,nod);
1171 @@ -1163,17 +1739,17 @@
1175 - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1176 + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
1177 if(extend) // allocate double indirect block
1178 b[bw->bpind] = alloc_blk(fs,nod);
1179 if(reduce) // free double indirect block
1180 free_blk(fs, b[bw->bpind]);
1181 - b = (uint32*)get_blk(fs, b[bw->bpind]);
1182 + b = get_blkmap(fs, b[bw->bpind], &bmi2);
1183 if(extend) // allocate single indirect block
1184 b[bw->bpdind] = alloc_blk(fs,nod);
1185 if(reduce) // free indirect block
1186 free_blk(fs, b[bw->bpind]);
1187 - b = (uint32*)get_blk(fs, b[bw->bpdind]);
1188 + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
1189 bkref = &b[bw->bptind];
1190 if(extend) // allocate first block
1191 *bkref = hole ? 0 : alloc_blk(fs,nod);
1192 @@ -1184,56 +1760,105 @@
1193 error_msg_and_die("file too big !");
1194 /* End change for walking triple indirection */
1212 - if(!reduce && !allocated(GRP_GET_BLOCK_BITMAP(fs,*bkref), GRP_BBM_OFFSET(fs,*bkref)))
1213 - error_msg_and_die("[block %d of inode %d is unallocated !]", *bkref, nod);
1214 + block = GRP_GET_BLOCK_BITMAP(fs,bk,&bi,&gi);
1215 + if(!reduce && !allocated(block, GRP_BBM_OFFSET(fs,bk)))
1216 + error_msg_and_die("[block %d of inode %d is unallocated !]", bk, nod);
1217 + GRP_PUT_BLOCK_BITMAP(bi, gi);
1220 - get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK;
1222 + inod->i_blocks = bw->bnum * INOBLK;
1227 -// add blocks to an inode (file/dir/etc...)
1229 -extend_blk(filesystem *fs, uint32 nod, block b, int amount)
1232 - int create = amount;
1233 - blockwalker bw, lbw;
1239 - for(i = 0; i < get_nod(fs, nod)->i_blocks / INOBLK + amount; i++)
1240 - walk_bw(fs, nod, &bw, 0, 0);
1241 - while(walk_bw(fs, nod, &bw, &create, 0) != WALK_END)
1247 +#define INODE_POS_TRUNCATE 0
1248 +#define INODE_POS_EXTEND 1
1250 +// Call this to set up an ipos structure for future use with
1251 +// extend_inode_blk to append blocks to the given inode. If
1252 +// op is INODE_POS_TRUNCATE, the inode is truncated to zero size.
1253 +// If op is INODE_POS_EXTEND, the position is moved to the end
1254 +// of the inode's data blocks.
1255 +// Call inode_pos_finish when done with the inode_pos structure.
1257 +inode_pos_init(filesystem *fs, inode_pos *ipos, uint32 nod, int op,
1258 + blockwalker *endbw)
1262 + init_bw(&ipos->bw);
1264 + ipos->inod = get_nod(fs, nod, &ipos->ni);
1265 + if (op == INODE_POS_TRUNCATE) {
1266 + int32 create = -1;
1267 + while(walk_bw(fs, nod, &ipos->bw, &create, 0) != WALK_END)
1269 - get_nod(fs, nod)->i_blocks += amount * INOBLK;
1270 + ipos->inod->i_blocks = 0;
1275 + ipos->bw = *endbw;
1277 + /* Seek to the end */
1278 + init_bw(&ipos->bw);
1280 + while(walk_bw(fs, nod, &ipos->bw, 0, 0) != WALK_END)
1286 +// Clean up the inode_pos structure.
1288 +inode_pos_finish(filesystem *fs, inode_pos *ipos)
1290 + put_nod(ipos->ni);
1293 +// add blocks to an inode (file/dir/etc...) at the given position.
1294 +// This will only work when appending to the end of an inode.
1296 +extend_inode_blk(filesystem *fs, inode_pos *ipos, block b, int amount)
1302 + error_msg_and_die("extend_inode_blk: Got negative amount");
1304 + for (pos = 0; amount; pos += BLOCKSIZE)
1307 - while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
1313 - if(!(fs->sb.s_reserved[200] & OP_HOLES))
1316 - for(i = 0; i < BLOCKSIZE / 4; i++)
1317 - if(((int32*)(b + BLOCKSIZE * (amount - create)))[i])
1322 - if((bk = walk_bw(fs, nod, &bw, &create, !copyb)) == WALK_END)
1325 - memcpy(get_blk(fs, bk), b + BLOCKSIZE * (amount - create - 1), BLOCKSIZE);
1326 + int hole = (fs->holes && is_blk_empty(b + pos));
1328 + bk = walk_bw(fs, ipos->nod, &ipos->bw, &amount, hole);
1329 + if (bk == WALK_END)
1330 + error_msg_and_die("extend_inode_blk: extend failed");
1333 + uint8 *block = get_blk(fs, bk, &bi);
1334 + memcpy(block, b + pos, BLOCKSIZE);
1339 @@ -1242,15 +1867,17 @@
1341 add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name)
1344 + blockwalker bw, lbw;
1352 + nod_info *dni, *ni;
1355 - pnode = get_nod(fs, dnod);
1356 + pnode = get_nod(fs, dnod, &dni);
1357 if((pnode->i_mode & FM_IFMT) != FM_IFDIR)
1358 error_msg_and_die("can't add '%s' to a non-directory", name);
1360 @@ -1262,52 +1889,52 @@
1361 if(reclen > BLOCKSIZE)
1362 error_msg_and_die("bad name '%s' (too long)", name);
1365 while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir
1367 - b = get_blk(fs, bk);
1368 // for all dir entries in block
1369 - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
1370 + for(d = get_dir(fs, bk, &dw); d; d = next_dir(&dw))
1372 // if empty dir entry, large enough, use it
1373 if((!d->d_inode) && (d->d_rec_len >= reclen))
1376 - node = get_nod(fs, nod);
1377 + node = get_nod(fs, nod, &ni);
1378 + dir_set_name(&dw, name, nlen);
1380 node->i_links_count++;
1381 - d->d_name_len = nlen;
1382 - strncpy(d->d_name, name, nlen);
1387 // if entry with enough room (last one?), shrink it & use it
1388 if(d->d_rec_len >= (sizeof(directory) + rndup(d->d_name_len, 4) + reclen))
1390 - reclen = d->d_rec_len;
1391 - d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4);
1392 - reclen -= d->d_rec_len;
1393 - d = (directory*) (((int8*)d) + d->d_rec_len);
1394 - d->d_rec_len = reclen;
1396 - node = get_nod(fs, nod);
1397 + d = shrink_dir(&dw, nod, name, nlen);
1399 + node = get_nod(fs, nod, &ni);
1400 node->i_links_count++;
1401 - d->d_name_len = nlen;
1402 - strncpy(d->d_name, name, nlen);
1411 // we found no free entry in the directory, so we add a block
1412 - if(!(b = get_workblk()))
1413 - error_msg_and_die("get_workblk() failed.");
1414 - d = (directory*)b;
1416 - node = get_nod(fs, nod);
1417 + node = get_nod(fs, nod, &ni);
1418 + d = new_dir(fs, nod, name, nlen, &dw);
1419 node->i_links_count++;
1420 - d->d_rec_len = BLOCKSIZE;
1421 - d->d_name_len = nlen;
1422 - strncpy(d->d_name, name, nlen);
1423 - extend_blk(fs, dnod, b, 1);
1424 - get_nod(fs, dnod)->i_size += BLOCKSIZE;
1427 + next_dir(&dw); // Force the data into the buffer
1429 + inode_pos_init(fs, &ipos, dnod, INODE_POS_EXTEND, &lbw);
1430 + extend_inode_blk(fs, &ipos, dir_data(&dw), 1);
1431 + inode_pos_finish(fs, &ipos);
1434 + pnode->i_size += BLOCKSIZE;
1439 // find an entry in a directory
1440 @@ -1321,11 +1948,13 @@
1441 while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
1445 - b = get_blk(fs, bk);
1446 - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
1447 - if(d->d_inode && (nlen == d->d_name_len) && !strncmp(d->d_name, name, nlen))
1449 + for (d = get_dir(fs, bk, &dw); d; d=next_dir(&dw))
1450 + if(d->d_inode && (nlen == d->d_name_len) && !strncmp(dir_name(&dw), name, nlen)) {
1458 @@ -1356,47 +1985,55 @@
1464 +chmod_fs(filesystem *fs, uint32 nod, uint16 mode, uint16 uid, uint16 gid)
1468 + node = get_nod(fs, nod, &ni);
1469 + node->i_mode = (node->i_mode & ~FM_IMASK) | (mode & FM_IMASK);
1470 + node->i_uid = uid;
1471 + node->i_gid = gid;
1475 // create a simple inode
1477 mknod_fs(filesystem *fs, uint32 parent_nod, const char *name, uint16 mode, uint16 uid, uint16 gid, uint8 major, uint8 minor, uint32 ctime, uint32 mtime)
1481 - if((nod = find_dir(fs, parent_nod, name)))
1483 - node = get_nod(fs, nod);
1484 - if((node->i_mode & FM_IFMT) != (mode & FM_IFMT))
1485 - error_msg_and_die("node '%s' already exists and isn't of the same type", name);
1486 - node->i_mode = mode;
1492 + nod = alloc_nod(fs);
1493 + node = get_nod(fs, nod, &ni);
1494 + node->i_mode = mode;
1495 + add2dir(fs, parent_nod, nod, name);
1496 + switch(mode & FM_IFMT)
1498 - nod = alloc_nod(fs);
1499 - node = get_nod(fs, nod);
1500 - node->i_mode = mode;
1501 - add2dir(fs, parent_nod, nod, name);
1502 - switch(mode & FM_IFMT)
1505 - mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
1509 - ((uint8*)get_nod(fs, nod)->i_block)[0] = minor;
1510 - ((uint8*)get_nod(fs, nod)->i_block)[1] = major;
1513 - add2dir(fs, nod, nod, ".");
1514 - add2dir(fs, nod, parent_nod, "..");
1515 - fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++;
1519 + mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
1523 + ((uint8*)node->i_block)[0] = minor;
1524 + ((uint8*)node->i_block)[1] = major;
1527 + add2dir(fs, nod, nod, ".");
1528 + add2dir(fs, nod, parent_nod, "..");
1529 + get_gd(fs,GRP_GROUP_OF_INODE(fs,nod),&gi)->bg_used_dirs_count++;
1535 node->i_atime = mtime;
1536 node->i_ctime = ctime;
1537 node->i_mtime = mtime;
1542 @@ -1413,33 +2050,73 @@
1543 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint8 *b, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
1545 uint32 nod = mknod_fs(fs, parent_nod, name, FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO, uid, gid, 0, 0, ctime, mtime);
1546 - extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
1547 - get_nod(fs, nod)->i_size = size;
1548 - if(size <= 4 * (EXT2_TIND_BLOCK+1))
1550 - strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size);
1552 + inode *node = get_nod(fs, nod, &ni);
1555 + inode_pos_init(fs, &ipos, nod, INODE_POS_TRUNCATE, NULL);
1556 + node->i_size = size;
1557 + if(size < 4 * (EXT2_TIND_BLOCK+1))
1559 + strncpy((char*)node->i_block, (char*)b, size);
1560 + ((char*)node->i_block)[size+1] = '\0';
1561 + inode_pos_finish(fs, &ipos);
1565 - extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
1566 + extend_inode_blk(fs, &ipos, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
1567 + inode_pos_finish(fs, &ipos);
1573 +fs_upgrade_rev1_largefile(filesystem *fs)
1575 + fs->sb->s_rev_level = 1;
1576 + fs->sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
1577 + fs->sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
1580 +#define COPY_BLOCKS 16
1581 +#define CB_SIZE (COPY_BLOCKS * BLOCKSIZE)
1583 // make a file from a FILE*
1585 -mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
1586 +mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, FILE *f, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
1589 uint32 nod = mknod_fs(fs, parent_nod, name, mode|FM_IFREG, uid, gid, 0, 0, ctime, mtime);
1590 - extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
1591 - get_nod(fs, nod)->i_size = size;
1593 - if(!(b = (uint8*)calloc(rndup(size, BLOCKSIZE), 1)))
1594 - error_msg_and_die("not enough mem to read file '%s'", name);
1596 - fread(b, size, 1, f); // FIXME: ugly. use mmap() ...
1597 - extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
1601 + inode *node = get_nod(fs, nod, &ni);
1607 + b = malloc(CB_SIZE);
1609 + error_msg_and_die("mkfile_fs: out of memory");
1610 + inode_pos_init(fs, &ipos, nod, INODE_POS_TRUNCATE, NULL);
1611 + readbytes = fread(b, 1, CB_SIZE, f);
1612 + while (readbytes) {
1613 + fullsize = rndup(readbytes, BLOCKSIZE);
1614 + // Fill to end of block with zeros.
1615 + memset(b + readbytes, 0, fullsize - readbytes);
1616 + extend_inode_blk(fs, &ipos, b, fullsize / BLOCKSIZE);
1617 + size += readbytes;
1618 + readbytes = fread(b, 1, CB_SIZE, f);
1620 + if (size > 0x7fffffff) {
1621 + if (fs->sb->s_rev_level < 1)
1622 + fs_upgrade_rev1_largefile(fs);
1623 + fs->sb->s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
1625 + node->i_dir_acl = size >> 32;
1626 + node->i_size = size;
1627 + inode_pos_finish(fs, &ipos);
1633 @@ -1591,13 +2268,24 @@
1634 dname = malloc(len + 1);
1635 for(i = start; i < count; i++)
1638 SNPRINTF(dname, len, "%s%lu", name, i);
1639 - mknod_fs(fs, nod, dname, mode, uid, gid, major, minor + (i * increment - start), ctime, mtime);
1640 + oldnod = find_dir(fs, nod, dname);
1642 + chmod_fs(fs, oldnod, mode, uid, gid);
1644 + mknod_fs(fs, nod, dname, mode, uid, gid, major, minor + (i * increment - start), ctime, mtime);
1649 - mknod_fs(fs, nod, name, mode, uid, gid, major, minor, ctime, mtime);
1651 + uint32 oldnod = find_dir(fs, nod, name);
1653 + chmod_fs(fs, oldnod, mode, uid, gid);
1655 + mknod_fs(fs, nod, name, mode, uid, gid, major, minor, ctime, mtime);
1660 @@ -1643,6 +2331,10 @@
1661 switch(st.st_mode & S_IFMT)
1664 + if((st.st_mode & S_IFMT) == S_IFREG || st.st_size >= 4 * (EXT2_TIND_BLOCK+1))
1665 + stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
1669 if((st.st_mode & S_IFMT) == S_IFREG || st.st_size > 4 * (EXT2_TIND_BLOCK+1))
1670 stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
1671 @@ -1657,19 +2349,33 @@
1672 if(chdir(dent->d_name) < 0)
1673 perror_msg_and_die(dent->d_name);
1674 add2fs_from_dir(fs, this_nod, squash_uids, squash_perms, fs_timestamp, stats);
1676 + if (chdir("..") == -1)
1677 + perror_msg_and_die("..");
1685 + if((nod = find_dir(fs, this_nod, name)))
1687 + error_msg("ignoring duplicate entry %s", name);
1688 + if(S_ISDIR(st.st_mode)) {
1689 + if(chdir(dent->d_name) < 0)
1690 + perror_msg_and_die(name);
1691 + add2fs_from_dir(fs, nod, squash_uids, squash_perms, fs_timestamp, stats);
1692 + if (chdir("..") == -1)
1693 + perror_msg_and_die("..");
1698 /* Check for hardlinks */
1699 if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) && st.st_nlink > 1) {
1700 - int32 hdlink = is_hardlink(st.st_ino);
1701 + int32 hdlink = is_hardlink(fs, st.st_ino);
1703 - add2dir(fs, this_nod, hdlinks.hdl[hdlink].dst_nod, name);
1704 + add2dir(fs, this_nod, fs->hdlinks.hdl[hdlink].dst_nod, name);
1708 @@ -1697,8 +2403,12 @@
1712 - fh = xfopen(dent->d_name, "rb");
1713 - nod = mkfile_fs(fs, this_nod, name, mode, st.st_size, fh, uid, gid, ctime, mtime);
1714 + fh = fopen(dent->d_name, "rb");
1716 + error_msg("Unable to open file %s", dent->d_name);
1719 + nod = mkfile_fs(fs, this_nod, name, mode, fh, uid, gid, ctime, mtime);
1723 @@ -1706,199 +2416,128 @@
1724 if(chdir(dent->d_name) < 0)
1725 perror_msg_and_die(name);
1726 add2fs_from_dir(fs, nod, squash_uids, squash_perms, fs_timestamp, stats);
1728 + if (chdir("..") == -1)
1729 + perror_msg_and_die("..");
1732 error_msg("ignoring entry %s", name);
1735 - if (hdlinks.count == hdlink_cnt) {
1736 - if ((hdlinks.hdl =
1737 - realloc (hdlinks.hdl, (hdlink_cnt + HDLINK_CNT) *
1738 + if (fs->hdlinks.count == fs->hdlink_cnt) {
1739 + if ((fs->hdlinks.hdl =
1740 + realloc (fs->hdlinks.hdl, (fs->hdlink_cnt + HDLINK_CNT) *
1741 sizeof (struct hdlink_s))) == NULL) {
1742 error_msg_and_die("Not enough memory");
1744 - hdlink_cnt += HDLINK_CNT;
1745 + fs->hdlink_cnt += HDLINK_CNT;
1747 - hdlinks.hdl[hdlinks.count].src_inode = st.st_ino;
1748 - hdlinks.hdl[hdlinks.count].dst_nod = nod;
1750 + fs->hdlinks.hdl[fs->hdlinks.count].src_inode = st.st_ino;
1751 + fs->hdlinks.hdl[fs->hdlinks.count].dst_nod = nod;
1752 + fs->hdlinks.count++;
1759 -// endianness swap of x-indirect blocks
1760 +// Copy size blocks from src to dst, putting holes in the output
1761 +// file (if possible) if the input block is all zeros.
1762 +// Copy size blocks from src to dst, putting holes in the output
1763 +// file (if possible) if the input block is all zeros.
1765 -swap_goodblocks(filesystem *fs, inode *nod)
1766 +copy_file(filesystem *fs, FILE *dst, FILE *src, size_t size)
1773 - uint32 nblk = nod->i_blocks / INOBLK;
1774 - if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
1775 - for(i = 0; i <= EXT2_TIND_BLOCK; i++)
1776 - nod->i_block[i] = swab32(nod->i_block[i]);
1777 - if(nblk <= EXT2_IND_BLOCK)
1779 - swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
1780 - if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4)
1782 - /* Currently this will fail b'cos the number of blocks as stored
1783 - in i_blocks also includes the indirection blocks (see
1784 - walk_bw). But this function assumes that i_blocks only
1785 - stores the count of data blocks ( Actually according to
1786 - "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed)
1787 - i_blocks IS supposed to store the count of data blocks). so
1788 - with a file of size 268K nblk would be 269.The above check
1789 - will be false even though double indirection hasn't been
1790 - started.This is benign as 0 means block 0 which has been
1791 - zeroed out and therefore points back to itself from any offset
1793 - // FIXME: I have fixed that, but I have the feeling the rest of
1794 - // ths function needs to be fixed for the same reasons - Xav
1795 - assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
1796 - for(i = 0; i < BLOCKSIZE/4; i++)
1797 - if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
1798 - swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
1799 - swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
1800 - if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
1802 - /* Adding support for triple indirection */
1803 - b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
1804 - for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
1805 - b2 = (uint32*)get_blk(fs,b[i]);
1806 - for(j=0; j<BLOCKSIZE/4;j++) {
1807 - if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
1808 - (BLOCKSIZE/4)*(BLOCKSIZE/4) +
1809 - i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
1810 - j*(BLOCKSIZE/4)) )
1811 - swap_block(get_blk(fs,b2[j]));
1816 + b = malloc(BLOCKSIZE);
1818 + error_msg_and_die("copy_file: out of memory");
1819 + if (fseek(src, 0, SEEK_SET))
1820 + perror_msg_and_die("fseek");
1821 + if (ftruncate(fileno(dst), 0))
1822 + perror_msg_and_die("copy_file: ftruncate");
1823 + while (size > 0) {
1824 + if (fread(b, BLOCKSIZE, 1, src) != 1)
1825 + perror_msg_and_die("copy failed on read");
1826 + if ((dst != stdout) && fs->holes && is_blk_empty(b)) {
1827 + /* Empty block, just skip it */
1828 + if (fseek(dst, BLOCKSIZE, SEEK_CUR))
1829 + perror_msg_and_die("fseek");
1831 + if (fwrite(b, BLOCKSIZE, 1, dst) != 1)
1832 + perror_msg_and_die("copy failed on write");
1834 - swap_block((uint8 *)b2);
1837 - swap_block((uint8 *)b);
1843 -swap_badblocks(filesystem *fs, inode *nod)
1844 +// Allocate a new filesystem structure, allocate internal memory,
1845 +// and initialize the contents.
1846 +static filesystem *
1847 +alloc_fs(int swapit, char *fname, uint32 nbblocks, FILE *srcfile)
1853 + struct stat srcstat, dststat;
1855 - uint32 nblk = nod->i_blocks / INOBLK;
1856 - if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
1857 - for(i = 0; i <= EXT2_TIND_BLOCK; i++)
1858 - nod->i_block[i] = swab32(nod->i_block[i]);
1859 - if(nblk <= EXT2_IND_BLOCK)
1861 - swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
1862 - if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4)
1864 - /* See comment in swap_goodblocks */
1865 - assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
1866 - swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
1867 - for(i = 0; i < BLOCKSIZE/4; i++)
1868 - if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
1869 - swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
1870 - if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
1872 - /* Adding support for triple indirection */
1873 - b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
1874 - swap_block((uint8 *)b);
1875 - for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
1876 - b2 = (uint32*)get_blk(fs,b[i]);
1877 - swap_block((uint8 *)b2);
1878 - for(j=0; j<BLOCKSIZE/4;j++) {
1879 - if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
1880 - (BLOCKSIZE/4)*(BLOCKSIZE/4) +
1881 - i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
1882 - j*(BLOCKSIZE/4)) )
1883 - swap_block(get_blk(fs,b2[j]));
1892 + fs = malloc(sizeof(*fs));
1894 + error_msg_and_die("not enough memory for filesystem");
1895 + memset(fs, 0, sizeof(*fs));
1896 + fs->swapit = swapit;
1897 + cache_init(&fs->blks, MAX_FREE_CACHE_BLOCKS, blk_elem_val, blk_freed);
1898 + cache_init(&fs->gds, MAX_FREE_CACHE_GDS, gd_elem_val, gd_freed);
1899 + cache_init(&fs->blkmaps, MAX_FREE_CACHE_BLOCKMAPS,
1900 + blkmap_elem_val, blkmap_freed);
1901 + cache_init(&fs->inodes, MAX_FREE_CACHE_INODES,
1902 + inode_elem_val, inode_freed);
1903 + fs->hdlink_cnt = HDLINK_CNT;
1904 + fs->hdlinks.hdl = calloc(sizeof(struct hdlink_s), fs->hdlink_cnt);
1905 + if (!fs->hdlinks.hdl)
1906 + error_msg_and_die("Not enough memory");
1907 + fs->hdlinks.count = 0 ;
1909 -// endianness swap of the whole filesystem
1911 -swap_goodfs(filesystem *fs)
1914 - for(i = 1; i < fs->sb.s_inodes_count; i++)
1916 - inode *nod = get_nod(fs, i);
1917 - if(nod->i_mode & FM_IFDIR)
1922 - while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
1926 - b = get_blk(fs, bk);
1927 - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + swab16(d->d_rec_len)))
1931 - swap_goodblocks(fs, nod);
1934 - for(i=0;i<GRP_NBGROUPS(fs);i++)
1935 - swap_gd(&(fs->gd[i]));
1937 + if (strcmp(fname, "-") == 0)
1938 + fs->f = tmpfile();
1939 + else if (srcfile) {
1940 + if (fstat(fileno(srcfile), &srcstat))
1941 + perror_msg_and_die("fstat srcfile");
1942 + if (stat(fname, &dststat) == 0
1943 + && srcstat.st_ino == dststat.st_ino
1944 + && srcstat.st_dev == dststat.st_dev)
1946 + // source and destination are the same file, don't
1947 + // truncate or copy, just use the file.
1948 + fs->f = fopen(fname, "r+b");
1950 + fs->f = fopen(fname, "w+b");
1952 + copy_file(fs, fs->f, srcfile, nbblocks);
1955 + fs->f = fopen(fname, "w+b");
1957 + perror_msg_and_die("opening %s", fname);
1961 +/* Make sure the output file is the right size */
1963 -swap_badfs(filesystem *fs)
1964 +set_file_size(filesystem *fs)
1968 - for(i=0;i<GRP_NBGROUPS(fs);i++)
1969 - swap_gd(&(fs->gd[i]));
1970 - for(i = 1; i < fs->sb.s_inodes_count; i++)
1972 - inode *nod = get_nod(fs, i);
1974 - swap_badblocks(fs, nod);
1975 - if(nod->i_mode & FM_IFDIR)
1980 - while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
1984 - b = get_blk(fs, bk);
1985 - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
1990 + if (ftruncate(fileno(fs->f),
1991 + ((off_t) fs->sb->s_blocks_count) * BLOCKSIZE))
1992 + perror_msg_and_die("set_file_size: ftruncate");
1995 // initialize an empty filesystem
1997 -init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp)
1998 +init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes,
1999 + uint32 fs_timestamp, uint32 creator_os, int swapit, char *fname)
2006 uint32 nod, first_block;
2007 uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
2008 free_blocks_per_group,nbblocks_per_group,min_nbgroups;
2009 @@ -1906,6 +2545,11 @@
2015 + groupdescriptor *gd;
2020 error_msg_and_die("reserved blocks value is invalid. Note: options have changed, see --help or the man page.");
2021 @@ -1919,10 +2563,14 @@
2023 min_nbgroups = (nbinodes + INODES_PER_GROUP - 1) / INODES_PER_GROUP;
2025 + /* On filesystems with 1k block size, the bootloader area uses a full
2026 + * block. For 2048 and up, the superblock can be fitted into block 0.
2028 + first_block = (BLOCKSIZE == 1024);
2030 /* nbblocks is the total number of blocks in the filesystem.
2031 * a block group can have no more than 8192 blocks.
2033 - first_block = (BLOCKSIZE == 1024);
2034 nbgroups = (nbblocks - first_block + BLOCKS_PER_GROUP - 1) / BLOCKS_PER_GROUP;
2035 if(nbgroups < min_nbgroups) nbgroups = min_nbgroups;
2036 nbblocks_per_group = rndup((nbblocks - first_block + nbgroups - 1)/nbgroups, 8);
2037 @@ -1934,51 +2582,59 @@
2038 gdsz = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
2039 itblsz = nbinodes_per_group * sizeof(inode)/BLOCKSIZE;
2040 overhead_per_group = 3 /*sb,bbm,ibm*/ + gdsz + itblsz;
2041 - if((uint32)nbblocks - 1 < overhead_per_group * nbgroups)
2042 - error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
2043 - free_blocks = nbblocks - overhead_per_group*nbgroups - 1 /*boot block*/;
2044 + free_blocks = nbblocks - overhead_per_group*nbgroups - first_block;
2045 free_blocks_per_group = nbblocks_per_group - overhead_per_group;
2046 + if(free_blocks < 0)
2047 + error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
2049 - if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
2050 - error_msg_and_die("not enough memory for filesystem");
2051 + fs = alloc_fs(swapit, fname, nbblocks, NULL);
2052 + fs->sb = calloc(1, SUPERBLOCK_SIZE);
2054 + error_msg_and_die("error allocating header memory");
2056 // create the superblock for an empty filesystem
2057 - fs->sb.s_inodes_count = nbinodes_per_group * nbgroups;
2058 - fs->sb.s_blocks_count = nbblocks;
2059 - fs->sb.s_r_blocks_count = nbresrvd;
2060 - fs->sb.s_free_blocks_count = free_blocks;
2061 - fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
2062 - fs->sb.s_first_data_block = first_block;
2063 - fs->sb.s_log_block_size = BLOCKSIZE >> 11;
2064 - fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
2065 - fs->sb.s_blocks_per_group = nbblocks_per_group;
2066 - fs->sb.s_frags_per_group = nbblocks_per_group;
2067 - fs->sb.s_inodes_per_group = nbinodes_per_group;
2068 - fs->sb.s_wtime = fs_timestamp;
2069 - fs->sb.s_magic = EXT2_MAGIC_NUMBER;
2070 - fs->sb.s_lastcheck = fs_timestamp;
2071 + fs->sb->s_inodes_count = nbinodes_per_group * nbgroups;
2072 + fs->sb->s_blocks_count = nbblocks;
2073 + fs->sb->s_r_blocks_count = nbresrvd;
2074 + fs->sb->s_free_blocks_count = free_blocks;
2075 + fs->sb->s_free_inodes_count = fs->sb->s_inodes_count - EXT2_FIRST_INO + 1;
2076 + fs->sb->s_first_data_block = first_block;
2077 + fs->sb->s_log_block_size = BLOCKSIZE >> 11;
2078 + fs->sb->s_log_frag_size = BLOCKSIZE >> 11;
2079 + fs->sb->s_blocks_per_group = nbblocks_per_group;
2080 + fs->sb->s_frags_per_group = nbblocks_per_group;
2081 + fs->sb->s_inodes_per_group = nbinodes_per_group;
2082 + fs->sb->s_wtime = fs_timestamp;
2083 + fs->sb->s_magic = EXT2_MAGIC_NUMBER;
2084 + fs->sb->s_lastcheck = fs_timestamp;
2085 + fs->sb->s_creator_os = creator_os;
2087 + set_file_size(fs);
2089 // set up groupdescriptors
2090 - for(i=0, bbmpos=gdsz+2, ibmpos=bbmpos+1, itblpos=ibmpos+1;
2091 + for(i=0, bbmpos=first_block+1+gdsz, ibmpos=bbmpos+1, itblpos=ibmpos+1;
2093 i++, bbmpos+=nbblocks_per_group, ibmpos+=nbblocks_per_group, itblpos+=nbblocks_per_group)
2095 + gd = get_gd(fs, i, &gi);
2097 if(free_blocks > free_blocks_per_group) {
2098 - fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
2099 + gd->bg_free_blocks_count = free_blocks_per_group;
2100 free_blocks -= free_blocks_per_group;
2102 - fs->gd[i].bg_free_blocks_count = free_blocks;
2103 + gd->bg_free_blocks_count = free_blocks;
2104 free_blocks = 0; // this is the last block group
2107 - fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
2108 + gd->bg_free_inodes_count = nbinodes_per_group;
2110 - fs->gd[i].bg_free_inodes_count = nbinodes_per_group -
2111 + gd->bg_free_inodes_count = nbinodes_per_group -
2113 - fs->gd[i].bg_used_dirs_count = 0;
2114 - fs->gd[i].bg_block_bitmap = bbmpos;
2115 - fs->gd[i].bg_inode_bitmap = ibmpos;
2116 - fs->gd[i].bg_inode_table = itblpos;
2117 + gd->bg_used_dirs_count = 0;
2118 + gd->bg_block_bitmap = bbmpos;
2119 + gd->bg_inode_bitmap = ibmpos;
2120 + gd->bg_inode_table = itblpos;
2124 /* Mark non-filesystem blocks and inodes as allocated */
2125 @@ -1984,110 +2640,143 @@
2126 /* Mark non-filesystem blocks and inodes as allocated */
2127 /* Mark system blocks and inodes as allocated */
2128 for(i = 0; i<nbgroups;i++) {
2131 - bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);
2132 + gd = get_gd(fs, i, &gi);
2133 + bbm = GRP_GET_GROUP_BBM(fs, gd, &bi);
2134 //non-filesystem blocks
2135 - for(j = fs->gd[i].bg_free_blocks_count
2136 + for(j = gd->bg_free_blocks_count
2137 + overhead_per_group + 1; j <= BLOCKSIZE * 8; j++)
2140 for(j = 1; j <= overhead_per_group; j++)
2143 + GRP_PUT_GROUP_BBM(bi);
2146 - ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);
2147 + ibm = GRP_GET_GROUP_IBM(fs, gd, &bi);
2148 //non-filesystem inodes
2149 - for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
2150 + for(j = fs->sb->s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
2155 for(j = 1; j < EXT2_FIRST_INO; j++)
2157 + GRP_PUT_GROUP_IBM(bi);
2161 // make root inode and directory
2162 /* We have groups now. Add the root filesystem in group 0 */
2163 /* Also increment the directory count for group 0 */
2164 - fs->gd[0].bg_free_inodes_count--;
2165 - fs->gd[0].bg_used_dirs_count = 1;
2166 - itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table);
2167 - itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH;
2168 - itab0[EXT2_ROOT_INO-1].i_ctime = fs_timestamp;
2169 - itab0[EXT2_ROOT_INO-1].i_mtime = fs_timestamp;
2170 - itab0[EXT2_ROOT_INO-1].i_atime = fs_timestamp;
2171 - itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
2172 - itab0[EXT2_ROOT_INO-1].i_links_count = 2;
2174 - if(!(b = get_workblk()))
2175 - error_msg_and_die("get_workblk() failed.");
2176 - d = (directory*)b;
2177 - d->d_inode = EXT2_ROOT_INO;
2178 - d->d_rec_len = sizeof(directory)+4;
2179 - d->d_name_len = 1;
2180 - strcpy(d->d_name, ".");
2181 - d = (directory*)(b + d->d_rec_len);
2182 - d->d_inode = EXT2_ROOT_INO;
2183 - d->d_rec_len = BLOCKSIZE - (sizeof(directory)+4);
2184 - d->d_name_len = 2;
2185 - strcpy(d->d_name, "..");
2186 - extend_blk(fs, EXT2_ROOT_INO, b, 1);
2187 + gd = get_gd(fs, 0, &gi);
2188 + gd->bg_free_inodes_count--;
2189 + gd->bg_used_dirs_count = 1;
2191 + itab0 = get_nod(fs, EXT2_ROOT_INO, &ni);
2192 + itab0->i_mode = FM_IFDIR | FM_IRWXU | FM_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH;
2193 + itab0->i_ctime = fs_timestamp;
2194 + itab0->i_mtime = fs_timestamp;
2195 + itab0->i_atime = fs_timestamp;
2196 + itab0->i_size = BLOCKSIZE;
2197 + itab0->i_links_count = 2;
2200 + new_dir(fs, EXT2_ROOT_INO, ".", 1, &dw);
2201 + shrink_dir(&dw, EXT2_ROOT_INO, "..", 2);
2202 + next_dir(&dw); // Force the data into the buffer
2203 + inode_pos_init(fs, &ipos, EXT2_ROOT_INO, INODE_POS_EXTEND, NULL);
2204 + extend_inode_blk(fs, &ipos, dir_data(&dw), 1);
2205 + inode_pos_finish(fs, &ipos);
2208 - // make lost+found directory and reserve blocks
2209 - if(fs->sb.s_r_blocks_count)
2210 + // make lost+found directory
2211 + if(fs->sb->s_r_blocks_count)
2213 - nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU, 0, 0, fs_timestamp, fs_timestamp);
2217 + nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU,
2218 + 0, 0, fs_timestamp, fs_timestamp);
2219 + b = get_workblk();
2220 memset(b, 0, BLOCKSIZE);
2221 ((directory*)b)->d_rec_len = BLOCKSIZE;
2222 - /* We run into problems with e2fsck if directory lost+found grows
2223 - * bigger than this. Need to find out why this happens - sundar
2225 - if (fs->sb.s_r_blocks_count > fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS )
2226 - fs->sb.s_r_blocks_count = fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS;
2227 - for(i = 1; i < fs->sb.s_r_blocks_count; i++)
2228 - extend_blk(fs, nod, b, 1);
2229 - get_nod(fs, nod)->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE;
2230 + inode_pos_init(fs, &ipos, nod, INODE_POS_EXTEND, NULL);
2231 + // It is always 16 blocks to start out with
2232 + for(i = 1; i < 16; i++)
2233 + extend_inode_blk(fs, &ipos, b, 1);
2234 + inode_pos_finish(fs, &ipos);
2236 + node = get_nod(fs, nod, &ni);
2237 + node->i_size = 16 * BLOCKSIZE;
2242 // administrative info
2243 - fs->sb.s_state = 1;
2244 - fs->sb.s_max_mnt_count = 20;
2245 + fs->sb->s_state = 1;
2246 + fs->sb->s_max_mnt_count = 20;
2250 - fs->sb.s_reserved[200] |= OP_HOLES;
2251 + fs->holes = holes;
2256 // loads a filesystem from disk
2258 -load_fs(FILE * fh, int swapit)
2259 +load_fs(FILE *fh, int swapit, char *fname)
2264 - if((fseek(fh, 0, SEEK_END) < 0) || ((ssize_t)(fssize = ftell(fh)) == -1))
2266 + if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftello(fh)) == -1))
2267 perror_msg_and_die("input filesystem image");
2269 - fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
2270 + if ((fssize % BLOCKSIZE) != 0)
2271 + error_msg_and_die("Input file not a multiple of block size");
2272 + fssize /= BLOCKSIZE;
2273 if(fssize < 16) // totally arbitrary
2274 error_msg_and_die("too small filesystem");
2275 - if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
2276 - error_msg_and_die("not enough memory for filesystem");
2277 - if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
2278 - perror_msg_and_die("input filesystem image");
2279 + fs = alloc_fs(swapit, fname, fssize, fh);
2281 + /* Read and check the superblock, then read the superblock
2282 + * and all the group descriptors */
2283 + fs->sb = malloc(SUPERBLOCK_SIZE);
2285 + error_msg_and_die("error allocating header memory");
2286 + if (fseek(fs->f, SUPERBLOCK_OFFSET, SEEK_SET))
2287 + perror_msg_and_die("fseek");
2288 + if (fread(fs->sb, SUPERBLOCK_SIZE, 1, fs->f) != 1)
2289 + perror_msg_and_die("fread filesystem image superblock");
2292 - if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
2295 + if((fs->sb->s_rev_level > 1) || (fs->sb->s_magic != EXT2_MAGIC_NUMBER))
2296 error_msg_and_die("not a suitable ext2 filesystem");
2297 + if (fs->sb->s_rev_level > 0) {
2298 + if (fs->sb->s_first_ino != EXT2_GOOD_OLD_FIRST_INO)
2299 + error_msg_and_die("First inode incompatible");
2300 + if (fs->sb->s_inode_size != EXT2_GOOD_OLD_INODE_SIZE)
2301 + error_msg_and_die("inode size incompatible");
2302 + if (fs->sb->s_feature_compat)
2303 + error_msg_and_die("Unsupported compat features");
2304 + if (fs->sb->s_feature_incompat)
2305 + error_msg_and_die("Unsupported incompat features");
2306 + if (fs->sb->s_feature_ro_compat
2307 + & ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
2308 + error_msg_and_die("Unsupported ro compat features");
2311 + set_file_size(fs);
2316 free_fs(filesystem *fs)
2318 + free(fs->hdlinks.hdl);
2324 @@ -2123,16 +2812,23 @@
2328 - int32 fsize = get_nod(fs, nod)->i_size;
2330 + inode *node = get_nod(fs, nod, &ni);
2331 + int32 fsize = node->i_size;
2335 while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
2338 error_msg_and_die("wrong size while saving inode %d", nod);
2339 - if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
2340 + if(fwrite(get_blk(fs, bk, &bi),
2341 + (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
2342 error_msg_and_die("error while saving inode %d", nod);
2350 @@ -2141,8 +2837,11 @@
2351 print_dev(filesystem *fs, uint32 nod)
2354 - minor = ((uint8*)get_nod(fs, nod)->i_block)[0];
2355 - major = ((uint8*)get_nod(fs, nod)->i_block)[1];
2357 + inode *node = get_nod(fs, nod, &ni);
2358 + minor = ((uint8*)node->i_block)[0];
2359 + major = ((uint8*)node->i_block)[1];
2361 printf("major: %d, minor: %d\n", major, minor);
2364 @@ -2157,17 +2856,15 @@
2365 while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
2369 - b = get_blk(fs, bk);
2370 - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
2372 + for (d = get_dir(fs, bk, &dw); d; d = next_dir(&dw))
2377 - for(i = 0; i < d->d_name_len; i++)
2378 - putchar(d->d_name[i]);
2379 + fwrite(dir_name(&dw), 1, d->d_name_len, stdout);
2380 printf("' (inode %d): rec_len: %d (name_len: %d)\n", d->d_inode, d->d_rec_len, d->d_name_len);
2386 @@ -2175,14 +2872,18 @@
2388 print_link(filesystem *fs, uint32 nod)
2390 - if(!get_nod(fs, nod)->i_blocks)
2391 - printf("links to '%s'\n", (char*)get_nod(fs, nod)->i_block);
2393 + inode *node = get_nod(fs, nod, &ni);
2395 + if(!node->i_blocks)
2396 + printf("links to '%s'\n", (char*)node->i_block);
2399 printf("links to '");
2400 write_blocks(fs, nod, stdout);
2406 // make a ls-like printout of permissions
2407 @@ -2251,8 +2952,13 @@
2411 - if(!get_nod(fs, nod)->i_mode)
2414 + inode *node = get_nod(fs, nod, &ni);
2423 @@ -2274,15 +2980,18 @@
2425 s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved";
2427 - printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count);
2428 - if(!allocated(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
2429 + printf("inode %d (%s, %d links): ", nod, s, node->i_links_count);
2430 + if(!allocated(GRP_GET_INODE_BITMAP(fs,nod,&bi,&gi), GRP_IBM_OFFSET(fs,nod)))
2432 + GRP_PUT_INODE_BITMAP(bi,gi);
2433 printf("unallocated\n");
2437 - make_perms(get_nod(fs, nod)->i_mode, perms);
2438 - printf("%s, size: %d byte%s (%d block%s)\n", perms, plural(get_nod(fs, nod)->i_size), plural(get_nod(fs, nod)->i_blocks / INOBLK));
2439 - switch(get_nod(fs, nod)->i_mode & FM_IFMT)
2440 + GRP_PUT_INODE_BITMAP(bi,gi);
2441 + make_perms(node->i_mode, perms);
2442 + printf("%s, size: %d byte%s (%d block%s)\n", perms,
2443 + plural(node->i_size), plural(node->i_blocks / INOBLK));
2444 + switch(node->i_mode & FM_IFMT)
2447 list_blocks(fs, nod);
2448 @@ -2310,6 +3019,8 @@
2449 list_blocks(fs, nod);
2451 printf("Done with inode %d\n",nod);
2456 // describes various fields in a filesystem
2457 @@ -2317,49 +3028,65 @@
2458 print_fs(filesystem *fs)
2462 + groupdescriptor *gd;
2466 printf("%d blocks (%d free, %d reserved), first data block: %d\n",
2467 - fs->sb.s_blocks_count, fs->sb.s_free_blocks_count,
2468 - fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
2469 - printf("%d inodes (%d free)\n", fs->sb.s_inodes_count,
2470 - fs->sb.s_free_inodes_count);
2471 + fs->sb->s_blocks_count, fs->sb->s_free_blocks_count,
2472 + fs->sb->s_r_blocks_count, fs->sb->s_first_data_block);
2473 + printf("%d inodes (%d free)\n", fs->sb->s_inodes_count,
2474 + fs->sb->s_free_inodes_count);
2475 printf("block size = %d, frag size = %d\n",
2476 - fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024,
2477 - fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
2478 + fs->sb->s_log_block_size ? (fs->sb->s_log_block_size << 11) : 1024,
2479 + fs->sb->s_log_frag_size ? (fs->sb->s_log_frag_size << 11) : 1024);
2480 printf("number of groups: %d\n",GRP_NBGROUPS(fs));
2481 printf("%d blocks per group,%d frags per group,%d inodes per group\n",
2482 - fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group,
2483 - fs->sb.s_inodes_per_group);
2484 + fs->sb->s_blocks_per_group, fs->sb->s_frags_per_group,
2485 + fs->sb->s_inodes_per_group);
2486 printf("Size of inode table: %d blocks\n",
2487 - (int)(fs->sb.s_inodes_per_group * sizeof(inode) / BLOCKSIZE));
2488 + (int)(fs->sb->s_inodes_per_group * sizeof(inode) / BLOCKSIZE));
2489 for (i = 0; i < GRP_NBGROUPS(fs); i++) {
2490 printf("Group No: %d\n", i+1);
2491 + gd = get_gd(fs, i, &gi);
2492 printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
2493 - fs->gd[i].bg_block_bitmap, fs->gd[i].bg_inode_bitmap,
2494 - fs->gd[i].bg_inode_table);
2495 + gd->bg_block_bitmap,
2496 + gd->bg_inode_bitmap,
2497 + gd->bg_inode_table);
2498 printf("block bitmap allocation:\n");
2499 - print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
2500 + print_bm(GRP_GET_GROUP_BBM(fs, gd, &bi),fs->sb->s_blocks_per_group);
2501 + GRP_PUT_GROUP_BBM(bi);
2502 printf("inode bitmap allocation:\n");
2503 - ibm = GRP_GET_GROUP_IBM(fs, i);
2504 - print_bm(ibm, fs->sb.s_inodes_per_group);
2505 - for (i = 1; i <= fs->sb.s_inodes_per_group; i++)
2506 + ibm = GRP_GET_GROUP_IBM(fs, gd, &bi);
2507 + print_bm(ibm, fs->sb->s_inodes_per_group);
2508 + for (i = 1; i <= fs->sb->s_inodes_per_group; i++)
2509 if (allocated(ibm, i))
2511 + GRP_PUT_GROUP_IBM(bi);
2517 -dump_fs(filesystem *fs, FILE * fh, int swapit)
2518 +finish_fs(filesystem *fs)
2520 - uint32 nbblocks = fs->sb.s_blocks_count;
2521 - fs->sb.s_reserved[200] = 0;
2524 - if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
2525 - perror_msg_and_die("output filesystem image");
2528 + if (cache_flush(&fs->inodes))
2529 + error_msg_and_die("entry mismatch on inode cache flush");
2530 + if (cache_flush(&fs->blkmaps))
2531 + error_msg_and_die("entry mismatch on blockmap cache flush");
2532 + if (cache_flush(&fs->gds))
2533 + error_msg_and_die("entry mismatch on gd cache flush");
2534 + if (cache_flush(&fs->blks))
2535 + error_msg_and_die("entry mismatch on block cache flush");
2538 + if (fseek(fs->f, SUPERBLOCK_OFFSET, SEEK_SET))
2539 + perror_msg_and_die("fseek");
2540 + if(fwrite(fs->sb, SUPERBLOCK_SIZE, 1, fs->f) != 1)
2541 + perror_msg_and_die("output filesystem superblock");
2547 @@ -2419,10 +3146,12 @@
2548 " -x, --starting-image <image>\n"
2549 " -d, --root <directory>\n"
2550 " -D, --devtable <file>\n"
2551 + " -B, --block-size <bytes>\n"
2552 " -b, --size-in-blocks <blocks>\n"
2553 " -i, --bytes-per-inode <bytes per inode>\n"
2554 " -N, --number-of-inodes <number of inodes>\n"
2555 " -m, --reserved-percentage <percentage of blocks to reserve>\n"
2556 + " -o, --creator-os <os> 'linux' (default), 'hurd', 'freebsd' or number.\n"
2557 " -g, --block-map <path> Generate a block map file for this path.\n"
2558 " -e, --fill-value <value> Fill unallocated blocks with value.\n"
2559 " -z, --allow-holes Allow files with holes.\n"
2560 @@ -2444,15 +3173,34 @@
2561 extern char* optarg;
2562 extern int optind, opterr, optopt;
2564 +// parse the value for -o <os>
2566 +lookup_creator_os(const char *name)
2568 + if (isdigit (*name))
2569 + return atoi(name);
2570 + else if (strcasecmp(name, "linux") == 0)
2571 + return EXT2_OS_LINUX;
2572 + else if (strcasecmp(name, "GNU") == 0 || strcasecmp(name, "hurd") == 0)
2573 + return EXT2_OS_HURD;
2574 + else if (strcasecmp(name, "freebsd") == 0)
2575 + return EXT2_OS_FREEBSD;
2576 + else if (strcasecmp(name, "lites") == 0)
2577 + return EXT2_OS_LITES;
2579 + return EXT2_OS_LINUX;
2583 main(int argc, char **argv)
2585 - int nbblocks = -1;
2586 + long long nbblocks = -1;
2589 float bytes_per_inode = -1;
2590 float reserved_frac = -1;
2591 int fs_timestamp = -1;
2592 + int creator_os = CREATOR_OS;
2595 char * dopt[MAX_DOPT];
2596 @@ -2466,6 +3214,7 @@
2597 int squash_perms = 0;
2599 int bigendian = !*(char*)&endian;
2600 + char *volumelabel = NULL;
2604 @@ -2476,13 +3225,16 @@
2605 { "starting-image", required_argument, NULL, 'x' },
2606 { "root", required_argument, NULL, 'd' },
2607 { "devtable", required_argument, NULL, 'D' },
2608 + { "block-size", required_argument, NULL, 'B' },
2609 { "size-in-blocks", required_argument, NULL, 'b' },
2610 { "bytes-per-inode", required_argument, NULL, 'i' },
2611 { "number-of-inodes", required_argument, NULL, 'N' },
2612 + { "volume-label", required_argument, NULL, 'L' },
2613 { "reserved-percentage", required_argument, NULL, 'm' },
2614 + { "creator-os", required_argument, NULL, 'o' },
2615 { "block-map", required_argument, NULL, 'g' },
2616 { "fill-value", required_argument, NULL, 'e' },
2617 - { "allow-holes", no_argument, NULL, 'z' },
2618 + { "allow-holes", no_argument, NULL, 'z' },
2619 { "faketime", no_argument, NULL, 'f' },
2620 { "squash", no_argument, NULL, 'q' },
2621 { "squash-uids", no_argument, NULL, 'U' },
2622 @@ -2495,11 +3247,11 @@
2626 - while((c = getopt_long(argc, argv, "x:d:D:b:i:N:m:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
2627 + while((c = getopt_long(argc, argv, "x:d:D:B:b:i:N:L:m:o:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
2631 - while((c = getopt(argc, argv, "x:d:D:b:i:N:m:g:e:zfqUPhVv")) != EOF) {
2632 + while((c = getopt(argc, argv, "x:d:D:B:b:i:N:L:m:o:g:e:zfqUPhVv")) != EOF) {
2633 #endif /* HAVE_GETOPT_LONG */
2636 @@ -2510,6 +3262,9 @@
2638 dopt[didx++] = optarg;
2641 + blocksize = SI_atof(optarg);
2644 nbblocks = SI_atof(optarg);
2646 @@ -2519,9 +3274,15 @@
2648 nbinodes = SI_atof(optarg);
2651 + volumelabel = optarg;
2654 reserved_frac = SI_atof(optarg) / 100;
2657 + creator_os = lookup_creator_os(optarg);
2660 gopt[gidx++] = optarg;
2662 @@ -2565,21 +3326,21 @@
2663 error_msg_and_die("Not enough arguments. Try --help or else see the man page.");
2664 fsout = argv[optind];
2666 - hdlinks.hdl = (struct hdlink_s *)malloc(hdlink_cnt * sizeof(struct hdlink_s));
2668 - error_msg_and_die("Not enough memory");
2669 - hdlinks.count = 0 ;
2670 + if(blocksize != 1024 && blocksize != 2048 && blocksize != 4096)
2671 + error_msg_and_die("Valid block sizes: 1024, 2048 or 4096.");
2672 + if(creator_os < 0)
2673 + error_msg_and_die("Creator OS unknown.");
2677 if(strcmp(fsin, "-"))
2679 FILE * fh = xfopen(fsin, "rb");
2680 - fs = load_fs(fh, bigendian);
2681 + fs = load_fs(fh, bigendian, fsout);
2685 - fs = load_fs(stdin, bigendian);
2686 + fs = load_fs(stdin, bigendian, fsout);
2690 @@ -2609,16 +3370,29 @@
2692 if(fs_timestamp == -1)
2693 fs_timestamp = time(NULL);
2694 - fs = init_fs(nbblocks, nbinodes, nbresrvd, holes, fs_timestamp);
2695 + fs = init_fs(nbblocks, nbinodes, nbresrvd, holes,
2696 + fs_timestamp, creator_os, bigendian, fsout);
2698 + if (volumelabel != NULL)
2699 + strncpy((char *)fs->sb->s_volume_name, volumelabel,
2700 + sizeof(fs->sb->s_volume_name));
2702 populate_fs(fs, dopt, didx, squash_uids, squash_perms, fs_timestamp, NULL);
2706 - for(b = 1; b < fs->sb.s_blocks_count; b++)
2707 - if(!allocated(GRP_GET_BLOCK_BITMAP(fs,b),GRP_BBM_OFFSET(fs,b)))
2708 - memset(get_blk(fs, b), emptyval, BLOCKSIZE);
2709 + for(b = 1; b < fs->sb->s_blocks_count; b++) {
2712 + if(!allocated(GRP_GET_BLOCK_BITMAP(fs,b,&bi,&gi),
2713 + GRP_BBM_OFFSET(fs,b))) {
2715 + memset(get_blk(fs, b, &bi2), emptyval,
2719 + GRP_PUT_BLOCK_BITMAP(bi,gi);
2724 @@ -2628,24 +3402,22 @@
2725 char fname[MAX_FILENAME];
2729 if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
2730 error_msg_and_die("path %s not found in filesystem", gopt[i]);
2731 while((p = strchr(gopt[i], '/')))
2733 SNPRINTF(fname, MAX_FILENAME-1, "%s.blk", gopt[i]);
2734 fh = xfopen(fname, "wb");
2735 - fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
2736 + fprintf(fh, "%d:", get_nod(fs, nod, &ni)->i_size);
2738 flist_blocks(fs, nod, fh);
2741 - if(strcmp(fsout, "-"))
2743 - FILE * fh = xfopen(fsout, "wb");
2744 - dump_fs(fs, fh, bigendian);
2748 - dump_fs(fs, stdout, bigendian);
2750 + if(strcmp(fsout, "-") == 0)
2751 + copy_file(fs, stdout, fs->f, fs->sb->s_blocks_count);
2756 Index: genext2fs-1.4.1/cache.h
2757 ===================================================================
2759 +++ genext2fs-1.4.1/cache.h
2761 +#ifndef __CACHE_H__
2762 +#define __CACHE_H__
2766 +#define CACHE_LISTS 256
2771 + list_elem lru_link;
2776 + /* LRU list holds unused items */
2777 + unsigned int lru_entries;
2778 + list_elem lru_list;
2779 + unsigned int max_free_entries;
2781 + unsigned int entries;
2782 + list_elem lists[CACHE_LISTS];
2783 + unsigned int (*elem_val)(cache_link *elem);
2784 + void (*freed)(cache_link *elem);
2788 +cache_add(listcache *c, cache_link *elem)
2790 + unsigned int hash = c->elem_val(elem) % CACHE_LISTS;
2791 + int delcount = c->lru_entries - c->max_free_entries;
2793 + if (delcount > 0) {
2794 + /* Delete some unused items. */
2795 + list_elem *lru, *next;
2797 + list_for_each_elem_safe(&c->lru_list, lru, next) {
2798 + l = container_of(lru, cache_link, lru_link);
2800 + list_del(&l->link);
2805 + if (delcount <= 0)
2811 + list_item_init(&elem->lru_link); /* Mark it not in the LRU list */
2812 + list_add_after(&c->lists[hash], &elem->link);
2816 +cache_item_set_unused(listcache *c, cache_link *elem)
2818 + list_add_before(&c->lru_list, &elem->lru_link);
2822 +static inline cache_link *
2823 +cache_find(listcache *c, unsigned int val)
2825 + unsigned int hash = val % CACHE_LISTS;
2828 + list_for_each_elem(&c->lists[hash], elem) {
2829 + cache_link *l = container_of(elem, cache_link, link);
2830 + if (c->elem_val(l) == val) {
2831 + if (!list_empty(&l->lru_link)) {
2832 + /* It's in the unused list, remove it. */
2833 + list_del(&l->lru_link);
2834 + list_item_init(&l->lru_link);
2844 +cache_flush(listcache *c)
2846 + list_elem *elem, *next;
2850 + list_for_each_elem_safe(&c->lru_list, elem, next) {
2851 + l = container_of(elem, cache_link, lru_link);
2853 + list_del(&l->link);
2859 + for (i = 0; i < CACHE_LISTS; i++) {
2860 + list_for_each_elem_safe(&c->lists[i], elem, next) {
2861 + l = container_of(elem, cache_link, link);
2862 + list_del(&l->link);
2868 + return c->entries || c->lru_entries;
2872 +cache_init(listcache *c, unsigned int max_free_entries,
2873 + unsigned int (*elem_val)(cache_link *elem),
2874 + void (*freed)(cache_link *elem))
2879 + c->lru_entries = 0;
2880 + c->max_free_entries = max_free_entries;
2881 + list_init(&c->lru_list);
2882 + for (i = 0; i < CACHE_LISTS; i++)
2883 + list_init(&c->lists[i]);
2884 + c->elem_val = elem_val;
2888 +#endif /* __CACHE_H__ */
2889 Index: genext2fs-1.4.1/list.h
2890 ===================================================================
2892 +++ genext2fs-1.4.1/list.h
2898 +# include <stdlib.h>
2899 +# include <stddef.h>
2902 +# include <stdlib.h>
2905 +# include <stddef.h>
2910 +#define offsetof(st, m) \
2911 + ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
2914 +#define container_of(ptr, type, member) ({ \
2915 + const typeof( ((type *)0)->member ) *__mptr = (ptr); \
2916 + (type *)( (char *)__mptr - offsetof(type,member) );})
2918 +typedef struct list_elem
2920 + struct list_elem *next;
2921 + struct list_elem *prev;
2924 +static inline void list_init(list_elem *list)
2926 + list->next = list;
2927 + list->prev = list;
2930 +static inline void list_add_after(list_elem *pos, list_elem *elem)
2932 + elem->next = pos->next;
2934 + pos->next->prev = elem;
2938 +static inline void list_add_before(list_elem *pos, list_elem *elem)
2940 + elem->prev = pos->prev;
2942 + pos->prev->next = elem;
2946 +static inline void list_del(list_elem *elem)
2948 + elem->next->prev = elem->prev;
2949 + elem->prev->next = elem->next;
2952 +static inline void list_item_init(list_elem *elem)
2954 + elem->next = elem;
2955 + elem->prev = elem;
2958 +static inline int list_empty(list_elem *elem)
2960 + return elem->next == elem;
2963 +#define list_for_each_elem(list, curr) \
2964 + for ((curr) = (list)->next; (curr) != (list); (curr) = (curr)->next)
2966 +#define list_for_each_elem_safe(list, curr, next) \
2967 + for ((curr) = (list)->next, (next) = (curr)->next; \
2968 + (curr) != (list); \
2969 + (curr) = (next), (next) = (curr)->next)
2971 +#endif /* __LIST_H__ */