All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
To: buildroot@busybox.net
Subject: [Buildroot] [PATCH 03/44] cramfs: new package
Date: Fri,  9 Apr 2010 11:06:41 +0200	[thread overview]
Message-ID: <f601bb72db8505def5b3acad13c67d99e2e62a1d.1270803901.git.thomas.petazzoni@free-electrons.com> (raw)
In-Reply-To: <cover.1270803901.git.thomas.petazzoni@free-electrons.com>

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
 package/Config.in                        |    1 +
 package/cramfs/Config.in                 |    7 +
 package/cramfs/cramfs-01-devtable.patch  | 1269 ++++++++++++++++++++++++++++++
 package/cramfs/cramfs-02-endian.patch    |  284 +++++++
 package/cramfs/cramfs-03-cygwin_IO.patch |   13 +
 package/cramfs/cramfs.mk                 |   33 +
 6 files changed, 1607 insertions(+), 0 deletions(-)
 create mode 100644 package/cramfs/Config.in
 create mode 100644 package/cramfs/cramfs-01-devtable.patch
 create mode 100644 package/cramfs/cramfs-02-endian.patch
 create mode 100644 package/cramfs/cramfs-03-cygwin_IO.patch
 create mode 100644 package/cramfs/cramfs.mk

diff --git a/package/Config.in b/package/Config.in
index 856048a..5a7bf27 100644
--- a/package/Config.in
+++ b/package/Config.in
@@ -146,6 +146,7 @@ endmenu
 
 menu "Hardware handling"
 source "package/acpid/Config.in"
+source "package/cramfs/Config.in"
 source "package/dbus/Config.in"
 source "package/dbus-glib/Config.in"
 source "package/dbus-python/Config.in"
diff --git a/package/cramfs/Config.in b/package/cramfs/Config.in
new file mode 100644
index 0000000..553fb8a
--- /dev/null
+++ b/package/cramfs/Config.in
@@ -0,0 +1,7 @@
+config BR2_PACKAGE_CRAMFS
+       bool "cramfs"
+       help
+         cramfs is a comporessed read-only filesystem. This package
+         contains the tools to generate and check a cramfs filesystem.
+
+	 http://sourceforge.net/projects/cramfs/
\ No newline at end of file
diff --git a/package/cramfs/cramfs-01-devtable.patch b/package/cramfs/cramfs-01-devtable.patch
new file mode 100644
index 0000000..884eb8c
--- /dev/null
+++ b/package/cramfs/cramfs-01-devtable.patch
@@ -0,0 +1,1269 @@
+--- cramfs-1.1.orig/cramfsck.c	2002-02-22 17:00:42.000000000 -0700
++++ cramfs-1.1/cramfsck.c	2002-12-21 01:25:17.000000000 -0700
+@@ -51,10 +51,11 @@
+ #include <utime.h>
+ #include <sys/ioctl.h>
+ #define _LINUX_STRING_H_
+-#include <linux/fs.h>
+-#include <linux/cramfs_fs.h>
++#include "linux/cramfs_fs.h"
+ #include <zlib.h>
+ 
++#define BLKGETSIZE	_IO(0x12,96) /* return device size /512 (long *arg) */
++
+ /* Exit codes used by fsck-type programs */
+ #define FSCK_OK          0	/* No errors */
+ #define FSCK_NONDESTRUCT 1	/* File system errors corrected */
+@@ -75,7 +76,7 @@
+ static int opt_verbose = 0;	/* 1 = verbose (-v), 2+ = very verbose (-vv) */
+ #ifdef INCLUDE_FS_TESTS
+ static int opt_extract = 0;		/* extract cramfs (-x) */
+-static char *extract_dir = "root";	/* extraction directory (-x) */
++static char *extract_dir = "/";	/* extraction directory (-x) */
+ static uid_t euid;			/* effective UID */
+ 
+ /* (cramfs_super + start) <= start_dir < end_dir <= start_data <= end_data */
+@@ -155,7 +156,7 @@
+ 	}
+ 
+ 	if (*length < sizeof(struct cramfs_super)) {
+-		die(FSCK_UNCORRECTED, 0, "file length too short");
++		die(FSCK_UNCORRECTED, 0, "filesystem smaller than a cramfs superblock!");
+ 	}
+ 
+ 	/* find superblock */
+@@ -190,7 +191,8 @@
+ 			die(FSCK_UNCORRECTED, 0, "zero file count");
+ 		}
+ 		if (*length < super.size) {
+-			die(FSCK_UNCORRECTED, 0, "file length too short");
++			die(FSCK_UNCORRECTED, 0, "file length too short, %lu is smaller than %lu",
++				*length, super.size);
+ 		}
+ 		else if (*length > super.size) {
+ 			fprintf(stderr, "warning: file extends past end of filesystem\n");
+@@ -267,11 +269,11 @@
+ #ifdef INCLUDE_FS_TESTS
+ static void print_node(char type, struct cramfs_inode *i, char *name)
+ {
+-	char info[10];
++	char info[11];
+ 
+ 	if (S_ISCHR(i->mode) || (S_ISBLK(i->mode))) {
+ 		/* major/minor numbers can be as high as 2^12 or 4096 */
+-		snprintf(info, 10, "%4d,%4d", major(i->size), minor(i->size));
++		snprintf(info, 11, "%4d,%4d", major(i->size), minor(i->size));
+ 	}
+ 	else {
+ 		/* size be as high as 2^24 or 16777216 */
+@@ -445,8 +447,10 @@
+ 	}
+ 	/* TODO: Do we need to check end_dir for empty case? */
+ 	memcpy(newpath, path, pathlen);
+-	newpath[pathlen] = '/';
+-	pathlen++;
++	if (pathlen > 1) {
++	    newpath[pathlen] = '/';
++	    pathlen++;
++	}
+ 	if (opt_verbose) {
+ 		print_node('d', i, path);
+ 	}
+--- cramfs-1.1.orig/device_table.txt	1969-12-31 17:00:00.000000000 -0700
++++ cramfs-1.1/device_table.txt	2003-01-01 05:13:44.000000000 -0700
+@@ -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 mkcramfs.  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	-
++
+--- cramfs-1.1.orig/mkcramfs.c	2002-02-20 01:03:32.000000000 -0700
++++ cramfs-1.1/mkcramfs.c	2002-12-21 01:25:17.000000000 -0700
+@@ -1,3 +1,4 @@
++/* vi: set sw=8 ts=8: */
+ /*
+  * mkcramfs - make a cramfs file system
+  *
+@@ -16,12 +17,21 @@
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ * Added device table support (code taken from mkfs.jffs2.c, credit to
++ * Erik Andersen <andersen@codepoet.org>) as well as an option to squash
++ * permissions. - Russ Dill <Russ.Dill@asu.edu> September 2002
++ *
++ * Reworked, cleaned up, and updated for cramfs-1.1, December 2002
++ *  - Erik Andersen <andersen@codepoet.org>
++ *
+  */
+ 
+ /*
+  * If you change the disk format of cramfs, please update fs/cramfs/README.
+  */
+ 
++#define _GNU_SOURCE
+ #include <sys/types.h>
+ #include <stdio.h>
+ #include <sys/stat.h>
+@@ -33,8 +43,15 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <stdarg.h>
++#include <libgen.h>
++#include <ctype.h>
++#include <assert.h>
++#include <getopt.h>
+ #include <linux/cramfs_fs.h>
+ #include <zlib.h>
++#ifdef DMALLOC
++#include <dmalloc.h>
++#endif
+ 
+ /* Exit codes used by mkfs-type programs */
+ #define MKFS_OK          0	/* No errors */
+@@ -71,11 +88,17 @@
+ 		  + (1 << CRAMFS_SIZE_WIDTH) - 1 /* filesize */ \
+ 		  + (1 << CRAMFS_SIZE_WIDTH) * 4 / PAGE_CACHE_SIZE /* block pointers */ )
+ 
++
++/* The kernel assumes PAGE_CACHE_SIZE as block size. */
++#define PAGE_CACHE_SIZE (4096)
++
++
+ static const char *progname = "mkcramfs";
+ static unsigned int blksize = PAGE_CACHE_SIZE;
+ static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */
+ static int image_length = 0;
+ 
++
+ /*
+  * If opt_holes is set, then mkcramfs can create explicit holes in the
+  * data, which saves 26 bytes per hole (which is a lot smaller a
+@@ -91,10 +114,12 @@
+ static int opt_holes = 0;
+ static int opt_pad = 0;
+ static int opt_verbose = 0;
++static int opt_squash = 0;
+ static char *opt_image = NULL;
+ static char *opt_name = NULL;
+ 
+ static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid;
++static const char *const memory_exhausted = "memory exhausted";
+ 
+ /* In-core version of inode / directory entry. */
+ struct entry {
+@@ -123,7 +148,7 @@
+ {
+ 	FILE *stream = status ? stderr : stdout;
+ 
+-	fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] dirname outfile\n"
++	fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] [-D file] dirname outfile\n"
+ 		" -h         print this help\n"
+ 		" -E         make all warnings errors (non-zero exit status)\n"
+ 		" -e edition set edition number (part of fsid)\n"
+@@ -133,39 +158,157 @@
+ 		" -s         sort directory entries (old option, ignored)\n"
+ 		" -v         be more verbose\n"
+ 		" -z         make explicit holes (requires >= 2.3.39)\n"
+-		" dirname    root of the directory tree to be compressed\n"
++		" -D         Use the named FILE as a device table file\n"
++		" -q         squash permissions (make everything owned by root)\n"
++		" dirname    root of the filesystem to be compressed\n"
+ 		" outfile    output file\n", progname, PAD_SIZE);
+ 
+ 	exit(status);
+ }
+ 
+-static void die(int status, int syserr, const char *fmt, ...)
++static void verror_msg(const char *s, va_list p)
++{
++	fflush(stdout);
++	fprintf(stderr, "mkcramfs: ");
++	vfprintf(stderr, s, p);
++}
++
++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));
++}
++
++static void perror_msg(const char *s, ...)
++{
++	va_list p;
++
++	va_start(p, s);
++	vperror_msg(s, p);
++	va_end(p);
++}
++
++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(MKFS_ERROR);
++}
++
++static void perror_msg_and_die(const char *s, ...)
++{
++	va_list p;
++
++	va_start(p, s);
++	vperror_msg(s, p);
++	va_end(p);
++	exit(MKFS_ERROR);
++}
++#ifndef DMALLOC
++extern 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 *xmalloc(size_t size)
++{
++	void *ptr = malloc(size);
++
++	if (ptr == NULL && size != 0)
++		error_msg_and_die(memory_exhausted);
++	return ptr;
++}
++
++extern void *xcalloc(size_t nmemb, size_t size)
++{
++	void *ptr = calloc(nmemb, size);
++
++	if (ptr == NULL && nmemb != 0 && size != 0)
++		error_msg_and_die(memory_exhausted);
++	return ptr;
++}
++
++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;
++}
++#endif
++
++static FILE *xfopen(const char *path, const char *mode)
+ {
+-	va_list arg_ptr;
+-	int save = errno;
++	FILE *fp;
++
++	if ((fp = fopen(path, mode)) == NULL)
++		perror_msg_and_die("%s", path);
++	return fp;
++}
+ 
+-	fflush(0);
+-	va_start(arg_ptr, fmt);
+-	fprintf(stderr, "%s: ", progname);
+-	vfprintf(stderr, fmt, arg_ptr);
+-	if (syserr) {
+-		fprintf(stderr, ": %s", strerror(save));
++extern int xopen(const char *pathname, int flags, mode_t mode)
++{
++	int ret;
++	
++	if (flags & O_CREAT)
++		ret = open(pathname, flags, mode);
++	else
++		ret = open(pathname, flags);
++	if (ret == -1) {
++		perror_msg_and_die("%s", pathname);
+ 	}
+-	fprintf(stderr, "\n");
+-	va_end(arg_ptr);
+-	exit(status);
++	return ret;
+ }
+ 
++extern 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("%s:%s", progname, path);
++		    return NULL;
++		}
++	}           
++	while (bufsize < readsize + 1);
++
++	buf[readsize] = '\0';
++
++	return buf;
++}       
++
+ static void map_entry(struct entry *entry)
+ {
+ 	if (entry->path) {
+ 		entry->fd = open(entry->path, O_RDONLY);
+ 		if (entry->fd < 0) {
+-			die(MKFS_ERROR, 1, "open failed: %s", entry->path);
++			error_msg_and_die("open failed: %s", entry->path);
+ 		}
+ 		entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, entry->fd, 0);
+ 		if (entry->uncompressed == MAP_FAILED) {
+-			die(MKFS_ERROR, 1, "mmap failed: %s", entry->path);
++			error_msg_and_die("mmap failed: %s", entry->path);
+ 		}
+ 	}
+ }
+@@ -174,8 +317,9 @@
+ {
+ 	if (entry->path) {
+ 		if (munmap(entry->uncompressed, entry->size) < 0) {
+-			die(MKFS_ERROR, 1, "munmap failed: %s", entry->path);
++			error_msg_and_die("munmap failed: %s", entry->path);
+ 		}
++		entry->uncompressed=NULL;
+ 		close(entry->fd);
+ 	}
+ }
+@@ -204,7 +348,8 @@
+ 		find_identical_file(orig->next, newfile));
+ }
+ 
+-static void eliminate_doubles(struct entry *root, struct entry *orig) {
++static void eliminate_doubles(struct entry *root, struct entry *orig) 
++{
+ 	if (orig) {
+ 		if (orig->size && (orig->path || orig->uncompressed))
+ 			find_identical_file(root, orig);
+@@ -232,10 +377,7 @@
+ 
+ 	/* Set up the path. */
+ 	/* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */
+-	path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1);
+-	if (!path) {
+-		die(MKFS_ERROR, 1, "malloc failed");
+-	}
++	path = xmalloc(len + 1 + MAX_INPUT_NAMELEN + 1);
+ 	memcpy(path, name, len);
+ 	endpath = path + len;
+ 	*endpath = '/';
+@@ -245,7 +387,7 @@
+ 	dircount = scandir(name, &dirlist, 0, cramsort);
+ 
+ 	if (dircount < 0) {
+-		die(MKFS_ERROR, 1, "scandir failed: %s", name);
++		error_msg_and_die("scandir failed: %s", name);
+ 	}
+ 
+ 	/* process directory */
+@@ -269,25 +411,20 @@
+ 		}
+ 		namelen = strlen(dirent->d_name);
+ 		if (namelen > MAX_INPUT_NAMELEN) {
+-			die(MKFS_ERROR, 0,
+-				"very long (%u bytes) filename found: %s\n"
+-				"please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile",
++			error_msg_and_die(
++				"Very long (%u bytes) filename `%s' found.\n"
++				" Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile.  Exiting.\n",
+ 				namelen, dirent->d_name);
+ 		}
+ 		memcpy(endpath, dirent->d_name, namelen + 1);
+ 
+ 		if (lstat(path, &st) < 0) {
++			perror(endpath);
+ 			warn_skip = 1;
+ 			continue;
+ 		}
+-		entry = calloc(1, sizeof(struct entry));
+-		if (!entry) {
+-			die(MKFS_ERROR, 1, "calloc failed");
+-		}
+-		entry->name = strdup(dirent->d_name);
+-		if (!entry->name) {
+-			die(MKFS_ERROR, 1, "strdup failed");
+-		}
++		entry = xcalloc(1, sizeof(struct entry));
++		entry->name = xstrdup(dirent->d_name);
+ 		/* truncate multi-byte UTF-8 filenames on character boundary */
+ 		if (namelen > CRAMFS_MAXPATHLEN) {
+ 			namelen = CRAMFS_MAXPATHLEN;
+@@ -297,24 +434,25 @@
+ 				namelen--;
+ 				/* are we reasonably certain it was UTF-8 ? */
+ 				if (entry->name[namelen] < 0x80 || !namelen) {
+-					die(MKFS_ERROR, 0, "cannot truncate filenames not encoded in UTF-8");
++					error_msg_and_die("cannot truncate filenames not encoded in UTF-8");
+ 				}
+ 			}
+ 			entry->name[namelen] = '\0';
+ 		}
+ 		entry->mode = st.st_mode;
+ 		entry->size = st.st_size;
+-		entry->uid = st.st_uid;
++		entry->uid = opt_squash ? 0 : st.st_uid;
+ 		if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
+ 			warn_uid = 1;
+-		entry->gid = st.st_gid;
+-		if (entry->gid >= 1 << CRAMFS_GID_WIDTH)
++		entry->gid = opt_squash ? 0 : st.st_gid;
++		if (entry->gid >= 1 << CRAMFS_GID_WIDTH) {
+ 			/* TODO: We ought to replace with a default
+ 			   gid instead of truncating; otherwise there
+ 			   are security problems.  Maybe mode should
+ 			   be &= ~070.  Same goes for uid once Linux
+ 			   supports >16-bit uids. */
+ 			warn_gid = 1;
++		}
+ 		size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
+ 		*fslen_ub += size;
+ 		if (S_ISDIR(st.st_mode)) {
+@@ -325,21 +463,15 @@
+ 					warn_skip = 1;
+ 					continue;
+ 				}
+-				entry->path = strdup(path);
+-				if (!entry->path) {
+-					die(MKFS_ERROR, 1, "strdup failed");
+-				}
++				entry->path = xstrdup(path);
+ 				if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) {
+ 					warn_size = 1;
+ 					entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1;
+ 				}
+ 			}
+ 		} else if (S_ISLNK(st.st_mode)) {
+-			entry->uncompressed = malloc(entry->size);
++			entry->uncompressed = xreadlink(path);
+ 			if (!entry->uncompressed) {
+-				die(MKFS_ERROR, 1, "malloc failed");
+-			}
+-			if (readlink(path, entry->uncompressed, entry->size) < 0) {
+ 				warn_skip = 1;
+ 				continue;
+ 			}
+@@ -351,7 +483,7 @@
+ 			if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
+ 				warn_dev = 1;
+ 		} else {
+-			die(MKFS_ERROR, 0, "bogus file type: %s", entry->name);
++			error_msg_and_die("bogus file type: %s", entry->name);
+ 		}
+ 
+ 		if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+@@ -378,7 +510,9 @@
+ 	struct cramfs_super *super = (struct cramfs_super *) base;
+ 	unsigned int offset = sizeof(struct cramfs_super) + image_length;
+ 
+-	offset += opt_pad;	/* 0 if no padding */
++	if (opt_pad) {
++		offset += opt_pad;	/* 0 if no padding */
++	}
+ 
+ 	super->magic = CRAMFS_MAGIC;
+ 	super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS;
+@@ -414,10 +548,10 @@
+ 	struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
+ 
+ 	if ((offset & 3) != 0) {
+-		die(MKFS_ERROR, 0, "illegal offset of %lu bytes", offset);
++		error_msg_and_die("illegal offset of %lu bytes", offset);
+ 	}
+ 	if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
+-		die(MKFS_ERROR, 0, "filesystem too big");
++		error_msg_and_die("filesystem too big");
+ 	}
+ 	inode->offset = (offset >> 2);
+ }
+@@ -429,7 +563,7 @@
+  */
+ static void print_node(struct entry *e)
+ {
+-	char info[10];
++	char info[12];
+ 	char type = '?';
+ 
+ 	if (S_ISREG(e->mode)) type = 'f';
+@@ -442,11 +576,11 @@
+ 
+ 	if (S_ISCHR(e->mode) || (S_ISBLK(e->mode))) {
+ 		/* major/minor numbers can be as high as 2^12 or 4096 */
+-		snprintf(info, 10, "%4d,%4d", major(e->size), minor(e->size));
++		snprintf(info, 11, "%4d,%4d", major(e->size), minor(e->size));
+ 	}
+ 	else {
+ 		/* size be as high as 2^24 or 16777216 */
+-		snprintf(info, 10, "%9d", e->size);
++		snprintf(info, 11, "%9d", e->size);
+ 	}
+ 
+ 	printf("%c %04o %s %5d:%-3d %s\n",
+@@ -462,17 +596,9 @@
+ {
+ 	int stack_entries = 0;
+ 	int stack_size = 64;
+-	struct entry **entry_stack;
+-
+-	entry_stack = malloc(stack_size * sizeof(struct entry *));
+-	if (!entry_stack) {
+-		die(MKFS_ERROR, 1, "malloc failed");
+-	}
+-
+-	if (opt_verbose) {
+-		printf("root:\n");
+-	}
++	struct entry **entry_stack = NULL;
+ 
++	entry_stack = xmalloc(stack_size * sizeof(struct entry *));
+ 	for (;;) {
+ 		int dir_start = stack_entries;
+ 		while (entry) {
+@@ -506,10 +632,7 @@
+ 			if (entry->child) {
+ 				if (stack_entries >= stack_size) {
+ 					stack_size *= 2;
+-					entry_stack = realloc(entry_stack, stack_size * sizeof(struct entry *));
+-					if (!entry_stack) {
+-						die(MKFS_ERROR, 1, "realloc failed");
+-					}
++					entry_stack = xrealloc(entry_stack, stack_size * sizeof(struct entry *));
+ 				}
+ 				entry_stack[stack_entries] = entry;
+ 				stack_entries++;
+@@ -543,7 +666,7 @@
+ 
+ 		set_data_offset(entry, base, offset);
+ 		if (opt_verbose) {
+-			printf("%s:\n", entry->name);
++		    printf("'%s':\n", entry->name);
+ 		}
+ 		entry = entry->child;
+ 	}
+@@ -553,16 +676,21 @@
+ 
+ static int is_zero(char const *begin, unsigned len)
+ {
+-	/* Returns non-zero iff the first LEN bytes from BEGIN are all NULs. */
+-	return (len-- == 0 ||
+-		(begin[0] == '\0' &&
+-		 (len-- == 0 ||
+-		  (begin[1] == '\0' &&
+-		   (len-- == 0 ||
+-		    (begin[2] == '\0' &&
+-		     (len-- == 0 ||
+-		      (begin[3] == '\0' &&
+-		       memcmp(begin, begin + 4, len) == 0))))))));
++	if (opt_holes)
++		/* Returns non-zero iff the first LEN bytes from BEGIN are
++		   all NULs. */
++		return (len-- == 0 ||
++			(begin[0] == '\0' &&
++			 (len-- == 0 ||
++			  (begin[1] == '\0' &&
++			   (len-- == 0 ||
++			    (begin[2] == '\0' &&
++			     (len-- == 0 ||
++			      (begin[3] == '\0' &&
++			       memcmp(begin, begin + 4, len) == 0))))))));
++	else
++		/* Never create holes. */
++		return 0;
+ }
+ 
+ /*
+@@ -575,37 +703,34 @@
+  * Note that size > 0, as a zero-sized file wouldn't ever
+  * have gotten here in the first place.
+  */
+-static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size)
++static unsigned int do_compress(char *base, unsigned int offset, struct entry *entry)
+ {
++	unsigned int size = entry->size;
+ 	unsigned long original_size = size;
+ 	unsigned long original_offset = offset;
+ 	unsigned long new_size;
+ 	unsigned long blocks = (size - 1) / blksize + 1;
+ 	unsigned long curr = offset + 4 * blocks;
+ 	int change;
++	char *uncompressed = entry->uncompressed;
+ 
+-	total_blocks += blocks;
++	total_blocks += blocks; 
+ 
+ 	do {
+ 		unsigned long len = 2 * blksize;
+ 		unsigned int input = size;
+-		int err;
+-
+ 		if (input > blksize)
+ 			input = blksize;
+ 		size -= input;
+-		if (!(opt_holes && is_zero (uncompressed, input))) {
+-			err = compress2(base + curr, &len, uncompressed, input, Z_BEST_COMPRESSION);
+-			if (err != Z_OK) {
+-				die(MKFS_ERROR, 0, "compression error: %s", zError(err));
+-			}
++		if (!is_zero (uncompressed, input)) {
++			compress(base + curr, &len, uncompressed, input);
+ 			curr += len;
+ 		}
+ 		uncompressed += input;
+ 
+ 		if (len > blksize*2) {
+ 			/* (I don't think this can happen with zlib.) */
+-			die(MKFS_ERROR, 0, "AIEEE: block \"compressed\" to > 2*blocklength (%ld)", len);
++			error_msg_and_die("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len);
+ 		}
+ 
+ 		*(u32 *) (base + offset) = curr;
+@@ -618,10 +743,12 @@
+ 	   st_blocks * 512.  But if you say that then perhaps
+ 	   administrative data should also be included in both. */
+ 	change = new_size - original_size;
+-	if (opt_verbose > 1) {
+-		printf("%6.2f%% (%+d bytes)\t%s\n",
+-		       (change * 100) / (double) original_size, change, name);
++#if 0
++	if (opt_verbose) {
++	    printf("%6.2f%% (%+d bytes)\t%s\n",
++		    (change * 100) / (double) original_size, change, entry->name);
+ 	}
++#endif
+ 
+ 	return curr;
+ }
+@@ -644,7 +771,7 @@
+ 				set_data_offset(entry, base, offset);
+ 				entry->offset = offset;
+ 				map_entry(entry);
+-				offset = do_compress(base, offset, entry->name, entry->uncompressed, entry->size);
++				offset = do_compress(base, offset, entry);
+ 				unmap_entry(entry);
+ 			}
+ 		}
+@@ -660,13 +787,10 @@
+ 	int fd;
+ 	char *buf;
+ 
+-	fd = open(file, O_RDONLY);
+-	if (fd < 0) {
+-		die(MKFS_ERROR, 1, "open failed: %s", file);
+-	}
++	fd = xopen(file, O_RDONLY, 0);
+ 	buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0);
+ 	if (buf == MAP_FAILED) {
+-		die(MKFS_ERROR, 1, "mmap failed");
++		error_msg_and_die("mmap failed");
+ 	}
+ 	memcpy(base + offset, buf, image_length);
+ 	munmap(buf, image_length);
+@@ -679,6 +803,328 @@
+ 	return (offset + image_length);
+ }
+ 
++static struct entry *find_filesystem_entry(struct entry *dir, char *name, mode_t type)
++{
++	struct entry *e = dir;
++
++	if (S_ISDIR(dir->mode)) {
++		e = dir->child;
++	}
++	while (e) {
++		/* Only bother to do the expensive strcmp on matching file types */
++		if (type == (e->mode & S_IFMT) && e->name) {
++			if (S_ISDIR(e->mode)) {
++				int len = strlen(e->name);
++
++				/* Check if we are a parent of the correct path */
++				if (strncmp(e->name, name, len) == 0) {
++					/* Is this an _exact_ match? */
++					if (strcmp(name, e->name) == 0) {
++						return (e);
++					}
++					/* Looks like we found a parent of the correct path */
++					if (name[len] == '/') {
++						if (e->child) {
++							return (find_filesystem_entry (e, name + len + 1, type));
++						} else {
++							return NULL;
++						}
++					}
++				}
++			} else {
++				if (strcmp(name, e->name) == 0) {
++					return (e);
++				}
++			}
++		}
++		e = e->next;
++	}
++	return (NULL);
++}
++
++void modify_entry(char *full_path, unsigned long uid, unsigned long gid, 
++	unsigned long mode, unsigned long rdev, struct entry *root, loff_t *fslen_ub)
++{
++	char *name, *path, *full;
++	struct entry *curr, *parent, *entry, *prev;
++	
++	full = xstrdup(full_path);
++	path = xstrdup(dirname(full));
++	name = full_path + strlen(path) + 1;
++	free(full);
++	if (strcmp(path, "/") == 0) {
++		parent = root;
++		name = full_path + 1;
++	} else {
++		if (!(parent = find_filesystem_entry(root, path+1, S_IFDIR)))
++			error_msg_and_die("%s/%s: could not find parent\n", path, name);
++	}
++	if ((entry = find_filesystem_entry(parent, name, (mode & S_IFMT)))) {
++		/* its there, just modify permissions */
++		entry->mode = mode;
++		entry->uid = uid;
++		entry->gid = gid;
++	} else { /* make a new entry */
++	
++		/* code partially replicated from parse_directory() */
++		size_t namelen;
++		if (S_ISREG(mode)) {
++			error_msg_and_die("%s: regular file from device_table file must exist on disk!", full_path);
++		}
++
++		namelen = strlen(name);
++		if (namelen > MAX_INPUT_NAMELEN) {
++			error_msg_and_die(
++				"Very long (%u bytes) filename `%s' found.\n"
++				" Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile.  Exiting.\n",
++				namelen, name);
++		}
++		entry = xcalloc(1, sizeof(struct entry));
++		entry->name = xstrdup(name);
++		/* truncate multi-byte UTF-8 filenames on character boundary */
++		if (namelen > CRAMFS_MAXPATHLEN) {
++			namelen = CRAMFS_MAXPATHLEN;
++			warn_namelen = 1;
++			/* the first lost byte must not be a trail byte */
++			while ((entry->name[namelen] & 0xc0) == 0x80) {
++				namelen--;
++				/* are we reasonably certain it was UTF-8 ? */
++				if (entry->name[namelen] < 0x80 || !namelen) {
++					error_msg_and_die("cannot truncate filenames not encoded in UTF-8");
++				}
++			}
++			entry->name[namelen] = '\0';
++		}
++		entry->mode = mode;
++		entry->uid = uid;
++		entry->gid = gid;
++		entry->size = 0;
++		if (S_ISBLK(mode) || S_ISCHR(mode)) {
++			entry->size = rdev;
++			if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
++				warn_dev = 1;
++		}
++		
++		/* ok, now we have to backup and correct the size of all the entries above us */
++		*fslen_ub += sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
++		parent->size += sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
++
++		/* alright, time to link us in */
++		curr = parent->child;
++		prev = NULL;
++		while (curr && strcmp(name, curr->name) > 0) {
++			prev = curr;
++			curr = curr->next;
++		}
++		if (!prev) parent->child = entry;
++		else prev->next = entry;
++		entry->next = curr;
++		entry->child = NULL;
++	}
++	if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
++		warn_uid = 1;
++	if (entry->gid >= 1 << CRAMFS_GID_WIDTH) {
++		/* TODO: We ought to replace with a default
++		   gid instead of truncating; otherwise there
++		   are security problems.  Maybe mode should
++		   be &= ~070.  Same goes for uid once Linux
++		   supports >16-bit uids. */
++		warn_gid = 1;
++	}
++	free(path);
++}
++
++/* the GNU C library has a wonderful scanf("%as", string) which will
++ allocate the string with the right size, good to avoid buffer overruns. 
++ the following macros use it if available or use a hacky workaround...
++ */
++
++#ifdef __GNUC__
++#define SCANF_PREFIX "a"
++#define SCANF_STRING(s) (&s)
++#define GETCWD_SIZE 0
++#else
++#define SCANF_PREFIX "511"
++#define SCANF_STRING(s) (s = xmalloc(512))
++#define GETCWD_SIZE -1
++inline int snprintf(char *str, size_t n, const char *fmt, ...)
++{
++	int ret;
++	va_list ap;
++
++	va_start(ap, fmt);
++	ret = vsprintf(str, fmt, ap);
++	va_end(ap);
++	return ret;
++}
++#endif
++
++/*  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(char *line, struct entry *root, loff_t *fslen_ub)
++{
++	char type, *name = NULL;
++	unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
++	unsigned long start = 0, increment = 1, count = 0;
++
++	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");
++	}
++
++	switch (type) {
++	case 'd':
++		mode |= S_IFDIR;
++		modify_entry(name, uid, gid, mode, 0, root, fslen_ub);
++		break;
++	case 'f':
++		mode |= S_IFREG;
++		modify_entry(name, uid, gid, mode, 0, root, fslen_ub);
++		break;
++	case 'p':
++		mode |= S_IFIFO;
++		modify_entry(name, uid, gid, mode, 0, root, fslen_ub);
++		break;
++	case 'c':
++	case 'b':
++		mode |= (type == 'c') ? S_IFCHR : S_IFBLK;
++		if (count > 0) {
++			char *buf;
++			unsigned long i;
++			dev_t rdev;
++
++			for (i = start; i < count; i++) {
++				asprintf(&buf, "%s%lu", name, i);
++				rdev = makedev(major, minor + (i * increment - start));
++				modify_entry(buf, uid, gid, mode, rdev, root, fslen_ub);
++				free(buf);
++			}
++		} else {
++			dev_t rdev = makedev(major, minor);
++			modify_entry(name, uid, gid, mode, rdev, root, fslen_ub);
++		}
++		break;
++	default:
++		error_msg_and_die("Unsupported file type");
++	}
++	free(name);
++	return 0;
++}
++
++static int parse_device_table(FILE *file, struct entry *root, loff_t *fslen_ub)
++{
++	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 */
++	opt_squash = 0;
++
++	/* Looks ok so far.  The general plan now is to read in one
++	 * line@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(line, root, fslen_ub))
++				status = 1;
++		}
++
++		free(line);
++		line = NULL;
++	}
++	free(line);
++	fclose(file);
++
++	return status;
++}
++
++void traverse(struct entry *entry, int depth)
++{
++	struct entry *curr = entry;
++	int i;
++
++	while (curr) {
++		for (i = 0; i < depth; i++) putchar(' ');
++		printf("%s: size=%d mode=%d same=%p\n",
++			(curr->name)? (char*)curr->name : "/", 
++			curr->size, curr->mode, curr->same);
++		if (curr->child) traverse(curr->child, depth + 4);
++		curr = curr->next;
++	}
++}
++
++static void free_filesystem_entry(struct entry *dir)
++{
++	struct entry *e = dir, *last;
++
++	if (S_ISDIR(dir->mode)) {
++		e = dir->child;
++	}
++	while (e) {
++		if (e->name)
++			free(e->name);
++		if (e->path)
++			free(e->path);
++		if (e->uncompressed)
++			free(e->uncompressed);
++		last = e;
++		if (e->child) {
++			free_filesystem_entry(e);
++		}
++		e = e->next;
++		free(last);
++	}
++}
++
++
++/*
++ * Usage:
++ *
++ *      mkcramfs directory-name outfile
++ *
++ * where "directory-name" is simply the root of the directory
++ * tree that we want to generate a compressed filesystem out
++ * of.
++ */
+ int main(int argc, char **argv)
+ {
+ 	struct stat st;		/* used twice... */
+@@ -692,6 +1138,7 @@
+ 	u32 crc;
+ 	int c;			/* for getopt */
+ 	char *ep;		/* for strtoul */
++	FILE *devtable = NULL;
+ 
+ 	total_blocks = 0;
+ 
+@@ -699,7 +1146,7 @@
+ 		progname = argv[0];
+ 
+ 	/* command line options */
+-	while ((c = getopt(argc, argv, "hEe:i:n:psvz")) != EOF) {
++	while ((c = getopt(argc, argv, "hEe:i:n:psvzD:q")) != EOF) {
+ 		switch (c) {
+ 		case 'h':
+ 			usage(MKFS_OK);
+@@ -715,7 +1162,7 @@
+ 		case 'i':
+ 			opt_image = optarg;
+ 			if (lstat(opt_image, &st) < 0) {
+-				die(MKFS_ERROR, 1, "lstat failed: %s", opt_image);
++				error_msg_and_die("lstat failed: %s", opt_image);
+ 			}
+ 			image_length = st.st_size; /* may be padded later */
+ 			fslen_ub += (image_length + 3); /* 3 is for padding */
+@@ -736,6 +1183,16 @@
+ 		case 'z':
+ 			opt_holes = 1;
+ 			break;
++		case 'q':
++			opt_squash = 1;
++			break;
++		case 'D':
++			devtable = xfopen(optarg, "r");
++			if (fstat(fileno(devtable), &st) < 0)
++				perror_msg_and_die(optarg);
++			if (st.st_size < 10)
++				error_msg_and_die("%s: not a proper device table file\n", optarg);
++			break;
+ 		}
+ 	}
+ 
+@@ -745,25 +1202,23 @@
+ 	outfile = argv[optind + 1];
+ 
+ 	if (stat(dirname, &st) < 0) {
+-		die(MKFS_USAGE, 1, "stat failed: %s", dirname);
+-	}
+-	fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+-	if (fd < 0) {
+-		die(MKFS_USAGE, 1, "open failed: %s", outfile);
++		error_msg_and_die("stat failed: %s", dirname);
+ 	}
++	fd = xopen(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ 
+-	root_entry = calloc(1, sizeof(struct entry));
+-	if (!root_entry) {
+-		die(MKFS_ERROR, 1, "calloc failed");
+-	}
++	root_entry = xcalloc(1, sizeof(struct entry));
+ 	root_entry->mode = st.st_mode;
+ 	root_entry->uid = st.st_uid;
+ 	root_entry->gid = st.st_gid;
+ 
+ 	root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub);
+ 
++	if (devtable) {
++		parse_device_table(devtable, root_entry, &fslen_ub);
++	}
++
+ 	/* always allocate a multiple of blksize bytes because that's
+-	   what we're going to write later on */
++           what we're going to write later on */
+ 	fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1;
+ 
+ 	if (fslen_ub > MAXFSLEN) {
+@@ -790,7 +1245,7 @@
+ 	rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ 
+ 	if (rom_image == MAP_FAILED) {
+-		die(MKFS_ERROR, 1, "mmap failed");
++		error_msg_and_die("mmap failed");
+ 	}
+ 
+ 	/* Skip the first opt_pad bytes for boot loader code */
+@@ -807,6 +1262,7 @@
+ 	}
+ 
+ 	offset = write_directory_structure(root_entry->child, rom_image, offset);
++	if (opt_verbose)
+ 	printf("Directory data: %d bytes\n", offset);
+ 
+ 	offset = write_data(root_entry, rom_image, offset);
+@@ -814,30 +1270,38 @@
+ 	/* We always write a multiple of blksize bytes, so that
+ 	   losetup works. */
+ 	offset = ((offset - 1) | (blksize - 1)) + 1;
++	if (opt_verbose)
+ 	printf("Everything: %d kilobytes\n", offset >> 10);
+ 
+ 	/* Write the superblock now that we can fill in all of the fields. */
+ 	write_superblock(root_entry, rom_image+opt_pad, offset);
++	if (opt_verbose)
+ 	printf("Super block: %d bytes\n", sizeof(struct cramfs_super));
+ 
+ 	/* Put the checksum in. */
+ 	crc = crc32(0L, Z_NULL, 0);
+ 	crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad));
+ 	((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc;
++	if (opt_verbose)
+ 	printf("CRC: %x\n", crc);
+ 
+ 	/* Check to make sure we allocated enough space. */
+ 	if (fslen_ub < offset) {
+-		die(MKFS_ERROR, 0, "not enough space allocated for ROM image (%Ld allocated, %d used)", fslen_ub, offset);
++		error_msg_and_die("not enough space allocated for ROM "
++			"image (%Ld allocated, %d used)", fslen_ub, offset);
+ 	}
+ 
+ 	written = write(fd, rom_image, offset);
+ 	if (written < 0) {
+-		die(MKFS_ERROR, 1, "write failed");
++		error_msg_and_die("write failed");
+ 	}
+ 	if (offset != written) {
+-		die(MKFS_ERROR, 0, "ROM image write failed (wrote %d of %d bytes)", written, offset);
++		error_msg_and_die("ROM image write failed (wrote %d of %d bytes)", written, offset);
+ 	}
++	
++	/* Free up memory */
++	free_filesystem_entry(root_entry);
++	free(root_entry);
+ 
+ 	/* (These warnings used to come@the start, but they scroll off the
+ 	   screen too quickly.) */
diff --git a/package/cramfs/cramfs-02-endian.patch b/package/cramfs/cramfs-02-endian.patch
new file mode 100644
index 0000000..0da55bf
--- /dev/null
+++ b/package/cramfs/cramfs-02-endian.patch
@@ -0,0 +1,284 @@
+--- cramfs-1.1/mkcramfs.c.orig	2005-04-13 05:55:57.000000000 -0600
++++ cramfs-1.1/mkcramfs.c	2005-04-13 16:19:57.000000000 -0600
+@@ -117,6 +117,7 @@
+ static int opt_squash = 0;
+ static char *opt_image = NULL;
+ static char *opt_name = NULL;
++static int swap_endian = 0;
+ 
+ static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid;
+ static const char *const memory_exhausted = "memory exhausted";
+@@ -155,6 +156,8 @@
+ 		" -i file    insert a file image into the filesystem (requires >= 2.4.0)\n"
+ 		" -n name    set name of cramfs filesystem\n"
+ 		" -p         pad by %d bytes for boot code\n"
++		" -l         litte endian filesystem\n"
++		" -b         big endian filesystem\n"
+ 		" -s         sort directory entries (old option, ignored)\n"
+ 		" -v         be more verbose\n"
+ 		" -z         make explicit holes (requires >= 2.3.39)\n"
+@@ -504,6 +506,50 @@
+ 	return totalsize;
+ }
+ 
++/* routines to swap endianness/bitfields in inode/superblock block data */
++static void fix_inode(struct cramfs_inode *inode)
++{
++#define wswap(x)    (((x)>>24) | (((x)>>8)&0xff00) | (((x)&0xff00)<<8) | (((x)&0xff)<<24))
++	/* attempt #2 */
++	inode->mode = (inode->mode >> 8) | ((inode->mode&0xff)<<8);
++	inode->uid = (inode->uid >> 8) | ((inode->uid&0xff)<<8);
++	inode->size = (inode->size >> 16) | (inode->size&0xff00) |
++		((inode->size&0xff)<<16);
++	((u32*)inode)[2] = wswap(inode->offset | (inode->namelen<<26));
++}
++
++static void fix_offset(struct cramfs_inode *inode, u32 offset)
++{
++	u32 tmp = wswap(((u32*)inode)[2]);
++	((u32*)inode)[2] = wswap((offset >> 2) | (tmp&0xfc000000));
++}
++
++static void fix_block_pointer(u32 *p)
++{
++	*p = wswap(*p);
++}
++
++static void fix_super(struct cramfs_super *super)
++{
++	u32 *p = (u32*)super;
++
++	/* fix superblock fields */
++	p[0] = wswap(p[0]);	/* magic */
++	p[1] = wswap(p[1]);	/* size */
++	p[2] = wswap(p[2]);	/* flags */
++	p[3] = wswap(p[3]);	/* future */
++
++	/* fix filesystem info fields */
++	p = (u32*)&super->fsid;
++	p[0] = wswap(p[0]);	/* crc */
++	p[1] = wswap(p[1]);	/* edition */
++	p[2] = wswap(p[2]);	/* blocks */
++	p[3] = wswap(p[3]);	/* files */
++
++	fix_inode(&super->root);
++#undef wswap
++}
++
+ /* Returns sizeof(struct cramfs_super), which includes the root inode. */
+ static unsigned int write_superblock(struct entry *root, char *base, int size)
+ {
+@@ -539,6 +585,7 @@
+ 	super->root.gid = root->gid;
+ 	super->root.size = root->size;
+ 	super->root.offset = offset >> 2;
++	if (swap_endian) fix_super(super);
+ 
+ 	return offset;
+ }
+@@ -553,7 +600,10 @@
+ 	if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
+ 		error_msg_and_die("filesystem too big");
+ 	}
+-	inode->offset = (offset >> 2);
++	if (swap_endian)
++		fix_offset(inode, offset);
++	else
++		inode->offset = (offset >> 2);
+ }
+ 
+ /*
+@@ -638,6 +688,7 @@
+ 				stack_entries++;
+ 			}
+ 			entry = entry->next;
++			if (swap_endian) fix_inode(inode);
+ 		}
+ 
+ 		/*
+@@ -734,6 +785,7 @@
+ 		}
+ 
+ 		*(u32 *) (base + offset) = curr;
++		if (swap_endian) fix_block_pointer((u32*)(base + offset));
+ 		offset += 4;
+ 	} while (size);
+ 
+@@ -1146,7 +1198,7 @@
+ 		progname = argv[0];
+ 
+ 	/* command line options */
+-	while ((c = getopt(argc, argv, "hEe:i:n:psvzD:q")) != EOF) {
++	while ((c = getopt(argc, argv, "hEe:i:n:psvzD:qlb")) != EOF) {
+ 		switch (c) {
+ 		case 'h':
+ 			usage(MKFS_OK);
+@@ -1174,6 +1227,18 @@
+ 			opt_pad = PAD_SIZE;
+ 			fslen_ub += PAD_SIZE;
+ 			break;
++		case 'b':
++#if __BYTE_ORDER == __LITTLE_ENDIAN
++			swap_endian = 1;
++			printf("Swapping filesystem endian-ness\n");
++#endif
++			break;
++		case 'l':
++#if __BYTE_ORDER == __BIG_ENDIAN
++			swap_endian = 1;
++			printf("Swapping filesystem endian-ness\n");
++#endif
++			break;
+ 		case 's':
+ 			/* old option, ignored */
+ 			break;
+--- cramfs-1.1/cramfsck.c.orig	2005-04-25 11:50:31.000000000 -0700
++++ cramfs-1.1/cramfsck.c	2005-04-25 16:53:25.000000000 -0700
+@@ -30,6 +30,7 @@
+  * 2000/07/15: Daniel Quinlan (initial support for block devices)
+  * 2002/01/10: Daniel Quinlan (additional checks, test more return codes,
+  *                            use read if mmap fails, standardize messages)
++ * 2004/09/01: Alfonso Acosta (Add swapping support)
+  */
+ 
+ /* compile-time options */
+@@ -51,6 +52,7 @@
+ #include <utime.h>
+ #include <sys/ioctl.h>
+ #define _LINUX_STRING_H_
++#include <byteswap.h>
+ #include "linux/cramfs_fs.h"
+ #include <zlib.h>
+ 
+@@ -74,6 +76,7 @@
+ static char *filename;		/* ROM image filename */
+ struct cramfs_super super;	/* just find the cramfs superblock once */
+ static int opt_verbose = 0;	/* 1 = verbose (-v), 2+ = very verbose (-vv) */
++static int need_swapping = 0;   /* fs and host dont have the same endianness */
+ #ifdef INCLUDE_FS_TESTS
+ static int opt_extract = 0;		/* extract cramfs (-x) */
+ static char *extract_dir = "/";	/* extraction directory (-x) */
+@@ -85,6 +88,9 @@
+ static unsigned long start_data = ~0UL;	/* start of the data (256 MB = max) */
+ static unsigned long end_data = 0;	/* end of the data */
+ 
++/* access 32 byte variables */
++#define CRAMFS_32(x)  (need_swapping ? bswap_32(x) : x)
++
+ /* Guarantee access to at least 8kB at a time */
+ #define ROMBUFFER_BITS	13
+ #define ROMBUFFERSIZE	(1 << ROMBUFFER_BITS)
+@@ -166,20 +172,34 @@
+ 	if (super.magic == CRAMFS_MAGIC) {
+ 		*start = 0;
+ 	}
++	else if (super.magic == bswap_32(CRAMFS_MAGIC)) {
++		*start = 0;
++		need_swapping = 1;
++	}
++
+ 	else if (*length >= (PAD_SIZE + sizeof(super))) {
+ 		lseek(fd, PAD_SIZE, SEEK_SET);
+ 		if (read(fd, &super, sizeof(super)) != sizeof(super)) {
+ 			die(FSCK_ERROR, 1, "read failed: %s", filename);
+ 		}
+-		if (super.magic == CRAMFS_MAGIC) {
++		if (super.magic == CRAMFS_32(CRAMFS_MAGIC)) {
+ 			*start = PAD_SIZE;
+ 		}
+ 	}
+ 
+ 	/* superblock tests */
+-	if (super.magic != CRAMFS_MAGIC) {
++	if (super.magic != CRAMFS_32(CRAMFS_MAGIC)) {
+ 		die(FSCK_UNCORRECTED, 0, "superblock magic not found");
+ 	}
++	if (need_swapping){
++		super.size = bswap_32(super.size);
++		super.flags = bswap_32(super.flags);
++		super.future = bswap_32(super.future);
++		super.fsid.crc = bswap_32(super.fsid.crc);
++		super.fsid.edition = bswap_32(super.fsid.edition);
++		super.fsid.blocks = bswap_32(super.fsid.blocks);
++		super.fsid.files = bswap_32(super.fsid.files); 
++	}	
+ 	if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
+ 		die(FSCK_ERROR, 0, "unsupported filesystem features");
+ 	}
+@@ -215,7 +235,10 @@
+ 		die(FSCK_USAGE, 0, "unable to test CRC: old cramfs format");
+ #endif /* not INCLUDE_FS_TESTS */
+ 	}
+-
++	else if (need_swapping) {
++       /* crc checking in this case would mean  translating the whole file */
++		return;
++	}
+ 	crc = crc32(0L, Z_NULL, 0);
+ 
+ 	buf = mmap(NULL, super.size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+@@ -300,12 +323,23 @@
+ 
+ static struct cramfs_inode *cramfs_iget(struct cramfs_inode * i)
+ {
++#define wswap(x)    (((x)>>24) | (((x)>>8)&0xff00) | (((x)&0xff00)<<8) | (((x)&0xff)<<24))
+ 	struct cramfs_inode *inode = malloc(sizeof(struct cramfs_inode));
+ 
+ 	if (!inode) {
+ 		die(FSCK_ERROR, 1, "malloc failed");
+ 	}
+-	*inode = *i;
++	if(!need_swapping) {
++		*inode = *i;
++	}
++	else { 
++		inode->mode=bswap_16(i->mode);
++		inode->uid=bswap_16(i->uid);
++		inode->size=bswap_32(i->size << 8);
++		inode->gid=i->gid;
++		inode->namelen = bswap_32(((u32*)i)[2]) >> 26;
++		inode->offset = bswap_32(((u32*)i)[2]) & 0x3FFFFFFF;
++	}
+ 	return inode;
+ }
+ 
+@@ -324,9 +358,9 @@
+  */
+ static struct cramfs_inode *read_super(void)
+ {
+-	unsigned long offset = super.root.offset << 2;
+-
+-	if (!S_ISDIR(super.root.mode))
++	struct cramfs_inode *root = cramfs_iget(&super.root);
++	unsigned long offset = root->offset << 2; 
++	if (!S_ISDIR(root->mode))
+ 		die(FSCK_UNCORRECTED, 0, "root inode is not directory");
+ 	if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&
+ 	    ((offset != sizeof(struct cramfs_super)) &&
+@@ -334,7 +368,7 @@
+ 	{
+ 		die(FSCK_UNCORRECTED, 0, "bad root offset (%lu)", offset);
+ 	}
+-	return cramfs_iget(&super.root);
++	return root;
+ }
+ 
+ static int uncompress_block(void *src, int len)
+@@ -366,7 +400,7 @@
+ 
+ 	do {
+ 		unsigned long out = PAGE_CACHE_SIZE;
+-		unsigned long next = *(u32 *) romfs_read(offset);
++		unsigned long next = CRAMFS_32(*(u32 *) romfs_read(offset));
+ 
+ 		if (next > end_data) {
+ 			end_data = next;
+@@ -529,7 +563,7 @@
+ {
+ 	unsigned long offset = i->offset << 2;
+ 	unsigned long curr = offset + 4;
+-	unsigned long next = *(u32 *) romfs_read(offset);
++	unsigned long next = CRAMFS_32(*(u32 *) romfs_read(offset));
+ 	unsigned long size;
+ 
+ 	if (offset == 0) {
diff --git a/package/cramfs/cramfs-03-cygwin_IO.patch b/package/cramfs/cramfs-03-cygwin_IO.patch
new file mode 100644
index 0000000..4ea358e
--- /dev/null
+++ b/package/cramfs/cramfs-03-cygwin_IO.patch
@@ -0,0 +1,13 @@
+--- cramfs-1.1/cramfsck.c.orig	2006-12-22 22:16:59.328125000 +1100
++++ cramfs-1.1/cramfsck.c	2006-12-19 01:02:05.531250000 +1100
+@@ -56,6 +56,10 @@
+ #include "linux/cramfs_fs.h"
+ #include <zlib.h>
+ 
++#ifdef __CYGWIN__
++#define _IO(type,nr)	_IOC(_IOC_NONE,(type),(nr),0)
++#endif /* __CYGWIN__ */
++
+ #define BLKGETSIZE	_IO(0x12,96) /* return device size /512 (long *arg) */
+ 
+ /* Exit codes used by fsck-type programs */
diff --git a/package/cramfs/cramfs.mk b/package/cramfs/cramfs.mk
new file mode 100644
index 0000000..7b1924e
--- /dev/null
+++ b/package/cramfs/cramfs.mk
@@ -0,0 +1,33 @@
+#############################################################
+#
+# cramfs
+#
+#############################################################
+
+CRAMFS_VERSION=1.1
+CRAMFS_SOURCE=cramfs-$(CRAMFS_VERSION).tar.gz
+CRAMFS_SITE=http://$(BR2_SOURCEFORGE_MIRROR).dl.sourceforge.net/sourceforge/cramfs
+
+CRAMFS_DEPENDENCIES = zlib
+HOST_CRAMFS_DEPENDENCIES = host-zlib
+
+define CRAMFS_BUILD_CMDS
+ $(TARGET_MAKE_ENV) $(MAKE) CC="$(TARGET_CC)" CFLAGS="$(TARGET_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS)" -C $(@D)
+endef
+
+define CRAMFS_INSTALL_TARGET_CMDS
+ install -m 755 $(@D)/mkcramfs $(TARGET_DIR)/usr/bin
+ install -m 755 $(@D)/cramfsck $(TARGET_DIR)/usr/bin
+endef
+
+define HOST_CRAMFS_BUILD_CMDS
+ $(HOST_MAKE_ENV) $(MAKE) CFLAGS="$(HOST_CFLAGS) -Wall -O2 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64" LDFLAGS="$(HOST_LDFLAGS)" -C $(@D)
+endef
+
+define HOST_CRAMFS_INSTALL_CMDS
+ install -m 755 $(@D)/mkcramfs $(HOST_DIR)/usr/bin
+ install -m 755 $(@D)/cramfsck $(HOST_DIR)/usr/bin
+endef
+
+$(eval $(call GENTARGETS,package,cramfs))
+$(eval $(call GENTARGETS,package,cramfs,host))
-- 
1.6.3.3

  parent reply	other threads:[~2010-04-09  9:06 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-04-09  9:06 [Buildroot] [pull request] Pull request for branch fs-cleanup Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 01/44] genromfs: add new package Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 02/44] genext2fs: " Thomas Petazzoni
2010-04-09  9:06 ` Thomas Petazzoni [this message]
2010-04-09  9:06 ` [Buildroot] [PATCH 04/44] squashfs: " Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 05/44] libcap: " Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 06/44] bzip2: convert to gentargets, add host package, bump version Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 07/44] cmake: new package Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 08/44] cdrkit: " Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 09/44] e2fsprogs: add support for host package Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 10/44] mtd: convert to gentargets, add " Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 11/44] cloop: new package Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 12/44] lzma: convert the host package to the autotools infrastructure Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 13/44] target/cloop: cleanup Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 14/44] target/cpio: cleanup Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 15/44] target/cramfs: cleanup Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 16/44] target/ext2: cleanup Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 17/44] target/iso9660: cleanup Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 18/44] target/jffs2: cleanup Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 19/44] target/romfs: cleanup Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 20/44] target/squashfs: cleanup, remove support for 3.x Thomas Petazzoni
2010-04-09  9:06 ` [Buildroot] [PATCH 21/44] target/tar: cleanup Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 22/44] target/ubifs: cleanup, unbroken Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 23/44] fakeroot: convert to the autotools infrastructure Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 24/44] fakeroot: remove all references to BR2_HOST_FAKEROOT Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 25/44] target/: remove the COPYTO mess Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 26/44] target: Add new infrastructure for filesystem generation Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 27/44] cloop: convert to ROOTFS_TARGET infrastructure Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 28/44] cpio: " Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 29/44] cramfs: " Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 30/44] romfs: " Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 31/44] tar: " Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 32/44] squashfs: " Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 33/44] ext2: " Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 34/44] jffs2: " Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 35/44] ubifs: " Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 36/44] initramfs: " Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 37/44] busybox initramfs: do not use the IMAGE variable Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 38/44] target/common: do not use IMAGE Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 39/44] iso9660: rework in a similar way to ROOTFS_TARGET Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 40/44] Remove IMAGE and related configuration options Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 41/44] Move all filesystem generation code to fs/ Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 42/44] Coherent naming for .mk files in fs/ Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 43/44] Update defconfigs after fs cleanup Thomas Petazzoni
2010-04-09  9:07 ` [Buildroot] [PATCH 44/44] fs/*/Config.in: remove useless configuration comments Thomas Petazzoni
2010-04-09  9:20 ` [Buildroot] [pull request] Pull request for branch fs-cleanup Peter Korsgaard
2010-04-09 12:54   ` Thomas Petazzoni
2010-04-09 14:19 ` Peter Korsgaard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f601bb72db8505def5b3acad13c67d99e2e62a1d.1270803901.git.thomas.petazzoni@free-electrons.com \
    --to=thomas.petazzoni@free-electrons.com \
    --cc=buildroot@busybox.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.