[Buildroot] [PATCH 1/1] package/genext2fs: bump to version 1.5.0

Arnout Vandecappelle arnout at mind.be
Thu Apr 15 19:20:46 UTC 2021



On 14/04/2021 23:44, Fabrice Fontaine wrote:
> - Retrieve latest version from github
> - Drop patch (already in version)
> 
> Fixes:
>  - https://bugs.buildroot.org/show_bug.cgi?id=13741
> 
> Signed-off-by: Fabrice Fontaine <fontaine.fabrice at gmail.com>


 Applied to master, thanks.

 I guess for stable, the patch [1] should be backported rather than bumping. But
is it worth spending effort on that for a borderline package like genext2fs?

 Regards,
 Arnout


[1]
https://github.com/bestouff/genext2fs/pull/14/commits/8e4b9ae6f051454953a80b8e64443bcea6c9cc46



> ---
>  ...0001-update-genext2fs.c-to-rev-1.118.patch | 2971 -----------------
>  package/genext2fs/genext2fs.hash              |    2 +-
>  package/genext2fs/genext2fs.mk                |    6 +-
>  3 files changed, 5 insertions(+), 2974 deletions(-)
>  delete mode 100644 package/genext2fs/0001-update-genext2fs.c-to-rev-1.118.patch
> 
> diff --git a/package/genext2fs/0001-update-genext2fs.c-to-rev-1.118.patch b/package/genext2fs/0001-update-genext2fs.c-to-rev-1.118.patch
> deleted file mode 100644
> index 755ee9dee2..0000000000
> --- a/package/genext2fs/0001-update-genext2fs.c-to-rev-1.118.patch
> +++ /dev/null
> @@ -1,2971 +0,0 @@
> -[PATCH] update genext2fs.c to CVS rev 1.118
> -
> -See http://genext2fs.cvs.sourceforge.net/viewvc/genext2fs/genext2fs/genext2fs.c?view=log
> -for details.
> -
> -Numerous bugfixes, large file and filesystem support, rev 1 filesystems,
> -volume id support, block size, ..
> -
> -Signed-off-by: Peter Korsgaard <jacmet at sunsite.dk>
> ----
> - cache.h     |  128 ++++
> - genext2fs.c | 1870 ++++++++++++++++++++++++++++++++++++++++++------------------
> - list.h      |   78 ++
> - 3 files changed, 1527 insertions(+), 549 deletions(-)
> -
> -Index: genext2fs-1.4.1/genext2fs.c
> -===================================================================
> ---- genext2fs-1.4.1.orig/genext2fs.c
> -+++ genext2fs-1.4.1/genext2fs.c
> -@@ -53,6 +53,12 @@
> - // 			along with -q, -P, -U
> - 
> - 
> -+/*
> -+ * Allow fseeko/off_t to be 64-bit offsets to allow filesystems and
> -+ * individual files >2GB.
> -+ */
> -+#define _FILE_OFFSET_BITS 64
> -+
> - #include <config.h>
> - #include <stdio.h>
> - 
> -@@ -107,10 +113,8 @@
> - 
> - #if HAVE_DIRENT_H
> - # include <dirent.h>
> --# define NAMLEN(dirent) strlen((dirent)->d_name)
> - #else
> - # define dirent direct
> --# define NAMLEN(dirent) (dirent)->d_namlen
> - # if HAVE_SYS_NDIR_H
> - #  include <sys/ndir.h>
> - # endif
> -@@ -144,6 +148,8 @@
> - # include <limits.h>
> - #endif
> - 
> -+#include "cache.h"
> -+
> - struct stats {
> - 	unsigned long nblocks;
> - 	unsigned long ninodes;
> -@@ -151,13 +157,42 @@
> - 
> - // block size
> - 
> --#define BLOCKSIZE         1024
> -+static int blocksize = 1024;
> -+
> -+#define SUPERBLOCK_OFFSET	1024
> -+#define SUPERBLOCK_SIZE		1024
> -+
> -+#define BLOCKSIZE         blocksize
> - #define BLOCKS_PER_GROUP  8192
> - #define INODES_PER_GROUP  8192
> - /* Percentage of blocks that are reserved.*/
> - #define RESERVED_BLOCKS       5/100
> - #define MAX_RESERVED_BLOCKS  25/100
> - 
> -+/* The default value for s_creator_os. */
> -+#if defined(__linux__)    &&    defined(EXT2_OS_LINUX)
> -+#define CREATOR_OS EXT2_OS_LINUX
> -+#define CREATOR_OS_NAME "linux"
> -+#else
> -+#if defined(__GNU__)     &&     defined(EXT2_OS_HURD)
> -+#define CREATOR_OS EXT2_OS_HURD
> -+#define CREATOR_OS_NAME "hurd"
> -+#else
> -+#if defined(__FreeBSD__) &&     defined(EXT2_OS_FREEBSD)
> -+#define CREATOR_OS EXT2_OS_FREEBSD
> -+#define CREATOR_OS_NAME "freebsd"
> -+#else
> -+#if defined(LITES)         &&   defined(EXT2_OS_LITES)
> -+#define CREATOR_OS EXT2_OS_LITES
> -+#define CREATOR_OS_NAME "lites"
> -+#else
> -+#define CREATOR_OS EXT2_OS_LINUX /* by default */
> -+#define CREATOR_OS_NAME "linux"
> -+#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
> -+#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
> -+#endif /* defined(__GNU__)     && defined(EXT2_OS_HURD) */
> -+#endif /* defined(__linux__)   && defined(EXT2_OS_LINUX) */
> -+
> - 
> - // inode block size (why is it != BLOCKSIZE ?!?)
> - /* The field i_blocks in the ext2 inode stores the number of data blocks
> -@@ -190,6 +225,14 @@
> - #define EXT2_TIND_BLOCK    14                    // triple indirect block
> - #define EXT2_INIT_BLOCK    0xFFFFFFFF            // just initialized (not really a block address)
> - 
> -+// codes for operating systems
> -+
> -+#define EXT2_OS_LINUX           0
> -+#define EXT2_OS_HURD            1
> -+#define EXT2_OS_MASIX           2
> -+#define EXT2_OS_FREEBSD         3
> -+#define EXT2_OS_LITES           4
> -+
> - // end of a block walk
> - 
> - #define WALK_END           0xFFFFFFFE
> -@@ -227,44 +270,46 @@
> - #define FM_IWOTH   0000002	// write
> - #define FM_IXOTH   0000001	// execute
> - 
> --// options
> --
> --#define OP_HOLES     0x01       // make files with holes
> --
> - /* Defines for accessing group details */
> - 
> - // Number of groups in the filesystem
> - #define GRP_NBGROUPS(fs) \
> --	(((fs)->sb.s_blocks_count - fs->sb.s_first_data_block + \
> --	  (fs)->sb.s_blocks_per_group - 1) / (fs)->sb.s_blocks_per_group)
> -+	(((fs)->sb->s_blocks_count - fs->sb->s_first_data_block + \
> -+	  (fs)->sb->s_blocks_per_group - 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) )
> -+#define GRP_GET_GROUP_BBM(fs,grp,bi) (get_blk((fs),(grp)->bg_block_bitmap,(bi)))
> -+#define GRP_PUT_GROUP_BBM(bi) ( put_blk((bi)) )
> - 
> - // 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) )
> --		
> -+#define GRP_GET_GROUP_IBM(fs,grp,bi) (get_blk((fs), (grp)->bg_inode_bitmap,(bi)))
> -+#define GRP_PUT_GROUP_IBM(bi) ( put_blk((bi)) )
> -+
> - // 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)
> -+#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))) )
> -+#define GRP_GET_INODE_BITMAP(fs,nod,bi,gi)				\
> -+	( GRP_GET_GROUP_IBM((fs),get_gd(fs,GRP_GROUP_OF_INODE((fs),(nod)),gi),bi) )
> -+#define GRP_PUT_INODE_BITMAP(bi,gi)		\
> -+	( GRP_PUT_GROUP_IBM((bi)),put_gd((gi)) )
> - 
> - //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 )
> -+	( (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)
> -+#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 get/put the block bitmap that covers it
> -+#define GRP_GET_BLOCK_BITMAP(fs,blk,bi,gi)				\
> -+	( GRP_GET_GROUP_BBM((fs),get_gd(fs,GRP_GROUP_OF_BLOCK((fs),(blk)),(gi)),(bi)) )
> -+#define GRP_PUT_BLOCK_BITMAP(bi,gi)		\
> -+	( GRP_PUT_GROUP_BBM((bi)),put_gd((gi)) )
> - 
> - //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 )
> -+	( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb->s_blocks_per_group )
> - 
> - 
> - // used types
> -@@ -286,7 +331,9 @@
> - // older solaris. Note that this is still not very portable, in that
> - // the return value cannot be trusted.
> - 
> --#if SCANF_CAN_MALLOC
> -+#if 0 // SCANF_CAN_MALLOC
> -+// C99 define "a" for floating point, so you can have runtime surprise
> -+// according the library versions
> - # define SCANF_PREFIX "a"
> - # define SCANF_STRING(s) (&s)
> - #else
> -@@ -430,6 +477,17 @@
> - 			((val<<8)&0xFF0000) | (val<<24));
> - }
> - 
> -+static inline int
> -+is_blk_empty(uint8 *b)
> -+{
> -+	uint32 i;
> -+	uint32 *v = (uint32 *) b;
> -+
> -+	for(i = 0; i < BLOCKSIZE / 4; i++)
> -+		if (*v++)
> -+			return 0;
> -+	return 1;
> -+}
> - 
> - // on-disk structures
> - // this trick makes me declare things only once
> -@@ -460,7 +518,22 @@
> - 	udecl32(s_creator_os)          /* Indicator of which OS created the filesystem */ \
> - 	udecl32(s_rev_level)           /* The revision level of the filesystem */ \
> - 	udecl16(s_def_resuid)          /* The default uid for reserved blocks */ \
> --	udecl16(s_def_resgid)          /* The default gid for reserved blocks */
> -+	udecl16(s_def_resgid)          /* The default gid for reserved blocks */ \
> -+	/* rev 1 version fields start here */ \
> -+	udecl32(s_first_ino) 		/* First non-reserved inode */	\
> -+	udecl16(s_inode_size) 		/* size of inode structure */	\
> -+	udecl16(s_block_group_nr) 	/* block group # of this superblock */ \
> -+	udecl32(s_feature_compat) 	/* compatible feature set */	\
> -+	udecl32(s_feature_incompat) 	/* incompatible feature set */	\
> -+	udecl32(s_feature_ro_compat) 	/* readonly-compatible feature set */ \
> -+	utdecl8(s_uuid,16)		/* 128-bit uuid for volume */	\
> -+	utdecl8(s_volume_name,16) 	/* volume name */		\
> -+	utdecl8(s_last_mounted,64) 	/* directory where last mounted */ \
> -+	udecl32(s_algorithm_usage_bitmap) /* For compression */
> -+
> -+#define EXT2_GOOD_OLD_FIRST_INO	11
> -+#define EXT2_GOOD_OLD_INODE_SIZE 128
> -+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
> - 
> - #define groupdescriptor_decl \
> - 	udecl32(bg_block_bitmap)       /* Block number of the block bitmap */ \
> -@@ -500,6 +573,7 @@
> - 
> - #define decl8(x) int8 x;
> - #define udecl8(x) uint8 x;
> -+#define utdecl8(x,n) uint8 x[n];
> - #define decl16(x) int16 x;
> - #define udecl16(x) uint16 x;
> - #define decl32(x) int32 x;
> -@@ -509,7 +583,7 @@
> - typedef struct
> - {
> - 	superblock_decl
> --	uint32 s_reserved[235];       // Reserved
> -+	uint32 s_reserved[205];       // Reserved
> - } superblock;
> - 
> - typedef struct
> -@@ -527,10 +601,9 @@
> - typedef struct
> - {
> - 	directory_decl
> --	char d_name[0];
> - } directory;
> - 
> --typedef uint8 block[BLOCKSIZE];
> -+typedef uint8 *block;
> - 
> - /* blockwalker fields:
> -    The blockwalker is used to access all the blocks of a file (including
> -@@ -567,23 +640,41 @@
> - 	uint32 bptind;
> - } blockwalker;
> - 
> -+#define HDLINK_CNT   16
> -+struct hdlink_s
> -+{
> -+	uint32	src_inode;
> -+	uint32	dst_nod;
> -+};
> -+
> -+struct hdlinks_s
> -+{
> -+	int32 count;
> -+	struct hdlink_s *hdl;
> -+};
> - 
> - /* Filesystem structure that support groups */
> --#if BLOCKSIZE == 1024
> - typedef struct
> - {
> --	block zero;            // The famous block 0
> --	superblock sb;         // The superblock
> --	groupdescriptor gd[0]; // The group descriptors
> -+	FILE *f;
> -+	superblock *sb;
> -+	int swapit;
> -+	int32 hdlink_cnt;
> -+	struct hdlinks_s hdlinks;
> -+
> -+	int holes;
> -+
> -+	listcache blks;
> -+	listcache gds;
> -+	listcache inodes;
> -+	listcache blkmaps;
> - } filesystem;
> --#else
> --#error UNHANDLED BLOCKSIZE
> --#endif
> - 
> - // now the endianness swap
> - 
> - #undef decl8
> - #undef udecl8
> -+#undef utdecl8
> - #undef decl16
> - #undef udecl16
> - #undef decl32
> -@@ -592,28 +683,13 @@
> - 
> - #define decl8(x)
> - #define udecl8(x)
> -+#define utdecl8(x,n)
> - #define decl16(x) this->x = swab16(this->x);
> - #define udecl16(x) this->x = swab16(this->x);
> - #define decl32(x) this->x = swab32(this->x);
> - #define udecl32(x) this->x = swab32(this->x);
> - #define utdecl32(x,n) { int i; for(i=0; i<n; i++) this->x[i] = swab32(this->x[i]); }
> - 
> --#define HDLINK_CNT   16
> --static int32 hdlink_cnt = HDLINK_CNT;
> --struct hdlink_s
> --{
> --	uint32	src_inode;
> --	uint32	dst_nod;
> --};
> --
> --struct hdlinks_s 
> --{
> --	int32 count;
> --	struct hdlink_s *hdl;
> --};
> --
> --static struct hdlinks_s hdlinks;
> --
> - static void
> - swap_sb(superblock *sb)
> - {
> -@@ -633,9 +709,24 @@
> - static void
> - swap_nod(inode *nod)
> - {
> -+	uint32 nblk;
> -+
> - #define this nod
> - 	inode_decl
> - #undef this
> -+
> -+	// block and character inodes store the major and minor in the
> -+	// i_block, so we need to unswap to get those.  Also, if it's
> -+	// zero iblocks, put the data back like it belongs.
> -+	nblk = nod->i_blocks / INOBLK;
> -+	if ((nod->i_size && !nblk)
> -+	    || ((nod->i_mode & FM_IFBLK) == FM_IFBLK)
> -+	    || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
> -+	{
> -+		int i;
> -+		for(i = 0; i <= EXT2_TIND_BLOCK; i++)
> -+			nod->i_block[i] = swab32(nod->i_block[i]);
> -+	}
> - }
> - 
> - static void
> -@@ -657,6 +748,7 @@
> - 
> - #undef decl8
> - #undef udecl8
> -+#undef utdecl8
> - #undef decl16
> - #undef udecl16
> - #undef decl32
> -@@ -770,15 +862,15 @@
> - }
> - 
> - int
> --is_hardlink(ino_t inode)
> -+is_hardlink(filesystem *fs, ino_t inode)
> - {
> - 	int i;
> - 
> --	for(i = 0; i < hdlinks.count; i++) {
> --		if(hdlinks.hdl[i].src_inode == inode)
> -+	for(i = 0; i < fs->hdlinks.count; i++) {
> -+		if(fs->hdlinks.hdl[i].src_inode == inode)
> - 			return i;
> - 	}
> --	return -1;		
> -+	return -1;
> - }
> - 
> - // printf helper macro
> -@@ -789,6 +881,8 @@
> - get_workblk(void)
> - {
> - 	unsigned char* b=calloc(1,BLOCKSIZE);
> -+	if (!b)
> -+		error_msg_and_die("get_workblk() failed, out of memory");
> - 	return b;
> - }
> - static inline void
> -@@ -811,24 +905,464 @@
> - 	return b[(item-1) / 8] & (1 << ((item-1) % 8));
> - }
> - 
> --// return a given block from a filesystem
> -+// Used by get_blk/put_blk to hold information about a block owned
> -+// by the user.
> -+typedef struct
> -+{
> -+	cache_link link;
> -+
> -+	filesystem *fs;
> -+	uint32 blk;
> -+	uint8 *b;
> -+	uint32 usecount;
> -+} blk_info;
> -+
> -+#define MAX_FREE_CACHE_BLOCKS 100
> -+
> -+static uint32
> -+blk_elem_val(cache_link *elem)
> -+{
> -+	blk_info *bi = container_of(elem, blk_info, link);
> -+	return bi->blk;
> -+}
> -+
> -+static void
> -+blk_freed(cache_link *elem)
> -+{
> -+	blk_info *bi = container_of(elem, blk_info, link);
> -+
> -+	if (fseeko(bi->fs->f, ((off_t) bi->blk) * BLOCKSIZE, SEEK_SET))
> -+		perror_msg_and_die("fseek");
> -+	if (fwrite(bi->b, BLOCKSIZE, 1, bi->fs->f) != 1)
> -+		perror_msg_and_die("get_blk: write");
> -+	free(bi->b);
> -+	free(bi);
> -+}
> -+
> -+// Return a given block from a filesystem.  Make sure to call
> -+// put_blk when you are done with it.
> - static inline uint8 *
> --get_blk(filesystem *fs, uint32 blk)
> -+get_blk(filesystem *fs, uint32 blk, blk_info **rbi)
> - {
> --	return (uint8*)fs + blk*BLOCKSIZE;
> -+	cache_link *curr;
> -+	blk_info *bi;
> -+
> -+	if (blk >= fs->sb->s_blocks_count)
> -+		error_msg_and_die("Internal error, block out of range");
> -+
> -+	curr = cache_find(&fs->blks, blk);
> -+	if (curr) {
> -+		bi = container_of(curr, blk_info, link);
> -+		bi->usecount++;
> -+		goto out;
> -+	}
> -+
> -+	bi = malloc(sizeof(*bi));
> -+	if (!bi)
> -+		error_msg_and_die("get_blk: out of memory");
> -+	bi->fs = fs;
> -+	bi->blk = blk;
> -+	bi->usecount = 1;
> -+	bi->b = malloc(BLOCKSIZE);
> -+	if (!bi->b)
> -+		error_msg_and_die("get_blk: out of memory");
> -+	cache_add(&fs->blks, &bi->link);
> -+	if (fseeko(fs->f, ((off_t) blk) * BLOCKSIZE, SEEK_SET))
> -+		perror_msg_and_die("fseek");
> -+	if (fread(bi->b, BLOCKSIZE, 1, fs->f) != 1) {
> -+		if (ferror(fs->f))
> -+			perror_msg_and_die("fread");
> -+		memset(bi->b, 0, BLOCKSIZE);
> -+	}
> -+
> -+out:
> -+	*rbi = bi;
> -+	return bi->b;
> - }
> - 
> - // return a given inode from a filesystem
> --static inline inode *
> --get_nod(filesystem *fs, uint32 nod)
> -+static inline void
> -+put_blk(blk_info *bi)
> -+{
> -+	if (bi->usecount == 0)
> -+		error_msg_and_die("Internal error: put_blk usecount zero");
> -+	bi->usecount--;
> -+	if (bi->usecount == 0)
> -+		/* Free happens in the cache code */
> -+		cache_item_set_unused(&bi->fs->blks, &bi->link);
> -+}
> -+
> -+typedef struct
> - {
> --	int grp,offset;
> -+	cache_link link;
> -+
> -+	filesystem *fs;
> -+	int gds;
> -+	blk_info *bi;
> -+	groupdescriptor *gd;
> -+	uint32 usecount;
> -+} gd_info;
> -+
> -+#define MAX_FREE_CACHE_GDS 100
> -+
> -+static uint32
> -+gd_elem_val(cache_link *elem)
> -+{
> -+	gd_info *gi = container_of(elem, gd_info, link);
> -+	return gi->gds;
> -+}
> -+
> -+static void
> -+gd_freed(cache_link *elem)
> -+{
> -+	gd_info *gi = container_of(elem, gd_info, link);
> -+
> -+	if (gi->fs->swapit)
> -+		swap_gd(gi->gd);
> -+	put_blk(gi->bi);
> -+	free(gi);
> -+}
> -+
> -+#define GDS_START ((SUPERBLOCK_OFFSET + SUPERBLOCK_SIZE + BLOCKSIZE - 1) / BLOCKSIZE)
> -+#define GDS_PER_BLOCK (BLOCKSIZE / sizeof(groupdescriptor))
> -+// the group descriptors are aligned on the block size
> -+static inline groupdescriptor *
> -+get_gd(filesystem *fs, uint32 no, gd_info **rgi)
> -+{
> -+	uint32 gdblk;
> -+	uint32 offset;
> -+	gd_info *gi;
> -+	cache_link *curr;
> -+
> -+	curr = cache_find(&fs->gds, no);
> -+	if (curr) {
> -+		gi = container_of(curr, gd_info, link);
> -+		gi->usecount++;
> -+		goto out;
> -+	}
> -+
> -+	gi = malloc(sizeof(*gi));
> -+	if (!gi)
> -+		error_msg_and_die("get_gd: out of memory");
> -+	gi->fs = fs;
> -+	gi->gds = no;
> -+	gi->usecount = 1;
> -+	gdblk = GDS_START + (no / GDS_PER_BLOCK);
> -+	offset = no % GDS_PER_BLOCK;
> -+	gi->gd = ((groupdescriptor *) get_blk(fs, gdblk, &gi->bi)) + offset;
> -+	cache_add(&fs->gds, &gi->link);
> -+	if (fs->swapit)
> -+		swap_gd(gi->gd);
> -+ out:
> -+	*rgi = gi;
> -+
> -+	return gi->gd;
> -+}
> -+
> -+static inline void
> -+put_gd(gd_info *gi)
> -+{
> -+	if (gi->usecount == 0)
> -+		error_msg_and_die("Internal error: put_gd usecount zero");
> -+
> -+	gi->usecount--;
> -+	if (gi->usecount == 0)
> -+		/* Free happens in the cache code */
> -+		cache_item_set_unused(&gi->fs->gds, &gi->link);
> -+}
> -+
> -+// Used by get_blkmap/put_blkmap to hold information about an block map
> -+// owned by the user.
> -+typedef struct
> -+{
> -+	cache_link link;
> -+
> -+	filesystem *fs;
> -+	uint32 blk;
> -+	uint8 *b;
> -+	blk_info *bi;
> -+	uint32 usecount;
> -+} blkmap_info;
> -+
> -+#define MAX_FREE_CACHE_BLOCKMAPS 100
> -+
> -+static uint32
> -+blkmap_elem_val(cache_link *elem)
> -+{
> -+	blkmap_info *bmi = container_of(elem, blkmap_info, link);
> -+	return bmi->blk;
> -+}
> -+
> -+static void
> -+blkmap_freed(cache_link *elem)
> -+{
> -+	blkmap_info *bmi = container_of(elem, blkmap_info, link);
> -+
> -+	if (bmi->fs->swapit)
> -+		swap_block(bmi->b);
> -+	put_blk(bmi->bi);
> -+	free(bmi);
> -+}
> -+
> -+// Return a given block map from a filesystem.  Make sure to call
> -+// put_blkmap when you are done with it.
> -+static inline uint32 *
> -+get_blkmap(filesystem *fs, uint32 blk, blkmap_info **rbmi)
> -+{
> -+	blkmap_info *bmi;
> -+	cache_link *curr;
> -+
> -+	curr = cache_find(&fs->blkmaps, blk);
> -+	if (curr) {
> -+		bmi = container_of(curr, blkmap_info, link);
> -+		bmi->usecount++;
> -+		goto out;
> -+	}
> -+
> -+	bmi = malloc(sizeof(*bmi));
> -+	if (!bmi)
> -+		error_msg_and_die("get_blkmap: out of memory");
> -+	bmi->fs = fs;
> -+	bmi->blk = blk;
> -+	bmi->b = get_blk(fs, blk, &bmi->bi);
> -+	bmi->usecount = 1;
> -+	cache_add(&fs->blkmaps, &bmi->link);
> -+
> -+	if (fs->swapit)
> -+		swap_block(bmi->b);
> -+ out:
> -+	*rbmi = bmi;
> -+	return (uint32 *) bmi->b;
> -+}
> -+
> -+static inline void
> -+put_blkmap(blkmap_info *bmi)
> -+{
> -+	if (bmi->usecount == 0)
> -+		error_msg_and_die("Internal error: put_blkmap usecount zero");
> -+
> -+	bmi->usecount--;
> -+	if (bmi->usecount == 0)
> -+		/* Free happens in the cache code */
> -+		cache_item_set_unused(&bmi->fs->blkmaps, &bmi->link);
> -+}
> -+
> -+// Used by get_nod/put_nod to hold information about an inode owned
> -+// by the user.
> -+typedef struct
> -+{
> -+	cache_link link;
> -+
> -+	filesystem *fs;
> -+	uint32 nod;
> -+	uint8 *b;
> -+	blk_info *bi;
> - 	inode *itab;
> -+	uint32 usecount;
> -+} nod_info;
> -+
> -+#define MAX_FREE_CACHE_INODES 100
> -+
> -+static uint32
> -+inode_elem_val(cache_link *elem)
> -+{
> -+	nod_info *ni = container_of(elem, nod_info, link);
> -+	return ni->nod;
> -+}
> -+
> -+static void
> -+inode_freed(cache_link *elem)
> -+{
> -+	nod_info *ni = container_of(elem, nod_info, link);
> -+
> -+	if (ni->fs->swapit)
> -+		swap_nod(ni->itab);
> -+	put_blk(ni->bi);
> -+	free(ni);
> -+}
> -+
> -+#define INODES_PER_BLOCK (BLOCKSIZE / sizeof(inode))
> - 
> --	offset = GRP_IBM_OFFSET(fs,nod);
> -+// return a given inode from a filesystem
> -+static inline inode *
> -+get_nod(filesystem *fs, uint32 nod, nod_info **rni)
> -+{
> -+	uint32 grp, boffset, offset;
> -+	cache_link *curr;
> -+	groupdescriptor *gd;
> -+	gd_info *gi;
> -+	nod_info *ni;
> -+
> -+	curr = cache_find(&fs->inodes, nod);
> -+	if (curr) {
> -+		ni = container_of(curr, nod_info, link);
> -+		ni->usecount++;
> -+		goto out;
> -+	}
> -+
> -+	ni = malloc(sizeof(*ni));
> -+	if (!ni)
> -+		error_msg_and_die("get_nod: out of memory");
> -+	ni->fs = fs;
> -+	ni->nod = nod;
> -+	ni->usecount = 1;
> -+	cache_add(&fs->inodes, &ni->link);
> -+
> -+	offset = GRP_IBM_OFFSET(fs,nod) - 1;
> -+	boffset = offset / INODES_PER_BLOCK;
> -+	offset %= INODES_PER_BLOCK;
> - 	grp = GRP_GROUP_OF_INODE(fs,nod);
> --	itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table);
> --	return itab+offset-1;
> -+	gd = get_gd(fs, grp, &gi);
> -+	ni->b = get_blk(fs, gd->bg_inode_table + boffset, &ni->bi);
> -+	ni->itab = ((inode *) ni->b) + offset;
> -+	if (fs->swapit)
> -+		swap_nod(ni->itab);
> -+	put_gd(gi);
> -+ out:
> -+	*rni = ni;
> -+	return ni->itab;
> -+}
> -+
> -+static inline void
> -+put_nod(nod_info *ni)
> -+{
> -+	if (ni->usecount == 0)
> -+		error_msg_and_die("Internal error: put_nod usecount zero");
> -+
> -+	ni->usecount--;
> -+	if (ni->usecount == 0)
> -+		/* Free happens in the cache code */
> -+		cache_item_set_unused(&ni->fs->inodes, &ni->link);
> -+}
> -+
> -+// Used to hold state information while walking a directory inode.
> -+typedef struct
> -+{
> -+	directory d;
> -+	filesystem *fs;
> -+	uint32 nod;
> -+	directory *last_d;
> -+	uint8 *b;
> -+	blk_info *bi;
> -+} dirwalker;
> -+
> -+// Start a directory walk on the given inode.  You must pass in a
> -+// dirwalker structure, then use that dirwalker for future operations.
> -+// Call put_dir when you are done walking the directory.
> -+static inline directory *
> -+get_dir(filesystem *fs, uint32 nod, dirwalker *dw)
> -+{
> -+	dw->fs = fs;
> -+	dw->b = get_blk(fs, nod, &dw->bi);
> -+	dw->nod = nod;
> -+	dw->last_d = (directory *) dw->b;
> -+
> -+	memcpy(&dw->d, dw->last_d, sizeof(directory));
> -+	if (fs->swapit)
> -+		swap_dir(&dw->d);
> -+	return &dw->d;
> -+}
> -+
> -+// Move to the next directory.
> -+static inline directory *
> -+next_dir(dirwalker *dw)
> -+{
> -+	directory *next_d = (directory *)((int8*)dw->last_d + dw->d.d_rec_len);
> -+
> -+	if (dw->fs->swapit)
> -+		swap_dir(&dw->d);
> -+	memcpy(dw->last_d, &dw->d, sizeof(directory));
> -+
> -+	if (((int8 *) next_d) >= ((int8 *) dw->b + BLOCKSIZE))
> -+		return NULL;
> -+
> -+	dw->last_d = next_d;
> -+	memcpy(&dw->d, next_d, sizeof(directory));
> -+	if (dw->fs->swapit)
> -+		swap_dir(&dw->d);
> -+	return &dw->d;
> -+}
> -+
> -+// Call then when you are done with the directory walk.
> -+static inline void
> -+put_dir(dirwalker *dw)
> -+{
> -+	if (dw->fs->swapit)
> -+		swap_dir(&dw->d);
> -+	memcpy(dw->last_d, &dw->d, sizeof(directory));
> -+
> -+	if (dw->nod == 0)
> -+		free_workblk(dw->b);
> -+	else
> -+		put_blk(dw->bi);
> -+}
> -+
> -+// Create a new directory block with the given inode as it's destination
> -+// and append it to the current dirwalker.
> -+static directory *
> -+new_dir(filesystem *fs, uint32 dnod, const char *name, int nlen, dirwalker *dw)
> -+{
> -+	directory *d;
> -+
> -+	dw->fs = fs;
> -+	dw->b = get_workblk();
> -+	dw->nod = 0;
> -+	dw->last_d = (directory *) dw->b;
> -+	d = &dw->d;
> -+	d->d_inode = dnod;
> -+	d->d_rec_len = BLOCKSIZE;
> -+	d->d_name_len = nlen;
> -+	strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
> -+	return d;
> -+}
> -+
> -+// Shrink the current directory entry, make a new one with the free
> -+// space, and return the new directory entry (making it current).
> -+static inline directory *
> -+shrink_dir(dirwalker *dw, uint32 nod, const char *name, int nlen)
> -+{
> -+	int reclen, preclen;
> -+	directory *d = &dw->d;
> -+
> -+	reclen = d->d_rec_len;
> -+	d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4);
> -+	preclen = d->d_rec_len;
> -+	reclen -= preclen;
> -+	if (dw->fs->swapit)
> -+		swap_dir(&dw->d);
> -+	memcpy(dw->last_d, &dw->d, sizeof(directory));
> -+
> -+	dw->last_d = (directory *) (((int8 *) dw->last_d) + preclen);
> -+	d->d_rec_len = reclen;
> -+	d->d_inode = nod;
> -+	d->d_name_len = nlen;
> -+	strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
> -+
> -+	return d;
> -+}
> -+
> -+// Return the current block the directory is walking
> -+static inline uint8 *
> -+dir_data(dirwalker *dw)
> -+{
> -+	return dw->b;
> -+}
> -+
> -+// Return the pointer to the name for the current directory
> -+static inline char *
> -+dir_name(dirwalker *dw)
> -+{
> -+	return ((char *) dw->last_d) + sizeof(directory);
> -+}
> -+
> -+// Set the name for the current directory.  Note that this doesn't
> -+// verify that there is space for the directory name, you must do
> -+// that yourself.
> -+static void
> -+dir_set_name(dirwalker *dw, const char *name, int nlen)
> -+{
> -+	dw->d.d_name_len = nlen;
> -+	strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
> - }
> - 
> - // allocate a given block/inode in the bitmap
> -@@ -870,21 +1404,34 @@
> - {
> - 	uint32 bk=0;
> - 	uint32 grp,nbgroups;
> -+	blk_info *bi;
> -+	groupdescriptor *gd;
> -+	gd_info *gi;
> - 
> - 	grp = GRP_GROUP_OF_INODE(fs,nod);
> - 	nbgroups = GRP_NBGROUPS(fs);
> --	if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) {
> --		for(grp=0;grp<nbgroups && !bk;grp++)
> --			bk=allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap),0);
> -+	gd = get_gd(fs, grp, &gi);
> -+	bk = allocate(GRP_GET_GROUP_BBM(fs, gd, &bi), 0);
> -+	GRP_PUT_GROUP_BBM(bi);
> -+	put_gd(gi);
> -+	if (!bk) {
> -+		for (grp=0; grp<nbgroups && !bk; grp++) {
> -+			gd = get_gd(fs, grp, &gi);
> -+			bk = allocate(GRP_GET_GROUP_BBM(fs, gd, &bi), 0);
> -+			GRP_PUT_GROUP_BBM(bi);
> -+			put_gd(gi);
> -+		}
> - 		grp--;
> - 	}
> - 	if (!bk)
> - 		error_msg_and_die("couldn't allocate a block (no free space)");
> --	if(!(fs->gd[grp].bg_free_blocks_count--))
> -+	gd = get_gd(fs, grp, &gi);
> -+	if(!(gd->bg_free_blocks_count--))
> - 		error_msg_and_die("group descr %d. free blocks count == 0 (corrupted fs?)",grp);
> --	if(!(fs->sb.s_free_blocks_count--))
> -+	put_gd(gi);
> -+	if(!(fs->sb->s_free_blocks_count--))
> - 		error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
> --	return fs->sb.s_blocks_per_group*grp + bk;
> -+	return fs->sb->s_first_data_block + fs->sb->s_blocks_per_group*grp + (bk-1);
> - }
> - 
> - // free a block
> -@@ -892,12 +1439,18 @@
> - free_blk(filesystem *fs, uint32 bk)
> - {
> - 	uint32 grp;
> --
> --	grp = bk / fs->sb.s_blocks_per_group;
> --	bk %= fs->sb.s_blocks_per_group;
> --	deallocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), bk);
> --	fs->gd[grp].bg_free_blocks_count++;
> --	fs->sb.s_free_blocks_count++;
> -+	blk_info *bi;
> -+	gd_info *gi;
> -+	groupdescriptor *gd;
> -+
> -+	grp = bk / fs->sb->s_blocks_per_group;
> -+	bk %= fs->sb->s_blocks_per_group;
> -+	gd = get_gd(fs, grp, &gi);
> -+	deallocate(GRP_GET_GROUP_BBM(fs, gd, &bi), bk);
> -+	GRP_PUT_GROUP_BBM(bi);
> -+	gd->bg_free_blocks_count++;
> -+	put_gd(gi);
> -+	fs->sb->s_free_blocks_count++;
> - }
> - 
> - // allocate an inode
> -@@ -906,6 +1459,9 @@
> - {
> - 	uint32 nod,best_group=0;
> - 	uint32 grp,nbgroups,avefreei;
> -+	blk_info *bi;
> -+	gd_info *gi, *bestgi;
> -+	groupdescriptor *gd, *bestgd;
> - 
> - 	nbgroups = GRP_NBGROUPS(fs);
> - 
> -@@ -914,22 +1470,32 @@
> - 	/* 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;
> -+	avefreei  =  fs->sb->s_free_inodes_count / nbgroups;
> -+	bestgd = get_gd(fs, best_group, &bestgi);
> - 	for(grp=0; grp<nbgroups; grp++) {
> --		if (fs->gd[grp].bg_free_inodes_count < avefreei ||
> --		    fs->gd[grp].bg_free_inodes_count == 0)
> -+		gd = get_gd(fs, grp, &gi);
> -+		if (gd->bg_free_inodes_count < avefreei ||
> -+		    gd->bg_free_inodes_count == 0) {
> -+			put_gd(gi);
> - 			continue;
> --		if (!best_group || 
> --			fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count)
> -+		}
> -+		if (!best_group || gd->bg_free_blocks_count > bestgd->bg_free_blocks_count) {
> -+			put_gd(bestgi);
> - 			best_group = grp;
> -+			bestgd = gd;
> -+			bestgi = gi;
> -+		} else
> -+			put_gd(gi);
> - 	}
> --	if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0)))
> -+	if (!(nod = allocate(GRP_GET_GROUP_IBM(fs, bestgd, &bi), 0)))
> - 		error_msg_and_die("couldn't allocate an inode (no free inode)");
> --	if(!(fs->gd[best_group].bg_free_inodes_count--))
> -+	GRP_PUT_GROUP_IBM(bi);
> -+	if(!(bestgd->bg_free_inodes_count--))
> - 		error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
> --	if(!(fs->sb.s_free_inodes_count--))
> -+	put_gd(bestgi);
> -+	if(!(fs->sb->s_free_inodes_count--))
> - 		error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
> --	return fs->sb.s_inodes_per_group*best_group+nod;
> -+	return fs->sb->s_inodes_per_group*best_group+nod;
> - }
> - 
> - // print a bitmap allocation
> -@@ -962,30 +1528,40 @@
> - //				  used after being freed, so once you start
> - //				  freeing blocks don't stop until the end of
> - //				  the file. moreover, i_blocks isn't updated.
> --//				  in fact, don't do that, just use extend_blk
> - // if hole!=0, create a hole in the file
> - static uint32
> - walk_bw(filesystem *fs, uint32 nod, blockwalker *bw, int32 *create, uint32 hole)
> - {
> - 	uint32 *bkref = 0;
> -+	uint32 bk = 0;
> -+	blkmap_info *bmi1 = NULL, *bmi2 = NULL, *bmi3 = NULL;
> - 	uint32 *b;
> - 	int extend = 0, reduce = 0;
> -+	inode *inod;
> -+	nod_info *ni;
> -+	uint32 *iblk;
> -+
> - 	if(create && (*create) < 0)
> - 		reduce = 1;
> --	if(bw->bnum >= get_nod(fs, nod)->i_blocks / INOBLK)
> -+	inod = get_nod(fs, nod, &ni);
> -+	if(bw->bnum >= inod->i_blocks / INOBLK)
> - 	{
> - 		if(create && (*create) > 0)
> - 		{
> - 			(*create)--;
> - 			extend = 1;
> - 		}
> --		else	
> -+		else
> -+		{
> -+			put_nod(ni);
> - 			return WALK_END;
> -+		}
> - 	}
> -+	iblk = inod->i_block;
> - 	// first direct block
> - 	if(bw->bpdir == EXT2_INIT_BLOCK)
> - 	{
> --		bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0];
> -+		bkref = &iblk[bw->bpdir = 0];
> - 		if(extend) // allocate first block
> - 			*bkref = hole ? 0 : alloc_blk(fs,nod);
> - 		if(reduce) // free first block
> -@@ -994,7 +1570,7 @@
> - 	// direct block
> - 	else if(bw->bpdir < EXT2_NDIR_BLOCKS)
> - 	{
> --		bkref = &get_nod(fs, nod)->i_block[++bw->bpdir];
> -+		bkref = &iblk[++bw->bpdir];
> - 		if(extend) // allocate block
> - 			*bkref = hole ? 0 : alloc_blk(fs,nod);
> - 		if(reduce) // free block
> -@@ -1007,10 +1583,10 @@
> - 		bw->bpdir = EXT2_IND_BLOCK;
> - 		bw->bpind = 0;
> - 		if(extend) // allocate indirect block
> --			get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
> -+			iblk[bw->bpdir] = alloc_blk(fs,nod);
> - 		if(reduce) // free indirect block
> --			free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
> --		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
> -+			free_blk(fs, iblk[bw->bpdir]);
> -+		b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
> - 		bkref = &b[bw->bpind];
> - 		if(extend) // allocate first block
> - 			*bkref = hole ? 0 : alloc_blk(fs,nod);
> -@@ -1021,7 +1597,7 @@
> - 	else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
> - 	{
> - 		bw->bpind++;
> --		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
> -+		b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
> - 		bkref = &b[bw->bpind];
> - 		if(extend) // allocate block
> - 			*bkref = hole ? 0 : alloc_blk(fs,nod);
> -@@ -1036,15 +1612,15 @@
> - 		bw->bpind = 0;
> - 		bw->bpdind = 0;
> - 		if(extend) // allocate double indirect block
> --			get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
> -+			iblk[bw->bpdir] = alloc_blk(fs,nod);
> - 		if(reduce) // free double indirect block
> --			free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
> --		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
> -+			free_blk(fs, iblk[bw->bpdir]);
> -+		b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
> - 		if(extend) // allocate first indirect block
> - 			b[bw->bpind] = alloc_blk(fs,nod);
> - 		if(reduce) // free  firstindirect block
> - 			free_blk(fs, b[bw->bpind]);
> --		b = (uint32*)get_blk(fs, b[bw->bpind]);
> -+		b = get_blkmap(fs, b[bw->bpind], &bmi2);
> - 		bkref = &b[bw->bpdind];
> - 		if(extend) // allocate first block
> - 			*bkref = hole ? 0 : alloc_blk(fs,nod);
> -@@ -1055,8 +1631,8 @@
> - 	else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1))
> - 	{
> - 		bw->bpdind++;
> --		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
> --		b = (uint32*)get_blk(fs, b[bw->bpind]);
> -+		b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
> -+		b = get_blkmap(fs, b[bw->bpind], &bmi2);
> - 		bkref = &b[bw->bpdind];
> - 		if(extend) // allocate block
> - 			*bkref = hole ? 0 : alloc_blk(fs,nod);
> -@@ -1069,12 +1645,12 @@
> - 		bw->bnum++;
> - 		bw->bpdind = 0;
> - 		bw->bpind++;
> --		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
> -+		b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
> - 		if(extend) // allocate indirect block
> - 			b[bw->bpind] = alloc_blk(fs,nod);
> - 		if(reduce) // free indirect block
> - 			free_blk(fs, b[bw->bpind]);
> --		b = (uint32*)get_blk(fs, b[bw->bpind]);
> -+		b = get_blkmap(fs, b[bw->bpind], &bmi2);
> - 		bkref = &b[bw->bpdind];
> - 		if(extend) // allocate first block
> - 			*bkref = hole ? 0 : alloc_blk(fs,nod);
> -@@ -1094,20 +1670,20 @@
> - 		bw->bpdind = 0;
> - 		bw->bptind = 0;
> - 		if(extend) // allocate triple indirect block
> --			get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
> -+			iblk[bw->bpdir] = alloc_blk(fs,nod);
> - 		if(reduce) // free triple indirect block
> --			free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
> --		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
> -+			free_blk(fs, iblk[bw->bpdir]);
> -+		b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
> - 		if(extend) // allocate first double indirect block
> - 			b[bw->bpind] = alloc_blk(fs,nod);
> - 		if(reduce) // free first double indirect block
> - 			free_blk(fs, b[bw->bpind]);
> --		b = (uint32*)get_blk(fs, b[bw->bpind]);
> -+		b = get_blkmap(fs, b[bw->bpind], &bmi2);
> - 		if(extend) // allocate first indirect block
> - 			b[bw->bpdind] = alloc_blk(fs,nod);
> - 		if(reduce) // free first indirect block
> - 			free_blk(fs, b[bw->bpind]);
> --		b = (uint32*)get_blk(fs, b[bw->bpdind]);
> -+		b = get_blkmap(fs, b[bw->bpdind], &bmi3);
> - 		bkref = &b[bw->bptind];
> - 		if(extend) // allocate first data block
> - 			*bkref = hole ? 0 : alloc_blk(fs,nod);
> -@@ -1121,9 +1697,9 @@
> - 		  (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]);
> -+		b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
> -+		b = get_blkmap(fs, b[bw->bpind], &bmi2);
> -+		b = get_blkmap(fs, b[bw->bpdind], &bmi3);
> - 		bkref = &b[bw->bptind];
> - 		if(extend) // allocate data block
> - 			*bkref = hole ? 0 : alloc_blk(fs,nod);
> -@@ -1140,13 +1716,13 @@
> - 		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]);
> -+		b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
> -+		b = get_blkmap(fs, b[bw->bpind], &bmi2);
> - 		if(extend) // allocate single indirect block
> - 			b[bw->bpdind] = alloc_blk(fs,nod);
> - 		if(reduce) // free indirect block
> - 			free_blk(fs, b[bw->bpind]);
> --		b = (uint32*)get_blk(fs, b[bw->bpdind]);
> -+		b = get_blkmap(fs, b[bw->bpdind], &bmi3);
> - 		bkref = &b[bw->bptind];
> - 		if(extend) // allocate first data block
> - 			*bkref = hole ? 0 : alloc_blk(fs,nod);
> -@@ -1163,17 +1739,17 @@
> - 		bw->bpdind = 0;
> - 		bw->bptind = 0;
> - 		bw->bpind++;
> --		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
> -+		b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
> - 		if(extend) // allocate double indirect block
> - 			b[bw->bpind] = alloc_blk(fs,nod);
> - 		if(reduce) // free double indirect block
> - 			free_blk(fs, b[bw->bpind]);
> --		b = (uint32*)get_blk(fs, b[bw->bpind]);
> -+		b = get_blkmap(fs, b[bw->bpind], &bmi2);
> - 		if(extend) // allocate single indirect block
> - 			b[bw->bpdind] = alloc_blk(fs,nod);
> - 		if(reduce) // free indirect block
> - 			free_blk(fs, b[bw->bpind]);
> --		b = (uint32*)get_blk(fs, b[bw->bpdind]);
> -+		b = get_blkmap(fs, b[bw->bpdind], &bmi3);
> - 		bkref = &b[bw->bptind];
> - 		if(extend) // allocate first block
> - 			*bkref = hole ? 0 : alloc_blk(fs,nod);
> -@@ -1184,56 +1760,105 @@
> - 		error_msg_and_die("file too big !"); 
> - 	/* End change for walking triple indirection */
> - 
> --	if(*bkref)
> --	{
> -+	bk = *bkref;
> -+	if (bmi3)
> -+		put_blkmap(bmi3);
> -+	if (bmi2)
> -+		put_blkmap(bmi2);
> -+	if (bmi1)
> -+		put_blkmap(bmi1);
> -+
> -+	if(bk)
> -+	{
> -+		blk_info *bi;
> -+		gd_info *gi;
> -+		uint8 *block;
> - 		bw->bnum++;
> --		if(!reduce && !allocated(GRP_GET_BLOCK_BITMAP(fs,*bkref), GRP_BBM_OFFSET(fs,*bkref)))
> --			error_msg_and_die("[block %d of inode %d is unallocated !]", *bkref, nod);
> -+		block = GRP_GET_BLOCK_BITMAP(fs,bk,&bi,&gi);
> -+		if(!reduce && !allocated(block, GRP_BBM_OFFSET(fs,bk)))
> -+			error_msg_and_die("[block %d of inode %d is unallocated !]", bk, nod);
> -+		GRP_PUT_BLOCK_BITMAP(bi, gi);
> - 	}
> - 	if(extend)
> --		get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK;
> --	return *bkref;
> -+		inod->i_blocks = bw->bnum * INOBLK;
> -+	put_nod(ni);
> -+	return bk;
> - }
> - 
> --// add blocks to an inode (file/dir/etc...)
> --static void
> --extend_blk(filesystem *fs, uint32 nod, block b, int amount)
> -+typedef struct
> - {
> --	int create = amount;
> --	blockwalker bw, lbw;
> --	uint32 bk;
> --	init_bw(&bw);
> --	if(amount < 0)
> --	{
> --		uint32 i;
> --		for(i = 0; i < get_nod(fs, nod)->i_blocks / INOBLK + amount; i++)
> --			walk_bw(fs, nod, &bw, 0, 0);
> --		while(walk_bw(fs, nod, &bw, &create, 0) != WALK_END)
> -+	blockwalker bw;
> -+	uint32 nod;
> -+	nod_info *ni;
> -+	inode *inod;
> -+} inode_pos;
> -+#define INODE_POS_TRUNCATE 0
> -+#define INODE_POS_EXTEND 1
> -+
> -+// Call this to set up an ipos structure for future use with
> -+// extend_inode_blk to append blocks to the given inode.  If
> -+// op is INODE_POS_TRUNCATE, the inode is truncated to zero size.
> -+// If op is INODE_POS_EXTEND, the position is moved to the end
> -+// of the inode's data blocks.
> -+// Call inode_pos_finish when done with the inode_pos structure.
> -+static void
> -+inode_pos_init(filesystem *fs, inode_pos *ipos, uint32 nod, int op,
> -+	       blockwalker *endbw)
> -+{
> -+	blockwalker lbw;
> -+
> -+	init_bw(&ipos->bw);
> -+	ipos->nod = nod;
> -+	ipos->inod = get_nod(fs, nod, &ipos->ni);
> -+	if (op == INODE_POS_TRUNCATE) {
> -+		int32 create = -1;
> -+		while(walk_bw(fs, nod, &ipos->bw, &create, 0) != WALK_END)
> - 			/*nop*/;
> --		get_nod(fs, nod)->i_blocks += amount * INOBLK;
> -+		ipos->inod->i_blocks = 0;
> - 	}
> --	else
> -+
> -+	if (endbw)
> -+		ipos->bw = *endbw;
> -+	else {
> -+		/* Seek to the end */
> -+		init_bw(&ipos->bw);
> -+		lbw = ipos->bw;
> -+		while(walk_bw(fs, nod, &ipos->bw, 0, 0) != WALK_END)
> -+			lbw = ipos->bw;
> -+		ipos->bw = lbw;
> -+	}
> -+}
> -+
> -+// Clean up the inode_pos structure.
> -+static void
> -+inode_pos_finish(filesystem *fs, inode_pos *ipos)
> -+{
> -+	put_nod(ipos->ni);
> -+}
> -+
> -+// add blocks to an inode (file/dir/etc...) at the given position.
> -+// This will only work when appending to the end of an inode.
> -+static void
> -+extend_inode_blk(filesystem *fs, inode_pos *ipos, block b, int amount)
> -+{
> -+	uint32 bk;
> -+	uint32 pos;
> -+
> -+	if (amount < 0)
> -+		error_msg_and_die("extend_inode_blk: Got negative amount");
> -+
> -+	for (pos = 0; amount; pos += BLOCKSIZE)
> - 	{
> --		lbw = bw;
> --		while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
> --			lbw = bw;
> --		bw = lbw;
> --		while(create)
> --		{
> --			int i, copyb = 0;
> --			if(!(fs->sb.s_reserved[200] & OP_HOLES))
> --				copyb = 1;
> --			else
> --				for(i = 0; i < BLOCKSIZE / 4; i++)
> --					if(((int32*)(b + BLOCKSIZE * (amount - create)))[i])
> --					{
> --						copyb = 1;
> --						break;
> --					}
> --			if((bk = walk_bw(fs, nod, &bw, &create, !copyb)) == WALK_END)
> --				break;
> --			if(copyb)
> --				memcpy(get_blk(fs, bk), b + BLOCKSIZE * (amount - create - 1), BLOCKSIZE);
> -+		int hole = (fs->holes && is_blk_empty(b + pos));
> -+
> -+		bk = walk_bw(fs, ipos->nod, &ipos->bw, &amount, hole);
> -+		if (bk == WALK_END)
> -+			error_msg_and_die("extend_inode_blk: extend failed");
> -+		if (!hole) {
> -+			blk_info *bi;
> -+			uint8 *block = get_blk(fs, bk, &bi);
> -+			memcpy(block, b + pos, BLOCKSIZE);
> -+			put_blk(bi);
> - 		}
> - 	}
> - }
> -@@ -1242,15 +1867,17 @@
> - static void
> - add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name)
> - {
> --	blockwalker bw;
> -+	blockwalker bw, lbw;
> - 	uint32 bk;
> --	uint8 *b;
> - 	directory *d;
> -+	dirwalker dw;
> - 	int reclen, nlen;
> - 	inode *node;
> - 	inode *pnode;
> -+	nod_info *dni, *ni;
> -+	inode_pos ipos;
> - 
> --	pnode = get_nod(fs, dnod);
> -+	pnode = get_nod(fs, dnod, &dni);
> - 	if((pnode->i_mode & FM_IFMT) != FM_IFDIR)
> - 		error_msg_and_die("can't add '%s' to a non-directory", name);
> - 	if(!*name)
> -@@ -1262,52 +1889,52 @@
> - 	if(reclen > BLOCKSIZE)
> - 		error_msg_and_die("bad name '%s' (too long)", name);
> - 	init_bw(&bw);
> -+	lbw = bw;
> - 	while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir
> - 	{
> --		b = get_blk(fs, bk);
> - 		// for all dir entries in block
> --		for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
> -+		for(d = get_dir(fs, bk, &dw); d; d = next_dir(&dw))
> - 		{
> - 			// if empty dir entry, large enough, use it
> - 			if((!d->d_inode) && (d->d_rec_len >= reclen))
> - 			{
> - 				d->d_inode = nod;
> --				node = get_nod(fs, nod);
> -+				node = get_nod(fs, nod, &ni);
> -+				dir_set_name(&dw, name, nlen);
> -+				put_dir(&dw);
> - 				node->i_links_count++;
> --				d->d_name_len = nlen;
> --				strncpy(d->d_name, name, nlen);
> --				return;
> -+				put_nod(ni);
> -+				goto out;
> - 			}
> - 			// if entry with enough room (last one?), shrink it & use it
> - 			if(d->d_rec_len >= (sizeof(directory) + rndup(d->d_name_len, 4) + reclen))
> - 			{
> --				reclen = d->d_rec_len;
> --				d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4);
> --				reclen -= d->d_rec_len;
> --				d = (directory*) (((int8*)d) + d->d_rec_len);
> --				d->d_rec_len = reclen;
> --				d->d_inode = nod;
> --				node = get_nod(fs, nod);
> -+				d = shrink_dir(&dw, nod, name, nlen);
> -+				put_dir(&dw);
> -+				node = get_nod(fs, nod, &ni);
> - 				node->i_links_count++;
> --				d->d_name_len = nlen;
> --				strncpy(d->d_name, name, nlen);
> --				return;
> -+				put_nod(ni);
> -+				goto out;
> - 			}
> - 		}
> -+		put_dir(&dw);
> -+		lbw = bw;
> - 	}
> - 	// we found no free entry in the directory, so we add a block
> --	if(!(b = get_workblk()))
> --		error_msg_and_die("get_workblk() failed.");
> --	d = (directory*)b;
> --	d->d_inode = nod;
> --	node = get_nod(fs, nod);
> -+	node = get_nod(fs, nod, &ni);
> -+	d = new_dir(fs, nod, name, nlen, &dw);
> - 	node->i_links_count++;
> --	d->d_rec_len = BLOCKSIZE;
> --	d->d_name_len = nlen;
> --	strncpy(d->d_name, name, nlen);
> --	extend_blk(fs, dnod, b, 1);
> --	get_nod(fs, dnod)->i_size += BLOCKSIZE;
> --	free_workblk(b);
> -+	put_nod(ni);
> -+	next_dir(&dw); // Force the data into the buffer
> -+
> -+	inode_pos_init(fs, &ipos, dnod, INODE_POS_EXTEND, &lbw);
> -+	extend_inode_blk(fs, &ipos, dir_data(&dw), 1);
> -+	inode_pos_finish(fs, &ipos);
> -+
> -+	put_dir(&dw);
> -+	pnode->i_size += BLOCKSIZE;
> -+out:
> -+	put_nod(dni);
> - }
> - 
> - // find an entry in a directory
> -@@ -1321,11 +1948,13 @@
> - 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
> - 	{
> - 		directory *d;
> --		uint8 *b;
> --		b = get_blk(fs, bk);
> --		for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
> --			if(d->d_inode && (nlen == d->d_name_len) && !strncmp(d->d_name, name, nlen))
> -+		dirwalker dw;
> -+		for (d = get_dir(fs, bk, &dw); d; d=next_dir(&dw))
> -+			if(d->d_inode && (nlen == d->d_name_len) && !strncmp(dir_name(&dw), name, nlen)) {
> -+				put_dir(&dw);
> - 				return d->d_inode;
> -+			}
> -+		put_dir(&dw);
> - 	}
> - 	return 0;
> - }
> -@@ -1356,47 +1985,55 @@
> - 	return nod;
> - }
> - 
> -+// chmod an inode
> -+void
> -+chmod_fs(filesystem *fs, uint32 nod, uint16 mode, uint16 uid, uint16 gid)
> -+{
> -+	inode *node;
> -+	nod_info *ni;
> -+	node = get_nod(fs, nod, &ni);
> -+	node->i_mode = (node->i_mode & ~FM_IMASK) | (mode & FM_IMASK);
> -+	node->i_uid = uid;
> -+	node->i_gid = gid;
> -+	put_nod(ni);
> -+}
> -+
> - // create a simple inode
> - static uint32
> - mknod_fs(filesystem *fs, uint32 parent_nod, const char *name, uint16 mode, uint16 uid, uint16 gid, uint8 major, uint8 minor, uint32 ctime, uint32 mtime)
> - {
> - 	uint32 nod;
> - 	inode *node;
> --	if((nod = find_dir(fs, parent_nod, name)))
> --	{
> --		node = get_nod(fs, nod);
> --		if((node->i_mode & FM_IFMT) != (mode & FM_IFMT))
> --			error_msg_and_die("node '%s' already exists and isn't of the same type", name);
> --		node->i_mode = mode;
> --	}
> --	else
> -+	nod_info *ni;
> -+	gd_info *gi;
> -+
> -+	nod = alloc_nod(fs);
> -+	node = get_nod(fs, nod, &ni);
> -+	node->i_mode = mode;
> -+	add2dir(fs, parent_nod, nod, name);
> -+	switch(mode & FM_IFMT)
> - 	{
> --		nod = alloc_nod(fs);
> --		node = get_nod(fs, nod);
> --		node->i_mode = mode;
> --		add2dir(fs, parent_nod, nod, name);
> --		switch(mode & FM_IFMT)
> --		{
> --			case FM_IFLNK:
> --				mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
> --				break;
> --			case FM_IFBLK:
> --			case FM_IFCHR:
> --				((uint8*)get_nod(fs, nod)->i_block)[0] = minor;
> --				((uint8*)get_nod(fs, nod)->i_block)[1] = major;
> --				break;
> --			case FM_IFDIR:
> --				add2dir(fs, nod, nod, ".");
> --				add2dir(fs, nod, parent_nod, "..");
> --				fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++;
> --				break;
> --		}
> -+	case FM_IFLNK:
> -+		mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
> -+		break;
> -+	case FM_IFBLK:
> -+	case FM_IFCHR:
> -+		((uint8*)node->i_block)[0] = minor;
> -+		((uint8*)node->i_block)[1] = major;
> -+		break;
> -+	case FM_IFDIR:
> -+		add2dir(fs, nod, nod, ".");
> -+		add2dir(fs, nod, parent_nod, "..");
> -+		get_gd(fs,GRP_GROUP_OF_INODE(fs,nod),&gi)->bg_used_dirs_count++;
> -+		put_gd(gi);
> -+		break;
> - 	}
> - 	node->i_uid = uid;
> - 	node->i_gid = gid;
> - 	node->i_atime = mtime;
> - 	node->i_ctime = ctime;
> - 	node->i_mtime = mtime;
> -+	put_nod(ni);
> - 	return nod;
> - }
> - 
> -@@ -1413,33 +2050,73 @@
> - 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)
> - {
> - 	uint32 nod = mknod_fs(fs, parent_nod, name, FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO, uid, gid, 0, 0, ctime, mtime);
> --	extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
> --	get_nod(fs, nod)->i_size = size;
> --	if(size <= 4 * (EXT2_TIND_BLOCK+1))
> --	{
> --		strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size);
> -+	nod_info *ni;
> -+	inode *node = get_nod(fs, nod, &ni);
> -+	inode_pos ipos;
> -+
> -+	inode_pos_init(fs, &ipos, nod, INODE_POS_TRUNCATE, NULL);
> -+	node->i_size = size;
> -+	if(size < 4 * (EXT2_TIND_BLOCK+1))
> -+	{
> -+		strncpy((char*)node->i_block, (char*)b, size);
> -+		((char*)node->i_block)[size+1] = '\0';
> -+		inode_pos_finish(fs, &ipos);
> -+		put_nod(ni);
> - 		return nod;
> - 	}
> --	extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
> -+	extend_inode_blk(fs, &ipos, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
> -+	inode_pos_finish(fs, &ipos);
> -+	put_nod(ni);
> - 	return nod;
> - }
> - 
> -+static void
> -+fs_upgrade_rev1_largefile(filesystem *fs)
> -+{
> -+	fs->sb->s_rev_level = 1;
> -+	fs->sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
> -+	fs->sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
> -+}
> -+
> -+#define COPY_BLOCKS 16
> -+#define CB_SIZE (COPY_BLOCKS * BLOCKSIZE)
> -+
> - // make a file from a FILE*
> - static uint32
> --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)
> -+mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, FILE *f, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
> - {
> - 	uint8 * b;
> - 	uint32 nod = mknod_fs(fs, parent_nod, name, mode|FM_IFREG, uid, gid, 0, 0, ctime, mtime);
> --	extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
> --	get_nod(fs, nod)->i_size = size;
> --	if (size) {
> --		if(!(b = (uint8*)calloc(rndup(size, BLOCKSIZE), 1)))
> --			error_msg_and_die("not enough mem to read file '%s'", name);
> --		if(f)
> --			fread(b, size, 1, f); // FIXME: ugly. use mmap() ...
> --		extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
> --		free(b);
> --	}
> -+	nod_info *ni;
> -+	inode *node = get_nod(fs, nod, &ni);
> -+	off_t size = 0;
> -+	size_t readbytes;
> -+	inode_pos ipos;
> -+	int fullsize;
> -+
> -+	b = malloc(CB_SIZE);
> -+	if (!b)
> -+		error_msg_and_die("mkfile_fs: out of memory");
> -+	inode_pos_init(fs, &ipos, nod, INODE_POS_TRUNCATE, NULL);
> -+	readbytes = fread(b, 1, CB_SIZE, f);
> -+	while (readbytes) {
> -+		fullsize = rndup(readbytes, BLOCKSIZE);
> -+		// Fill to end of block with zeros.
> -+		memset(b + readbytes, 0, fullsize - readbytes);
> -+		extend_inode_blk(fs, &ipos, b, fullsize / BLOCKSIZE);
> -+		size += readbytes;
> -+		readbytes = fread(b, 1, CB_SIZE, f);
> -+	}
> -+	if (size > 0x7fffffff) {
> -+		if (fs->sb->s_rev_level < 1)
> -+			fs_upgrade_rev1_largefile(fs);
> -+		fs->sb->s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
> -+	}
> -+	node->i_dir_acl = size >> 32;
> -+	node->i_size = size;
> -+	inode_pos_finish(fs, &ipos);
> -+	put_nod(ni);
> -+	free(b);
> - 	return nod;
> - }
> - 
> -@@ -1591,13 +2268,24 @@
> - 				dname = malloc(len + 1);
> - 				for(i = start; i < count; i++)
> - 				{
> -+					uint32 oldnod;
> - 					SNPRINTF(dname, len, "%s%lu", name, i);
> --					mknod_fs(fs, nod, dname, mode, uid, gid, major, minor + (i * increment - start), ctime, mtime);
> -+					oldnod = find_dir(fs, nod, dname);
> -+					if(oldnod)
> -+						chmod_fs(fs, oldnod, mode, uid, gid);
> -+					else
> -+						mknod_fs(fs, nod, dname, mode, uid, gid, major, minor + (i * increment - start), ctime, mtime);
> - 				}
> - 				free(dname);
> - 			}
> - 			else
> --				mknod_fs(fs, nod, name, mode, uid, gid, major, minor, ctime, mtime);
> -+			{
> -+				uint32 oldnod = find_dir(fs, nod, name);
> -+				if(oldnod)
> -+					chmod_fs(fs, oldnod, mode, uid, gid);
> -+				else
> -+					mknod_fs(fs, nod, name, mode, uid, gid, major, minor, ctime, mtime);
> -+			}
> - 		}
> - 	}
> - 	if (line)
> -@@ -1643,6 +2331,10 @@
> - 			switch(st.st_mode & S_IFMT)
> - 			{
> - 				case S_IFLNK:
> -+					if((st.st_mode & S_IFMT) == S_IFREG || st.st_size >= 4 * (EXT2_TIND_BLOCK+1))
> -+						stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
> -+					stats->ninodes++;
> -+					break;
> - 				case S_IFREG:
> - 					if((st.st_mode & S_IFMT) == S_IFREG || st.st_size > 4 * (EXT2_TIND_BLOCK+1))
> - 						stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
> -@@ -1657,19 +2349,33 @@
> - 					if(chdir(dent->d_name) < 0)
> - 						perror_msg_and_die(dent->d_name);
> - 					add2fs_from_dir(fs, this_nod, squash_uids, squash_perms, fs_timestamp, stats);
> --					chdir("..");
> -+					if (chdir("..") == -1)
> -+						perror_msg_and_die("..");
> -+
> - 					break;
> - 				default:
> - 					break;
> - 			}
> - 		else
> - 		{
> -+			if((nod = find_dir(fs, this_nod, name)))
> -+			{
> -+				error_msg("ignoring duplicate entry %s", name);
> -+				if(S_ISDIR(st.st_mode)) {
> -+					if(chdir(dent->d_name) < 0)
> -+						perror_msg_and_die(name);
> -+					add2fs_from_dir(fs, nod, squash_uids, squash_perms, fs_timestamp, stats);
> -+					if (chdir("..") == -1)
> -+						perror_msg_and_die("..");
> -+				}
> -+				continue;
> -+			}
> - 			save_nod = 0;
> - 			/* Check for hardlinks */
> - 			if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) && st.st_nlink > 1) {
> --				int32 hdlink = is_hardlink(st.st_ino);
> -+				int32 hdlink = is_hardlink(fs, st.st_ino);
> - 				if (hdlink >= 0) {
> --					add2dir(fs, this_nod, hdlinks.hdl[hdlink].dst_nod, name);
> -+					add2dir(fs, this_nod, fs->hdlinks.hdl[hdlink].dst_nod, name);
> - 					continue;
> - 				} else {
> - 					save_nod = 1;
> -@@ -1697,8 +2403,12 @@
> - 					free(lnk);
> - 					break;
> - 				case S_IFREG:
> --					fh = xfopen(dent->d_name, "rb");
> --					nod = mkfile_fs(fs, this_nod, name, mode, st.st_size, fh, uid, gid, ctime, mtime);
> -+					fh = fopen(dent->d_name, "rb");
> -+					if (!fh) {
> -+						error_msg("Unable to open file %s", dent->d_name);
> -+						break;
> -+					}
> -+					nod = mkfile_fs(fs, this_nod, name, mode, fh, uid, gid, ctime, mtime);
> - 					fclose(fh);
> - 					break;
> - 				case S_IFDIR:
> -@@ -1706,199 +2416,128 @@
> - 					if(chdir(dent->d_name) < 0)
> - 						perror_msg_and_die(name);
> - 					add2fs_from_dir(fs, nod, squash_uids, squash_perms, fs_timestamp, stats);
> --					chdir("..");
> -+					if (chdir("..") == -1)
> -+						perror_msg_and_die("..");
> - 					break;
> - 				default:
> - 					error_msg("ignoring entry %s", name);
> - 			}
> - 			if (save_nod) {
> --				if (hdlinks.count == hdlink_cnt) {
> --					if ((hdlinks.hdl = 
> --						 realloc (hdlinks.hdl, (hdlink_cnt + HDLINK_CNT) *
> -+				if (fs->hdlinks.count == fs->hdlink_cnt) {
> -+					if ((fs->hdlinks.hdl =
> -+						 realloc (fs->hdlinks.hdl, (fs->hdlink_cnt + HDLINK_CNT) *
> - 								  sizeof (struct hdlink_s))) == NULL) {
> - 						error_msg_and_die("Not enough memory");
> - 					}
> --					hdlink_cnt += HDLINK_CNT;
> -+					fs->hdlink_cnt += HDLINK_CNT;
> - 				}
> --				hdlinks.hdl[hdlinks.count].src_inode = st.st_ino;
> --				hdlinks.hdl[hdlinks.count].dst_nod = nod;
> --				hdlinks.count++;
> -+				fs->hdlinks.hdl[fs->hdlinks.count].src_inode = st.st_ino;
> -+				fs->hdlinks.hdl[fs->hdlinks.count].dst_nod = nod;
> -+				fs->hdlinks.count++;
> - 			}
> - 		}
> - 	}
> - 	closedir(dh);
> - }
> - 
> --// endianness swap of x-indirect blocks
> -+// Copy size blocks from src to dst, putting holes in the output
> -+// file (if possible) if the input block is all zeros.
> -+// Copy size blocks from src to dst, putting holes in the output
> -+// file (if possible) if the input block is all zeros.
> - static void
> --swap_goodblocks(filesystem *fs, inode *nod)
> -+copy_file(filesystem *fs, FILE *dst, FILE *src, size_t size)
> - {
> --	uint32 i,j;
> --	int done=0;
> --	uint32 *b,*b2;
> -+	uint8 *b;
> - 
> --	uint32 nblk = nod->i_blocks / INOBLK;
> --	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_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
> --	 */
> --	// FIXME: I have fixed that, but I have the feeling the rest of
> --	// ths function needs to be fixed for the same reasons - Xav
> --	assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
> --	for(i = 0; i < 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;
> --	/* 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<BLOCKSIZE/4;j++) {
> --			if (nblk > ( 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;
> --			}
> -+	b = malloc(BLOCKSIZE);
> -+	if (!b)
> -+		error_msg_and_die("copy_file: out of memory");
> -+	if (fseek(src, 0, SEEK_SET))
> -+		perror_msg_and_die("fseek");
> -+	if (ftruncate(fileno(dst), 0))
> -+		perror_msg_and_die("copy_file: ftruncate");
> -+	while (size > 0) {
> -+		if (fread(b, BLOCKSIZE, 1, src) != 1)
> -+			perror_msg_and_die("copy failed on read");
> -+		if ((dst != stdout) && fs->holes && is_blk_empty(b)) {
> -+			/* Empty block, just skip it */
> -+			if (fseek(dst, BLOCKSIZE, SEEK_CUR))
> -+				perror_msg_and_die("fseek");
> -+		} else {
> -+			if (fwrite(b, BLOCKSIZE, 1, dst) != 1)
> -+				perror_msg_and_die("copy failed on write");
> - 		}
> --		swap_block((uint8 *)b2);
> -+		size--;
> - 	}
> --	swap_block((uint8 *)b);
> --	return;
> -+	free(b);
> - }
> - 
> --static void
> --swap_badblocks(filesystem *fs, inode *nod)
> -+// Allocate a new filesystem structure, allocate internal memory,
> -+// and initialize the contents.
> -+static filesystem *
> -+alloc_fs(int swapit, char *fname, uint32 nbblocks, FILE *srcfile)
> - {
> --	uint32 i,j;
> --	int done=0;
> --	uint32 *b,*b2;
> -+	filesystem *fs;
> -+	struct stat srcstat, dststat;
> - 
> --	uint32 nblk = nod->i_blocks / INOBLK;
> --	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_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 + (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;
> --	/* 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<BLOCKSIZE/4;j++) {
> --			if (nblk > ( 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;
> --}
> -+	fs = malloc(sizeof(*fs));
> -+	if (!fs)
> -+		error_msg_and_die("not enough memory for filesystem");
> -+	memset(fs, 0, sizeof(*fs));
> -+	fs->swapit = swapit;
> -+	cache_init(&fs->blks, MAX_FREE_CACHE_BLOCKS, blk_elem_val, blk_freed);
> -+	cache_init(&fs->gds, MAX_FREE_CACHE_GDS, gd_elem_val, gd_freed);
> -+	cache_init(&fs->blkmaps, MAX_FREE_CACHE_BLOCKMAPS,
> -+		   blkmap_elem_val, blkmap_freed);
> -+	cache_init(&fs->inodes, MAX_FREE_CACHE_INODES,
> -+		   inode_elem_val, inode_freed);
> -+	fs->hdlink_cnt = HDLINK_CNT;
> -+	fs->hdlinks.hdl = calloc(sizeof(struct hdlink_s), fs->hdlink_cnt);
> -+	if (!fs->hdlinks.hdl)
> -+		error_msg_and_die("Not enough memory");
> -+	fs->hdlinks.count = 0 ;
> - 
> --// endianness swap of the whole filesystem
> --static void
> --swap_goodfs(filesystem *fs)
> --{
> --	uint32 i;
> --	for(i = 1; i < fs->sb.s_inodes_count; i++)
> --	{
> --		inode *nod = get_nod(fs, i);
> --		if(nod->i_mode & FM_IFDIR)
> --		{
> --			blockwalker bw;
> --			uint32 bk;
> --			init_bw(&bw);
> --			while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
> --			{
> --				directory *d;
> --				uint8 *b;
> --				b = get_blk(fs, bk);
> --				for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + swab16(d->d_rec_len)))
> --					swap_dir(d);
> --			}
> --		}
> --		swap_goodblocks(fs, nod);
> --		swap_nod(nod);
> --	}
> --	for(i=0;i<GRP_NBGROUPS(fs);i++)
> --		swap_gd(&(fs->gd[i]));
> --	swap_sb(&fs->sb);
> -+	if (strcmp(fname, "-") == 0)
> -+		fs->f = tmpfile();
> -+	else if (srcfile) {
> -+		if (fstat(fileno(srcfile), &srcstat))
> -+			perror_msg_and_die("fstat srcfile");
> -+		if (stat(fname, &dststat) == 0
> -+		    && srcstat.st_ino == dststat.st_ino
> -+		    && srcstat.st_dev == dststat.st_dev)
> -+		  {
> -+			// source and destination are the same file, don't
> -+			// truncate or copy, just use the file.
> -+			fs->f = fopen(fname, "r+b");
> -+		} else {
> -+			fs->f = fopen(fname, "w+b");
> -+			if (fs->f)
> -+				copy_file(fs, fs->f, srcfile, nbblocks);
> -+		}
> -+	} else
> -+		fs->f = fopen(fname, "w+b");
> -+	if (!fs->f)
> -+		perror_msg_and_die("opening %s", fname);
> -+	return fs;
> - }
> - 
> -+/* Make sure the output file is the right size */
> - static void
> --swap_badfs(filesystem *fs)
> -+set_file_size(filesystem *fs)
> - {
> --	uint32 i;
> --	swap_sb(&fs->sb);
> --	for(i=0;i<GRP_NBGROUPS(fs);i++)
> --		swap_gd(&(fs->gd[i]));
> --	for(i = 1; i < fs->sb.s_inodes_count; i++)
> --	{
> --		inode *nod = get_nod(fs, i);
> --		swap_nod(nod);
> --		swap_badblocks(fs, nod);
> --		if(nod->i_mode & FM_IFDIR)
> --		{
> --			blockwalker bw;
> --			uint32 bk;
> --			init_bw(&bw);
> --			while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
> --			{
> --				directory *d;
> --				uint8 *b;
> --				b = get_blk(fs, bk);
> --				for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
> --					swap_dir(d);
> --			}
> --		}
> --	}
> -+	if (ftruncate(fileno(fs->f),
> -+		      ((off_t) fs->sb->s_blocks_count) * BLOCKSIZE))
> -+		perror_msg_and_die("set_file_size: ftruncate");
> - }
> - 
> - // initialize an empty filesystem
> - static filesystem *
> --init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp)
> -+init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes,
> -+	uint32 fs_timestamp, uint32 creator_os, int swapit, char *fname)
> - {
> - 	uint32 i;
> - 	filesystem *fs;
> --	directory *d;
> --	uint8 * b;
> -+	dirwalker dw;
> - 	uint32 nod, first_block;
> - 	uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
> - 		free_blocks_per_group,nbblocks_per_group,min_nbgroups;
> -@@ -1906,6 +2545,11 @@
> - 	uint32 j;
> - 	uint8 *bbm,*ibm;
> - 	inode *itab0;
> -+	blk_info *bi;
> -+	nod_info *ni;
> -+	groupdescriptor *gd;
> -+	gd_info *gi;
> -+	inode_pos ipos;
> - 	
> - 	if(nbresrvd < 0)
> - 		error_msg_and_die("reserved blocks value is invalid. Note: options have changed, see --help or the man page.");
> -@@ -1919,10 +2563,14 @@
> - 	 */
> - 	min_nbgroups = (nbinodes + INODES_PER_GROUP - 1) / INODES_PER_GROUP;
> - 
> -+	/* On filesystems with 1k block size, the bootloader area uses a full
> -+	 * block. For 2048 and up, the superblock can be fitted into block 0.
> -+	 */
> -+	first_block = (BLOCKSIZE == 1024);
> -+
> - 	/* nbblocks is the total number of blocks in the filesystem.
> - 	 * a block group can have no more than 8192 blocks.
> - 	 */
> --	first_block = (BLOCKSIZE == 1024);
> - 	nbgroups = (nbblocks - first_block + BLOCKS_PER_GROUP - 1) / BLOCKS_PER_GROUP;
> - 	if(nbgroups < min_nbgroups) nbgroups = min_nbgroups;
> - 	nbblocks_per_group = rndup((nbblocks - first_block + nbgroups - 1)/nbgroups, 8);
> -@@ -1934,51 +2582,59 @@
> - 	gdsz = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
> - 	itblsz = nbinodes_per_group * sizeof(inode)/BLOCKSIZE;
> - 	overhead_per_group = 3 /*sb,bbm,ibm*/ + gdsz + itblsz;
> --	if((uint32)nbblocks - 1 < overhead_per_group * nbgroups)
> --		error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
> --	free_blocks = nbblocks - overhead_per_group*nbgroups - 1 /*boot block*/;
> -+	free_blocks = nbblocks - overhead_per_group*nbgroups - first_block;
> - 	free_blocks_per_group = nbblocks_per_group - overhead_per_group;
> -+	if(free_blocks < 0)
> -+		error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
> - 
> --	if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
> --		error_msg_and_die("not enough memory for filesystem");
> -+	fs = alloc_fs(swapit, fname, nbblocks, NULL);
> -+	fs->sb = calloc(1, SUPERBLOCK_SIZE);
> -+	if (!fs->sb)
> -+		error_msg_and_die("error allocating header memory");
> - 
> - 	// create the superblock for an empty filesystem
> --	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 = free_blocks;
> --	fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
> --	fs->sb.s_first_data_block = first_block;
> --	fs->sb.s_log_block_size = BLOCKSIZE >> 11;
> --	fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
> --	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_wtime = fs_timestamp;
> --	fs->sb.s_magic = EXT2_MAGIC_NUMBER;
> --	fs->sb.s_lastcheck = fs_timestamp;
> -+	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 = free_blocks;
> -+	fs->sb->s_free_inodes_count = fs->sb->s_inodes_count - EXT2_FIRST_INO + 1;
> -+	fs->sb->s_first_data_block = first_block;
> -+	fs->sb->s_log_block_size = BLOCKSIZE >> 11;
> -+	fs->sb->s_log_frag_size = BLOCKSIZE >> 11;
> -+	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_wtime = fs_timestamp;
> -+	fs->sb->s_magic = EXT2_MAGIC_NUMBER;
> -+	fs->sb->s_lastcheck = fs_timestamp;
> -+	fs->sb->s_creator_os = creator_os;
> -+
> -+	set_file_size(fs);
> - 
> - 	// set up groupdescriptors
> --	for(i=0, bbmpos=gdsz+2, ibmpos=bbmpos+1, itblpos=ibmpos+1;
> -+	for(i=0, bbmpos=first_block+1+gdsz, ibmpos=bbmpos+1, itblpos=ibmpos+1;
> - 		i<nbgroups;
> - 		i++, bbmpos+=nbblocks_per_group, ibmpos+=nbblocks_per_group, itblpos+=nbblocks_per_group)
> - 	{
> -+		gd = get_gd(fs, i, &gi);
> -+
> - 		if(free_blocks > free_blocks_per_group) {
> --			fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
> -+			gd->bg_free_blocks_count = free_blocks_per_group;
> - 			free_blocks -= free_blocks_per_group;
> - 		} else {
> --			fs->gd[i].bg_free_blocks_count = free_blocks;
> -+			gd->bg_free_blocks_count = free_blocks;
> - 			free_blocks = 0; // this is the last block group
> - 		}
> - 		if(i)
> --			fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
> -+			gd->bg_free_inodes_count = nbinodes_per_group;
> - 		else
> --			fs->gd[i].bg_free_inodes_count = nbinodes_per_group -
> -+			gd->bg_free_inodes_count = nbinodes_per_group -
> - 							EXT2_FIRST_INO + 2;
> --		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;
> -+		gd->bg_used_dirs_count = 0;
> -+		gd->bg_block_bitmap = bbmpos;
> -+		gd->bg_inode_bitmap = ibmpos;
> -+		gd->bg_inode_table = itblpos;
> -+		put_gd(gi);
> - 	}
> - 
> - 	/* Mark non-filesystem blocks and inodes as allocated */
> -@@ -1984,110 +2640,143 @@
> - 	/* Mark non-filesystem blocks and inodes as allocated */
> - 	/* Mark system blocks and inodes as allocated         */
> - 	for(i = 0; i<nbgroups;i++) {
> --
> - 		/* Block bitmap */
> --		bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);	
> -+		gd = get_gd(fs, i, &gi);
> -+		bbm = GRP_GET_GROUP_BBM(fs, gd, &bi);
> - 		//non-filesystem blocks
> --		for(j = fs->gd[i].bg_free_blocks_count
> -+		for(j = gd->bg_free_blocks_count
> - 		        + overhead_per_group + 1; j <= BLOCKSIZE * 8; j++)
> - 			allocate(bbm, j); 
> - 		//system blocks
> - 		for(j = 1; j <= overhead_per_group; j++)
> - 			allocate(bbm, j); 
> --		
> -+		GRP_PUT_GROUP_BBM(bi);
> -+
> - 		/* Inode bitmap */
> --		ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);	
> -+		ibm = GRP_GET_GROUP_IBM(fs, gd, &bi);
> - 		//non-filesystem inodes
> --		for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
> -+		for(j = fs->sb->s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
> - 			allocate(ibm, j);
> - 
> - 		//system inodes
> - 		if(i == 0)
> - 			for(j = 1; j < EXT2_FIRST_INO; j++)
> - 				allocate(ibm, j);
> -+		GRP_PUT_GROUP_IBM(bi);
> -+		put_gd(gi);
> - 	}
> - 
> - 	// make root inode and directory
> - 	/* 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_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH; 
> --	itab0[EXT2_ROOT_INO-1].i_ctime = fs_timestamp;
> --	itab0[EXT2_ROOT_INO-1].i_mtime = fs_timestamp;
> --	itab0[EXT2_ROOT_INO-1].i_atime = fs_timestamp;
> --	itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
> --	itab0[EXT2_ROOT_INO-1].i_links_count = 2;
> --
> --	if(!(b = get_workblk()))
> --		error_msg_and_die("get_workblk() failed.");
> --	d = (directory*)b;
> --	d->d_inode = EXT2_ROOT_INO;
> --	d->d_rec_len = sizeof(directory)+4;
> --	d->d_name_len = 1;
> --	strcpy(d->d_name, ".");
> --	d = (directory*)(b + d->d_rec_len);
> --	d->d_inode = EXT2_ROOT_INO;
> --	d->d_rec_len = BLOCKSIZE - (sizeof(directory)+4);
> --	d->d_name_len = 2;
> --	strcpy(d->d_name, "..");
> --	extend_blk(fs, EXT2_ROOT_INO, b, 1);
> -+	gd = get_gd(fs, 0, &gi);
> -+	gd->bg_free_inodes_count--;
> -+	gd->bg_used_dirs_count = 1;
> -+	put_gd(gi);
> -+	itab0 = get_nod(fs, EXT2_ROOT_INO, &ni);
> -+	itab0->i_mode = FM_IFDIR | FM_IRWXU | FM_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH;
> -+	itab0->i_ctime = fs_timestamp;
> -+	itab0->i_mtime = fs_timestamp;
> -+	itab0->i_atime = fs_timestamp;
> -+	itab0->i_size = BLOCKSIZE;
> -+	itab0->i_links_count = 2;
> -+	put_nod(ni);
> -+
> -+	new_dir(fs, EXT2_ROOT_INO, ".", 1, &dw);
> -+	shrink_dir(&dw, EXT2_ROOT_INO, "..", 2);
> -+	next_dir(&dw); // Force the data into the buffer
> -+	inode_pos_init(fs, &ipos, EXT2_ROOT_INO, INODE_POS_EXTEND, NULL);
> -+	extend_inode_blk(fs, &ipos, dir_data(&dw), 1);
> -+	inode_pos_finish(fs, &ipos);
> -+	put_dir(&dw);
> - 
> --	// make lost+found directory and reserve blocks
> --	if(fs->sb.s_r_blocks_count)
> -+	// make lost+found directory
> -+	if(fs->sb->s_r_blocks_count)
> - 	{
> --		nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU, 0, 0, fs_timestamp, fs_timestamp);
> -+		inode *node;
> -+		uint8 *b;
> -+
> -+		nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU,
> -+			       0, 0, fs_timestamp, fs_timestamp);
> -+		b = get_workblk();
> - 		memset(b, 0, BLOCKSIZE);
> - 		((directory*)b)->d_rec_len = BLOCKSIZE;
> --		/* We run into problems with e2fsck if directory lost+found grows
> --		 * bigger than this. Need to find out why this happens - sundar
> --		 */
> --		if (fs->sb.s_r_blocks_count > fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS ) 
> --			fs->sb.s_r_blocks_count = fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS;
> --		for(i = 1; i < fs->sb.s_r_blocks_count; i++)
> --			extend_blk(fs, nod, b, 1);
> --		get_nod(fs, nod)->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE;
> -+		inode_pos_init(fs, &ipos, nod, INODE_POS_EXTEND, NULL);
> -+		// It is always 16 blocks to start out with
> -+		for(i = 1; i < 16; i++)
> -+			extend_inode_blk(fs, &ipos, b, 1);
> -+		inode_pos_finish(fs, &ipos);
> -+		free_workblk(b);
> -+		node = get_nod(fs, nod, &ni);
> -+		node->i_size = 16 * BLOCKSIZE;
> -+		put_nod(ni);
> - 	}
> --	free_workblk(b);
> - 
> - 	// administrative info
> --	fs->sb.s_state = 1;
> --	fs->sb.s_max_mnt_count = 20;
> -+	fs->sb->s_state = 1;
> -+	fs->sb->s_max_mnt_count = 20;
> - 
> - 	// options for me
> --	if(holes)
> --		fs->sb.s_reserved[200] |= OP_HOLES;
> -+	fs->holes = holes;
> - 	
> - 	return fs;
> - }
> - 
> - // loads a filesystem from disk
> - static filesystem *
> --load_fs(FILE * fh, int swapit)
> -+load_fs(FILE *fh, int swapit, char *fname)
> - {
> --	size_t fssize;
> -+	off_t fssize;
> - 	filesystem *fs;
> --	if((fseek(fh, 0, SEEK_END) < 0) || ((ssize_t)(fssize = ftell(fh)) == -1))
> -+
> -+	if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftello(fh)) == -1))
> - 		perror_msg_and_die("input filesystem image");
> - 	rewind(fh);
> --	fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
> -+	if ((fssize % BLOCKSIZE) != 0)
> -+		error_msg_and_die("Input file not a multiple of block size");
> -+	fssize /= BLOCKSIZE;
> - 	if(fssize < 16) // totally arbitrary
> - 		error_msg_and_die("too small filesystem");
> --	if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
> --		error_msg_and_die("not enough memory for filesystem");
> --	if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
> --		perror_msg_and_die("input filesystem image");
> -+	fs = alloc_fs(swapit, fname, fssize, fh);
> -+
> -+	/* Read and check the superblock, then read the superblock
> -+	 * and all the group descriptors */
> -+	fs->sb = malloc(SUPERBLOCK_SIZE);
> -+	if (!fs->sb)
> -+		error_msg_and_die("error allocating header memory");
> -+	if (fseek(fs->f, SUPERBLOCK_OFFSET, SEEK_SET))
> -+		perror_msg_and_die("fseek");
> -+	if (fread(fs->sb, SUPERBLOCK_SIZE, 1, fs->f) != 1)
> -+		perror_msg_and_die("fread filesystem image superblock");
> - 	if(swapit)
> --		swap_badfs(fs);
> --	if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
> -+		swap_sb(fs->sb);
> -+
> -+	if((fs->sb->s_rev_level > 1) || (fs->sb->s_magic != EXT2_MAGIC_NUMBER))
> - 		error_msg_and_die("not a suitable ext2 filesystem");
> -+	if (fs->sb->s_rev_level > 0) {
> -+		if (fs->sb->s_first_ino != EXT2_GOOD_OLD_FIRST_INO)
> -+			error_msg_and_die("First inode incompatible");
> -+		if (fs->sb->s_inode_size != EXT2_GOOD_OLD_INODE_SIZE)
> -+			error_msg_and_die("inode size incompatible");
> -+		if (fs->sb->s_feature_compat)
> -+			error_msg_and_die("Unsupported compat features");
> -+		if (fs->sb->s_feature_incompat)
> -+			error_msg_and_die("Unsupported incompat features");
> -+		if (fs->sb->s_feature_ro_compat
> -+		    & ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
> -+			error_msg_and_die("Unsupported ro compat features");
> -+	}
> -+
> -+	set_file_size(fs);
> - 	return fs;
> - }
> - 
> - static void
> - free_fs(filesystem *fs)
> - {
> -+	free(fs->hdlinks.hdl);
> -+	fclose(fs->f);
> -+	free(fs->sb);
> - 	free(fs);
> - }
> - 
> -@@ -2123,16 +2812,23 @@
> - {
> - 	blockwalker bw;
> - 	uint32 bk;
> --	int32 fsize = get_nod(fs, nod)->i_size;
> -+	nod_info *ni;
> -+	inode *node = get_nod(fs, nod, &ni);
> -+	int32 fsize = node->i_size;
> -+	blk_info *bi;
> -+
> - 	init_bw(&bw);
> - 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
> - 	{
> - 		if(fsize <= 0)
> - 			error_msg_and_die("wrong size while saving inode %d", nod);
> --		if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
> -+		if(fwrite(get_blk(fs, bk, &bi),
> -+			  (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
> - 			error_msg_and_die("error while saving inode %d", nod);
> -+		put_blk(bi);
> - 		fsize -= BLOCKSIZE;
> - 	}
> -+	put_nod(ni);
> - }
> - 
> - 
> -@@ -2141,8 +2837,11 @@
> - print_dev(filesystem *fs, uint32 nod)
> - {
> - 	int minor, major;
> --	minor = ((uint8*)get_nod(fs, nod)->i_block)[0];
> --	major = ((uint8*)get_nod(fs, nod)->i_block)[1];
> -+	nod_info *ni;
> -+	inode *node = get_nod(fs, nod, &ni);
> -+	minor = ((uint8*)node->i_block)[0];
> -+	major = ((uint8*)node->i_block)[1];
> -+	put_nod(ni);
> - 	printf("major: %d, minor: %d\n", major, minor);
> - }
> - 
> -@@ -2157,17 +2856,15 @@
> - 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
> - 	{
> - 		directory *d;
> --		uint8 *b;
> --		b = get_blk(fs, bk);
> --		for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
> -+		dirwalker dw;
> -+		for (d = get_dir(fs, bk, &dw); d; d = next_dir(&dw))
> - 			if(d->d_inode)
> - 			{
> --				int i;
> - 				printf("entry '");
> --				for(i = 0; i < d->d_name_len; i++)
> --					putchar(d->d_name[i]);
> -+				fwrite(dir_name(&dw), 1, d->d_name_len, stdout);
> - 				printf("' (inode %d): rec_len: %d (name_len: %d)\n", d->d_inode, d->d_rec_len, d->d_name_len);
> - 			}
> -+		put_dir(&dw);
> - 	}
> - }
> - 
> -@@ -2175,14 +2872,18 @@
> - static void
> - print_link(filesystem *fs, uint32 nod)
> - {
> --	if(!get_nod(fs, nod)->i_blocks)
> --		printf("links to '%s'\n", (char*)get_nod(fs, nod)->i_block);
> -+	nod_info *ni;
> -+	inode *node = get_nod(fs, nod, &ni);
> -+
> -+	if(!node->i_blocks)
> -+		printf("links to '%s'\n", (char*)node->i_block);
> - 	else
> - 	{
> - 		printf("links to '");
> - 		write_blocks(fs, nod, stdout);
> - 		printf("'\n");
> - 	}
> -+	put_nod(ni);
> - }
> - 
> - // make a ls-like printout of permissions
> -@@ -2251,8 +2952,13 @@
> - {
> - 	char *s;
> - 	char perms[11];
> --	if(!get_nod(fs, nod)->i_mode)
> --		return;
> -+	nod_info *ni;
> -+	inode *node = get_nod(fs, nod, &ni);
> -+	blk_info *bi;
> -+	gd_info *gi;
> -+
> -+	if(!node->i_mode)
> -+		goto out;
> - 	switch(nod)
> - 	{
> - 		case EXT2_BAD_INO:
> -@@ -2274,15 +2980,18 @@
> - 		default:
> - 			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(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
> -+	printf("inode %d (%s, %d links): ", nod, s, node->i_links_count);
> -+	if(!allocated(GRP_GET_INODE_BITMAP(fs,nod,&bi,&gi), GRP_IBM_OFFSET(fs,nod)))
> - 	{
> -+		GRP_PUT_INODE_BITMAP(bi,gi);
> - 		printf("unallocated\n");
> --		return;
> -+		goto out;
> - 	}
> --	make_perms(get_nod(fs, nod)->i_mode, perms);
> --	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));
> --	switch(get_nod(fs, nod)->i_mode & FM_IFMT)
> -+	GRP_PUT_INODE_BITMAP(bi,gi);
> -+	make_perms(node->i_mode, perms);
> -+	printf("%s,  size: %d byte%s (%d block%s)\n", perms,
> -+	       plural(node->i_size), plural(node->i_blocks / INOBLK));
> -+	switch(node->i_mode & FM_IFMT)
> - 	{
> - 		case FM_IFSOCK:
> - 			list_blocks(fs, nod);
> -@@ -2310,6 +3019,8 @@
> - 			list_blocks(fs, nod);
> - 	}
> - 	printf("Done with inode %d\n",nod);
> -+out:
> -+	put_nod(ni);
> - }
> - 
> - // describes various fields in a filesystem
> -@@ -2317,49 +3028,65 @@
> - print_fs(filesystem *fs)
> - {
> - 	uint32 i;
> -+	blk_info *bi;
> -+	groupdescriptor *gd;
> -+	gd_info *gi;
> - 	uint8 *ibm;
> - 
> - 	printf("%d blocks (%d free, %d reserved), first data block: %d\n",
> --	       fs->sb.s_blocks_count, fs->sb.s_free_blocks_count,
> --	       fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
> --	printf("%d inodes (%d free)\n", fs->sb.s_inodes_count,
> --	       fs->sb.s_free_inodes_count);
> -+	       fs->sb->s_blocks_count, fs->sb->s_free_blocks_count,
> -+	       fs->sb->s_r_blocks_count, fs->sb->s_first_data_block);
> -+	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);
> -+	       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("number of groups: %d\n",GRP_NBGROUPS(fs));
> - 	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);
> -+	     fs->sb->s_blocks_per_group, fs->sb->s_frags_per_group,
> -+	     fs->sb->s_inodes_per_group);
> - 	printf("Size of inode table: %d blocks\n",
> --		(int)(fs->sb.s_inodes_per_group * sizeof(inode) / BLOCKSIZE));
> -+		(int)(fs->sb->s_inodes_per_group * sizeof(inode) / BLOCKSIZE));
> - 	for (i = 0; i < GRP_NBGROUPS(fs); i++) {
> - 		printf("Group No: %d\n", i+1);
> -+		gd = get_gd(fs, i, &gi);
> - 		printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
> --		     fs->gd[i].bg_block_bitmap, fs->gd[i].bg_inode_bitmap,
> --		     fs->gd[i].bg_inode_table);
> -+		     gd->bg_block_bitmap,
> -+		     gd->bg_inode_bitmap,
> -+		     gd->bg_inode_table);
> - 		printf("block bitmap allocation:\n");
> --		print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
> -+		print_bm(GRP_GET_GROUP_BBM(fs, gd, &bi),fs->sb->s_blocks_per_group);
> -+		GRP_PUT_GROUP_BBM(bi);
> - 		printf("inode bitmap allocation:\n");
> --		ibm = GRP_GET_GROUP_IBM(fs, i);
> --		print_bm(ibm, fs->sb.s_inodes_per_group);
> --		for (i = 1; i <= fs->sb.s_inodes_per_group; i++)
> -+		ibm = GRP_GET_GROUP_IBM(fs, gd, &bi);
> -+		print_bm(ibm, fs->sb->s_inodes_per_group);
> -+		for (i = 1; i <= fs->sb->s_inodes_per_group; i++)
> - 			if (allocated(ibm, i))
> - 				print_inode(fs, i);
> -+		GRP_PUT_GROUP_IBM(bi);
> -+		put_gd(gi);
> - 	}
> - }
> - 
> - static void
> --dump_fs(filesystem *fs, FILE * fh, int swapit)
> -+finish_fs(filesystem *fs)
> - {
> --	uint32 nbblocks = fs->sb.s_blocks_count;
> --	fs->sb.s_reserved[200] = 0;
> --	if(swapit)
> --		swap_goodfs(fs);
> --	if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
> --		perror_msg_and_die("output filesystem image");
> --	if(swapit)
> --		swap_badfs(fs);
> -+	if (cache_flush(&fs->inodes))
> -+		error_msg_and_die("entry mismatch on inode cache flush");
> -+	if (cache_flush(&fs->blkmaps))
> -+		error_msg_and_die("entry mismatch on blockmap cache flush");
> -+	if (cache_flush(&fs->gds))
> -+		error_msg_and_die("entry mismatch on gd cache flush");
> -+	if (cache_flush(&fs->blks))
> -+		error_msg_and_die("entry mismatch on block cache flush");
> -+	if(fs->swapit)
> -+		swap_sb(fs->sb);
> -+	if (fseek(fs->f, SUPERBLOCK_OFFSET, SEEK_SET))
> -+		perror_msg_and_die("fseek");
> -+	if(fwrite(fs->sb, SUPERBLOCK_SIZE, 1, fs->f) != 1)
> -+		perror_msg_and_die("output filesystem superblock");
> -+	if(fs->swapit)
> -+		swap_sb(fs->sb);
> - }
> - 
> - static void
> -@@ -2419,10 +3146,12 @@
> - 	"  -x, --starting-image <image>\n"
> - 	"  -d, --root <directory>\n"
> - 	"  -D, --devtable <file>\n"
> -+	"  -B, --block-size <bytes>\n"
> - 	"  -b, --size-in-blocks <blocks>\n"
> - 	"  -i, --bytes-per-inode <bytes per inode>\n"
> - 	"  -N, --number-of-inodes <number of inodes>\n"
> - 	"  -m, --reserved-percentage <percentage of blocks to reserve>\n"
> -+	"  -o, --creator-os <os>      'linux' (default), 'hurd', 'freebsd' or number.\n"
> - 	"  -g, --block-map <path>     Generate a block map file for this path.\n"
> - 	"  -e, --fill-value <value>   Fill unallocated blocks with value.\n"
> - 	"  -z, --allow-holes          Allow files with holes.\n"
> -@@ -2444,15 +3173,34 @@
> - extern char* optarg;
> - extern int optind, opterr, optopt;
> - 
> -+// parse the value for -o <os>
> -+int
> -+lookup_creator_os(const char *name)
> -+{
> -+        if (isdigit (*name))
> -+                return atoi(name);
> -+        else if (strcasecmp(name, "linux") == 0)
> -+                return EXT2_OS_LINUX;
> -+        else if (strcasecmp(name, "GNU") == 0 || strcasecmp(name, "hurd") == 0)
> -+                return EXT2_OS_HURD;
> -+        else if (strcasecmp(name, "freebsd") == 0)
> -+                return EXT2_OS_FREEBSD;
> -+        else if (strcasecmp(name, "lites") == 0)
> -+                return EXT2_OS_LITES;
> -+        else
> -+                return EXT2_OS_LINUX;
> -+}
> -+
> - int
> - main(int argc, char **argv)
> - {
> --	int nbblocks = -1;
> -+	long long nbblocks = -1;
> - 	int nbinodes = -1;
> - 	int nbresrvd = -1;
> - 	float bytes_per_inode = -1;
> - 	float reserved_frac = -1;
> - 	int fs_timestamp = -1;
> -+	int creator_os = CREATOR_OS;
> - 	char * fsout = "-";
> - 	char * fsin = 0;
> - 	char * dopt[MAX_DOPT];
> -@@ -2466,6 +3214,7 @@
> - 	int squash_perms = 0;
> - 	uint16 endian = 1;
> - 	int bigendian = !*(char*)&endian;
> -+	char *volumelabel = NULL;
> - 	filesystem *fs;
> - 	int i;
> - 	int c;
> -@@ -2476,13 +3225,16 @@
> - 	  { "starting-image",	required_argument,	NULL, 'x' },
> - 	  { "root",		required_argument,	NULL, 'd' },
> - 	  { "devtable",		required_argument,	NULL, 'D' },
> -+	  { "block-size",	required_argument,	NULL, 'B' },
> - 	  { "size-in-blocks",	required_argument,	NULL, 'b' },
> - 	  { "bytes-per-inode",	required_argument,	NULL, 'i' },
> - 	  { "number-of-inodes",	required_argument,	NULL, 'N' },
> -+	  { "volume-label",     required_argument,      NULL, 'L' },
> - 	  { "reserved-percentage", required_argument,	NULL, 'm' },
> -+	  { "creator-os",	required_argument,	NULL, 'o' },
> - 	  { "block-map",	required_argument,	NULL, 'g' },
> - 	  { "fill-value",	required_argument,	NULL, 'e' },
> --	  { "allow-holes",	no_argument, 		NULL, 'z' },
> -+	  { "allow-holes",	no_argument,		NULL, 'z' },
> - 	  { "faketime",		no_argument,		NULL, 'f' },
> - 	  { "squash",		no_argument,		NULL, 'q' },
> - 	  { "squash-uids",	no_argument,		NULL, 'U' },
> -@@ -2495,11 +3247,11 @@
> - 
> - 	app_name = argv[0];
> - 
> --	while((c = getopt_long(argc, argv, "x:d:D:b:i:N:m:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
> -+	while((c = getopt_long(argc, argv, "x:d:D:B:b:i:N:L:m:o:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
> - #else
> - 	app_name = argv[0];
> - 
> --	while((c = getopt(argc, argv,      "x:d:D:b:i:N:m:g:e:zfqUPhVv")) != EOF) {
> -+	while((c = getopt(argc, argv,      "x:d:D:B:b:i:N:L:m:o:g:e:zfqUPhVv")) != EOF) {
> - #endif /* HAVE_GETOPT_LONG */
> - 		switch(c)
> - 		{
> -@@ -2510,6 +3262,9 @@
> - 			case 'D':
> - 				dopt[didx++] = optarg;
> - 				break;
> -+			case 'B':
> -+				blocksize = SI_atof(optarg);
> -+				break;
> - 			case 'b':
> - 				nbblocks = SI_atof(optarg);
> - 				break;
> -@@ -2519,9 +3274,15 @@
> - 			case 'N':
> - 				nbinodes = SI_atof(optarg);
> - 				break;
> -+			case 'L':
> -+				volumelabel = optarg;
> -+				break;
> - 			case 'm':
> - 				reserved_frac = SI_atof(optarg) / 100;
> - 				break;
> -+			case 'o':
> -+				creator_os = lookup_creator_os(optarg);
> -+				break;
> - 			case 'g':
> - 				gopt[gidx++] = optarg;
> - 				break;
> -@@ -2565,21 +3326,21 @@
> - 		error_msg_and_die("Not enough arguments. Try --help or else see the man page.");
> - 	fsout = argv[optind];
> - 
> --	hdlinks.hdl = (struct hdlink_s *)malloc(hdlink_cnt * sizeof(struct hdlink_s));
> --	if (!hdlinks.hdl)
> --		error_msg_and_die("Not enough memory");
> --	hdlinks.count = 0 ;
> -+	if(blocksize != 1024 && blocksize != 2048 && blocksize != 4096)
> -+		error_msg_and_die("Valid block sizes: 1024, 2048 or 4096.");
> -+	if(creator_os < 0)
> -+		error_msg_and_die("Creator OS unknown.");
> - 
> - 	if(fsin)
> - 	{
> - 		if(strcmp(fsin, "-"))
> - 		{
> - 			FILE * fh = xfopen(fsin, "rb");
> --			fs = load_fs(fh, bigendian);
> -+			fs = load_fs(fh, bigendian, fsout);
> - 			fclose(fh);
> - 		}
> - 		else
> --			fs = load_fs(stdin, bigendian);
> -+			fs = load_fs(stdin, bigendian, fsout);
> - 	}
> - 	else
> - 	{
> -@@ -2609,16 +3370,29 @@
> - 		}
> - 		if(fs_timestamp == -1)
> - 			fs_timestamp = time(NULL);
> --		fs = init_fs(nbblocks, nbinodes, nbresrvd, holes, fs_timestamp);
> -+		fs = init_fs(nbblocks, nbinodes, nbresrvd, holes,
> -+			     fs_timestamp, creator_os, bigendian, fsout);
> - 	}
> -+	if (volumelabel != NULL)
> -+		strncpy((char *)fs->sb->s_volume_name, volumelabel,
> -+			sizeof(fs->sb->s_volume_name));
> - 	
> - 	populate_fs(fs, dopt, didx, squash_uids, squash_perms, fs_timestamp, NULL);
> - 
> - 	if(emptyval) {
> - 		uint32 b;
> --		for(b = 1; b < fs->sb.s_blocks_count; b++)
> --			if(!allocated(GRP_GET_BLOCK_BITMAP(fs,b),GRP_BBM_OFFSET(fs,b)))
> --				memset(get_blk(fs, b), emptyval, BLOCKSIZE);
> -+		for(b = 1; b < fs->sb->s_blocks_count; b++) {
> -+			blk_info *bi;
> -+			gd_info *gi;
> -+			if(!allocated(GRP_GET_BLOCK_BITMAP(fs,b,&bi,&gi),
> -+				      GRP_BBM_OFFSET(fs,b))) {
> -+				blk_info *bi2;
> -+				memset(get_blk(fs, b, &bi2), emptyval,
> -+				       BLOCKSIZE);
> -+				put_blk(bi2);
> -+			}
> -+			GRP_PUT_BLOCK_BITMAP(bi,gi);
> -+		}
> - 	}
> - 	if(verbose)
> - 		print_fs(fs);
> -@@ -2628,24 +3402,22 @@
> - 		char fname[MAX_FILENAME];
> - 		char *p;
> - 		FILE *fh;
> -+		nod_info *ni;
> - 		if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
> - 			error_msg_and_die("path %s not found in filesystem", gopt[i]);
> - 		while((p = strchr(gopt[i], '/')))
> - 			*p = '_';
> - 		SNPRINTF(fname, MAX_FILENAME-1, "%s.blk", gopt[i]);
> - 		fh = xfopen(fname, "wb");
> --		fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
> -+		fprintf(fh, "%d:", get_nod(fs, nod, &ni)->i_size);
> -+		put_nod(ni);
> - 		flist_blocks(fs, nod, fh);
> - 		fclose(fh);
> - 	}
> --	if(strcmp(fsout, "-"))
> --	{
> --		FILE * fh = xfopen(fsout, "wb");
> --		dump_fs(fs, fh, bigendian);
> --		fclose(fh);
> --	}
> --	else
> --		dump_fs(fs, stdout, bigendian);
> -+	finish_fs(fs);
> -+	if(strcmp(fsout, "-") == 0)
> -+		copy_file(fs, stdout, fs->f, fs->sb->s_blocks_count);
> -+
> - 	free_fs(fs);
> - 	return 0;
> - }
> -Index: genext2fs-1.4.1/cache.h
> -===================================================================
> ---- /dev/null
> -+++ genext2fs-1.4.1/cache.h
> -@@ -0,0 +1,128 @@
> -+#ifndef __CACHE_H__
> -+#define __CACHE_H__
> -+
> -+#include "list.h"
> -+
> -+#define CACHE_LISTS 256
> -+
> -+typedef struct
> -+{
> -+    list_elem link;
> -+    list_elem lru_link;
> -+} cache_link;
> -+
> -+typedef struct
> -+{
> -+    /* LRU list holds unused items */
> -+    unsigned int lru_entries;
> -+    list_elem lru_list;
> -+    unsigned int max_free_entries;
> -+
> -+    unsigned int entries;
> -+    list_elem lists[CACHE_LISTS];
> -+    unsigned int (*elem_val)(cache_link *elem);
> -+    void (*freed)(cache_link *elem);
> -+} listcache;
> -+
> -+static inline void
> -+cache_add(listcache *c, cache_link *elem)
> -+{
> -+    unsigned int hash = c->elem_val(elem) % CACHE_LISTS;
> -+    int delcount = c->lru_entries - c->max_free_entries;
> -+
> -+    if (delcount > 0) {
> -+        /* Delete some unused items. */
> -+        list_elem *lru, *next;
> -+        cache_link *l;
> -+        list_for_each_elem_safe(&c->lru_list, lru, next) {
> -+            l = container_of(lru, cache_link, lru_link);
> -+            list_del(lru);
> -+            list_del(&l->link);
> -+            c->entries--;
> -+            c->lru_entries--;
> -+            c->freed(l);
> -+            delcount--;
> -+            if (delcount <= 0)
> -+                break;
> -+        }
> -+    }
> -+
> -+    c->entries++;
> -+    list_item_init(&elem->lru_link); /* Mark it not in the LRU list */
> -+    list_add_after(&c->lists[hash], &elem->link);
> -+}
> -+
> -+static inline void
> -+cache_item_set_unused(listcache *c, cache_link *elem)
> -+{
> -+    list_add_before(&c->lru_list, &elem->lru_link);
> -+    c->lru_entries++;
> -+}
> -+
> -+static inline cache_link *
> -+cache_find(listcache *c, unsigned int val)
> -+{
> -+    unsigned int hash = val % CACHE_LISTS;
> -+    list_elem *elem;
> -+
> -+    list_for_each_elem(&c->lists[hash], elem) {
> -+        cache_link *l = container_of(elem, cache_link, link);
> -+        if (c->elem_val(l) == val) {
> -+            if (!list_empty(&l->lru_link)) {
> -+                /* It's in the unused list, remove it. */
> -+                list_del(&l->lru_link);
> -+                list_item_init(&l->lru_link);
> -+                c->lru_entries--;
> -+            }
> -+            return l;
> -+        }
> -+    }
> -+    return NULL;
> -+}
> -+
> -+static inline int
> -+cache_flush(listcache *c)
> -+{
> -+    list_elem *elem, *next;
> -+    cache_link *l;
> -+    int i;
> -+
> -+    list_for_each_elem_safe(&c->lru_list, elem, next) {
> -+        l = container_of(elem, cache_link, lru_link);
> -+        list_del(elem);
> -+        list_del(&l->link);
> -+        c->entries--;
> -+        c->lru_entries--;
> -+        c->freed(l);
> -+    }
> -+
> -+    for (i = 0; i < CACHE_LISTS; i++) {
> -+        list_for_each_elem_safe(&c->lists[i], elem, next) {
> -+            l = container_of(elem, cache_link, link);
> -+            list_del(&l->link);
> -+            c->entries--;
> -+            c->freed(l);
> -+        }
> -+    }
> -+
> -+    return c->entries || c->lru_entries;
> -+}
> -+
> -+static inline void
> -+cache_init(listcache *c, unsigned int max_free_entries,
> -+       unsigned int (*elem_val)(cache_link *elem),
> -+       void (*freed)(cache_link *elem))
> -+{
> -+    int i;
> -+
> -+    c->entries = 0;
> -+    c->lru_entries = 0;
> -+    c->max_free_entries = max_free_entries;
> -+    list_init(&c->lru_list);
> -+    for (i = 0; i < CACHE_LISTS; i++)
> -+        list_init(&c->lists[i]);
> -+    c->elem_val = elem_val;
> -+    c->freed = freed;
> -+}
> -+
> -+#endif /* __CACHE_H__ */
> -Index: genext2fs-1.4.1/list.h
> -===================================================================
> ---- /dev/null
> -+++ genext2fs-1.4.1/list.h
> -@@ -0,0 +1,78 @@
> -+#ifndef __LIST_H__
> -+#define __LIST_H__
> -+
> -+#if STDC_HEADERS
> -+# include <stdlib.h>
> -+# include <stddef.h>
> -+#else
> -+# if HAVE_STDLIB_H
> -+#  include <stdlib.h>
> -+# endif
> -+# if HAVE_STDDEF_H
> -+#  include <stddef.h>
> -+# endif
> -+#endif
> -+
> -+#ifndef offsetof
> -+#define offsetof(st, m) \
> -+     ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
> -+#endif
> -+
> -+#define container_of(ptr, type, member) ({ \
> -+                const typeof( ((type *)0)->member ) *__mptr = (ptr); \
> -+                (type *)( (char *)__mptr - offsetof(type,member) );})
> -+
> -+typedef struct list_elem
> -+{
> -+    struct list_elem *next;
> -+    struct list_elem *prev;
> -+} list_elem;
> -+
> -+static inline void list_init(list_elem *list)
> -+{
> -+    list->next = list;
> -+    list->prev = list;
> -+}
> -+
> -+static inline void list_add_after(list_elem *pos, list_elem *elem)
> -+{
> -+    elem->next = pos->next;
> -+    elem->prev = pos;
> -+    pos->next->prev = elem;
> -+    pos->next = elem;
> -+}
> -+
> -+static inline void list_add_before(list_elem *pos, list_elem *elem)
> -+{
> -+    elem->prev = pos->prev;
> -+    elem->next = pos;
> -+    pos->prev->next = elem;
> -+    pos->prev = elem;
> -+}
> -+
> -+static inline void list_del(list_elem *elem)
> -+{
> -+    elem->next->prev = elem->prev;
> -+    elem->prev->next = elem->next;
> -+}
> -+
> -+static inline void list_item_init(list_elem *elem)
> -+{
> -+    elem->next = elem;
> -+    elem->prev = elem;
> -+}
> -+
> -+static inline int list_empty(list_elem *elem)
> -+{
> -+    return elem->next == elem;
> -+}
> -+
> -+#define list_for_each_elem(list, curr)            \
> -+    for ((curr) = (list)->next; (curr) != (list); (curr) = (curr)->next)
> -+
> -+#define list_for_each_elem_safe(list, curr, next)    \
> -+    for ((curr) = (list)->next, (next) = (curr)->next;    \
> -+         (curr) != (list);                    \
> -+         (curr) = (next), (next) = (curr)->next)
> -+
> -+#endif /* __LIST_H__ */
> diff --git a/package/genext2fs/genext2fs.hash b/package/genext2fs/genext2fs.hash
> index add44c4c4e..20bb1c641b 100644
> --- a/package/genext2fs/genext2fs.hash
> +++ b/package/genext2fs/genext2fs.hash
> @@ -1,3 +1,3 @@
>  # Locally computed:
> -sha256  404dbbfa7a86a6c3de8225c8da254d026b17fd288e05cec4df2cc7e1f4feecfc  genext2fs-1.4.1.tar.gz
> +sha256  d3861e4fe89131bd21fbd25cf0b683b727b5c030c4c336fadcd738ada830aab0  genext2fs-1.5.0.tar.gz
>  sha256  32b1062f7da84967e7019d01ab805935caa7ab7321a7ced0e30ebe75e5df1670  COPYING
> diff --git a/package/genext2fs/genext2fs.mk b/package/genext2fs/genext2fs.mk
> index dd907c8b12..adfa412e66 100644
> --- a/package/genext2fs/genext2fs.mk
> +++ b/package/genext2fs/genext2fs.mk
> @@ -4,10 +4,12 @@
>  #
>  ################################################################################
>  
> -GENEXT2FS_VERSION = 1.4.1
> -GENEXT2FS_SITE = http://downloads.sourceforge.net/project/genext2fs/genext2fs/$(GENEXT2FS_VERSION)
> +GENEXT2FS_VERSION = 1.5.0
> +GENEXT2FS_SITE = $(call github,bestouff,genext2fs,v$(GENEXT2FS_VERSION))
>  GENEXT2FS_LICENSE = GPL-2.0
>  GENEXT2FS_LICENSE_FILES = COPYING
> +# From git
> +GENEXT2FS_AUTORECONF = YES
>  
>  $(eval $(autotools-package))
>  $(eval $(host-autotools-package))
> 



More information about the buildroot mailing list