package/genext2fs: bump to version 1.5.0
authorFabrice Fontaine <fontaine.fabrice@gmail.com>
Wed, 14 Apr 2021 21:44:39 +0000 (23:44 +0200)
committerArnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
Thu, 15 Apr 2021 19:08:17 +0000 (21:08 +0200)
- 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@gmail.com>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
package/genext2fs/0001-update-genext2fs.c-to-rev-1.118.patch [deleted file]
package/genext2fs/genext2fs.hash
package/genext2fs/genext2fs.mk

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 (file)
index 755ee9d..0000000
+++ /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@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__ */
index add44c4c4e8a49a76503855cae86376fa6973453..20bb1c641b129028b36903b5760486400ce12f05 100644 (file)
@@ -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
index dd907c8b1236497cce5e87e2fbc2cbdd37726929..adfa412e6602bca01ba1f012653109ba591cadd6 100644 (file)
@@ -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))