From 709c4d66e0b107ca606941b988bad717c0b45d9b Mon Sep 17 00:00:00 2001
From: Denys Dmytriyenko <denis@denix.org>
Date: Tue, 17 Mar 2009 14:32:59 -0400
Subject: rename packages/ to recipes/ per earlier agreement

See links below for more details:
http://thread.gmane.org/gmane.comp.handhelds.openembedded/21326
http://thread.gmane.org/gmane.comp.handhelds.openembedded/21816

Signed-off-by: Denys Dmytriyenko <denis@denix.org>
Acked-by: Mike Westerhof <mwester@dls.net>
Acked-by: Philip Balister <philip@balister.org>
Acked-by: Khem Raj <raj.khem@gmail.com>
Acked-by: Marcin Juszkiewicz <hrw@openembedded.org>
Acked-by: Koen Kooi <koen@openembedded.org>
Acked-by: Frans Meulenbroeks <fransmeulenbroeks@gmail.com>
---
 recipes/genext2fs/files/volume.patch               |  107 +
 .../genext2fs-1.3+cvs/bytes_per_inode.patch        |   76 +
 recipes/genext2fs/genext2fs-1.3/autosize.patch     |  339 ++++
 recipes/genext2fs/genext2fs-1.3/misc.patch         | 2143 ++++++++++++++++++++
 recipes/genext2fs/genext2fs-native_1.3+1.4rc1.bb   |   10 +
 recipes/genext2fs/genext2fs-native_1.3+cvs.bb      |   10 +
 recipes/genext2fs/genext2fs-native_1.3.bb          |   11 +
 recipes/genext2fs/genext2fs.inc                    |    4 +
 recipes/genext2fs/genext2fs_1.3+1.4rc1.bb          |   10 +
 recipes/genext2fs/genext2fs_1.3+cvs.bb             |    9 +
 recipes/genext2fs/genext2fs_1.3.bb                 |   15 +
 11 files changed, 2734 insertions(+)
 create mode 100644 recipes/genext2fs/files/volume.patch
 create mode 100644 recipes/genext2fs/genext2fs-1.3+cvs/bytes_per_inode.patch
 create mode 100644 recipes/genext2fs/genext2fs-1.3/autosize.patch
 create mode 100644 recipes/genext2fs/genext2fs-1.3/misc.patch
 create mode 100644 recipes/genext2fs/genext2fs-native_1.3+1.4rc1.bb
 create mode 100644 recipes/genext2fs/genext2fs-native_1.3+cvs.bb
 create mode 100644 recipes/genext2fs/genext2fs-native_1.3.bb
 create mode 100644 recipes/genext2fs/genext2fs.inc
 create mode 100644 recipes/genext2fs/genext2fs_1.3+1.4rc1.bb
 create mode 100644 recipes/genext2fs/genext2fs_1.3+cvs.bb
 create mode 100644 recipes/genext2fs/genext2fs_1.3.bb

(limited to 'recipes/genext2fs')

diff --git a/recipes/genext2fs/files/volume.patch b/recipes/genext2fs/files/volume.patch
new file mode 100644
index 0000000000..32ef8dc52b
--- /dev/null
+++ b/recipes/genext2fs/files/volume.patch
@@ -0,0 +1,107 @@
+Index: genext2fs-1.4rc1/genext2fs.c
+===================================================================
+--- genext2fs-1.4rc1.orig/genext2fs.c
++++ genext2fs-1.4rc1/genext2fs.c
+@@ -409,7 +409,9 @@ swab32(uint32 val)
+ typedef struct
+ {
+ 	superblock_decl
+-	uint32 s_reserved[235];       // Reserved
++	uint32  s_reserved1[9];
++	char s_volume[16];
++	uint32 s_reserved2[222];       // Reserved
+ } superblock;
+ 
+ typedef struct
+@@ -1122,7 +1124,7 @@ extend_blk(filesystem *fs, uint32 nod, b
+ 	while(create)
+ 	{
+ 		int i, copyb = 0;
+-		if(!(fs->sb.s_reserved[200] & OP_HOLES))
++		if(!(fs->sb.s_reserved2[187] & OP_HOLES))
+ 			copyb = 1;
+ 		else
+ 			for(i = 0; i < BLOCKSIZE / 4; i++)
+@@ -1784,7 +1786,8 @@ swap_badfs(filesystem *fs)
+ 
+ // 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, char *volumeid)
+ {
+ 	int i;
+ 	filesystem *fs;
+@@ -1847,6 +1850,9 @@ init_fs(int nbblocks, int nbinodes, int 
+ 	fs->sb.s_magic = EXT2_MAGIC_NUMBER;
+ 	fs->sb.s_lastcheck = fs_timestamp;
+ 
++	if (volumeid != NULL)
++		strncpy(fs->sb.s_volume, volumeid, sizeof(fs->sb.s_volume));
++
+ 	// set up groupdescriptors
+ 	for(i = 0,bbmpos=2+gd,ibmpos=3+gd,itblpos =4+gd;
+ 		i<nbgroups;
+@@ -1945,7 +1951,7 @@ init_fs(int nbblocks, int nbinodes, int 
+ 
+ 	// options for me
+ 	if(holes)
+-		fs->sb.s_reserved[200] |= OP_HOLES;
++		fs->sb.s_reserved2[187] |= OP_HOLES;
+ 	
+ 	return fs;
+ }
+@@ -2276,7 +2282,7 @@ static void
+ dump_fs(filesystem *fs, FILE * fh, int swapit)
+ {
+ 	int nbblocks = fs->sb.s_blocks_count;
+-	fs->sb.s_reserved[200] = 0;
++	fs->sb.s_reserved2[187] = 0;
+ 	if(swapit)
+ 		swap_goodfs(fs);
+ 	if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
+@@ -2341,6 +2347,7 @@ main(int argc, char **argv)
+ 	uint16 endian = 1;
+ 	int bigendian = !*(char*)&endian;
+ 	filesystem *fs;
++	char *volumeid = NULL;
+ 	int i;
+ 	int c;
+ 	struct stats stats;
+@@ -2359,6 +2366,7 @@ main(int argc, char **argv)
+ 	  { "size-in-blocks",	required_argument,	NULL, 'b' },
+ 	  { "bytes-per-inode",	required_argument,	NULL, 'i' },
+ 	  { "number-of-inodes",	required_argument,	NULL, 'I' },
++	  { "volume-id",	required_argument,	NULL, 'L' },
+ 	  { "reserved-blocks",	required_argument,	NULL, 'r' },
+ 	  { "block-map",	required_argument,	NULL, 'g' },
+ 	  { "fill-value",	required_argument,	NULL, 'e' },
+@@ -2372,7 +2380,7 @@ main(int argc, char **argv)
+ 	  { 0, 0, 0, 0}
+ 	} ;
+ 
+-	while((c = getopt_long(argc, argv, "x:d:D:b:I:i:r:g:e:zfqUPhv", longopts, NULL)) != EOF) {
++	while((c = getopt_long(argc, argv, "x:d:D:b:I:i:L:r:g:e:zfqUPhv", longopts, NULL)) != EOF) {
+ 		switch(c)
+ 		{
+ 			case 'x':
+@@ -2391,6 +2399,9 @@ main(int argc, char **argv)
+ 			case 'I':
+ 				nbinodes = SI_atof(optarg);
+ 				break;
++			case 'L':
++				volumeid = optarg;
++				break;
+ 			case 'r':
+ 				nbresrvd = SI_atof(optarg);
+ 				break;
+@@ -2517,7 +2528,8 @@ main(int argc, char **argv)
+ 			nbresrvd = nbblocks * RESERVED_BLOCKS;
+ 		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, volumeid);
+ 	}
+ 	for(i = 0; i < didx; i++)
+ 	{
diff --git a/recipes/genext2fs/genext2fs-1.3+cvs/bytes_per_inode.patch b/recipes/genext2fs/genext2fs-1.3+cvs/bytes_per_inode.patch
new file mode 100644
index 0000000000..729f5d7708
--- /dev/null
+++ b/recipes/genext2fs/genext2fs-1.3+cvs/bytes_per_inode.patch
@@ -0,0 +1,76 @@
+Index: genext2fs/genext2fs.c
+===================================================================
+--- genext2fs.orig/genext2fs.c	2005-03-10 21:18:08.000000000 -0500
++++ genext2fs/genext2fs.c	2005-03-13 11:41:55.182746832 -0500
+@@ -2284,6 +2284,7 @@
+ 	"  -d, --root <directory>\n"
+ 	"  -D, --devtable <file>\n"
+ 	"  -b, --size-in-blocks <blocks>\n"
++	"  -I, --bytes-per-inode <bytes per inode>\n"
+ 	"  -i, --number-of-inodes <number of inodes>\n"
+ 	"  -r, --reserved-blocks <number of reserved blocks>\n"
+ 	"  -g, --block-map <path>     Generate a block map file for this path.\n"
+@@ -2314,6 +2315,7 @@
+ 	int nbresrvd = -1;
+ 	int tmp_nbblocks = -1;
+ 	int tmp_nbinodes = -1;
++	int bytes_per_inode = BYTES_PER_INODE;
+ 	uint32 fs_timestamp = -1;
+ 	char * fsout = "-";
+ 	char * fsin = 0;
+@@ -2345,6 +2347,7 @@
+ 	  { "root",		required_argument,	NULL, 'd' },
+ 	  { "devtable",		required_argument,	NULL, 'D' },
+ 	  { "size-in-blocks",	required_argument,	NULL, 'b' },
++	  { "bytes-per-inode",	required_argument,	NULL, 'I' },
+ 	  { "number-of-inodes",	required_argument,	NULL, 'i' },
+ 	  { "reserved-blocks",	required_argument,	NULL, 'r' },
+ 	  { "block-map",	required_argument,	NULL, 'g' },
+@@ -2359,7 +2362,7 @@
+ 	  { 0, 0, 0, 0}
+ 	} ;
+ 
+-	while((c = getopt_long(argc, argv, "x:d:D:b:i:r:g:e:zfqUPhv", longopts, NULL)) != EOF) {
++	while((c = getopt_long(argc, argv, "x:d:D:b:I:i:r:g:e:zfqUPhv", longopts, NULL)) != EOF) {
+ 		switch(c)
+ 		{
+ 			case 'x':
+@@ -2372,6 +2375,9 @@
+ 			case 'b':
+ 				nbblocks = atoi(optarg);
+ 				break;
++			case 'I':
++				bytes_per_inode = atoi(optarg);
++				break;
+ 			case 'i':
+ 				nbinodes = atoi(optarg);
+ 				break;
+@@ -2468,24 +2474,22 @@
+ 			if(pdest)
+ 				*pdest = ':';
+ 		}
+-	
++
+ 		tmp_nbinodes = stats.ninodes + EXT2_FIRST_INO + 1;
+ 		tmp_nbblocks = stats.nblocks; // FIXME: should add space taken by inodes too
+-	
++
+ 		if(tmp_nbblocks > nbblocks)
+ 		{
+ 			fprintf(stderr, "number of blocks too low, increasing to %d\n",tmp_nbblocks);
+ 			nbblocks = tmp_nbblocks;
+ 		}
++		if(nbinodes == -1)
++			nbinodes = nbblocks * BLOCKSIZE / rndup(bytes_per_inode, BLOCKSIZE);
+ 		if(tmp_nbinodes > nbinodes)
+ 		{
+ 			fprintf(stderr, "number of inodes too low, increasing to %d\n",tmp_nbinodes);
+ 			nbinodes = tmp_nbinodes;
+ 		}
+-		if(nbblocks == -1)
+-			error_msg_and_die("filesystem size unspecified");
+-		if(nbinodes == -1)
+-			nbinodes = nbblocks * BLOCKSIZE / rndup(BYTES_PER_INODE, BLOCKSIZE);
+ 		if(nbresrvd == -1)
+ 			nbresrvd = nbblocks * RESERVED_BLOCKS;
+ 		if(fs_timestamp == -1)
diff --git a/recipes/genext2fs/genext2fs-1.3/autosize.patch b/recipes/genext2fs/genext2fs-1.3/autosize.patch
new file mode 100644
index 0000000000..a4318a6eee
--- /dev/null
+++ b/recipes/genext2fs/genext2fs-1.3/autosize.patch
@@ -0,0 +1,339 @@
+
+#
+# Patch managed by http://www.holgerschurig.de/patcher.html
+#
+
+--- genext2fs-1.3.orig/genext2fs.c~autosize.patch
++++ genext2fs-1.3.orig/genext2fs.c
+@@ -4,6 +4,11 @@
+ // ext2 filesystem generator for embedded systems
+ // Copyright (C) 2000 Xavier Bestel <xavier.bestel@free.fr>
+ //
++// 'du' portions taken from coreutils/du.c in busybox:
++//	Copyright (C) 1999,2000 by Lineo, inc. and John Beppu
++//	Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
++//	Copyright (C) 2002  Edward Betts <edward@debian.org>
++//
+ // This program is free software; you can redistribute it and/or
+ // modify it under the terms of the GNU General Public License
+ // as published by the Free Software Foundation; version
+@@ -79,9 +84,93 @@
+ #include <ctype.h>
+ #include <errno.h>
+ #include <fcntl.h>
++#include <sys/types.h>
++#include <getopt.h>
++
++#define HASH_SIZE	311		/* Should be prime */
++#define hash_inode(i)	((i) % HASH_SIZE)
++
++typedef struct ino_dev_hash_bucket_struct {
++	struct ino_dev_hash_bucket_struct *next;
++	ino_t ino;
++	dev_t dev;
++	char name[1];
++} ino_dev_hashtable_bucket_t;
++
++static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
++
++struct stats {
++	unsigned long nblocks;
++	unsigned long ninodes;
++};
++
++int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
++{
++	ino_dev_hashtable_bucket_t *bucket;
++
++	bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
++	while (bucket != NULL) {
++		if ((bucket->ino == statbuf->st_ino) &&
++		    (bucket->dev == statbuf->st_dev))
++		{
++			if (name) *name = bucket->name;
++			return 1;
++		}
++		bucket = bucket->next;
++	}
++	return 0;
++}
++
++/* Add statbuf to statbuf hash table */
++void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
++{
++	int i;
++	size_t s;
++	ino_dev_hashtable_bucket_t *bucket;
++    
++	i = hash_inode(statbuf->st_ino);
++	s = name ? strlen(name) : 0;
++	bucket = malloc(sizeof(ino_dev_hashtable_bucket_t) + s);
++	bucket->ino = statbuf->st_ino;
++	bucket->dev = statbuf->st_dev;
++	if (name)
++		strcpy(bucket->name, name);
++	else
++		bucket->name[0] = '\0';
++	bucket->next = ino_dev_hashtable[i];
++	ino_dev_hashtable[i] = bucket;
++}
++
++/* Clear statbuf hash table */
++void reset_ino_dev_hashtable(void)
++{
++	int i;
++	ino_dev_hashtable_bucket_t *bucket;
++
++	for (i = 0; i < HASH_SIZE; i++) {
++		while (ino_dev_hashtable[i] != NULL) {
++			bucket = ino_dev_hashtable[i]->next;
++			free(ino_dev_hashtable[i]);
++			ino_dev_hashtable[i] = bucket;
++		}
++	}
++}
+ 
++static int count_ino_in_hashtable(void)
++{
++	long count = 0;
++	int i;
+ 
++	for (i = 0; i < HASH_SIZE; i++) {
++		ino_dev_hashtable_bucket_t *bucket = ino_dev_hashtable[i];
++		while (bucket != NULL) {
++			count++;
++			bucket = bucket->next;
++		}
++	}
+ 
++	return count;
++}
+ 
+ // block size
+ 
+@@ -1178,6 +1267,38 @@
+ 	return n;
+ }
+ 
++void stats_from_dir(struct stats *stats)
++{
++	DIR *dh;
++	struct dirent *dent;
++	struct stat st;
++	if(!(dh = opendir(".")))
++		perror_msg_and_die(".");
++	while((dent = readdir(dh)))
++	{
++		if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
++			continue;
++		lstat(dent->d_name, &st);
++		if (S_ISLNK(st.st_mode)) {
++			stats->ninodes++;
++		} else if (S_ISDIR(st.st_mode)) {
++			if(chdir(dent->d_name) < 0)
++				perror_msg_and_die(dent->d_name);
++			stats->ninodes++;
++			stats_from_dir(stats);
++			chdir("..");
++		} else {
++			if (!is_in_ino_dev_hashtable(&st, NULL)) {
++				add_to_ino_dev_hashtable(&st, NULL);
++				stats->nblocks += (st.st_blocks >> 1);
++				stats->ninodes++;
++			}
++		}
++	}
++	closedir(dh);
++	reset_ino_dev_hashtable();
++}
++
+ // adds a tree of entries to the filesystem from current dir
+ void add2fs_from_dir(filesystem *fs, uint32 this_nod)
+ {
+@@ -1436,7 +1557,6 @@
+ 		free_blocks_per_group = nbblocks_per_group - overhead_per_group;
+ 	}
+ 	nbblocks = nbblocks_per_group * nbgroups + 1;
+-	
+ 
+ 	if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
+ 		error_msg_and_die("not enough memory for filesystem");
+@@ -1891,6 +2011,7 @@
+     Regular files must exist in the target root directory.  If a char,
+     block, fifo, or directory does not exist, it will be created.
+ */
++
+ static int interpret_table_entry(filesystem *fs, char *line)
+ {
+ 	char type, *name = NULL, *tmp, *dir, *bname;
+@@ -2026,6 +2147,52 @@
+ 	return 0;
+ }
+ 
++static int stats_from_table_entry(char *line, struct stats *stats)
++{
++	char type, *name = NULL, *tmp, *dir, *bname;
++	unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
++	unsigned long start = 0, increment = 1, count = 0;
++	inode *entry;
++
++	if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
++				SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
++				&start, &increment, &count) < 0) 
++	{
++		return 1;
++	}
++
++	if (!strcmp(name, "/")) {
++		error_msg_and_die("Device table entries require absolute paths");
++	}
++
++	tmp = xstrdup(name);
++	bname = xstrdup(basename(tmp));
++	free(tmp);
++	switch (type) {
++		case 'd':
++			stats->ninodes++;
++			break;
++		case 'c':
++		case 'b':
++			if (count > 0) {
++				dev_t rdev;
++				char *dname;
++				unsigned long i;
++				for (i = start; i < count; i++) {
++					asprintf(&dname, "%s%lu", bname, i);
++					stats->ninodes++;
++					free(dname);
++				}
++			} else {
++				stats->ninodes++;
++			}
++			break;
++	}
++	free(bname);
++	free(name);
++	return 0;
++}
++
+ static int parse_device_table(filesystem *root, FILE * file)
+ {
+ 	char *line;
+@@ -2070,6 +2237,45 @@
+ 	return status;
+ }
+ 
++static int stats_from_dev_table(FILE *file, struct stats *stats)
++{
++	char *line;
++	int status = 0;
++	size_t length = 0;
++
++	/* Looks ok so far.  The general plan now is to read in one
++	 * line at a time, check for leading comment delimiters ('#'),
++	 * then try and parse the line as a device table.  If we fail
++	 * to parse things, try and help the poor fool to fix their
++	 * device table with a useful error msg... */
++	line = NULL;
++	while (getline(&line, &length, file) != -1) {
++		/* First trim off any whitespace */
++		int len = strlen(line);
++
++		/* trim trailing whitespace */
++		while (len > 0 && isspace(line[len - 1]))
++			line[--len] = '\0';
++		/* trim leading whitespace */
++		memmove(line, &line[strspn(line, " \n\r\t\v")], len);
++
++		/* How long are we after trimming? */
++		len = strlen(line);
++
++		/* If this is NOT a comment line, try to interpret it */
++		if (len && *line != '#') {
++			if (stats_from_table_entry(line, stats))
++				status = 1;
++		}
++
++		free(line);
++		line = NULL;
++	}
++	fclose(file);
++
++	return status;
++}
++
+ /*
+ Local Variables:
+ c-file-style: "linux"
+@@ -2112,6 +2318,8 @@
+ 	int nbblocks = -1;
+ 	int nbinodes = -1;
+ 	int nbresrvd = -1;
++	int tmp_nbblocks = -1;
++	int tmp_nbinodes = -1;
+ 	char * fsout = "-";
+ 	char * fsin = 0;
+ 	char * dopt[MAX_DOPT];
+@@ -2128,6 +2336,7 @@
+ 	int c;
+ 	struct stat sb;
+ 	FILE *devtable = NULL;
++	struct stats stats;
+ 
+ 	app_name = argv[0];
+ 	while((c = getopt(argc, argv, "x:d:b:i:r:g:e:zvhD:f:qUP")) != EOF)
+@@ -2184,6 +2393,7 @@
+ 			default:
+ 				exit(1);
+ 		}
++
+ 	if(optind < (argc - 1))
+ 		error_msg_and_die("too many arguments");
+ 	if(optind == (argc - 1))
+@@ -2201,6 +2411,46 @@
+ 	}
+ 	else
+ 	{
++		stats.ninodes = 0;
++		stats.nblocks = 0;
++		for(i = 0; i < didx; i++)
++		{
++			struct stat st;
++			char *pdir;
++			stat(dopt[i], &st);
++			switch(st.st_mode & S_IFMT)
++			{
++				case S_IFDIR:
++					if(!(pdir = getcwd(0, GETCWD_SIZE)))
++						perror_msg_and_die(dopt[i]);
++					if(chdir(dopt[i]) < 0)
++						perror_msg_and_die(dopt[i]);
++					stats_from_dir(&stats);
++					if(chdir(pdir) < 0)
++						perror_msg_and_die(pdir);
++					free(pdir);
++					break;
++				default:
++					error_msg_and_die("%s is neither a file nor a directory", dopt[i]);
++			}
++		}
++	
++		if(devtable)
++			stats_from_dev_table(devtable, &stats);
++	
++		tmp_nbinodes = stats.ninodes + EXT2_FIRST_INO + 1;
++		tmp_nbblocks = stats.nblocks;
++	
++		if(tmp_nbblocks > nbblocks)
++		{
++			printf("Number of blocks too low, increasing to %d\n",tmp_nbblocks);
++			nbblocks = tmp_nbblocks;
++		}
++		if(tmp_nbinodes > nbinodes)
++		{
++			printf("Number of inodes too low, increasing to %d\n",tmp_nbinodes);
++			nbinodes = tmp_nbinodes;
++		}
+ 		if(nbblocks == -1)
+ 			error_msg_and_die("filesystem size unspecified");
+ 		if(nbinodes == -1)
diff --git a/recipes/genext2fs/genext2fs-1.3/misc.patch b/recipes/genext2fs/genext2fs-1.3/misc.patch
new file mode 100644
index 0000000000..e5849eb797
--- /dev/null
+++ b/recipes/genext2fs/genext2fs-1.3/misc.patch
@@ -0,0 +1,2143 @@
+--- genext2fs-1.3.orig/Makefile
++++ genext2fs-1.3/Makefile
+@@ -0,0 +1,25 @@
++all: genext2fs
++INSTALL=install
++
++install:
++	$(INSTALL) -d $(DESTDIR)/usr/bin/
++	$(INSTALL) -m 755 genext2fs $(DESTDIR)/usr/bin/
++	$(INSTALL) -d $(DESTDIR)/usr/share/man/man8/
++	$(INSTALL) -m 644 genext2fs.8 $(DESTDIR)/usr/share/man/man8/
++
++clean:
++	-rm genext2fs
++	rm -rf test ext2.img
++
++check: all
++	mkdir -p test
++	dd if=/dev/zero of=test/zero count=1
++	./genext2fs -b 4096 -d test ext2.img
++	
++	md5=`md5sum ext2.img | cut -f 1 -d " "`; \
++	if [ "$$md5" != "a736fce6d45ea3631b01fd7b8f623131" ] ; then \
++		echo "test failed."; \
++	else \
++		echo "test succeeded."; \
++	fi
++	
+diff -urN genext2fs-1.3.orig/dev.txt genext2fs-1.3/dev.txt
+--- genext2fs-1.3.orig/dev.txt	2000-09-28 09:03:19.000000000 -0600
++++ genext2fs-1.3/dev.txt	1969-12-31 17:00:00.000000000 -0700
+@@ -1,94 +0,0 @@
+-drwx		/dev
+-crw-	10,190	/dev/lcd
+-crw-	10,191	/dev/splc781
+-crw-	4,0	/dev/console
+-crw-	5,64	/dev/cua0
+-crw-	5,65	/dev/cua1
+-crw-	5,66	/dev/cua2
+-crw-	5,70	/dev/cua6
+-crw-	5,71	/dev/cua7
+-crw-	5,72	/dev/cua8
+-crw-	5,73	/dev/cua9
+-crw-	29,0	/dev/fb0
+-crw-	29,32	/dev/fb1
+-crw-	1,2	/dev/kmem
+-crw-	1,1	/dev/mem
+-crw-	1,3	/dev/null
+-crw-	2,2	/dev/ptyp2
+-crw-	2,3	/dev/ptyp3
+-crw-	2,5	/dev/ptyp5
+-crw-	2,4	/dev/ptyp4
+-crw-	10,178	/dev/triokb
+-crw-	2,0	/dev/ptyp0
+-crw-	2,6	/dev/ptyp6
+-crw-	2,7	/dev/ptyp7
+-crw-	2,8	/dev/ptyp8
+-crw-	2,9	/dev/ptyp9
+-crw-	2,10	/dev/ptypa
+-crw-	2,11	/dev/ptypb
+-crw-	2,12	/dev/ptypc
+-crw-	2,13	/dev/ptypd
+-crw-	2,14	/dev/ptype
+-crw-	2,15	/dev/ptypf
+-brw-	1,0	/dev/ram0
+-brw-	1,1	/dev/ram1
+-brw-	1,2	/dev/ram2
+-brw-	1,3	/dev/ram3
+-br--	31,0	/dev/rom0
+-brw-	31,1	/dev/rom1
+-brw-	31,2	/dev/rom2
+-brw-	31,3	/dev/rom3
+-crw-	5,0	/dev/tty
+-crw-	4,0	/dev/tty0
+-crwx	4,1	/dev/tty1
+-crwx	4,2	/dev/tty2
+-crwx	4,3	/dev/tty3
+-crwx	4,4	/dev/tty4
+-crw-	4,5	/dev/tty5
+-crwx	4,6	/dev/tty6
+-crw-	4,7	/dev/tty7
+-crw-	4,8	/dev/tty8
+-crw-	4,9	/dev/tty9
+-crw-	4,64	/dev/ttyS0
+-crw-	4,65	/dev/ttyS1
+-crw-	4,66	/dev/ttyS2
+-crw-	4,67	/dev/ttyS3
+-crw-	4,68	/dev/ttyS4
+-crw-	4,69	/dev/ttyS5
+-crw-	4,70	/dev/ttyS6
+-crw-	4,71	/dev/ttyS7
+-crw-	4,72	/dev/ttyS8
+-crw-	4,73	/dev/ttyS9
+-crw-	3,0	/dev/ttyp0
+-crw-	3,1	/dev/ttyp1
+-crw-	3,2	/dev/ttyp2
+-crw-	3,3	/dev/ttyp3
+-crw-	3,4	/dev/ttyp4
+-crw-	3,5	/dev/ttyp5
+-crw-	3,6	/dev/ttyp6
+-crw-	3,7	/dev/ttyp7
+-crw-	3,8	/dev/ttyp8
+-crw-	3,9	/dev/ttyp9
+-crw-	3,10	/dev/ttypa
+-crw-	3,11	/dev/ttypb
+-crw-	3,12	/dev/ttypc
+-crw-	3,13	/dev/ttypd
+-crw-	3,14	/dev/ttype
+-crw-	3,15	/dev/ttypf
+-crw-	1,5	/dev/zero
+-crwx	10,111	/dev/dtedrv
+-crwx	4,110	/dev/ttyM
+-crw-	77,1	/dev/tssnd
+-crw-	77,2	/dev/tstone
+-crw-	2,1	/dev/ptyp1
+-crwx	10,180	/dev/triohook
+-crw-	90,0	/dev/mtd0
+-brw-	44,0	/dev/ftl0
+-crw-	10,175	/dev/tporta
+-crw-	10,176	/dev/tportb
+-crwx	10,100	/dev/softmodem
+-crwx	10,101	/dev/softmodem_signals
+-crwx	10,181	/dev/triovoice
+-crw-	5,67	/dev/cua3
+-crw-	5,68	/dev/cua4
+-crw-	5,69	/dev/cua5
+diff -urN genext2fs-1.3.orig/device_table.txt genext2fs-1.3/device_table.txt
+--- genext2fs-1.3.orig/device_table.txt	1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/device_table.txt	2003-04-21 01:41:42.000000000 -0600
+@@ -0,0 +1,129 @@
++# When building a target filesystem, it is desirable to not have to
++# become root and then run 'mknod' a thousand times.  Using a device 
++# table you can create device nodes and directories "on the fly".
++#
++# This is a sample device table file for use with genext2fs.  You can
++# do all sorts of interesting things with a device table file.  For
++# example, if you want to adjust the permissions on a particular file
++# you can just add an entry like:
++#   /sbin/foobar        f       2755    0       0       -       -       -       -       -
++# and (assuming the file /sbin/foobar exists) it will be made setuid
++# root (regardless of what its permissions are on the host filesystem.
++# Furthermore, you can use a single table entry to create a many device
++# minors.  For example, if I wanted to create /dev/hda and /dev/hda[0-15]
++# I could just use the following two table entries:
++#   /dev/hda    b       640     0       0       3       0       0       0       -
++#   /dev/hda    b       640     0       0       3       1       1       1       15
++# 
++# Device table entries take the form of:
++# <name>    <type>      <mode>  <uid>   <gid>   <major> <minor> <start> <inc>   <count>
++# where name is the file name,  type can be one of: 
++#       f       A regular file
++#       d       Directory
++#       c       Character special device file
++#       b       Block special device file
++#       p       Fifo (named pipe)
++# uid is the user id for the target file, gid is the group id for the
++# target file.  The rest of the entries (major, minor, etc) apply only 
++# to device special files.
++
++# Have fun
++# -Erik Andersen <andersen@codepoet.org>
++#
++
++#<name>		<type>	<mode>	<uid>	<gid>	<major>	<minor>	<start>	<inc>	<count>
++/dev		d	755	0	0	-	-	-	-	-
++/dev/mem	c	640	0	0	1	1	0	0	-
++/dev/kmem	c	640	0	0	1	2	0	0	-
++/dev/null	c	640	0	0	1	3	0	0	-
++/dev/zero	c	640	0	0	1	5	0	0	-
++/dev/random	c	640	0	0	1	8	0	0	-
++/dev/urandom	c	640	0	0	1	9	0	0	-
++/dev/tty	c	666	0	0	5	0	0	0	-
++/dev/tty	c	666	0	0	4	0	0	1	6
++/dev/console	c	640	0	0	5	1	0	0	-
++/dev/ram	b	640	0	0	1	1	0	0	-
++/dev/ram	b	640	0	0	1	0	0	1	4
++/dev/loop	b	640	0	0	7	0	0	1	2
++/dev/ptmx	c	666	0	0	5	2	0	0	-
++#/dev/ttyS	c	640	0	0	4	64	0	1	4
++#/dev/psaux	c	640	0	0	10	1	0	0	-
++#/dev/rtc	c	640	0	0	10	135	0	0	-
++
++# Adjust permissions on some normal files
++#/etc/shadow	f	600	0	0	-	-	-	-	-
++#/bin/tinylogin	f	4755	0	0	-	-	-	-	-
++
++# User-mode Linux stuff
++/dev/ubda	b	640	0	0	98	0	0	0	-
++/dev/ubda	b	640	0	0	98	1	1	1	15
++
++# IDE Devices
++/dev/hda	b	640	0	0	3	0	0	0	-
++/dev/hda	b	640	0	0	3	1	1	1	15
++/dev/hdb	b	640	0	0	3	64	0	0	-
++/dev/hdb	b	640	0	0	3	65	1	1	15
++#/dev/hdc	b	640	0	0	22	0	0	0	-
++#/dev/hdc	b	640	0	0	22	1	1	1	15
++#/dev/hdd	b	640	0	0	22	64	0	0	-
++#/dev/hdd	b	640	0	0	22	65	1	1	15
++#/dev/hde	b	640	0	0	33	0	0	0	-
++#/dev/hde	b	640	0	0	33	1	1	1	15
++#/dev/hdf	b	640	0	0	33	64	0	0	-
++#/dev/hdf	b	640	0	0	33	65	1	1	15
++#/dev/hdg	b	640	0	0	34	0	0	0	-
++#/dev/hdg	b	640	0	0	34	1	1	1	15
++#/dev/hdh	b	640	0	0	34	64	0	0	-
++#/dev/hdh	b	640	0	0	34	65	1	1	15
++
++# SCSI Devices
++#/dev/sda	b	640	0	0	8	0	0	0	-
++#/dev/sda	b	640	0	0	8	1	1	1	15
++#/dev/sdb	b	640	0	0	8	16	0	0	-
++#/dev/sdb	b	640	0	0	8	17	1	1	15
++#/dev/sdc	b	640	0	0	8	32	0	0	-
++#/dev/sdc	b	640	0	0	8	33	1	1	15
++#/dev/sdd	b	640	0	0	8	48	0	0	-
++#/dev/sdd	b	640	0	0	8	49	1	1	15
++#/dev/sde	b	640	0	0	8	64	0	0	-
++#/dev/sde	b	640	0	0	8	65	1	1	15
++#/dev/sdf	b	640	0	0	8	80	0	0	-
++#/dev/sdf	b	640	0	0	8	81	1	1	15
++#/dev/sdg	b	640	0	0	8	96	0	0	-
++#/dev/sdg	b	640	0	0	8	97	1	1	15
++#/dev/sdh	b	640	0	0	8	112	0	0	-
++#/dev/sdh	b	640	0	0	8	113	1	1	15
++#/dev/sg		c	640	0	0	21	0	0	1	15
++#/dev/scd	b	640	0	0	11	0	0	1	15
++#/dev/st		c	640	0	0	9	0	0	1	8
++#/dev/nst	c	640	0	0	9	128	0	1	8
++#/dev/st	c	640	0	0	9	32	1	1	4
++#/dev/st	c	640	0	0	9	64	1	1	4
++#/dev/st	c	640	0	0	9	96	1	1	4
++
++# Floppy disk devices
++#/dev/fd		b	640	0	0	2	0	0	1	2
++#/dev/fd0d360	b	640	0	0	2	4	0	0	-
++#/dev/fd1d360	b	640	0	0	2	5	0	0	-
++#/dev/fd0h1200	b	640	0	0	2	8	0	0	-
++#/dev/fd1h1200	b	640	0	0	2	9	0	0	-
++#/dev/fd0u1440	b	640	0	0	2	28	0	0	-
++#/dev/fd1u1440	b	640	0	0	2	29	0	0	-
++#/dev/fd0u2880	b	640	0	0	2	32	0	0	-
++#/dev/fd1u2880	b	640	0	0	2	33	0	0	-
++
++# All the proprietary cdrom devices in the world
++#/dev/aztcd	b	640	0	0	29	0	0	0	-
++#/dev/bpcd	b	640	0	0	41	0	0	0	-
++#/dev/capi20	c	640	0	0	68	0	0	1	2
++#/dev/cdu31a	b	640	0	0	15	0	0	0	-
++#/dev/cdu535	b	640	0	0	24	0	0	0	-
++#/dev/cm206cd	b	640	0	0	32	0	0	0	-
++#/dev/sjcd	b	640	0	0	18	0	0	0	-
++#/dev/sonycd	b	640	0	0	15	0	0	0	-
++#/dev/gscd	b	640	0	0	16	0	0	0	-
++#/dev/sbpcd	b	640	0	0	25	0	0	0	-
++#/dev/sbpcd	b	640	0	0	25	0	0	1	4
++#/dev/mcd	b	640	0	0	23	0	0	0	-
++#/dev/optcd	b	640	0	0	17	0	0	0	-
++
+diff -urN genext2fs-1.3.orig/genext2fs.8 genext2fs-1.3/genext2fs.8
+--- genext2fs-1.3.orig/genext2fs.8	1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/genext2fs.8	2003-04-21 01:41:42.000000000 -0600
+@@ -0,0 +1,125 @@
++.\"                                      Hey, EMACS: -*- nroff -*-
++.\" First parameter, NAME, should be all caps
++.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
++.\" other parameters are allowed: see man(7), man(1)
++.TH GENEXT2FS 8 "July 14, 2001"
++.\" Please adjust this date whenever revising the manpage.
++.\"
++.\" Some roff macros, for reference:
++.\" .nh        disable hyphenation
++.\" .hy        enable hyphenation
++.\" .ad l      left justify
++.\" .ad b      justify to both left and right margins
++.\" .nf        disable filling
++.\" .fi        enable filling
++.\" .br        insert line break
++.\" .sp <n>    insert n+1 empty lines
++.\" for manpage-specific macros, see man(7)
++.SH NAME
++genext2fs \- ext2 filesystem generator for embedded systems
++.SH SYNOPSIS
++.B genext2fs
++.RI [ options ]  " image"
++.SH DESCRIPTION
++\fBgenext2fs\fP generates an ext2 filesystem
++as a normal (non-root) user. It doesn't require you to mount
++the image file to copy files on it. It doesn't even require
++you to be the superuser to make device nodes.
++.SH OPTIONS
++.TP
++.BI -x \ image
++Use this image as a starting point
++.TP
++.BI -d \ directory
++Add this directory as source
++.TP
++.BI -f \ FILE
++.TP
++.BI -D \ FILE
++Uses the named FILE as a device table file, to create device 
++nodes and directories "on the fly".
++.TP
++.BI -b \ blocks
++Size in blocks
++.TP
++.BI -i \ inodes
++Number of inodes
++.TP
++.BI -r \ reserved
++Number of reserved blocks
++.TP
++.BI -g \ path
++Generate a block map file for this path
++.TP
++.BI -e \ value
++Fill unallocated blocks with value
++.TP
++.BI -z
++Make files with holes
++.TP
++.BI -U
++Squash owners making all files be owned by root
++.TP
++.BI -P
++Squash permissions on all files
++.TP
++.BI -q
++Squash permissions and owners (same as -P -U)
++.TP
++.BI -v
++Print resulting filesystem structure
++.TP
++.BI -h
++Display help
++.TP
++.SH EXAMPLES
++
++.EX
++.B
++ genext2fs -b 1440 -d src /dev/fd0
++.EE
++
++All files in the 
++.I src
++directory will be written to 
++.B /dev/fd0
++as a new ext2 filesystem image. You can then mount the floppy as
++usual.
++
++.EX
++.B
++ genext2fs -b 1024 -d src -D device_table.txt flashdisk.img
++.EE
++
++This example builds a filesystem from all the files in 
++.I src
++, then device nodes are created based on the content the device_table file
++.I dev.txt.
++An example device file follows:
++
++.EX
++ #<name>		<type>	<mode>	<uid>	<gid>	<major>	<minor>	<start>	<inc>	<count>
++ /dev		d	755	0	0	-	-	-	-	-
++ /dev/mem	c	640	0	0	1	1	0	0	-
++ /dev/tty	c	666	0	0	5	0	0	0	-
++ /dev/tty	c	666	0	0	4	0	0	1	6
++ /dev/loop	b	640	0	0	7	0	0	1	2
++ /dev/hda	b	640	0	0	3	0	0	0	-
++ /dev/hda	b	640	0	0	3	1	1	1	16
++.EE
++
++This device table creates the /dev directory, a character device
++node /dev/mem (major 1, minor 1), it also creates /dev/tty, 
++/dev/tty[0-5], /dev/loop[0-1], /dev/hda, and /dev/hda0 to /dev/hda15
++.SH BUGS
++\fBgenext2fs\fP does not support hard links.  Hard links present in the input
++tree will be represented as separate files in the ext2 image.
++
++.SH SEE ALSO
++.BR mkfs (8),
++.BR genromfs (8),
++.BR mkisofs (8).
++.br
++.SH AUTHOR
++This manual page was written by David Kimdon <dwhedon@debian.org>,
++for the Debian GNU/Linux system (but may be used by others).
+diff -urN genext2fs-1.3.orig/genext2fs.c genext2fs-1.3/genext2fs.c
+--- genext2fs-1.3.orig/genext2fs.c	2001-06-18 02:11:32.000000000 -0600
++++ genext2fs-1.3/genext2fs.c	2003-04-21 01:48:35.000000000 -0600
+@@ -1,3 +1,4 @@
++/* vi: set sw=8 ts=8: */
+ // genext2fs.c
+ //
+ // ext2 filesystem generator for embedded systems
+@@ -26,6 +27,22 @@
+ // 			Bugfix: getcwd values for Solaris	xavier.gueguen@col.bsf.alcatel.fr
+ // 			Bugfix: ANSI scanf for non-GNU C	xavier.gueguen@col.bsf.alcatel.fr
+ // 	28 Jun 2001	Bugfix: getcwd differs for Solaris/GNU	mike@sowbug.com
++// 	23 Mar 2002	Bugfix: test for IFCHR or IFBLK was flawed
++// 	10 Oct 2002	Added comments,makefile targets,	vsundar@ixiacom.com    
++// 			endianess swap assert check.  
++// 			Copyright (C) 2002 Ixia communications
++// 	12 Oct 2002	Added support for triple indirection	vsundar@ixiacom.com
++// 			Copyright (C) 2002 Ixia communications
++// 	14 Oct 2002	Added support for groups		vsundar@ixiacom.com
++// 			Copyright (C) 2002 Ixia communications
++// 	5 Jan 2003	Bugfixes: reserved inodes should be set vsundar@usc.edu
++// 			only in the first group; directory names
++// 			need to be null padded at the end; and 
++// 			number of blocks per group should be a 
++// 			multiple of 8. Updated md5 values. 
++// 	6 Jan 2003	Erik Andersen <andersee@debian.org> added
++// 	                    mkfs.jffs2 compatible device table support,
++// 	                    along with -q, -P, -U
+ 
+ 
+ // `genext2fs' is a mean to generate an ext2 filesystem
+@@ -33,10 +50,6 @@
+ // the image file to copy files on it. It doesn't even require
+ // you to be the superuser to make device nodes.
+ //
+-// Warning ! `genext2fs' has been designed for embedded
+-// systems. As such, it will generate a filesystem for single-user
+-// usage: all files/directories/etc... will belong to UID/GID 0
+-//
+ // Example usage:
+ //
+ // # genext2fs -b 1440 -d srcdir /dev/fd0
+@@ -45,21 +58,15 @@
+ // a new ext2 filesystem image. You can then mount the floppy as
+ // usual.
+ //
+-// # genext2fs -b 1024 -d builddir -f devices.txt flashdisk.img
++// # genext2fs -b 1024 -d builddir -D device_table.txt flashdisk.img
+ //
+ // This one would build a filesystem from all the files in builddir,
+-// then would read a devices list and make apropriate nodes. The
+-// format for the device list is:
+-//
+-// drwx            /dev
+-// crw-    10,190  /dev/lcd
+-// brw-    1,0     /dev/ram0
+-// 
+-// This device list builds the /dev directory, a character device
+-// node /dev/lcd (major 10, minor 190) and a block device node
+-// /dev/ram0 (major 1, minor 0)
++// then would read the device_table.txt file and make apropriate nodes.
++// The format for the device table file is covered in detail in the sample
++// device_table.txt file provided with the genext2fs source.
+ 
+ 
++#define _GNU_SOURCE
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -67,6 +74,11 @@
+ #include <stdarg.h>
+ #include <unistd.h>
+ #include <sys/stat.h>
++#include <assert.h>
++#include <time.h>
++#include <ctype.h>
++#include <errno.h>
++#include <fcntl.h>
+ 
+ 
+ 
+@@ -76,10 +88,14 @@
+ #define BLOCKSIZE         1024
+ #define BLOCKS_PER_GROUP  8192
+ #define BYTES_PER_INODE   (8*BLOCKSIZE)
++/* Percentage of blocks that are reserved.*/
+ #define RESERVED_INODES   5/100
+ 
+ 
+ // inode block size (why is it != BLOCKSIZE ?!?)
++/* The field i_blocks in the ext2 inode stores the number of data blocks
++   but in terms of 512 bytes. That is what INODE_BLOCKSIZE represents.
++   INOBLK is the number of such blocks in an actual disk block            */
+ 
+ #define INODE_BLOCKSIZE   512
+ #define INOBLK            (BLOCKSIZE / INODE_BLOCKSIZE)
+@@ -147,6 +163,39 @@
+ 
+ #define OP_HOLES     0x01       // make files with holes
+ 
++/* Defines for accessing group details */
++
++// Number of groups in the filesystem
++#define GRP_NBGROUPS(fs) ( ((fs)->sb.s_blocks_count-1)/(fs)->sb.s_blocks_per_group )
++
++// Get group block bitmap (bbm) given the group number
++#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_block_bitmap) )
++
++// Get group inode bitmap (ibm) given the group number
++#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_inode_bitmap) )
++		
++// Given an inode number find the group it belongs to
++#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group)
++
++//Given an inode number get the inode bitmap that covers it
++#define GRP_GET_INODE_BITMAP(fs,nod) \
++	( GRP_GET_GROUP_IBM((fs),GRP_GROUP_OF_INODE((fs),(nod))) )
++
++//Given an inode number find its offset within the inode bitmap that covers it
++#define GRP_IBM_OFFSET(fs,nod) \
++	( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb.s_inodes_per_group )
++
++// Given a block number find the group it belongs to
++#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb.s_blocks_per_group)
++	
++//Given a block number get the block bitmap that covers it
++#define GRP_GET_BLOCK_BITMAP(fs,blk) \
++	( GRP_GET_GROUP_BBM((fs),GRP_GROUP_OF_BLOCK((fs),(blk))) )
++
++//Given a block number find its offset within the block bitmap that covers it
++#define GRP_BBM_OFFSET(fs,blk) \
++	( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb.s_blocks_per_group )
++
+ 
+ // used types
+ 
+@@ -287,7 +336,6 @@
+ {
+ 	groupdescriptor_decl
+ 	uint32 bg_reserved[3];
+-	uint32 bg_pad_to_bk[(BLOCKSIZE-32)/sizeof(uint32)];
+ } groupdescriptor;
+ 
+ typedef struct
+@@ -304,6 +352,32 @@
+ 
+ typedef uint8 block[BLOCKSIZE];
+ 
++/* blockwalker fields:
++   The blockwalker is used to access all the blocks of a file (including
++   the indirection blocks) through repeated calls to walk_bw.  
++   
++   bpdir -> index into the inode->i_block[]. Indicates level of indirection.
++   bnum -> total number of blocks so far accessed. including indirection
++           blocks.
++   bpind,bpdind,bptind -> index into indirection blocks.
++   
++   bpind, bpdind, bptind do *NOT* index into single, double and triple
++   indirect blocks resp. as you might expect from their names. Instead 
++   they are in order the 1st, 2nd & 3rd index to be used
++   
++   As an example..
++   To access data block number 70000:
++        bpdir: 15 (we are doing triple indirection)
++        bpind: 0 ( index into the triple indirection block)
++        bpdind: 16 ( index into the double indirection block)
++        bptind: 99 ( index into the single indirection block)
++	70000 = 12 + 256 + 256*256 + 16*256 + 100 (indexing starts from zero)
++
++   So,for double indirection bpind will index into the double indirection 
++   block and bpdind into the single indirection block. For single indirection
++   only bpind will be used.
++*/
++   
+ typedef struct
+ {
+ 	uint32 bnum;
+@@ -313,15 +387,14 @@
+ 	uint32 bptind;
+ } blockwalker;
+ 
++
++/* Filesystem structure that support groups */
+ #if BLOCKSIZE == 1024
+ typedef struct
+ {
+ 	block zero;          // The famous block 0
+ 	superblock sb;       // The superblock
+-	groupdescriptor gd;  // The group desciptor
+-	block bbm;           // The block bitmap
+-	block ibm;           // The inode bitmap
+-	inode itab[0];       // The inode table
++	groupdescriptor gd[0]; // The group descriptors
+ } filesystem;
+ #else
+ #error UNHANDLED BLOCKSIZE
+@@ -389,25 +462,113 @@
+ #undef udecl32
+ #undef utdecl32
+ 
+-char * argv0;
++static char * app_name;
++static int squash_uids = 0;
++static int squash_perms = 0;
++static const char *const memory_exhausted = "memory exhausted";
+ 
+ // error (un)handling
+-inline void errexit(const char *fmt, ...)
++static void verror_msg(const char *s, va_list p)
+ {
+-	va_list ap;
+-	fprintf(stderr, "%s: ", argv0);
+-	va_start(ap, fmt);
+-	vfprintf(stderr, fmt, ap);
+-	va_end(ap);
+-	fprintf(stderr, "\n");
+-	exit(1);
++	fflush(stdout);
++	fprintf(stderr, "%s: ", app_name);
++	vfprintf(stderr, s, p);
++}
++static void error_msg(const char *s, ...)
++{
++	va_list p;
++	va_start(p, s);
++	verror_msg(s, p);
++	va_end(p);
++	putc('\n', stderr);
++}
++
++static void error_msg_and_die(const char *s, ...)
++{
++	va_list p;
++	va_start(p, s);
++	verror_msg(s, p);
++	va_end(p);
++	putc('\n', stderr);
++	exit(EXIT_FAILURE);
++}
++
++static void vperror_msg(const char *s, va_list p)
++{
++	int err = errno;
++	if (s == 0)
++		s = "";
++	verror_msg(s, p);
++	if (*s)
++		s = ": ";
++	fprintf(stderr, "%s%s\n", s, strerror(err));
++}
++
++#if 0
++static void perror_msg(const char *s, ...)
++{
++	va_list p;
++	va_start(p, s);
++	vperror_msg(s, p);
++	va_end(p);
++}
++#endif
++static void perror_msg_and_die(const char *s, ...)
++{
++	va_list p;
++	va_start(p, s);
++	vperror_msg(s, p);
++	va_end(p);
++	exit(EXIT_FAILURE);
+ }
+ 
+-inline void pexit(const char * fname)
++static FILE *xfopen(const char *path, const char *mode)
+ {
+-	fprintf(stderr, "%s: ", argv0);
+-	perror(fname);
+-	exit(1);
++	FILE *fp;
++	if ((fp = fopen(path, mode)) == NULL)
++		perror_msg_and_die("%s", path);
++	return fp;
++}
++
++static char *xstrdup(const char *s)
++{
++	char *t;
++
++	if (s == NULL)
++		return NULL;
++	t = strdup(s);
++	if (t == NULL)
++		error_msg_and_die(memory_exhausted);
++	return t;
++}
++
++extern void *xrealloc(void *ptr, size_t size)
++{
++	ptr = realloc(ptr, size);
++	if (ptr == NULL && size != 0)
++		error_msg_and_die(memory_exhausted);
++	return ptr;
++}
++
++static char *xreadlink(const char *path)
++{
++	static const int GROWBY = 80; /* how large we will grow strings by */
++
++	char *buf = NULL;
++	int bufsize = 0, readsize = 0;
++
++	do {
++		buf = xrealloc(buf, bufsize += GROWBY);
++		readsize = readlink(path, buf, bufsize); /* 1st try */
++		if (readsize == -1) {
++			perror_msg_and_die("%s:%s", app_name, path);
++		}
++	}
++	while (bufsize < readsize + 1);
++
++	buf[readsize] = '\0';
++
++	return buf;
+ }
+ 
+ // printf helper macro
+@@ -423,7 +584,7 @@
+ {
+ }
+ 
+-// rounds a quantity up to a blocksize
++/* Rounds qty upto a multiple of siz. siz should be a power of 2 */
+ uint32 rndup(uint32 qty, uint32 siz)
+ {
+ 	return (qty + (siz - 1)) & ~(siz - 1);
+@@ -444,7 +605,13 @@
+ // return a given inode from a filesystem
+ inline inode * get_nod(filesystem *fs, uint32 nod)
+ {
+-	return &fs->itab[nod-1];
++	int grp,offset;
++	inode *itab;
++
++	offset = GRP_IBM_OFFSET(fs,nod);
++	grp = GRP_GROUP_OF_INODE(fs,nod);
++	itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table);
++	return itab+offset-1;
+ }
+ 
+ // allocate a given block/inode in the bitmap
+@@ -479,29 +646,57 @@
+ }
+ 
+ // allocate a block
+-uint32 alloc_blk(filesystem *fs)
++uint32 alloc_blk(filesystem *fs, uint32  nod)
+ {
+-	uint32 bk;
+-	if(!(bk = allocate(fs->bbm, 0)))
+-		errexit("couldn't allocate a block (no free space)");
+-	if(!(fs->gd.bg_free_blocks_count--))
+-		errexit("group descr. free blocks count == 0 (corrupted fs?)");
++	uint32 bk=0;
++	uint32 grp,nbgroups;
++
++	grp = nod/fs->sb.s_inodes_per_group;
++	nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) / 
++					fs->sb.s_blocks_per_group;
++	if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) {
++		for(grp=0;grp<nbgroups && !bk;grp++)
++			bk=allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap),0);
++		grp--;
++	}
++	if (!bk)
++		error_msg_and_die("couldn't allocate a block (no free space)");
++	if(!(fs->gd[grp].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--))
+-		errexit("superblock free blocks count == 0 (corrupted fs?)");
+-	return bk;
++		error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
++	return fs->sb.s_blocks_per_group*grp + bk;
+ }
+ 
+ // allocate an inode
+ uint32 alloc_nod(filesystem *fs)
+ {
+-	uint32 nod;
+-	if(!(nod = allocate(fs->ibm, 0)))
+-		errexit("couldn't allocate an inode (no free inode)");
+-	if(!(fs->gd.bg_free_inodes_count--))
+-		errexit("group descr. free blocks count == 0 (corrupted fs?)");
++	uint32 nod=0,best_group=0;
++	uint32 grp,nbgroups,avefreei;
++
++	nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) / 
++					fs->sb.s_blocks_per_group;
++
++	/* Distribute inodes amongst all the blocks                           */
++	/* For every block group with more than average number of free inodes */
++	/* find the one with the most free blocks and allocate node there     */
++	/* Idea from find_group_dir in fs/ext2/ialloc.c in 2.4.19 kernel      */
++	/* We do it for all inodes.                                           */
++	avefreei  =  fs->sb.s_free_inodes_count / nbgroups;
++	for(grp=0;grp<nbgroups && !nod;grp++) {
++		if (fs->gd[grp].bg_free_inodes_count < avefreei)
++			continue;
++		if (!best_group || 
++			fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count)
++			best_group = grp;
++	}
++	if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0)))
++		error_msg_and_die("couldn't allocate an inode (no free inode)");
++	if(!(fs->gd[best_group].bg_free_inodes_count--))
++		error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
+ 	if(!(fs->sb.s_free_inodes_count--))
+-		errexit("superblock free blocks count == 0 (corrupted fs?)");
+-	return nod;
++		error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
++	return fs->sb.s_inodes_per_group*best_group+nod;
+ }
+ 
+ // print a bitmap allocation
+@@ -546,14 +741,14 @@
+ 	{
+ 		bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0];
+ 		if(extend) // allocate first block
+-			*bkref = hole ? 0 : alloc_blk(fs);
++			*bkref = hole ? 0 : alloc_blk(fs,nod);
+ 	}
+ 	// direct block
+ 	else if(bw->bpdir < EXT2_NDIR_BLOCKS)
+ 	{
+ 		bkref = &get_nod(fs, nod)->i_block[++bw->bpdir];
+ 		if(extend) // allocate block
+-			*bkref = hole ? 0 : alloc_blk(fs);
++			*bkref = hole ? 0 : alloc_blk(fs,nod);
+ 	}
+ 	// first block in indirect block
+ 	else if(bw->bpdir == EXT2_NDIR_BLOCKS)
+@@ -562,11 +757,11 @@
+ 		bw->bpdir = EXT2_IND_BLOCK;
+ 		bw->bpind = 0;
+ 		if(extend) // allocate indirect block
+-			get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs);
++			get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
+ 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ 		bkref = &b[bw->bpind];
+ 		if(extend) // allocate first block
+-			*bkref = hole ? 0 : alloc_blk(fs);
++			*bkref = hole ? 0 : alloc_blk(fs,nod);
+ 	}
+ 	// block in indirect block
+ 	else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
+@@ -575,7 +770,7 @@
+ 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ 		bkref = &b[bw->bpind];
+ 		if(extend) // allocate block
+-			*bkref = hole ? 0 : alloc_blk(fs);
++			*bkref = hole ? 0 : alloc_blk(fs,nod);
+ 	}
+ 	// first block in first indirect block in first double indirect block
+ 	else if(bw->bpdir == EXT2_IND_BLOCK)
+@@ -585,14 +780,14 @@
+ 		bw->bpind = 0;
+ 		bw->bpdind = 0;
+ 		if(extend) // allocate double indirect block
+-			get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs);
++			get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
+ 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ 		if(extend) // allocate first indirect block
+-			b[bw->bpind] = alloc_blk(fs);
++			b[bw->bpind] = alloc_blk(fs,nod);
+ 		b = (uint32*)get_blk(fs, b[bw->bpind]);
+ 		bkref = &b[bw->bpdind];
+ 		if(extend) // allocate first block
+-			*bkref = hole ? 0 : alloc_blk(fs);
++			*bkref = hole ? 0 : alloc_blk(fs,nod);
+ 	}
+ 	// block in indirect block in double indirect block
+ 	else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1))
+@@ -602,7 +797,7 @@
+ 		b = (uint32*)get_blk(fs, b[bw->bpind]);
+ 		bkref = &b[bw->bpdind];
+ 		if(extend) // allocate block
+-			*bkref = hole ? 0 : alloc_blk(fs);
++			*bkref = hole ? 0 : alloc_blk(fs,nod);
+ 	}
+ 	// first block in indirect block in double indirect block
+ 	else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
+@@ -612,20 +807,100 @@
+ 		bw->bpind++;
+ 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ 		if(extend) // allocate indirect block
+-			b[bw->bpind] = alloc_blk(fs);
++			b[bw->bpind] = alloc_blk(fs,nod);
+ 		b = (uint32*)get_blk(fs, b[bw->bpind]);
+ 		bkref = &b[bw->bpdind];
+ 		if(extend) // allocate first block
+-			*bkref = hole ? 0 : alloc_blk(fs);
++			*bkref = hole ? 0 : alloc_blk(fs,nod);
++	}
++
++	/* Adding support for triple indirection */
++	/* Just starting triple indirection. Allocate the indirection
++	   blocks and the first data block
++	 */
++	else if (bw->bpdir == EXT2_DIND_BLOCK) 
++	{
++	  	bw->bnum += 3;
++		bw->bpdir = EXT2_TIND_BLOCK;
++		bw->bpind = 0;
++		bw->bpdind = 0;
++		bw->bptind = 0;
++		if(extend) // allocate triple indirect block
++			get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
++		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++		if(extend) // allocate first double indirect block
++			b[bw->bpind] = alloc_blk(fs,nod);
++		b = (uint32*)get_blk(fs, b[bw->bpind]);
++		if(extend) // allocate first indirect block
++			b[bw->bpdind] = alloc_blk(fs,nod);
++		b = (uint32*)get_blk(fs, b[bw->bpdind]);
++		bkref = &b[bw->bptind];
++		if(extend) // allocate first data block
++			*bkref = hole ? 0 : alloc_blk(fs,nod);
++	}
++	/* Still processing a single indirect block down the indirection
++	   chain.Allocate a data block for it
++	 */
++	else if ( (bw->bpdir == EXT2_TIND_BLOCK) && 
++		  (bw->bptind < BLOCKSIZE/4 -1) )
++	{
++		bw->bptind++;
++		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++		b = (uint32*)get_blk(fs, b[bw->bpind]);
++		b = (uint32*)get_blk(fs, b[bw->bpdind]);
++		bkref = &b[bw->bptind];
++		if(extend) // allocate data block
++			*bkref = hole ? 0 : alloc_blk(fs,nod);
++	}
++	/* Finished processing a single indirect block. But still in the 
++	   same double indirect block. Allocate new single indirect block
++	   for it and a data block
++	 */
++	else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
++		  (bw->bpdind < BLOCKSIZE/4 -1) )
++	{
++		bw->bnum++;
++		bw->bptind = 0;
++		bw->bpdind++;
++		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++		b = (uint32*)get_blk(fs, b[bw->bpind]);
++		if (extend) // allocate single indirect block
++			b[bw->bpdind] = alloc_blk(fs,nod);
++		b = (uint32*)get_blk(fs, b[bw->bpdind]);
++		bkref = &b[bw->bptind];
++		if(extend) // allocate first data block
++			*bkref = hole ? 0 : alloc_blk(fs,nod);
++	}
++	/* Finished processing a double indirect block. Allocate the next
++	   double indirect block and the single,data blocks for it
++	 */
++	else if ( (bw->bpdir == EXT2_TIND_BLOCK) && 
++		  (bw->bpind < BLOCKSIZE/4 - 1) )
++	{
++		bw->bnum += 2;
++		bw->bpdind = 0;
++		bw->bptind = 0;
++		bw->bpind++;
++		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++		if(extend) // allocate double indirect block
++			b[bw->bpind] = alloc_blk(fs,nod);
++		b = (uint32*)get_blk(fs, b[bw->bpind]);
++		if(extend) // allocate single indirect block
++			b[bw->bpdind] = alloc_blk(fs,nod);
++		b = (uint32*)get_blk(fs, b[bw->bpdind]);
++		bkref = &b[bw->bptind];
++		if(extend) // allocate first block
++			*bkref = hole ? 0 : alloc_blk(fs,nod);
+ 	}
+-	// I don't do triple indirect - it's such a small filesystem ...
+ 	else
+-		errexit("file too big ! blocks list for inode %d extends past double indirect blocks!", nod);
++		error_msg_and_die("file too big !"); 
++	/* End change for walking triple indirection */
++
+ 	if(*bkref)
+ 	{
+ 		bw->bnum++;
+-		if(!allocated(fs->bbm, *bkref))
+-			errexit("[block %d of inode %d is unallocated !]", *bkref, nod);
++		if(!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);
+ 	}
+ 	if(extend)
+ 		get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK;
+@@ -663,23 +938,40 @@
+ }
+ 
+ // link an entry (inode #) to a directory
+-void add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name)
++void add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name, uint32 mode, uid_t uid, gid_t gid, time_t ctime)
+ {
+ 	blockwalker bw;
+ 	uint32 bk;
+ 	uint8 *b;
+ 	directory *d;
+ 	int reclen, nlen;
+-	if((get_nod(fs, dnod)->i_mode & FM_IFMT) != FM_IFDIR)
+-		errexit("can't add '%s' to a non-directory", name);
++	inode *node;
++	inode *pnode;
++	
++	/* Squash all permissions so files are owned by root 
++	 * and file permissions have group/other perms removed */
++	if (squash_uids) {
++		uid = gid = 0;
++	}
++	if (squash_perms) {
++		if (!S_ISLNK(mode)) {
++			mode &= ~(S_IWGRP | S_IWOTH);
++			mode &= ~(S_ISUID | S_ISGID);
++		}
++	}
++
++	pnode = get_nod(fs, dnod);
++
++	if(!S_ISDIR(pnode->i_mode))
++		error_msg_and_die("can't add '%s' to a non-directory", name);
+ 	if(!*name)
+-		errexit("bad name '%s' (not meaningful)", name);
++		error_msg_and_die("bad name '%s' (not meaningful)", name);
+ 	if(strchr(name, '/'))
+-		errexit("bad name '%s' (contains a slash)", name);
++		error_msg_and_die("bad name '%s' (contains a slash)", name);
+ 	nlen = strlen(name);
+ 	reclen = sizeof(directory) + rndup(nlen, 4);
+ 	if(reclen > BLOCKSIZE)
+-		errexit("bad name '%s' (too long)", name);
++		error_msg_and_die("bad name '%s' (too long)", name);
+ 	init_bw(fs, dnod, &bw);
+ 	while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir
+ 	{
+@@ -691,9 +983,16 @@
+ 			if((!d->d_inode) && (d->d_rec_len >= reclen))
+ 			{
+ 				d->d_inode = nod;
+-				get_nod(fs, nod)->i_links_count++;
++				node = get_nod(fs, nod);
++				node->i_links_count++;
+ 				d->d_name_len = nlen;
+-				strncpy(d->d_name, name, nlen);
++				strncpy(d->d_name, name, rndup(nlen,4));
++				node->i_mode = mode;
++				node->i_uid = uid;
++				node->i_gid = gid;
++				node->i_atime = ctime;
++				node->i_ctime = ctime;
++				node->i_mtime = ctime;
+ 				return;
+ 			}
+ 			// if entry with enough room (last one?), shrink it & use it
+@@ -705,9 +1004,16 @@
+ 				d = (directory*) (((int8*)d) + d->d_rec_len);
+ 				d->d_rec_len = reclen;
+ 				d->d_inode = nod;
+-				get_nod(fs, nod)->i_links_count++;
++				node = get_nod(fs, nod);
++				node->i_links_count++;
+ 				d->d_name_len = nlen;
+-				strncpy(d->d_name, name, nlen);
++				strncpy(d->d_name, name, rndup(nlen,4));
++				node->i_mode = mode;
++				node->i_uid = uid;
++				node->i_gid = gid;
++				node->i_atime = ctime;
++				node->i_ctime = ctime;
++				node->i_mtime = ctime;
+ 				return;
+ 			}
+ 		}
+@@ -716,10 +1022,17 @@
+ 	b = get_workblk();
+ 	d = (directory*)b;
+ 	d->d_inode = nod;
+-	get_nod(fs, nod)->i_links_count++;
++	node = get_nod(fs, nod);
++	node->i_links_count++;
+ 	d->d_rec_len = BLOCKSIZE;
+ 	d->d_name_len = nlen;
+-	strncpy(d->d_name, name, nlen);
++	strncpy(d->d_name, name, rndup(nlen,4));
++	node->i_mode = mode;
++	node->i_uid = uid;
++	node->i_gid = gid;
++	node->i_atime = ctime;
++	node->i_ctime = ctime;
++	node->i_mtime = ctime;
+ 	extend_blk(fs, dnod, b, 1);
+ 	get_nod(fs, dnod)->i_size += BLOCKSIZE;
+ 	free_workblk(b);
+@@ -747,7 +1060,7 @@
+ // find the inode of a full path
+ uint32 find_path(filesystem *fs, uint32 nod, const char * name)
+ {
+-	char *p, *n, *n2 = strdup(name);
++	char *p, *n, *n2 = xstrdup(name);
+ 	n = n2;
+ 	while(*n == '/')
+ 	{
+@@ -770,27 +1083,32 @@
+ }
+ 
+ // make a full-fledged directory (i.e. with "." & "..")
+-uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode)
++uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode,
++	uid_t uid, gid_t gid, time_t ctime)
+ {
+ 	uint32 nod;
+ 	if((nod = find_dir(fs, parent_nod, name)))
+ 		return nod;
+        	nod = alloc_nod(fs);
+-	get_nod(fs, nod)->i_mode = FM_IFDIR | mode;
+-	add2dir(fs, parent_nod, nod, name);
+-	add2dir(fs, nod, nod, ".");
+-	add2dir(fs, nod, parent_nod, "..");
+-	fs->gd.bg_used_dirs_count++;
++	if (!(mode & FM_IFDIR))
++	    mode |= FM_IFDIR;
++	add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
++	add2dir(fs, nod, nod, ".", mode, uid, gid, ctime);
++	add2dir(fs, nod, parent_nod, "..", mode, uid, gid, ctime);
++	fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++;
+ 	return nod;
+ }
+ 
+ // make a symlink
+-uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint8 * b)
++uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size,
++	uint8 * b, uid_t uid, gid_t gid, time_t ctime)
+ {
++	uint32 mode;
+ 	uint32 nod = alloc_nod(fs);
++	mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO; 
+ 	get_nod(fs, nod)->i_mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
+ 	get_nod(fs, nod)->i_size = size;
+-	add2dir(fs, parent_nod, nod, name);
++	add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
+ 	if(size <= 4 * (EXT2_TIND_BLOCK+1))
+ 	{
+ 		strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size);
+@@ -801,15 +1119,15 @@
+ }
+ 
+ // make a file from a FILE*
+-uint32 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f)
++uint32 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f, uid_t uid, gid_t gid, time_t ctime)
+ {
+ 	uint8 * b;
+ 	uint32 nod = alloc_nod(fs);
+-	get_nod(fs, nod)->i_mode = FM_IFREG | mode;
++	mode |= FM_IFREG;
+ 	get_nod(fs, nod)->i_size = size;
+-	add2dir(fs, parent_nod, nod, name);
++	add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
+ 	if(!(b = (uint8*)malloc(rndup(size, BLOCKSIZE))))
+-		errexit("not enough mem to read file '%s'", name);
++		error_msg_and_die("not enough mem to read file '%s'", name);
+ 	memset(b, 0,rndup(size, BLOCKSIZE));
+ 	if(f)
+ 		fread(b, size, 1, f);
+@@ -824,6 +1142,15 @@
+ uint32 get_mode(struct stat *st)
+ {
+ 	uint32 mode = 0;
++
++	/* Squash file permissions as needed */
++	if (squash_perms) {
++		if (!S_ISLNK(mode)) {
++			st->st_mode &= ~(S_IWGRP | S_IWOTH);
++			st->st_mode &= ~(S_ISUID | S_ISGID);
++		}
++	}
++
+ 	if(st->st_mode & S_IRUSR)
+ 		mode |= FM_IRUSR | FM_IRGRP | FM_IROTH;
+ 	if(st->st_mode & S_IWUSR)
+@@ -833,30 +1160,17 @@
+ 	return mode;
+ }
+ 
+-// retrieves a mode info from a string
+-uint32 get_modestr(const char *p)
+-{
+-	uint32 mode = 0;
+-	if(p[0] == 'r')
+-		mode |= FM_IRUSR | FM_IRGRP | FM_IROTH;
+-	if(p[1] == 'w')
+-		mode |= FM_IWUSR | FM_IWGRP | FM_IWOTH;
+-	if(p[2] == 'x' || p[2] == 's')
+-		mode |= FM_IXUSR | FM_IXGRP | FM_IXOTH;
+-	return mode;
+-}
+-
+ // basename of a path - free me
+ char * basename(const char * fullpath)
+ {
+ 	char * p = strrchr(fullpath, '/');
+-	return strdup(p ? p + 1 : fullpath);
++	return xstrdup(p ? p + 1 : fullpath);
+ }
+ 
+ // dirname of a path - free me
+ char * dirname(const char * fullpath)
+ {
+-	char * p, * n = strdup(fullpath);
++	char * p, * n = xstrdup(fullpath);
+ 	if((p = strrchr(n, '/')))
+ 		*(p+1) = 0;
+ 	else
+@@ -864,66 +1178,6 @@
+ 	return n;
+ }
+ 
+-// adds entries to the filesystem from a text file
+-void add2fs_from_file(filesystem *fs, uint32 this_nod, FILE * fh)
+-{
+-	uint32 mode;
+-	uint32 nod, nod2;
+-	char cmod[11], *path, *name, *dir;
+-	int major, minor;
+-	while(fscanf(fh, "%10s", cmod))
+-	{
+-		if(feof(fh))
+-			break;
+-		mode = get_modestr(cmod + 1);
+-		switch(*cmod)
+-		{
+-			case 'd':
+-				fscanf(fh, "%" SCANF_PREFIX "s\n", SCANF_STRING(path));
+-				break;
+-			case 'c':
+-				mode |= FM_IFCHR;
+-				fscanf(fh, "%i, %i %" SCANF_PREFIX "s\n", &major, &minor, SCANF_STRING(path));
+-				break;
+-			case 'b':
+-				mode |= FM_IFBLK;
+-				fscanf(fh, "%i, %i %" SCANF_PREFIX "s\n", &major, &minor, SCANF_STRING(path));
+-				break;
+-			case '#':
+-				while(fgetc(fh) != '\n');
+-				continue;
+-			default:
+-				errexit("malformed text input file");
+-		}
+-		name = basename(path);
+-		dir = dirname(path);
+-		free(path);
+-		if(!(nod = find_path(fs, this_nod, dir)))
+-			errexit("can't find directory '%s' to create '%s''", dir, name);
+-		free(dir);
+-		if((!strcmp(name, ".")) || (!strcmp(name, "..")))
+-		{
+-			free(name);
+-			continue;
+-		}
+-		switch(*cmod)
+-		{
+-			case 'd':
+-				mkdir_fs(fs, nod, name, mode);
+-				break;
+-			case 'c':
+-			case 'b':
+-				nod2 = alloc_nod(fs);
+-				get_nod(fs, nod2)->i_mode = mode;
+-				((uint8*)get_nod(fs, nod2)->i_block)[0] = minor;
+-				((uint8*)get_nod(fs, nod2)->i_block)[1] = major;
+-				add2dir(fs, nod, nod2, name);
+-				break;
+-		}
+-		free(name);
+-	}
+-}
+-
+ // adds a tree of entries to the filesystem from current dir
+ void add2fs_from_dir(filesystem *fs, uint32 this_nod)
+ {
+@@ -934,7 +1188,7 @@
+ 	struct stat st;
+ 	uint8 *b;
+ 	if(!(dh = opendir(".")))
+-		pexit(".");
++		perror_msg_and_die(".");
+ 	while((dent = readdir(dh)))
+ 	{
+ 		if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
+@@ -948,31 +1202,27 @@
+ 				get_nod(fs, nod)->i_mode = (((st.st_mode & S_IFMT) == S_IFCHR) ? FM_IFCHR : FM_IFBLK) | get_mode(&st);
+ 				((uint8*)get_nod(fs, nod)->i_block)[0] = (st.st_rdev & 0xff);
+ 				((uint8*)get_nod(fs, nod)->i_block)[1] = (st.st_rdev >> 8);
+-				add2dir(fs, this_nod, nod, dent->d_name);
++				add2dir(fs, this_nod, nod, dent->d_name, st.st_mode, st.st_uid, st.st_gid, st.st_ctime);
+ 				break;
+ 			case S_IFLNK:
+-				if(!(b = (uint8*)malloc(rndup(st.st_size, BLOCKSIZE))))
+-					errexit("out of memory");
+-				if(readlink(dent->d_name, (char*)b, st.st_size) < 0)
+-					pexit(dent->d_name);
+-				mklink_fs(fs, this_nod, dent->d_name, st.st_size, b);
++				b = xreadlink(dent->d_name);
++				mklink_fs(fs, this_nod, dent->d_name, st.st_size, b, st.st_uid, st.st_gid, st.st_ctime);
+ 				free(b);
+ 				break;
+ 			case S_IFREG:
+-				if(!(fh = fopen(dent->d_name, "r")))
+-					pexit(dent->d_name);
+-				mkfile_fs(fs, this_nod, dent->d_name, get_mode(&st), st.st_size, fh);
++				fh = xfopen(dent->d_name, "r");
++				mkfile_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_size, fh, st.st_uid, st.st_gid, st.st_ctime);
+ 				fclose(fh);
+ 				break;
+ 			case S_IFDIR:
+-				nod = mkdir_fs(fs, this_nod, dent->d_name, get_mode(&st));
++				nod = mkdir_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_uid, st.st_gid, st.st_ctime);
+ 				if(chdir(dent->d_name) < 0)
+-					pexit(dent->d_name);
++					perror_msg_and_die(dent->d_name);
+ 				add2fs_from_dir(fs, nod);
+ 				chdir("..");
+ 				break;
+ 			default:
+-				fprintf(stderr, "ignoring entry %s", dent->d_name);
++				error_msg("ignoring entry %s", dent->d_name);
+ 		}
+ 	}
+ 	closedir(dh);
+@@ -981,9 +1231,11 @@
+ // endianness swap of x-indirect blocks
+ void swap_goodblocks(filesystem *fs, inode *nod)
+ {
+-	int i;
++	int i,j,done=0;
++	uint32 *b,*b2;
++
+ 	int nblk = nod->i_blocks / INOBLK;
+-	if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR)))
++	if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
+ 		for(i = 0; i <= EXT2_TIND_BLOCK; i++)
+ 			nod->i_block[i] = swab32(nod->i_block[i]);
+ 	if(nblk <= EXT2_IND_BLOCK)
+@@ -991,20 +1243,55 @@
+ 	swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
+ 	if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4)
+ 		return;
++	/* Currently this will fail b'cos the number of blocks as stored
++	   in i_blocks also includes the indirection blocks (see
++	   walk_bw). But this function assumes that i_blocks only
++	   stores the count of data blocks ( Actually according to
++	   "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed)
++	   i_blocks IS supposed to store the count of data blocks). so
++	   with a file of size 268K nblk would be 269.The above check
++	   will be false even though double indirection hasn't been
++	   started.This is benign as 0 means block 0 which has been
++	   zeroed out and therefore points back to itself from any offset
++	 */
++	assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
+ 	for(i = 0; i < BLOCKSIZE/4; i++)
++		/* Should this be...
++		if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
++		*/
+ 		if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i)
+ 			swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
+ 	swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
+ 	if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
+ 		return;
+-	errexit("too big file on the filesystem");
++	/* Adding support for triple indirection */
++	b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
++	for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
++		b2 = (uint32*)get_blk(fs,b[i]); 
++		for(j=0; j<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;
++			}
++		}
++		swap_block((uint8 *)b2);
++	}
++	swap_block((uint8 *)b);
++	return;
+ }
+ 
+ void swap_badblocks(filesystem *fs, inode *nod)
+ {
+-	int i;
++	int i,j,done=0;
++	uint32 *b,*b2;
++
+ 	int nblk = nod->i_blocks / INOBLK;
+-	if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR)))
++	if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
+ 		for(i = 0; i <= EXT2_TIND_BLOCK; i++)
+ 			nod->i_block[i] = swab32(nod->i_block[i]);
+ 	if(nblk <= EXT2_IND_BLOCK)
+@@ -1012,13 +1299,34 @@
+ 	swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
+ 	if(nblk <= EXT2_IND_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++)
++		/* See comment in swap_goodblocks */
+ 		if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i)
+ 			swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
+ 	if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
+ 		return;
+-	errexit("too big file on the filesystem");
++	/* Adding support for triple indirection */
++	b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
++	swap_block((uint8 *)b);
++	for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
++		b2 = (uint32*)get_blk(fs,b[i]); 
++		swap_block((uint8 *)b2);
++		for(j=0; j<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;
+ }
+ 
+ // endianness swap of the whole filesystem
+@@ -1045,7 +1353,8 @@
+ 		swap_goodblocks(fs, nod);
+ 		swap_nod(nod);
+ 	}
+-	swap_gd(&fs->gd);
++	for(i=0;i<GRP_NBGROUPS(fs);i++)
++		swap_gd(&(fs->gd[i]));
+ 	swap_sb(&fs->sb);
+ }
+ 
+@@ -1053,7 +1362,8 @@
+ {
+ 	int i;
+ 	swap_sb(&fs->sb);
+-	swap_gd(&fs->gd);
++	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);
+@@ -1084,53 +1394,118 @@
+ 	directory *d;
+ 	uint8 * b;
+ 	uint32 nod;
++	uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
++		free_blocks_per_group,nbblocks_per_group;
++	uint32 gd,itbl,ibmpos,bbmpos,itblpos;
++	int j;
++	uint8 *bbm,*ibm;
++	inode *itab0;
+ 	
+ 	if(nbblocks < 16) // totally arbitrary
+-		errexit("too small filesystem");
+-	if(nbblocks >BLOCKS_PER_GROUP) // I build only one group
+-		errexit("too big filesystem");
++		error_msg_and_die("too small filesystem");
++
++	/* nbblocks is the total number of blocks in the system. First 
++	 * calculate how much overhead blocks - inode table blocks,bitmap 
++	 * blocks,group descriptor blocks etc. - are needed assuming each 
++	 * group has BLOCKS_PER_GROUP blocks.Then recalculate nbblocks with 
++	 * this figure. Each group has the same number of blocks. So the fs 
++	 * has a size atleast the given value but usually rounded off to a i
++	 * higher number.
++	 */
++	nbgroups = rndup(nbblocks,BLOCKS_PER_GROUP)/ BLOCKS_PER_GROUP;
++	nbinodes_per_group = nbinodes/nbgroups +1;
++	nbinodes_per_group = rndup(nbinodes_per_group, BLOCKSIZE/sizeof(inode));
++	if (nbinodes_per_group < 16)
++		nbinodes_per_group = 16; //minimum number b'cos the first 10 are reserved
++	overhead_per_group = 3 /*super block,ibm,bbm*/
++			     + /* No. of blocks that the inodes occupy */
++			       nbinodes_per_group *sizeof(inode)/BLOCKSIZE 
++			     + /* No. of blocks that group descriptors occupy */
++			       rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
++	free_blocks = nbblocks - overhead_per_group * nbgroups - 1 /*boot block */;
++	free_blocks_per_group = free_blocks/nbgroups;
++	if (free_blocks > free_blocks_per_group * nbgroups)
++		free_blocks_per_group++;
++	nbblocks_per_group = free_blocks_per_group + overhead_per_group;
++	/* e2fsck complains if nbblocks_per_group is not a multiple of 8 */
++	nbblocks_per_group = rndup(nbblocks_per_group,8);
++	free_blocks_per_group = nbblocks_per_group - overhead_per_group;
++	if (nbblocks_per_group > BLOCKS_PER_GROUP) {
++		/* Can this happen ? */
++		nbblocks_per_group = BLOCKS_PER_GROUP;
++		free_blocks_per_group = nbblocks_per_group - overhead_per_group;
++	}
++	nbblocks = nbblocks_per_group * nbgroups + 1;
++	
++
+ 	if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
+-		errexit("not enough memory for filesystem");
++		error_msg_and_die("not enough memory for filesystem");
+ 
+ 	// create the superblock for an empty filesystem
+-	fs->sb.s_inodes_count = rndup(nbinodes, BLOCKSIZE/sizeof(inode));
++	fs->sb.s_inodes_count = nbinodes_per_group * nbgroups;
+ 	fs->sb.s_blocks_count = nbblocks;
+ 	fs->sb.s_r_blocks_count = nbresrvd;
+-	fs->sb.s_free_blocks_count = nbblocks;
++	fs->sb.s_free_blocks_count = free_blocks_per_group*nbgroups;
+ 	fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
+ 	fs->sb.s_first_data_block = (BLOCKSIZE == 1024);
+ 	fs->sb.s_log_block_size = BLOCKSIZE >> 11;
+ 	fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
+-	fs->sb.s_blocks_per_group = BLOCKS_PER_GROUP;
+-	fs->sb.s_frags_per_group = BLOCKS_PER_GROUP;
+-	fs->sb.s_inodes_per_group = fs->sb.s_inodes_count;
++	fs->sb.s_blocks_per_group = nbblocks_per_group;
++	fs->sb.s_frags_per_group = nbblocks_per_group;
++	fs->sb.s_inodes_per_group = nbinodes_per_group;
+ 	fs->sb.s_magic = EXT2_MAGIC_NUMBER;
+ 
+ 	// set up groupdescriptors
+-	fs->sb.s_free_blocks_count -= 5 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE;
+-	fs->gd.bg_free_blocks_count = fs->sb.s_free_blocks_count;
+-	fs->gd.bg_free_inodes_count = fs->sb.s_free_inodes_count;
+-	fs->gd.bg_used_dirs_count = 1;
+-	fs->gd.bg_block_bitmap = 3;
+-	fs->gd.bg_inode_bitmap = 4;
+-	fs->gd.bg_inode_table = 5;
+-
+-	// mark non-filesystem blocks and inodes as allocated
+-	for(i = fs->sb.s_blocks_count; i <= BLOCKSIZE * 8; i++)
+-		allocate(fs->bbm, i);
+-	for(i = fs->sb.s_inodes_count + 1; i <= BLOCKSIZE * 8; i++)
+-		allocate(fs->ibm, i);
+-
+-	// mark system blocsk and inodes as allocated
+-	for(i = 1; i <= 4 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE; i++)
+-		allocate(fs->bbm, i);
+-	for(i = 1; i < EXT2_FIRST_INO; i++)
+-		allocate(fs->ibm, i);
+-
+-	// make root inode and directory
+-	fs->itab[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO;
+-	fs->itab[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
+-	fs->itab[EXT2_ROOT_INO-1].i_links_count = 2;
++	gd = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
++	itbl = nbinodes_per_group*sizeof(inode)/BLOCKSIZE;
++	for(i = 0,bbmpos=2+gd,ibmpos=3+gd,itblpos =4+gd;
++		i<nbgroups;
++		i++, bbmpos += nbblocks_per_group,ibmpos += nbblocks_per_group, 
++		itblpos += nbblocks_per_group)  {
++		
++		fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
++		fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
++		fs->gd[i].bg_used_dirs_count = 0;
++		fs->gd[i].bg_block_bitmap = bbmpos;
++		fs->gd[i].bg_inode_bitmap = ibmpos;
++		fs->gd[i].bg_inode_table = itblpos;
++	}
++
++	/* Mark non-filesystem blocks and inodes as allocated */
++	/* Mark system blocks and inodes as allocated         */
++	for(i = 0; i<nbgroups;i++) {
++
++		/* Block bitmap */
++		bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);	
++		//non-filesystem blocks.
++		for(j=fs->sb.s_blocks_per_group + 1; j <= BLOCKSIZE * 8; j++)
++			allocate(bbm, j); 
++		//system blocks
++		for(j = 1; j <= 3+gd+itbl; j++)
++			allocate(bbm, j); 
++		
++		/* Inode bitmap */
++		ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);	
++		//non-filesystem inodes
++		for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
++			allocate(ibm, j);
++	}
++
++	/* We have groups now. Add the root filesystem in group 0  */
++	/* Also allocate the system inodes in group 0 and update   */
++	/* directory count and inode count for group 0             */
++
++	ibm = get_blk(fs,fs->gd[0].bg_inode_bitmap);	
++	for(j = 1; j < EXT2_FIRST_INO; j++) {
++		allocate(ibm, j);
++		fs->gd[0].bg_free_inodes_count--;
++	}
++	fs->gd[0].bg_used_dirs_count = 1;
++	itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table);
++	itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO; 
++	itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
++	itab0[EXT2_ROOT_INO-1].i_links_count = 2;
++
+ 	b = get_workblk();
+ 	d = (directory*)b;
+ 	d->d_inode = EXT2_ROOT_INO;
+@@ -1147,9 +1522,14 @@
+ 	// make lost+found directory and reserve blocks
+ 	if(fs->sb.s_r_blocks_count)
+ 	{
+-		nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU | FM_IRWXG | FM_IRWXO);
++		nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, 0, 0, time(NULL));
+ 		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 > 2049 ) 
++			fs->sb.s_r_blocks_count=2049;
+ 		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;
+@@ -1170,24 +1550,24 @@
+ // loads a filesystem from disk
+ filesystem * load_fs(FILE * fh, int swapit)
+ {
+-	size_t fssize;
++	size_t fssize = 0;
+ 	filesystem *fs;
+ 	if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftell(fh)) < 0))
+-		pexit("input filesystem image");
++		perror_msg_and_die("input filesystem image");
+ 	rewind(fh);
+ 	fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
+ 	if(fssize < 16) // totally arbitrary
+-		errexit("too small filesystem");
+-	if(fssize > BLOCKS_PER_GROUP) // I build only one group
+-		errexit("too big filesystem");
++		error_msg_and_die("too small filesystem");
++/*	if(fssize > BLOCKS_PER_GROUP) // I build only one group
++		error_msg_and_die("too big filesystem"); */
+ 	if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
+-		errexit("not enough memory for filesystem");
++		error_msg_and_die("not enough memory for filesystem");
+ 	if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
+-		pexit("input filesystem image");
++		perror_msg_and_die("input filesystem image");
+ 	if(swapit)
+ 		swap_badfs(fs);
+ 	if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
+-		errexit("not a suitable ext2 filesystem");
++		error_msg_and_die("not a suitable ext2 filesystem");
+ 	return fs;
+ }
+ 
+@@ -1230,9 +1610,9 @@
+ 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
+ 	{
+ 		if(fsize <= 0)
+-			errexit("wrong size while saving inode %d", nod);
++			error_msg_and_die("wrong size while saving inode %d", nod);
+ 		if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
+-			errexit("error while saving inode %d", nod);
++			error_msg_and_die("error while saving inode %d", nod);
+ 		fsize -= BLOCKSIZE;
+ 	}
+ }
+@@ -1250,7 +1630,7 @@
+ 	{
+ 		int i, j;
+ 		if(fsize <= 0)
+-			errexit("wrong size while saving inode %d", nod);
++			error_msg_and_die("wrong size while saving inode %d", nod);
+ 		b = get_blk(fs, bk);
+ 		for(i = 0; i < 64; i++)
+ 		{
+@@ -1406,7 +1786,7 @@
+ 			s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved"; 
+ 	}
+ 	printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count);
+-	if(!allocated(fs->ibm, nod))
++	if(!allocated(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
+ 	{
+ 		printf("unallocated\n");
+ 		return;
+@@ -1440,24 +1820,46 @@
+ 		default:
+ 			list_blocks(fs, nod);
+ 	}
++	printf("Done with inode %d\n",nod);
+ }
+ 
+ // describes various fields in a filesystem
+ void print_fs(filesystem *fs)
+ {
+-	int i;
+-	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);
+-	printf("block size = %d, frag size = %d\n", fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024, fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
+-	printf("%d blocks per group, %d frags per group, %d inodes per group\n", fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group, fs->sb.s_inodes_per_group);
+-	printf("block bitmap: block %d, inode bitmap: block %d, inode table: block %d\n", fs->gd.bg_block_bitmap, fs->gd.bg_inode_bitmap, fs->gd.bg_inode_table);
+-	printf("block bitmap allocation:\n");
+-	print_bm(fs->bbm, fs->sb.s_blocks_count);
+-	printf("inode bitmap allocation:\n");
+-	print_bm(fs->ibm, fs->sb.s_inodes_count);
+-	for(i=1; i<=fs->sb.s_inodes_count; i++)
+-		if(allocated(fs->ibm, i))
+-			print_inode(fs, i);
++	int i,j;
++	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);
++	printf("block size = %d, frag size = %d\n",
++	       fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024,
++	       fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
++	printf("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);
++	printf("Size of inode table: %d blocks\n",
++			fs->sb.s_inodes_per_group * sizeof(inode)/BLOCKSIZE);
++	for (i = 0; i < GRP_NBGROUPS(fs); i++) {
++		printf("Group No: %d\n", i);
++		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);
++		printf("Free blocks count: %d\n",fs->gd[i].bg_free_blocks_count);
++		printf("Free inodes count: %d\n",fs->gd[i].bg_free_inodes_count);
++		printf("Used dir count: %d\n",fs->gd[i].bg_used_dirs_count);
++		printf("block bitmap allocation:\n");
++		print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
++		printf("inode bitmap allocation:\n");
++		ibm = GRP_GET_GROUP_IBM(fs, i);
++		print_bm(ibm, fs->sb.s_inodes_per_group);
++		for (j = 1; j <= fs->sb.s_inodes_per_group; j++)
++			if (allocated(ibm, j))
++				print_inode(fs, i*fs->sb.s_inodes_per_group + j);
++	}
+ }
+ 
+ void dump_fs(filesystem *fs, FILE * fh, int swapit)
+@@ -1467,31 +1869,234 @@
+ 	if(swapit)
+ 		swap_goodfs(fs);
+ 	if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
+-		pexit("output filesystem image");
++		perror_msg_and_die("output filesystem image");
+ 	if(swapit)
+ 		swap_badfs(fs);
+ }
+ 
++/*  device table entries take the form of:
++    <path>	<type> <mode>	<uid>	<gid>	<major>	<minor>	<start>	<inc>	<count>
++    /dev/mem     c    640       0       0         1       1       0     0         -
++
++    type can be one of: 
++	f	A regular file
++	d	Directory
++	c	Character special device file
++	b	Block special device file
++	p	Fifo (named pipe)
++
++    I don't bother with symlinks (permissions are irrelevant), hard
++    links (special cases of regular files), or sockets (why bother).
++
++    Regular files must exist in the target root directory.  If a char,
++    block, fifo, or directory does not exist, it will be created.
++*/
++static int interpret_table_entry(filesystem *fs, char *line)
++{
++	char type, *name = NULL, *tmp, *dir, *bname;
++	unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
++	unsigned long start = 0, increment = 1, count = 0;
++	inode *entry;
++	uint32 nod, parent;
++
++	if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
++				SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
++				&start, &increment, &count) < 0) 
++	{
++		return 1;
++	}
++
++	if (!strcmp(name, "/")) {
++		error_msg_and_die("Device table entries require absolute paths");
++	}
++
++	/* Check if this file already exists... */
++	switch (type) {
++		case 'd':
++			mode |= S_IFDIR;
++			break;
++		case 'f':
++			mode |= S_IFREG;
++			break;
++		case 'p':
++			mode |= S_IFIFO;
++			break;
++		case 'c':
++			mode |= S_IFCHR;
++			break;
++		case 'b':
++			mode |= S_IFBLK;
++			break;
++		default:
++			error_msg_and_die("Unsupported file type");
++	}
++	nod = 0;
++	if (count==0)
++		nod = find_path(fs, EXT2_ROOT_INO, name);
++	if (nod) {
++		/* Ok, we just need to fixup an existing entry 
++		 * and we will be all done... */
++		entry = get_nod(fs, nod);
++		entry->i_uid = uid;
++		entry->i_gid = gid;
++		entry->i_mode = mode;
++		if (major) {
++			dev_t rdev = makedev(major, minor);
++			((uint8*)entry->i_block)[0] = (rdev & 0xff);
++			((uint8*)entry->i_block)[1] = (rdev >> 8);
++		}
++	} else {
++		/* Try and find our parent now */
++		tmp = xstrdup(name);
++		dir = dirname(tmp);
++		parent = find_path(fs, EXT2_ROOT_INO, dir);
++		free(tmp);
++		if (!parent) {
++			error_msg ("skipping device_table entry '%s': no parent directory!", name);
++			free(name);
++			return 1;
++		}
++
++		tmp = xstrdup(name);
++		bname = xstrdup(basename(tmp));
++		free(tmp);
++		switch (type) {
++			case 'd':
++				mkdir_fs(fs, parent, bname, mode|FM_IFDIR, uid, gid, time(NULL));
++				break;
++			case 'f':
++#if 0
++				{
++					// This is a bit odd.. This will try to include
++					// the file of the same name from your _build_
++					// system...  Probably a very bad idea....
++					struct stat st;
++					FILE *fh = xfopen(name, "r");
++					lstat(name, &st);
++					mkfile_fs(fs, parent, bname, mode|FM_IFREG, st.st_size, fh, uid, gid, st.st_ctime);
++					fclose(fh);
++				}
++#else
++				error_msg("ignoring entry %s", name);
++#endif
++				break;
++			case 'p':
++				error_msg("ignoring entry %s", name);
++				break;
++			case 'c':
++			case 'b':
++				if (count > 0) {
++					dev_t rdev;
++					char *dname;
++					unsigned long i;
++					for (i = start; i < count; i++) {
++						asprintf(&dname, "%s%lu", bname, i);
++						nod = find_path(fs, EXT2_ROOT_INO, dname);
++						if (nod) {
++							/* We just need to fixup an existing entry */ 
++							entry = get_nod(fs, nod);
++						} else {
++							nod = alloc_nod(fs);
++							add2dir(fs, parent, nod, dname, mode, uid, gid, time(NULL));
++							entry = get_nod(fs, nod);
++						}
++						entry->i_uid = uid;
++						entry->i_gid = gid;
++						entry->i_mode = mode;
++						rdev = makedev(major, minor + (i * increment - start));
++						((uint8*)entry->i_block)[0] = (rdev & 0xff);
++						((uint8*)entry->i_block)[1] = (rdev >> 8);
++						free(dname);
++					}
++				} else {
++					dev_t rdev = makedev(major, minor);
++					nod = alloc_nod(fs);
++					add2dir(fs, parent, nod, bname, mode, uid, gid, time(NULL));
++					entry = get_nod(fs, nod);
++					((uint8*)entry->i_block)[0] = (rdev & 0xff);
++					((uint8*)entry->i_block)[1] = (rdev >> 8);
++				}
++				break;
++			default:
++				error_msg_and_die("Unsupported file type");
++		}
++		free(bname);
++	}
++	free(name);
++	return 0;
++}
++
++static int parse_device_table(filesystem *root, FILE * file)
++{
++	char *line;
++	int status = 0;
++	size_t length = 0;
++
++	/* Turn off squash, since we must ensure that values
++	 * entered via the device table are not squashed */
++	squash_uids = 0;
++	squash_perms = 0;
++
++	/* Looks ok so far.  The general plan now is to read in one
++	 * line at a time, check for leading comment delimiters ('#'),
++	 * then try and parse the line as a device table.  If we fail
++	 * to parse things, try and help the poor fool to fix their
++	 * device table with a useful error msg... */
++	line = NULL;
++	while (getline(&line, &length, file) != -1) {
++		/* First trim off any whitespace */
++		int len = strlen(line);
++
++		/* trim trailing whitespace */
++		while (len > 0 && isspace(line[len - 1]))
++			line[--len] = '\0';
++		/* trim leading whitespace */
++		memmove(line, &line[strspn(line, " \n\r\t\v")], len);
++
++		/* How long are we after trimming? */
++		len = strlen(line);
++
++		/* If this is NOT a comment line, try to interpret it */
++		if (len && *line != '#') {
++			if (interpret_table_entry(root, line))
++				status = 1;
++		}
++
++		free(line);
++		line = NULL;
++	}
++	fclose(file);
++
++	return status;
++}
++
++/*
++Local Variables:
++c-file-style: "linux"
++c-basic-offset: 4
++tab-width: 4
++End:
++*/
++
+ void showhelp(void)
+ {
+ 	fprintf(stderr, "Usage: %s [options] image\n"
+ 	"Create an ext2 filesystem image from directories/files\n\n"
+-	"  -x image                Use this image as a starting point\n"
+-	"  -d directory            Add this directory as source\n"
+-	"  -f file                 Add nodes (e.g. devices) from this spec file\n"
+-	"  -b blocks               Size in blocks\n"
+-	"  -i inodes               Number of inodes\n"
+-	"  -r reserved             Number of reserved blocks\n"
+-	"  -g path                 Generate a block map file for this path\n"
+-	"  -e value                Fill unallocated blocks with value\n"
+-	"  -z                      Make files with holes\n"
+-	"  -v                      Print resulting filesystem structure\n"
+-	"  -h                      Show this help\n\n"
+-	"Example of spec file:\n"
+-	"drwx            /dev\n"
+-	"crw-    10,190  /dev/lcd\n"
+-	"brw-    1,0     /dev/ram0\n\n"
+-	"Report bugs to xavier.bestel@free.fr\n", argv0);
++	"  -x image	    Use this image as a starting point\n"
++	"  -d directory     Add this directory as source\n"
++	"  -b blocks        Size in blocks\n"
++	"  -i inodes        Number of inodes\n"
++	"  -r reserved      Number of reserved blocks\n"
++	"  -g path          Generate a block map file for this path\n"
++	"  -e value         Fill unallocated blocks with value\n"
++	"  -z               Make files with holes\n"
++	"  -D,-f            Use the named FILE as a device table file\n"
++	"  -q               Squash permissions and owners making all files be owned by root\n"
++	"  -U               Squash owners making all files be owned by root\n"
++	"  -P               Squash permissions on all files\n"
++	"  -v               Print resulting filesystem structure\n"
++	"  -h               Show this help\n\n"
++	"Report bugs to xavier.bestel@free.fr\n", app_name);
+ }
+ 
+ #define MAX_DOPT 128
+@@ -1521,21 +2126,17 @@
+ 	filesystem *fs;
+ 	int i;
+ 	int c;
++	struct stat sb;
++	FILE *devtable = NULL;
+ 
+-	argv0 = argv[0];
+-	if(argc <= 1)
+-	{
+-		showhelp();
+-		exit(1);
+-	}
+-	while((c = getopt(argc, argv, "x:f:d:b:i:r:g:e:zvh")) != EOF)
++	app_name = argv[0];
++	while((c = getopt(argc, argv, "x:d:b:i:r:g:e:zvhD:f:qUP")) != EOF)
+ 		switch(c)
+ 		{
+ 			case 'x':
+ 				fsin = optarg;
+ 				break;
+ 			case 'd':
+-			case 'f':
+ 				dopt[didx++] = optarg;
+ 				break;
+ 			case 'b':
+@@ -1556,6 +2157,24 @@
+ 			case 'z':
+ 				holes = 1;
+ 				break;
++			case 'f':
++			case 'D':
++				devtable = xfopen(optarg, "r");
++				if (fstat(fileno(devtable), &sb) < 0)
++					perror_msg_and_die(optarg);
++				if (sb.st_size < 10)
++					error_msg_and_die("%s: not a proper device table file", optarg);
++				break;
++			case 'q':
++				squash_uids = 1;
++				squash_perms = 1;
++				break;
++			case 'U':
++				squash_uids = 1;
++				break;
++			case 'P':
++				squash_perms = 1;
++				break;
+ 			case 'v':
+ 				verbose = 1;
+ 				break;
+@@ -1566,16 +2185,14 @@
+ 				exit(1);
+ 		}
+ 	if(optind < (argc - 1))
+-		errexit("too many arguments");
++		error_msg_and_die("too many arguments");
+ 	if(optind == (argc - 1))
+ 		fsout = argv[optind];
+ 	if(fsin)
+ 	{
+ 		if(strcmp(fsin, "-"))
+ 		{
+-			FILE * fh = fopen(fsin, "r");
+-			if(!fh)
+-				pexit(fsin);
++			FILE * fh = xfopen(fsin, "r");
+ 			fs = load_fs(fh, bigendian);
+ 			fclose(fh);
+ 		}
+@@ -1585,7 +2202,7 @@
+ 	else
+ 	{
+ 		if(nbblocks == -1)
+-			errexit("filesystem size unspecified");
++			error_msg_and_die("filesystem size unspecified");
+ 		if(nbinodes == -1)
+ 			nbinodes = nbblocks * BLOCKSIZE / rndup(BYTES_PER_INODE, BLOCKSIZE);
+ 		if(nbresrvd == -1)
+@@ -1595,35 +2212,30 @@
+ 	for(i = 0; i < didx; i++)
+ 	{
+ 		struct stat st;
+-		FILE *fh;
+ 		char *pdir;
+ 		stat(dopt[i], &st);
+ 		switch(st.st_mode & S_IFMT)
+ 		{
+-			case S_IFREG:
+-				if(!(fh = fopen(dopt[i], "r")))
+-					pexit(dopt[i]);
+-				add2fs_from_file(fs, EXT2_ROOT_INO, fh);
+-				fclose(fh);
+-				break;
+ 			case S_IFDIR:
+ 				if(!(pdir = getcwd(0, GETCWD_SIZE)))
+-					pexit(dopt[i]);
++					perror_msg_and_die(dopt[i]);
+ 				if(chdir(dopt[i]) < 0)
+-					pexit(dopt[i]);
++					perror_msg_and_die(dopt[i]);
+ 				add2fs_from_dir(fs, EXT2_ROOT_INO);
+ 				if(chdir(pdir) < 0)
+-					pexit(pdir);
++					perror_msg_and_die(pdir);
+ 				free(pdir);
+ 				break;
+ 			default:
+-				errexit("%s in neither a file nor a directory", dopt[i]);
++				error_msg_and_die("%s is neither a file nor a directory", dopt[i]);
+ 		}
+ 	}
+ 	if(emptyval)
+ 		for(i = 1; i < fs->sb.s_blocks_count; i++)
+-			if(!allocated(fs->bbm, i))
++			if(!allocated(GRP_GET_BLOCK_BITMAP(fs,i),GRP_BBM_OFFSET(fs,i)))
+ 				memset(get_blk(fs, i), emptyval, BLOCKSIZE);
++	if(devtable)
++		parse_device_table(fs, devtable);
+ 	if(verbose)
+ 		print_fs(fs);
+ 	for(i = 0; i < gidx; i++)
+@@ -1633,21 +2245,18 @@
+ 		char *p;
+ 		FILE *fh;
+ 		if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
+-			errexit("path %s not found in filesystem", 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]);
+-		if(!(fh = fopen(fname, "w")))
+-			pexit(fname);
++		fh = xfopen(fname, "w");
+ 		fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
+ 		flist_blocks(fs, nod, fh);
+ 		fclose(fh);
+ 	}
+ 	if(strcmp(fsout, "-"))
+ 	{
+-		FILE * fh = fopen(fsout, "w");
+-		if(!fh)
+-			pexit(fsout);
++		FILE * fh = xfopen(fsout, "w");
+ 		dump_fs(fs, fh, bigendian);
+ 		fclose(fh);
+ 	}
+diff -urN genext2fs-1.3.orig/test-mount.sh genext2fs-1.3/test-mount.sh
+diff -urN genext2fs-1.3.orig/test.sh genext2fs-1.3/test.sh
diff --git a/recipes/genext2fs/genext2fs-native_1.3+1.4rc1.bb b/recipes/genext2fs/genext2fs-native_1.3+1.4rc1.bb
new file mode 100644
index 0000000000..50b371b97e
--- /dev/null
+++ b/recipes/genext2fs/genext2fs-native_1.3+1.4rc1.bb
@@ -0,0 +1,10 @@
+require genext2fs_${PV}.bb
+inherit native
+
+do_stage () {
+	install -m 0755 genext2fs ${STAGING_BINDIR}/
+}
+
+do_install () {
+	:
+}
diff --git a/recipes/genext2fs/genext2fs-native_1.3+cvs.bb b/recipes/genext2fs/genext2fs-native_1.3+cvs.bb
new file mode 100644
index 0000000000..50b371b97e
--- /dev/null
+++ b/recipes/genext2fs/genext2fs-native_1.3+cvs.bb
@@ -0,0 +1,10 @@
+require genext2fs_${PV}.bb
+inherit native
+
+do_stage () {
+	install -m 0755 genext2fs ${STAGING_BINDIR}/
+}
+
+do_install () {
+	:
+}
diff --git a/recipes/genext2fs/genext2fs-native_1.3.bb b/recipes/genext2fs/genext2fs-native_1.3.bb
new file mode 100644
index 0000000000..2e26fa0110
--- /dev/null
+++ b/recipes/genext2fs/genext2fs-native_1.3.bb
@@ -0,0 +1,11 @@
+require genext2fs_${PV}.bb
+inherit native
+FILESPATH = "${@base_set_filespath([ '${FILE_DIRNAME}/genext2fs-${PV}', '${FILE_DIRNAME}/genext2fs', '${FILE_DIRNAME}/files', '${FILE_DIRNAME}' ], d)}"
+
+do_stage () {
+	install -m 0755 genext2fs ${STAGING_BINDIR}/
+}
+
+do_install () {
+	:
+}
diff --git a/recipes/genext2fs/genext2fs.inc b/recipes/genext2fs/genext2fs.inc
new file mode 100644
index 0000000000..c2984bccdd
--- /dev/null
+++ b/recipes/genext2fs/genext2fs.inc
@@ -0,0 +1,4 @@
+LICENSE = "GPL"
+DESCRIPTION = "A tool to generate an ext2 filesystem \
+as a normal (non-root) user."
+SECTION = "console/utils"
diff --git a/recipes/genext2fs/genext2fs_1.3+1.4rc1.bb b/recipes/genext2fs/genext2fs_1.3+1.4rc1.bb
new file mode 100644
index 0000000000..9723036871
--- /dev/null
+++ b/recipes/genext2fs/genext2fs_1.3+1.4rc1.bb
@@ -0,0 +1,10 @@
+require genext2fs.inc
+
+TRIMMEDV = "${@bb.data.getVar('PV', d, 1).split('+')[1]}"
+FILESPATH = "${FILE_DIRNAME}/genext2fs-${PV}:${FILE_DIRNAME}/genext2fs:${FILE_DIRNAME}/files"
+SRC_URI = "${SOURCEFORGE_MIRROR}/genext2fs/genext2fs-${TRIMMEDV}.tar.gz \
+	   file://volume.patch;patch=1"
+S = "${WORKDIR}/genext2fs-${TRIMMEDV}"
+DEFAULT_PREFERENCE = "1"
+
+inherit autotools
diff --git a/recipes/genext2fs/genext2fs_1.3+cvs.bb b/recipes/genext2fs/genext2fs_1.3+cvs.bb
new file mode 100644
index 0000000000..82af2041ab
--- /dev/null
+++ b/recipes/genext2fs/genext2fs_1.3+cvs.bb
@@ -0,0 +1,9 @@
+require genext2fs.inc
+
+PV_append = "${SRCDATE}"
+PR = "r3"
+FILESPATH = "${FILE_DIRNAME}/genext2fs-1.3+cvs:${FILE_DIRNAME}/genext2fs:${FILE_DIRNAME}/files"
+SRC_URI = "cvs://anonymous:@genext2fs.cvs.sourceforge.net/cvsroot/genext2fs;module=genext2fs"
+S = "${WORKDIR}/genext2fs"
+
+inherit autotools
diff --git a/recipes/genext2fs/genext2fs_1.3.bb b/recipes/genext2fs/genext2fs_1.3.bb
new file mode 100644
index 0000000000..e57f78ae50
--- /dev/null
+++ b/recipes/genext2fs/genext2fs_1.3.bb
@@ -0,0 +1,15 @@
+require genext2fs.inc
+
+PR = "r3"
+
+SRC_URI = "${DEBIAN_MIRROR}/main/g/genext2fs/genext2fs_${PV}.orig.tar.gz \
+	   file://misc.patch;patch=1"
+S = "${WORKDIR}/genext2fs-${PV}.orig"
+
+do_compile () {
+	oe_runmake
+}
+
+do_install () {
+	oe_runmake 'DESTDIR=${D}' install
+}
-- 
cgit v1.2.3