[PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source.

Dongsheng Yang yangds.fnst at cn.fujitsu.com
Wed Oct 14 21:04:24 PDT 2015


* There is no code modification in this commit, only moving
* the files to proper place.

The user tools looks a little messy as we place almost
the all tools in the root directory of mtd-utils. To make
it more clear, I propose to introduce the following structure
for our source code.

mtd-utils/
	|-- lib
	|-- include
	|-- misc-utils
	|-- flash-utils
	|-- jffsX-utils
	|-- nand-utils
	|-- nor-utils
	|-- ubi-utils
	|-- ubifs-utils
	`-- tests

Signed-off-by: Dongsheng Yang <yangds.fnst at cn.fujitsu.com>
---
 MAKEDEV                                            |   41 -
 Makefile                                           |   66 +-
 compr.c                                            |  538 -----
 compr.h                                            |  119 -
 compr_lzo.c                                        |  135 --
 compr_rtime.c                                      |  119 -
 compr_zlib.c                                       |  148 --
 device_table.txt                                   |  128 --
 doc_loadbios.c                                     |  150 --
 docfdisk.c                                         |  318 ---
 fectest.c                                          |   91 -
 flash-utils/flash_erase.c                          |  295 +++
 flash-utils/flash_eraseall                         |    4 +
 flash-utils/flash_lock.c                           |    8 +
 flash-utils/flash_otp_dump.c                       |   56 +
 flash-utils/flash_otp_info.c                       |   65 +
 flash-utils/flash_otp_lock.c                       |   72 +
 flash-utils/flash_otp_write.c                      |  122 +
 flash-utils/flash_unlock.c                         |   90 +
 flash-utils/flashcp.c                              |  389 ++++
 flash_erase.c                                      |  295 ---
 flash_eraseall                                     |    4 -
 flash_lock.c                                       |    8 -
 flash_otp_dump.c                                   |   56 -
 flash_otp_info.c                                   |   65 -
 flash_otp_lock.c                                   |   72 -
 flash_otp_write.c                                  |  122 -
 flash_unlock.c                                     |   90 -
 flashcp.c                                          |  389 ----
 ftl_check.c                                        |  217 --
 ftl_format.c                                       |  324 ---
 jffs-dump.c                                        |  359 ---
 jffs2dump.c                                        |  805 -------
 jffs2reader.c                                      |  918 --------
 jffsX-utils/compr.c                                |  538 +++++
 jffsX-utils/compr.h                                |  119 +
 jffsX-utils/compr_lzo.c                            |  135 ++
 jffsX-utils/compr_rtime.c                          |  119 +
 jffsX-utils/compr_zlib.c                           |  148 ++
 jffsX-utils/device_table.txt                       |  128 ++
 jffsX-utils/jffs-dump.c                            |  359 +++
 jffsX-utils/jffs2dump.c                            |  805 +++++++
 jffsX-utils/jffs2reader.c                          |  918 ++++++++
 jffsX-utils/mkfs.jffs2.1                           |  268 +++
 jffsX-utils/mkfs.jffs2.c                           | 1805 +++++++++++++++
 jffsX-utils/rbtree.c                               |  390 ++++
 jffsX-utils/rbtree.h                               |  171 ++
 jffsX-utils/summary.h                              |  177 ++
 jffsX-utils/sumtool.c                              |  872 ++++++++
 load_nandsim.sh                                    |  127 --
 mcast_image.h                                      |   54 -
 misc-utils/MAKEDEV                                 |   41 +
 misc-utils/doc_loadbios.c                          |  150 ++
 misc-utils/docfdisk.c                              |  318 +++
 misc-utils/fectest.c                               |   91 +
 misc-utils/ftl_check.c                             |  217 ++
 misc-utils/ftl_format.c                            |  324 +++
 misc-utils/mcast_image.h                           |   54 +
 misc-utils/mtd_debug.c                             |  397 ++++
 misc-utils/mtdpart.c                               |  194 ++
 misc-utils/recv_image.c                            |  484 ++++
 misc-utils/serve_image.c                           |  300 +++
 mkfs.jffs2.1                                       |  268 ---
 mkfs.jffs2.c                                       | 1805 ---------------
 mkfs.ubifs/.gitignore                              |    1 -
 mkfs.ubifs/COPYING                                 |  340 ---
 mkfs.ubifs/README                                  |    9 -
 mkfs.ubifs/compr.c                                 |  219 --
 mkfs.ubifs/compr.h                                 |   46 -
 mkfs.ubifs/crc16.c                                 |   56 -
 mkfs.ubifs/crc16.h                                 |   27 -
 mkfs.ubifs/defs.h                                  |   92 -
 mkfs.ubifs/devtable.c                              |  524 -----
 mkfs.ubifs/hashtable/hashtable.c                   |  277 ---
 mkfs.ubifs/hashtable/hashtable.h                   |  199 --
 mkfs.ubifs/hashtable/hashtable_itr.c               |  176 --
 mkfs.ubifs/hashtable/hashtable_itr.h               |  112 -
 mkfs.ubifs/hashtable/hashtable_private.h           |   85 -
 mkfs.ubifs/key.h                                   |  189 --
 mkfs.ubifs/lpt.c                                   |  578 -----
 mkfs.ubifs/lpt.h                                   |   28 -
 mkfs.ubifs/mkfs.ubifs.c                            | 2324 --------------------
 mkfs.ubifs/mkfs.ubifs.h                            |  150 --
 mkfs.ubifs/ubifs.h                                 |  441 ----
 mtd_debug.c                                        |  397 ----
 mtdpart.c                                          |  194 --
 nand-utils/load_nandsim.sh                         |  127 ++
 nand-utils/nanddump.c                              |  490 +++++
 nand-utils/nandtest.c                              |  313 +++
 nand-utils/nandwrite.c                             |  578 +++++
 nand-utils/nftl_format.c                           |  422 ++++
 nand-utils/nftldump.c                              |  278 +++
 nanddump.c                                         |  490 -----
 nandtest.c                                         |  313 ---
 nandwrite.c                                        |  578 -----
 nftl_format.c                                      |  422 ----
 nftldump.c                                         |  278 ---
 nor-utils/rfddump.c                                |  337 +++
 nor-utils/rfdformat.c                              |  160 ++
 rbtree.c                                           |  390 ----
 rbtree.h                                           |  171 --
 recv_image.c                                       |  484 ----
 rfddump.c                                          |  337 ---
 rfdformat.c                                        |  160 --
 serve_image.c                                      |  300 ---
 summary.h                                          |  177 --
 sumtool.c                                          |  872 --------
 ubifs-utils/mkfs.ubifs/.gitignore                  |    1 +
 ubifs-utils/mkfs.ubifs/COPYING                     |  340 +++
 ubifs-utils/mkfs.ubifs/README                      |    9 +
 ubifs-utils/mkfs.ubifs/compr.c                     |  219 ++
 ubifs-utils/mkfs.ubifs/compr.h                     |   46 +
 ubifs-utils/mkfs.ubifs/crc16.c                     |   56 +
 ubifs-utils/mkfs.ubifs/crc16.h                     |   27 +
 ubifs-utils/mkfs.ubifs/defs.h                      |   92 +
 ubifs-utils/mkfs.ubifs/devtable.c                  |  524 +++++
 ubifs-utils/mkfs.ubifs/hashtable/hashtable.c       |  277 +++
 ubifs-utils/mkfs.ubifs/hashtable/hashtable.h       |  199 ++
 ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.c   |  176 ++
 ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.h   |  112 +
 .../mkfs.ubifs/hashtable/hashtable_private.h       |   85 +
 ubifs-utils/mkfs.ubifs/key.h                       |  189 ++
 ubifs-utils/mkfs.ubifs/lpt.c                       |  578 +++++
 ubifs-utils/mkfs.ubifs/lpt.h                       |   28 +
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.c                | 2324 ++++++++++++++++++++
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.h                |  150 ++
 ubifs-utils/mkfs.ubifs/ubifs.h                     |  441 ++++
 127 files changed, 19240 insertions(+), 19228 deletions(-)
 delete mode 100755 MAKEDEV
 delete mode 100644 compr.c
 delete mode 100644 compr.h
 delete mode 100644 compr_lzo.c
 delete mode 100644 compr_rtime.c
 delete mode 100644 compr_zlib.c
 delete mode 100644 device_table.txt
 delete mode 100644 doc_loadbios.c
 delete mode 100644 docfdisk.c
 delete mode 100644 fectest.c
 create mode 100644 flash-utils/flash_erase.c
 create mode 100755 flash-utils/flash_eraseall
 create mode 100644 flash-utils/flash_lock.c
 create mode 100644 flash-utils/flash_otp_dump.c
 create mode 100644 flash-utils/flash_otp_info.c
 create mode 100644 flash-utils/flash_otp_lock.c
 create mode 100644 flash-utils/flash_otp_write.c
 create mode 100644 flash-utils/flash_unlock.c
 create mode 100644 flash-utils/flashcp.c
 delete mode 100644 flash_erase.c
 delete mode 100755 flash_eraseall
 delete mode 100644 flash_lock.c
 delete mode 100644 flash_otp_dump.c
 delete mode 100644 flash_otp_info.c
 delete mode 100644 flash_otp_lock.c
 delete mode 100644 flash_otp_write.c
 delete mode 100644 flash_unlock.c
 delete mode 100644 flashcp.c
 delete mode 100644 ftl_check.c
 delete mode 100644 ftl_format.c
 delete mode 100644 jffs-dump.c
 delete mode 100644 jffs2dump.c
 delete mode 100644 jffs2reader.c
 create mode 100644 jffsX-utils/compr.c
 create mode 100644 jffsX-utils/compr.h
 create mode 100644 jffsX-utils/compr_lzo.c
 create mode 100644 jffsX-utils/compr_rtime.c
 create mode 100644 jffsX-utils/compr_zlib.c
 create mode 100644 jffsX-utils/device_table.txt
 create mode 100644 jffsX-utils/jffs-dump.c
 create mode 100644 jffsX-utils/jffs2dump.c
 create mode 100644 jffsX-utils/jffs2reader.c
 create mode 100644 jffsX-utils/mkfs.jffs2.1
 create mode 100644 jffsX-utils/mkfs.jffs2.c
 create mode 100644 jffsX-utils/rbtree.c
 create mode 100644 jffsX-utils/rbtree.h
 create mode 100644 jffsX-utils/summary.h
 create mode 100644 jffsX-utils/sumtool.c
 delete mode 100755 load_nandsim.sh
 delete mode 100644 mcast_image.h
 create mode 100755 misc-utils/MAKEDEV
 create mode 100644 misc-utils/doc_loadbios.c
 create mode 100644 misc-utils/docfdisk.c
 create mode 100644 misc-utils/fectest.c
 create mode 100644 misc-utils/ftl_check.c
 create mode 100644 misc-utils/ftl_format.c
 create mode 100644 misc-utils/mcast_image.h
 create mode 100644 misc-utils/mtd_debug.c
 create mode 100644 misc-utils/mtdpart.c
 create mode 100644 misc-utils/recv_image.c
 create mode 100644 misc-utils/serve_image.c
 delete mode 100644 mkfs.jffs2.1
 delete mode 100644 mkfs.jffs2.c
 delete mode 100644 mkfs.ubifs/.gitignore
 delete mode 100644 mkfs.ubifs/COPYING
 delete mode 100644 mkfs.ubifs/README
 delete mode 100644 mkfs.ubifs/compr.c
 delete mode 100644 mkfs.ubifs/compr.h
 delete mode 100644 mkfs.ubifs/crc16.c
 delete mode 100644 mkfs.ubifs/crc16.h
 delete mode 100644 mkfs.ubifs/defs.h
 delete mode 100644 mkfs.ubifs/devtable.c
 delete mode 100644 mkfs.ubifs/hashtable/hashtable.c
 delete mode 100644 mkfs.ubifs/hashtable/hashtable.h
 delete mode 100644 mkfs.ubifs/hashtable/hashtable_itr.c
 delete mode 100644 mkfs.ubifs/hashtable/hashtable_itr.h
 delete mode 100644 mkfs.ubifs/hashtable/hashtable_private.h
 delete mode 100644 mkfs.ubifs/key.h
 delete mode 100644 mkfs.ubifs/lpt.c
 delete mode 100644 mkfs.ubifs/lpt.h
 delete mode 100644 mkfs.ubifs/mkfs.ubifs.c
 delete mode 100644 mkfs.ubifs/mkfs.ubifs.h
 delete mode 100644 mkfs.ubifs/ubifs.h
 delete mode 100644 mtd_debug.c
 delete mode 100644 mtdpart.c
 create mode 100755 nand-utils/load_nandsim.sh
 create mode 100644 nand-utils/nanddump.c
 create mode 100644 nand-utils/nandtest.c
 create mode 100644 nand-utils/nandwrite.c
 create mode 100644 nand-utils/nftl_format.c
 create mode 100644 nand-utils/nftldump.c
 delete mode 100644 nanddump.c
 delete mode 100644 nandtest.c
 delete mode 100644 nandwrite.c
 delete mode 100644 nftl_format.c
 delete mode 100644 nftldump.c
 create mode 100644 nor-utils/rfddump.c
 create mode 100644 nor-utils/rfdformat.c
 delete mode 100644 rbtree.c
 delete mode 100644 rbtree.h
 delete mode 100644 recv_image.c
 delete mode 100644 rfddump.c
 delete mode 100644 rfdformat.c
 delete mode 100644 serve_image.c
 delete mode 100644 summary.h
 delete mode 100644 sumtool.c
 create mode 100644 ubifs-utils/mkfs.ubifs/.gitignore
 create mode 100644 ubifs-utils/mkfs.ubifs/COPYING
 create mode 100644 ubifs-utils/mkfs.ubifs/README
 create mode 100644 ubifs-utils/mkfs.ubifs/compr.c
 create mode 100644 ubifs-utils/mkfs.ubifs/compr.h
 create mode 100644 ubifs-utils/mkfs.ubifs/crc16.c
 create mode 100644 ubifs-utils/mkfs.ubifs/crc16.h
 create mode 100644 ubifs-utils/mkfs.ubifs/defs.h
 create mode 100644 ubifs-utils/mkfs.ubifs/devtable.c
 create mode 100644 ubifs-utils/mkfs.ubifs/hashtable/hashtable.c
 create mode 100644 ubifs-utils/mkfs.ubifs/hashtable/hashtable.h
 create mode 100644 ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.c
 create mode 100644 ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.h
 create mode 100644 ubifs-utils/mkfs.ubifs/hashtable/hashtable_private.h
 create mode 100644 ubifs-utils/mkfs.ubifs/key.h
 create mode 100644 ubifs-utils/mkfs.ubifs/lpt.c
 create mode 100644 ubifs-utils/mkfs.ubifs/lpt.h
 create mode 100644 ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
 create mode 100644 ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
 create mode 100644 ubifs-utils/mkfs.ubifs/ubifs.h

diff --git a/MAKEDEV b/MAKEDEV
deleted file mode 100755
index b59e90e..0000000
--- a/MAKEDEV
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash
-
-function mkftl () {
-	mknod /dev/ftl$1 b 44 $2
-	for a in `seq 1 15`; do
-		mknod /dev/ftl$1$a b 44 `expr $2 + $a`
-	done
-}
-function mknftl () {
-	mknod /dev/nftl$1 b 93 $2
-	for a in `seq 1 15`; do
-		mknod /dev/nftl$1$a b 93 `expr $2 + $a`
-	done
-}
-function mkrfd () {
-	mknod /dev/rfd$1 b 256 $2
-	for a in `seq 1 15`; do
-		mknod /dev/rfd$1$a b 256 `expr $2 + $a`
-	done
-}
-function mkinftl () {
-	mknod /dev/inftl$1 b 96 $2
-	for a in `seq 1 15`; do
-		mknod /dev/inftl$1$a b 96 `expr $2 + $a`
-	done
-}
-
-M=0
-for C in a b c d e f g h i j k l m n o p; do
-    mkftl $C $M
-    mknftl $C $M
-    mkrfd $C $M
-    mkinftl $C $M
-    let M=M+16
-done
-
-for a in `seq 0 16` ; do
-	mknod /dev/mtd$a c 90 `expr $a + $a`
-	mknod /dev/mtdr$a c 90 `expr $a + $a + 1`
-	mknod /dev/mtdblock$a b 31 $a
-done
diff --git a/Makefile b/Makefile
index f4ce313..bb40929 100644
--- a/Makefile
+++ b/Makefile
@@ -16,24 +16,32 @@ endif
 
 TESTS = tests
 
-MTD_BINS = \
-	ftl_format flash_erase nanddump doc_loadbios \
-	ftl_check mkfs.jffs2 flash_lock flash_unlock \
-	flash_otp_info flash_otp_dump flash_otp_lock flash_otp_write \
-	mtd_debug flashcp nandwrite nandtest mtdpart \
-	jffs2dump \
-	nftldump nftl_format docfdisk \
-	rfddump rfdformat \
-	serve_image recv_image \
-	sumtool jffs2reader
+MISC_BINS = \
+	ftl_format doc_loadbios ftl_check mtd_debug docfdisk \
+	serve_image recv_image mtdpart
 UBI_BINS = \
 	ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \
 	ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock
-
-BINS = $(MTD_BINS)
-BINS += mkfs.ubifs/mkfs.ubifs
+UBIFS_BINS = \
+	mkfs.ubifs/mkfs.ubifs
+JFFSX_BINS = \
+	mkfs.jffs2 sumtool jffs2reader jffs2dump
+FLASH_BINS = \
+	flash_erase flash_lock flash_unlock flash_otp_info flash_otp_dump \
+	flash_otp_lock flash_otp_write flashcp
+NAND_BINS = \
+	nanddump nandwrite nandtest nftldump nftl_format
+NOR_BINS = \
+	rfddump rfdformat
+
+BINS = $(addprefix misc-utils/,$(MISC_BINS))
 BINS += $(addprefix ubi-utils/,$(UBI_BINS))
-SCRIPTS = flash_eraseall
+BINS += $(addprefix ubifs-utils/,$(UBIFS_BINS))
+BINS += $(addprefix jffsX-utils/,$(JFFSX_BINS))
+BINS += $(addprefix flash-utils/,$(FLASH_BINS))
+BINS += $(addprefix nand-utils/,$(NAND_BINS))
+BINS += $(addprefix nor-utils/,$(NOR_BINS))
+SCRIPTS = $(addprefix flash-utils/,flash_eraseall)
 
 TARGETS = $(BINS)
 TARGETS += lib/libmtd.a
@@ -61,11 +69,11 @@ endif
 	rm -f $(BUILDDIR)/include/version.h
 	$(MAKE) -C $(TESTS) clean
 
-install:: $(addprefix $(BUILDDIR)/,${BINS}) ${SCRIPTS}
+install:: $(addprefix $(BUILDDIR)/,${BINS} ${SCRIPTS})
 	mkdir -p ${DESTDIR}/${SBINDIR}
 	install -m 0755 $^ ${DESTDIR}/${SBINDIR}/
 	mkdir -p ${DESTDIR}/${MANDIR}/man1
-	install -m 0644 mkfs.jffs2.1 ${DESTDIR}/${MANDIR}/man1/
+	install -m 0644 jffsX-utils/mkfs.jffs2.1 ${DESTDIR}/${MANDIR}/man1/
 	-gzip -9f ${DESTDIR}/${MANDIR}/man1/*.1
 
 tests::
@@ -85,13 +93,17 @@ $(BUILDDIR)/include/version.h.tmp:
 # Utils in top level
 #
 obj-mkfs.jffs2 = compr_rtime.o compr_zlib.o compr_lzo.o compr.o rbtree.o
-LDFLAGS_mkfs.jffs2 = $(ZLIBLDFLAGS) $(LZOLDFLAGS)
+LDFLAGS_mkfs.jffs2 = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(CPPFLAGS)
 LDLIBS_mkfs.jffs2  = -lz $(LZOLDLIBS)
 
 LDFLAGS_jffs2reader = $(ZLIBLDFLAGS) $(LZOLDFLAGS)
 LDLIBS_jffs2reader  = -lz $(LZOLDLIBS)
 
-$(foreach v,$(MTD_BINS),$(eval $(call mkdep,,$(v))))
+$(foreach v,$(MISC_BINS),$(eval $(call mkdep,misc-utils/,$(v))))
+$(foreach v,$(JFFSX_BINS),$(eval $(call mkdep,jffsX-utils/,$(v))))
+$(foreach v,$(FLASH_BINS),$(eval $(call mkdep,flash-utils/,$(v))))
+$(foreach v,$(NAND_BINS),$(eval $(call mkdep,nand-utils/,$(v))))
+$(foreach v,$(NOR_BINS),$(eval $(call mkdep,nor-utils/,$(v))))
 
 #
 # Common libmtd
@@ -100,15 +112,6 @@ obj-libmtd.a = libmtd.o libmtd_legacy.o libcrc32.o libfec.o
 $(call _mkdep,lib/,libmtd.a)
 
 #
-# Utils in mkfs.ubifs subdir
-#
-obj-mkfs.ubifs = crc16.o lpt.o compr.o devtable.o \
-	hashtable/hashtable.o hashtable/hashtable_itr.o
-LDFLAGS_mkfs.ubifs = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
-LDLIBS_mkfs.ubifs = -lz -llzo2 -lm -luuid
-$(call mkdep,mkfs.ubifs/,mkfs.ubifs,,ubi-utils/libubi.a)
-
-#
 # Utils in ubi-utils/ subdir
 #
 obj-libiniparser.a = libiniparser.o dictionary.o
@@ -122,3 +125,12 @@ obj-ubiformat = libubigen.a libscan.a
 
 $(foreach v,libubi.a libubigen.a libiniparser.a libscan.a,$(eval $(call _mkdep,ubi-utils/,$(v))))
 $(foreach v,$(UBI_BINS),$(eval $(call mkdep,ubi-utils/,$(v),libubi.a ubiutils-common.o)))
+
+#
+# Utils in ubifs-utils subdir
+#
+obj-mkfs.ubifs = crc16.o lpt.o compr.o devtable.o \
+	hashtable/hashtable.o hashtable/hashtable_itr.o
+LDFLAGS_mkfs.ubifs = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
+LDLIBS_mkfs.ubifs = -lz -llzo2 -lm -luuid
+$(call mkdep,ubifs-utils/mkfs.ubifs/,mkfs.ubifs,,ubi-utils/libubi.a)
diff --git a/compr.c b/compr.c
deleted file mode 100644
index cb4432e..0000000
--- a/compr.c
+++ /dev/null
@@ -1,538 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2004 Ferenc Havasi <havasi at inf.u-szeged.hu>,
- *                    University of Szeged, Hungary
- *
- * For licensing information, see the file 'LICENCE' in this directory
- * in the jffs2 directory.
- */
-
-#include "compr.h"
-#include <string.h>
-#include <stdlib.h>
-#include <linux/jffs2.h>
-
-#define FAVOUR_LZO_PERCENT 80
-
-extern int page_size;
-
-/* LIST IMPLEMENTATION (from linux/list.h) */
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
-	struct list_head name = LIST_HEAD_INIT(name)
-
-static inline void __list_add(struct list_head *new,
-		struct list_head *prev,
-		struct list_head *next)
-{
-	next->prev = new;
-	new->next = next;
-	new->prev = prev;
-	prev->next = new;
-}
-
-static inline void list_add(struct list_head *new, struct list_head *head)
-{
-	__list_add(new, head, head->next);
-}
-
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
-{
-	__list_add(new, head->prev, head);
-}
-
-static inline void __list_del(struct list_head *prev, struct list_head *next)
-{
-	next->prev = prev;
-	prev->next = next;
-}
-
-static inline void list_del(struct list_head *entry)
-{
-	__list_del(entry->prev, entry->next);
-	entry->next = (void *) 0;
-	entry->prev = (void *) 0;
-}
-
-#define list_entry(ptr, type, member) \
-	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-
-#define list_for_each_entry(pos, head, member)                          \
-	for (pos = list_entry((head)->next, typeof(*pos), member);      \
-			&pos->member != (head);                                    \
-			pos = list_entry(pos->member.next, typeof(*pos), member))
-
-
-/* Available compressors are on this list */
-static LIST_HEAD(jffs2_compressor_list);
-
-/* Actual compression mode */
-static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
-
-void jffs2_set_compression_mode(int mode)
-{
-	jffs2_compression_mode = mode;
-}
-
-int jffs2_get_compression_mode(void)
-{
-	return jffs2_compression_mode;
-}
-
-/* Statistics for blocks stored without compression */
-static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
-
-/* Compression test stuffs */
-
-static int jffs2_compression_check = 0;
-
-static unsigned char *jffs2_compression_check_buf = NULL;
-
-void jffs2_compression_check_set(int yesno)
-{
-	jffs2_compression_check = yesno;
-}
-
-int jffs2_compression_check_get(void)
-{
-	return jffs2_compression_check;
-}
-
-static int jffs2_error_cnt = 0;
-
-int jffs2_compression_check_errorcnt_get(void)
-{
-	return jffs2_error_cnt;
-}
-
-#define JFFS2_BUFFER_FILL 0x55
-
-/* Called before compression (if compression_check is setted) to prepare
-   the buffer for buffer overflow test */
-static void jffs2_decompression_test_prepare(unsigned char *buf, int size)
-{
-	memset(buf,JFFS2_BUFFER_FILL,size+1);
-}
-
-/* Called after compression (if compression_check is setted) to test the result */
-static void jffs2_decompression_test(struct jffs2_compressor *compr,
-		unsigned char *data_in, unsigned char *output_buf,
-		uint32_t cdatalen, uint32_t datalen, uint32_t buf_size)
-{
-	uint32_t i;
-
-	/* buffer overflow test */
-	for (i=buf_size;i>cdatalen;i--) {
-		if (output_buf[i]!=JFFS2_BUFFER_FILL) {
-			fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. "
-					"(bs=%d csize=%d b[%d]=%d)\n", compr->name,
-					buf_size, cdatalen, i, (int)(output_buf[i]));
-			jffs2_error_cnt++;
-			return;
-		}
-	}
-	/* allocing temporary buffer for decompression */
-	if (!jffs2_compression_check_buf) {
-		jffs2_compression_check_buf = malloc(page_size);
-		if (!jffs2_compression_check_buf) {
-			fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n");
-			jffs2_compression_check = 0;
-			return;
-		}
-	}
-	/* decompressing */
-	if (!compr->decompress) {
-		fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name);
-		jffs2_error_cnt++;
-		return;
-	}
-	if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen)) {
-		fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name);
-		jffs2_error_cnt++;
-	}
-	/* validate decompression */
-	else {
-		for (i=0;i<datalen;i++) {
-			if (data_in[i]!=jffs2_compression_check_buf[i]) {
-				fprintf(stderr,"JFFS2 compression check: data mismatch at %s (pos %d).\n", compr->name, i);
-				jffs2_error_cnt++;
-				break;
-			}
-		}
-	}
-}
-
-/*
- * Return 1 to use this compression
- */
-static int jffs2_is_best_compression(struct jffs2_compressor *this,
-		struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
-{
-	switch (jffs2_compression_mode) {
-	case JFFS2_COMPR_MODE_SIZE:
-		if (bestsize > size)
-			return 1;
-		return 0;
-	case JFFS2_COMPR_MODE_FAVOURLZO:
-		if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size))
-			return 1;
-		if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
-			return 1;
-		if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
-			return 1;
-		if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
-			return 1;
-
-		return 0;
-	}
-	/* Shouldn't happen */
-	return 0;
-}
-
-/* jffs2_compress:
- * @data: Pointer to uncompressed data
- * @cdata: Pointer to returned pointer to buffer for compressed data
- * @datalen: On entry, holds the amount of data available for compression.
- *	On exit, expected to hold the amount of data actually compressed.
- * @cdatalen: On entry, holds the amount of space available for compressed
- *	data. On exit, expected to hold the actual size of the compressed
- *	data.
- *
- * Returns: Lower byte to be stored with data indicating compression type used.
- * Zero is used to show that the data could not be compressed - the
- * compressed version was actually larger than the original.
- * Upper byte will be used later. (soon)
- *
- * If the cdata buffer isn't large enough to hold all the uncompressed data,
- * jffs2_compress should compress as much as will fit, and should set
- * *datalen accordingly to show the amount of data which were compressed.
- */
-uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out,
-		uint32_t *datalen, uint32_t *cdatalen)
-{
-	int ret = JFFS2_COMPR_NONE;
-	int compr_ret;
-	struct jffs2_compressor *this, *best=NULL;
-	unsigned char *output_buf = NULL, *tmp_buf;
-	uint32_t orig_slen, orig_dlen;
-	uint32_t best_slen=0, best_dlen=0;
-
-	switch (jffs2_compression_mode) {
-		case JFFS2_COMPR_MODE_NONE:
-			break;
-		case JFFS2_COMPR_MODE_PRIORITY:
-			orig_slen = *datalen;
-			orig_dlen = *cdatalen;
-			output_buf = malloc(orig_dlen+jffs2_compression_check);
-			if (!output_buf) {
-				fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n");
-				goto out;
-			}
-			list_for_each_entry(this, &jffs2_compressor_list, list) {
-				/* Skip decompress-only backwards-compatibility and disabled modules */
-				if ((!this->compress)||(this->disabled))
-					continue;
-
-				this->usecount++;
-
-				if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
-					jffs2_decompression_test_prepare(output_buf, orig_dlen);
-
-				*datalen  = orig_slen;
-				*cdatalen = orig_dlen;
-				compr_ret = this->compress(data_in, output_buf, datalen, cdatalen);
-				this->usecount--;
-				if (!compr_ret) {
-					ret = this->compr;
-					this->stat_compr_blocks++;
-					this->stat_compr_orig_size += *datalen;
-					this->stat_compr_new_size  += *cdatalen;
-					if (jffs2_compression_check)
-						jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, orig_dlen);
-					break;
-				}
-			}
-			if (ret == JFFS2_COMPR_NONE) free(output_buf);
-			break;
-		case JFFS2_COMPR_MODE_FAVOURLZO:
-		case JFFS2_COMPR_MODE_SIZE:
-			orig_slen = *datalen;
-			orig_dlen = *cdatalen;
-			list_for_each_entry(this, &jffs2_compressor_list, list) {
-				uint32_t needed_buf_size;
-
-				if (jffs2_compression_mode == JFFS2_COMPR_MODE_FAVOURLZO)
-					needed_buf_size = orig_slen + jffs2_compression_check;
-				else
-					needed_buf_size = orig_dlen + jffs2_compression_check;
-
-				/* Skip decompress-only backwards-compatibility and disabled modules */
-				if ((!this->compress)||(this->disabled))
-					continue;
-				/* Allocating memory for output buffer if necessary */
-				if ((this->compr_buf_size < needed_buf_size) && (this->compr_buf)) {
-					free(this->compr_buf);
-					this->compr_buf_size=0;
-					this->compr_buf=NULL;
-				}
-				if (!this->compr_buf) {
-					tmp_buf = malloc(needed_buf_size);
-					if (!tmp_buf) {
-						fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
-						continue;
-					}
-					else {
-						this->compr_buf = tmp_buf;
-						this->compr_buf_size = orig_dlen;
-					}
-				}
-				this->usecount++;
-				if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
-					jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size);
-				*datalen  = orig_slen;
-				*cdatalen = orig_dlen;
-				compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
-				this->usecount--;
-				if (!compr_ret) {
-					if (jffs2_compression_check)
-						jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, this->compr_buf_size);
-					if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
-								&& (*cdatalen < *datalen)) {
-						best_dlen = *cdatalen;
-						best_slen = *datalen;
-						best = this;
-					}
-				}
-			}
-			if (best_dlen) {
-				*cdatalen = best_dlen;
-				*datalen  = best_slen;
-				output_buf = best->compr_buf;
-				best->compr_buf = NULL;
-				best->compr_buf_size = 0;
-				best->stat_compr_blocks++;
-				best->stat_compr_orig_size += best_slen;
-				best->stat_compr_new_size  += best_dlen;
-				ret = best->compr;
-			}
-			break;
-		default:
-			fprintf(stderr,"mkfs.jffs2: unknown compression mode.\n");
-	}
-out:
-	if (ret == JFFS2_COMPR_NONE) {
-		*cpage_out = data_in;
-		*datalen = *cdatalen;
-		none_stat_compr_blocks++;
-		none_stat_compr_size += *datalen;
-	}
-	else {
-		*cpage_out = output_buf;
-	}
-	return ret;
-}
-
-
-int jffs2_register_compressor(struct jffs2_compressor *comp)
-{
-	struct jffs2_compressor *this;
-
-	if (!comp->name) {
-		fprintf(stderr,"NULL compressor name at registering JFFS2 compressor. Failed.\n");
-		return -1;
-	}
-	comp->compr_buf_size=0;
-	comp->compr_buf=NULL;
-	comp->usecount=0;
-	comp->stat_compr_orig_size=0;
-	comp->stat_compr_new_size=0;
-	comp->stat_compr_blocks=0;
-	comp->stat_decompr_blocks=0;
-
-	list_for_each_entry(this, &jffs2_compressor_list, list) {
-		if (this->priority < comp->priority) {
-			list_add(&comp->list, this->list.prev);
-			goto out;
-		}
-	}
-	list_add_tail(&comp->list, &jffs2_compressor_list);
-out:
-	return 0;
-}
-
-int jffs2_unregister_compressor(struct jffs2_compressor *comp)
-{
-
-	if (comp->usecount) {
-		fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n");
-		return -1;
-	}
-	list_del(&comp->list);
-
-	return 0;
-}
-
-#define JFFS2_STAT_BUF_SIZE 16000
-
-char *jffs2_list_compressors(void)
-{
-	struct jffs2_compressor *this;
-	char *buf, *act_buf;
-
-	act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
-	list_for_each_entry(this, &jffs2_compressor_list, list) {
-		act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
-		if ((this->disabled)||(!this->compress))
-			act_buf += sprintf(act_buf,"disabled");
-		else
-			act_buf += sprintf(act_buf,"enabled");
-		act_buf += sprintf(act_buf,"\n");
-	}
-	return buf;
-}
-
-char *jffs2_stats(void)
-{
-	struct jffs2_compressor *this;
-	char *buf, *act_buf;
-
-	act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
-
-	act_buf += sprintf(act_buf,"Compression mode: ");
-	switch (jffs2_compression_mode) {
-		case JFFS2_COMPR_MODE_NONE:
-			act_buf += sprintf(act_buf,"none");
-			break;
-		case JFFS2_COMPR_MODE_PRIORITY:
-			act_buf += sprintf(act_buf,"priority");
-			break;
-		case JFFS2_COMPR_MODE_SIZE:
-			act_buf += sprintf(act_buf,"size");
-			break;
-		case JFFS2_COMPR_MODE_FAVOURLZO:
-			act_buf += sprintf(act_buf, "favourlzo");
-			break;
-		default:
-			act_buf += sprintf(act_buf, "unknown");
-			break;
-	}
-	act_buf += sprintf(act_buf,"\nCompressors:\n");
-	act_buf += sprintf(act_buf,"%10s             ","none");
-	act_buf += sprintf(act_buf,"compr: %d blocks (%d)  decompr: %d blocks\n", none_stat_compr_blocks,
-			none_stat_compr_size, none_stat_decompr_blocks);
-	list_for_each_entry(this, &jffs2_compressor_list, list) {
-		act_buf += sprintf(act_buf,"%10s (prio:%d) ",this->name,this->priority);
-		if ((this->disabled)||(!this->compress))
-			act_buf += sprintf(act_buf,"- ");
-		else
-			act_buf += sprintf(act_buf,"+ ");
-		act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks,
-				this->stat_compr_new_size, this->stat_compr_orig_size,
-				this->stat_decompr_blocks);
-		act_buf += sprintf(act_buf,"\n");
-	}
-	return buf;
-}
-
-int jffs2_set_compression_mode_name(const char *name)
-{
-	if (!strcmp("none",name)) {
-		jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
-		return 0;
-	}
-	if (!strcmp("priority",name)) {
-		jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
-		return 0;
-	}
-	if (!strcmp("size",name)) {
-		jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
-		return 0;
-	}
-	if (!strcmp("favourlzo", name)) {
-		jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
-		return 0;
-	}
-
-	return 1;
-}
-
-static int jffs2_compressor_Xable(const char *name, int disabled)
-{
-	struct jffs2_compressor *this;
-	list_for_each_entry(this, &jffs2_compressor_list, list) {
-		if (!strcmp(this->name, name)) {
-			this->disabled = disabled;
-			return 0;
-		}
-	}
-	return 1;
-}
-
-int jffs2_enable_compressor_name(const char *name)
-{
-	return jffs2_compressor_Xable(name, 0);
-}
-
-int jffs2_disable_compressor_name(const char *name)
-{
-	return jffs2_compressor_Xable(name, 1);
-}
-
-int jffs2_set_compressor_priority(const char *name, int priority)
-{
-	struct jffs2_compressor *this,*comp;
-	list_for_each_entry(this, &jffs2_compressor_list, list) {
-		if (!strcmp(this->name, name)) {
-			this->priority = priority;
-			comp = this;
-			goto reinsert;
-		}
-	}
-	fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name);
-	return 1;
-reinsert:
-	/* list is sorted in the order of priority, so if
-	   we change it we have to reinsert it into the
-	   good place */
-	list_del(&comp->list);
-	list_for_each_entry(this, &jffs2_compressor_list, list) {
-		if (this->priority < comp->priority) {
-			list_add(&comp->list, this->list.prev);
-			return 0;
-		}
-	}
-	list_add_tail(&comp->list, &jffs2_compressor_list);
-	return 0;
-}
-
-
-int jffs2_compressors_init(void)
-{
-#ifdef CONFIG_JFFS2_ZLIB
-	jffs2_zlib_init();
-#endif
-#ifdef CONFIG_JFFS2_RTIME
-	jffs2_rtime_init();
-#endif
-#ifdef CONFIG_JFFS2_LZO
-	jffs2_lzo_init();
-#endif
-	return 0;
-}
-
-int jffs2_compressors_exit(void)
-{
-#ifdef CONFIG_JFFS2_RTIME
-	jffs2_rtime_exit();
-#endif
-#ifdef CONFIG_JFFS2_ZLIB
-	jffs2_zlib_exit();
-#endif
-#ifdef CONFIG_JFFS2_LZO
-	jffs2_lzo_exit();
-#endif
-	return 0;
-}
diff --git a/compr.h b/compr.h
deleted file mode 100644
index a21e935..0000000
--- a/compr.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2004 Ferenc Havasi <havasi at inf.u-szeged.hu>,
- *                    University of Szeged, Hungary
- *
- * For licensing information, see the file 'LICENCE' in the
- * jffs2 directory.
- */
-
-#ifndef __JFFS2_COMPR_H__
-#define __JFFS2_COMPR_H__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "linux/jffs2.h"
-
-#define CONFIG_JFFS2_ZLIB
-#define CONFIG_JFFS2_RTIME
-#define CONFIG_JFFS2_LZO
-
-#define JFFS2_RUBINMIPS_PRIORITY 10
-#define JFFS2_DYNRUBIN_PRIORITY  20
-#define JFFS2_RTIME_PRIORITY     50
-#define JFFS2_ZLIB_PRIORITY      60
-#define JFFS2_LZO_PRIORITY       80
-
-#define JFFS2_COMPR_MODE_NONE       0
-#define JFFS2_COMPR_MODE_PRIORITY   1
-#define JFFS2_COMPR_MODE_SIZE       2
-#define JFFS2_COMPR_MODE_FAVOURLZO  3
-
-#define kmalloc(a,b)                malloc(a)
-#define kfree(a)                    free(a)
-#ifndef GFP_KERNEL
-#define GFP_KERNEL                  0
-#endif
-
-#define vmalloc(a)                  malloc(a)
-#define vfree(a)                    free(a)
-
-#define printk(...)                 fprintf(stderr,__VA_ARGS__)
-
-#define KERN_EMERG
-#define KERN_ALERT
-#define KERN_CRIT
-#define KERN_ERR
-#define KERN_WARNING
-#define KERN_NOTICE
-#define KERN_INFO
-#define KERN_DEBUG
-
-struct list_head {
-	struct list_head *next, *prev;
-};
-
-void jffs2_set_compression_mode(int mode);
-int jffs2_get_compression_mode(void);
-int jffs2_set_compression_mode_name(const char *mode_name);
-
-int jffs2_enable_compressor_name(const char *name);
-int jffs2_disable_compressor_name(const char *name);
-
-int jffs2_set_compressor_priority(const char *name, int priority);
-
-struct jffs2_compressor {
-	struct list_head list;
-	int priority;             /* used by prirority comr. mode */
-	const char *name;
-	char compr;               /* JFFS2_COMPR_XXX */
-	int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
-			uint32_t *srclen, uint32_t *destlen);
-	int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
-			uint32_t cdatalen, uint32_t datalen);
-	int usecount;
-	int disabled;             /* if seted the compressor won't compress */
-	unsigned char *compr_buf; /* used by size compr. mode */
-	uint32_t compr_buf_size;  /* used by size compr. mode */
-	uint32_t stat_compr_orig_size;
-	uint32_t stat_compr_new_size;
-	uint32_t stat_compr_blocks;
-	uint32_t stat_decompr_blocks;
-};
-
-int jffs2_register_compressor(struct jffs2_compressor *comp);
-int jffs2_unregister_compressor(struct jffs2_compressor *comp);
-
-int jffs2_compressors_init(void);
-int jffs2_compressors_exit(void);
-
-uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out,
-		uint32_t *datalen, uint32_t *cdatalen);
-
-/* If it is setted, a decompress will be called after every compress */
-void jffs2_compression_check_set(int yesno);
-int jffs2_compression_check_get(void);
-int jffs2_compression_check_errorcnt_get(void);
-
-char *jffs2_list_compressors(void);
-char *jffs2_stats(void);
-
-/* Compressor modules */
-
-/* These functions will be called by jffs2_compressors_init/exit */
-#ifdef CONFIG_JFFS2_ZLIB
-int jffs2_zlib_init(void);
-void jffs2_zlib_exit(void);
-#endif
-#ifdef CONFIG_JFFS2_RTIME
-int jffs2_rtime_init(void);
-void jffs2_rtime_exit(void);
-#endif
-#ifdef CONFIG_JFFS2_LZO
-int jffs2_lzo_init(void);
-void jffs2_lzo_exit(void);
-#endif
-
-#endif /* __JFFS2_COMPR_H__ */
diff --git a/compr_lzo.c b/compr_lzo.c
deleted file mode 100644
index d2e2afc..0000000
--- a/compr_lzo.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * JFFS2 LZO Compression Interface.
- *
- * Copyright (C) 2007 Nokia Corporation. All rights reserved.
- *
- * Author: Richard Purdie <rpurdie at openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifndef WITHOUT_LZO
-#include <asm/types.h>
-#include <linux/jffs2.h>
-#include <lzo/lzo1x.h>
-#include "compr.h"
-
-extern int page_size;
-
-static void *lzo_mem;
-static void *lzo_compress_buf;
-
-/*
- * Note about LZO compression.
- *
- * We want to use the _999_ compression routine which gives better compression
- * rates at the expense of time. Decompression time is unaffected. We might as
- * well use the standard lzo library routines for this but they will overflow
- * the destination buffer since they don't check the destination size.
- *
- * We therefore compress to a temporary buffer and copy if it will fit.
- *
- */
-static int jffs2_lzo_cmpr(unsigned char *data_in, unsigned char *cpage_out,
-			  uint32_t *sourcelen, uint32_t *dstlen)
-{
-	lzo_uint compress_size;
-	int ret;
-
-	ret = lzo1x_999_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem);
-
-	if (ret != LZO_E_OK)
-		return -1;
-
-	if (compress_size > *dstlen)
-		return -1;
-
-	memcpy(cpage_out, lzo_compress_buf, compress_size);
-	*dstlen = compress_size;
-
-	return 0;
-}
-
-static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out,
-				 uint32_t srclen, uint32_t destlen)
-{
-	int ret;
-	lzo_uint dl;
-
-	ret = lzo1x_decompress_safe(data_in,srclen,cpage_out,&dl,NULL);
-
-	if (ret != LZO_E_OK || dl != destlen)
-		return -1;
-
-	return 0;
-}
-
-static struct jffs2_compressor jffs2_lzo_comp = {
-	.priority = JFFS2_LZO_PRIORITY,
-	.name = "lzo",
-	.compr = JFFS2_COMPR_LZO,
-	.compress = &jffs2_lzo_cmpr,
-	.decompress = &jffs2_lzo_decompress,
-	.disabled = 1,
-};
-
-int jffs2_lzo_init(void)
-{
-	int ret;
-
-	lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
-	if (!lzo_mem)
-		return -1;
-
-	/* Worse case LZO compression size from their FAQ */
-	lzo_compress_buf = malloc(page_size + (page_size / 16) + 64 + 3);
-	if (!lzo_compress_buf) {
-		free(lzo_mem);
-		return -1;
-	}
-
-	ret = jffs2_register_compressor(&jffs2_lzo_comp);
-	if (ret < 0) {
-		free(lzo_compress_buf);
-		free(lzo_mem);
-	}
-
-	return ret;
-}
-
-void jffs2_lzo_exit(void)
-{
-	jffs2_unregister_compressor(&jffs2_lzo_comp);
-	free(lzo_compress_buf);
-	free(lzo_mem);
-}
-
-#else
-
-int jffs2_lzo_init(void)
-{
-	return 0;
-}
-
-void jffs2_lzo_exit(void)
-{
-}
-
-#endif
diff --git a/compr_rtime.c b/compr_rtime.c
deleted file mode 100644
index f24379d..0000000
--- a/compr_rtime.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2001-2003 Red Hat, Inc.
- *
- * Created by Arjan van de Ven <arjanv at redhat.com>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
- * Very simple lz77-ish encoder.
- *
- * Theory of operation: Both encoder and decoder have a list of "last
- * occurrences" for every possible source-value; after sending the
- * first source-byte, the second byte indicated the "run" length of
- * matches
- *
- * The algorithm is intended to only send "whole bytes", no bit-messing.
- *
- */
-
-#include <stdint.h>
-#include <string.h>
-#include "compr.h"
-
-/* _compress returns the compressed size, -1 if bigger */
-static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
-		uint32_t *sourcelen, uint32_t *dstlen)
-{
-	short positions[256];
-	int outpos = 0;
-	int pos=0;
-
-	memset(positions,0,sizeof(positions));
-
-	while (pos < (*sourcelen) && outpos+2 <= (*dstlen)) {
-		int backpos, runlen=0;
-		unsigned char value;
-
-		value = data_in[pos];
-
-		cpage_out[outpos++] = data_in[pos++];
-
-		backpos = positions[value];
-		positions[value]=pos;
-
-		while ((backpos < pos) && (pos < (*sourcelen)) &&
-				(data_in[pos]==data_in[backpos++]) && (runlen<255)) {
-			pos++;
-			runlen++;
-		}
-		cpage_out[outpos++] = runlen;
-	}
-
-	if (outpos >= pos) {
-		/* We failed */
-		return -1;
-	}
-
-	/* Tell the caller how much we managed to compress, and how much space it took */
-	*sourcelen = pos;
-	*dstlen = outpos;
-	return 0;
-}
-
-
-static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		__attribute__((unused)) uint32_t srclen, uint32_t destlen)
-{
-	short positions[256];
-	int outpos = 0;
-	int pos=0;
-
-	memset(positions,0,sizeof(positions));
-
-	while (outpos<destlen) {
-		unsigned char value;
-		int backoffs;
-		int repeat;
-
-		value = data_in[pos++];
-		cpage_out[outpos++] = value; /* first the verbatim copied byte */
-		repeat = data_in[pos++];
-		backoffs = positions[value];
-
-		positions[value]=outpos;
-		if (repeat) {
-			if (backoffs + repeat >= outpos) {
-				while(repeat) {
-					cpage_out[outpos++] = cpage_out[backoffs++];
-					repeat--;
-				}
-			} else {
-				memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat);
-				outpos+=repeat;
-			}
-		}
-	}
-	return 0;
-}
-
-
-static struct jffs2_compressor jffs2_rtime_comp = {
-	.priority = JFFS2_RTIME_PRIORITY,
-	.name = "rtime",
-	.disabled = 0,
-	.compr = JFFS2_COMPR_RTIME,
-	.compress = &jffs2_rtime_compress,
-	.decompress = &jffs2_rtime_decompress,
-};
-
-int jffs2_rtime_init(void)
-{
-	return jffs2_register_compressor(&jffs2_rtime_comp);
-}
-
-void jffs2_rtime_exit(void)
-{
-	jffs2_unregister_compressor(&jffs2_rtime_comp);
-}
diff --git a/compr_zlib.c b/compr_zlib.c
deleted file mode 100644
index 1f94628..0000000
--- a/compr_zlib.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2001 Red Hat, Inc.
- *
- * Created by David Woodhouse <dwmw2 at cambridge.redhat.com>
- *
- * The original JFFS, from which the design for JFFS2 was derived,
- * was designed and implemented by Axis Communications AB.
- *
- * The contents of this file are subject to the Red Hat eCos Public
- * License Version 1.1 (the "Licence"); you may not use this file
- * except in compliance with the Licence.  You may obtain a copy of
- * the Licence at http://www.redhat.com/
- *
- * Software distributed under the Licence is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- * See the Licence for the specific language governing rights and
- * limitations under the Licence.
- *
- * The Original Code is JFFS2 - Journalling Flash File System, version 2
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the RHEPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the RHEPL or the GPL.
- */
-
-#define PROGRAM_NAME "compr_zlib"
-
-#include <stdint.h>
-#define crc32 __zlib_crc32
-#include <zlib.h>
-#undef crc32
-#include <stdio.h>
-#include <asm/types.h>
-#include <linux/jffs2.h>
-#include "common.h"
-#include "compr.h"
-
-/* Plan: call deflate() with avail_in == *sourcelen,
-   avail_out = *dstlen - 12 and flush == Z_FINISH.
-   If it doesn't manage to finish,	call it again with
-   avail_in == 0 and avail_out set to the remaining 12
-   bytes for it to clean up.
-Q: Is 12 bytes sufficient?
- */
-#define STREAM_END_SPACE 12
-
-static int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
-		uint32_t *sourcelen, uint32_t *dstlen)
-{
-	z_stream strm;
-	int ret;
-
-	if (*dstlen <= STREAM_END_SPACE)
-		return -1;
-
-	strm.zalloc = (void *)0;
-	strm.zfree = (void *)0;
-
-	if (Z_OK != deflateInit(&strm, 3)) {
-		return -1;
-	}
-	strm.next_in = data_in;
-	strm.total_in = 0;
-
-	strm.next_out = cpage_out;
-	strm.total_out = 0;
-
-	while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) {
-		strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE);
-		strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
-		ret = deflate(&strm, Z_PARTIAL_FLUSH);
-		if (ret != Z_OK) {
-			deflateEnd(&strm);
-			return -1;
-		}
-	}
-	strm.avail_out += STREAM_END_SPACE;
-	strm.avail_in = 0;
-	ret = deflate(&strm, Z_FINISH);
-	if (ret != Z_STREAM_END) {
-		deflateEnd(&strm);
-		return -1;
-	}
-	deflateEnd(&strm);
-
-	if (strm.total_out >= strm.total_in)
-		return -1;
-
-
-	*dstlen = strm.total_out;
-	*sourcelen = strm.total_in;
-	return 0;
-}
-
-static int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		uint32_t srclen, uint32_t destlen)
-{
-	z_stream strm;
-	int ret;
-
-	strm.zalloc = (void *)0;
-	strm.zfree = (void *)0;
-
-	if (Z_OK != inflateInit(&strm)) {
-		return 1;
-	}
-	strm.next_in = data_in;
-	strm.avail_in = srclen;
-	strm.total_in = 0;
-
-	strm.next_out = cpage_out;
-	strm.avail_out = destlen;
-	strm.total_out = 0;
-
-	while((ret = inflate(&strm, Z_FINISH)) == Z_OK)
-		;
-
-	inflateEnd(&strm);
-	return 0;
-}
-
-static struct jffs2_compressor jffs2_zlib_comp = {
-	.priority = JFFS2_ZLIB_PRIORITY,
-	.name = "zlib",
-	.disabled = 0,
-	.compr = JFFS2_COMPR_ZLIB,
-	.compress = &jffs2_zlib_compress,
-	.decompress = &jffs2_zlib_decompress,
-};
-
-int jffs2_zlib_init(void)
-{
-	return jffs2_register_compressor(&jffs2_zlib_comp);
-}
-
-void jffs2_zlib_exit(void)
-{
-	jffs2_unregister_compressor(&jffs2_zlib_comp);
-}
diff --git a/device_table.txt b/device_table.txt
deleted file mode 100644
index 394a62b..0000000
--- a/device_table.txt
+++ /dev/null
@@ -1,128 +0,0 @@
-# This is a sample device table file for use with mkfs.jffs2.  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.
-#
-# 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 entried apply only to device special
-# file.
-
-# 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".
-# 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
-#
-# Have fun
-# -Erik Andersen <andersen at 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 --git a/doc_loadbios.c b/doc_loadbios.c
deleted file mode 100644
index b999c73..0000000
--- a/doc_loadbios.c
+++ /dev/null
@@ -1,150 +0,0 @@
-#define PROGRAM_NAME "doc_loadbios"
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <time.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/mount.h>
-
-#include <mtd/mtd-user.h>
-
-unsigned char databuf[512];
-
-int main(int argc,char **argv)
-{
-	mtd_info_t meminfo;
-	int ifd,ofd;
-	struct stat statbuf;
-	erase_info_t erase;
-	unsigned long retlen, ofs, iplsize, ipltailsize;
-	unsigned char *iplbuf;
-	iplbuf = NULL;
-
-	if (argc < 3) {
-		fprintf(stderr,"You must specify a device,"
-				" the source firmware file and the offset\n");
-		return 1;
-	}
-
-	// Open and size the device
-	if ((ofd = open(argv[1],O_RDWR)) < 0) {
-		perror("Open flash device");
-		return 1;
-	}
-
-	if ((ifd = open(argv[2], O_RDONLY)) < 0) {
-		perror("Open firmware file\n");
-		close(ofd);
-		return 1;
-	}
-
-	if (fstat(ifd, &statbuf) != 0) {
-		perror("Stat firmware file");
-		goto error;
-	}
-
-#if 0
-	if (statbuf.st_size > 65536) {
-		printf("Firmware too large (%ld bytes)\n",statbuf.st_size);
-		goto error;
-	}
-#endif
-
-	if (ioctl(ofd,MEMGETINFO,&meminfo) != 0) {
-		perror("ioctl(MEMGETINFO)");
-		goto error;
-	}
-
-	iplsize = (ipltailsize = 0);
-	if (argc >= 4) {
-		/* DoC Millennium has IPL in the first 1K of flash memory */
-		/* You may want to specify the offset 1024 to store
-		   the firmware next to IPL. */
-		iplsize = strtoul(argv[3], NULL, 0);
-		ipltailsize = iplsize % meminfo.erasesize;
-	}
-
-	if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) {
-		perror("lseek");
-		goto error;
-	}
-
-	if (ipltailsize) {
-		iplbuf = malloc(ipltailsize);
-		if (iplbuf == NULL) {
-			fprintf(stderr, "Not enough memory for IPL tail buffer of"
-					" %lu bytes\n", (unsigned long) ipltailsize);
-			goto error;
-		}
-		printf("Reading IPL%s area of length %lu at offset %lu\n",
-				(iplsize - ipltailsize) ? " tail" : "",
-				(long unsigned) ipltailsize,
-				(long unsigned) (iplsize - ipltailsize));
-		if (read(ofd, iplbuf, ipltailsize) != ipltailsize) {
-			perror("read");
-			goto error;
-		}
-	}
-
-	erase.length = meminfo.erasesize;
-
-	for (ofs = iplsize - ipltailsize ;
-			ofs < iplsize + statbuf.st_size ;
-			ofs += meminfo.erasesize) {
-		erase.start = ofs;
-		printf("Performing Flash Erase of length %lu at offset %lu\n",
-				(long unsigned) erase.length, (long unsigned) erase.start);
-
-		if (ioctl(ofd,MEMERASE,&erase) != 0) {
-			perror("ioctl(MEMERASE)");
-			goto error;
-		}
-	}
-
-	if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) {
-		perror("lseek");
-		goto error;
-	}
-
-	if (ipltailsize) {
-		printf("Writing IPL%s area of length %lu at offset %lu\n",
-				(iplsize - ipltailsize) ? " tail" : "",
-				(long unsigned) ipltailsize,
-				(long unsigned) (iplsize - ipltailsize));
-		if (write(ofd, iplbuf, ipltailsize) != ipltailsize) {
-			perror("write");
-			goto error;
-		}
-	}
-
-	printf("Writing the firmware of length %lu at %lu... ",
-			(unsigned long) statbuf.st_size,
-			(unsigned long) iplsize);
-	do {
-		retlen = read(ifd, databuf, 512);
-		if (retlen < 512)
-			memset(databuf+retlen, 0xff, 512-retlen);
-		if (write(ofd, databuf, 512) != 512) {
-			perror("write");
-			goto error;
-		}
-	} while (retlen == 512);
-	printf("Done.\n");
-
-	if (iplbuf != NULL)
-		free(iplbuf);
-	close(ifd);
-	close(ofd);
-	return 0;
-
-error:
-	if (iplbuf != NULL)
-		free(iplbuf);
-	close(ifd);
-	close(ofd);
-	return 1;
-}
diff --git a/docfdisk.c b/docfdisk.c
deleted file mode 100644
index 9956de5..0000000
--- a/docfdisk.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * docfdisk.c: Modify INFTL partition tables
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * 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
- */
-
-#define PROGRAM_NAME "docfdisk"
-
-#define _XOPEN_SOURCE 500 /* for pread/pwrite */
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/mount.h>
-#include <errno.h>
-#include <string.h>
-
-#include <asm/types.h>
-#include <mtd/mtd-user.h>
-#include <mtd/inftl-user.h>
-#include <mtd_swab.h>
-
-unsigned char *buf;
-
-mtd_info_t meminfo;
-erase_info_t erase;
-int fd;
-struct INFTLMediaHeader *mh;
-
-#define MAXSCAN 10
-
-void show_header(int mhoffs) {
-	int i, unitsize, numunits, bmbits, numpart;
-	int start, end, num, nextunit;
-	unsigned int flags;
-	struct INFTLPartition *ip;
-
-	bmbits = le32_to_cpu(mh->BlockMultiplierBits);
-	printf("  bootRecordID          = %s\n"
-			"  NoOfBootImageBlocks   = %d\n"
-			"  NoOfBinaryPartitions  = %d\n"
-			"  NoOfBDTLPartitions    = %d\n"
-			"  BlockMultiplierBits   = %d\n"
-			"  FormatFlags           = %d\n"
-			"  OsakVersion           = %d.%d.%d.%d\n"
-			"  PercentUsed           = %d\n",
-			mh->bootRecordID, le32_to_cpu(mh->NoOfBootImageBlocks),
-			le32_to_cpu(mh->NoOfBinaryPartitions),
-			le32_to_cpu(mh->NoOfBDTLPartitions),
-			bmbits,
-			le32_to_cpu(mh->FormatFlags),
-			((unsigned char *) &mh->OsakVersion)[0] & 0xf,
-			((unsigned char *) &mh->OsakVersion)[1] & 0xf,
-			((unsigned char *) &mh->OsakVersion)[2] & 0xf,
-			((unsigned char *) &mh->OsakVersion)[3] & 0xf,
-			le32_to_cpu(mh->PercentUsed));
-
-	numpart = le32_to_cpu(mh->NoOfBinaryPartitions) +
-		le32_to_cpu(mh->NoOfBDTLPartitions);
-	unitsize = meminfo.erasesize >> bmbits;
-	numunits = meminfo.size / unitsize;
-	nextunit = mhoffs / unitsize;
-	nextunit++;
-	printf("Unitsize is %d bytes.  Device has %d units.\n",
-			unitsize, numunits);
-	if (numunits > 32768) {
-		printf("WARNING: More than 32768 units! Unexpectedly small BlockMultiplierBits.\n");
-	}
-	if (bmbits && (numunits <= 16384)) {
-		printf("NOTICE: Unexpectedly large BlockMultiplierBits.\n");
-	}
-	for (i = 0; i < 4; i++) {
-		ip = &(mh->Partitions[i]);
-		flags = le32_to_cpu(ip->flags);
-		start = le32_to_cpu(ip->firstUnit);
-		end = le32_to_cpu(ip->lastUnit);
-		num = le32_to_cpu(ip->virtualUnits);
-		if (start < nextunit) {
-			printf("ERROR: Overlapping or misordered partitions!\n");
-		}
-		if (start > nextunit) {
-			printf("  Unpartitioned space: %d bytes\n"
-					"    virtualUnits  = %d\n"
-					"    firstUnit     = %d\n"
-					"    lastUnit      = %d\n",
-					(start - nextunit) * unitsize, start - nextunit,
-					nextunit, start - 1);
-		}
-		if (flags & INFTL_BINARY)
-			printf("  Partition %d   (BDK):", i+1);
-		else
-			printf("  Partition %d  (BDTL):", i+1);
-		printf(" %d bytes\n"
-				"    virtualUnits  = %d\n"
-				"    firstUnit     = %d\n"
-				"    lastUnit      = %d\n"
-				"    flags         = 0x%x\n"
-				"    spareUnits    = %d\n",
-				num * unitsize, num, start, end,
-				le32_to_cpu(ip->flags), le32_to_cpu(ip->spareUnits));
-		if (num > (1 + end - start)) {
-			printf("ERROR: virtualUnits not consistent with first/lastUnit!\n");
-		}
-		end++;
-		if (end > nextunit)
-			nextunit = end;
-		if (flags & INFTL_LAST)
-			break;
-	}
-	if (i >= 4) {
-		printf("Odd.  Last partition was not marked with INFTL_LAST.\n");
-		i--;
-	}
-	if ((i+1) != numpart) {
-		printf("ERROR: Number of partitions != (NoOfBinaryPartitions + NoOfBDTLPartitions)\n");
-	}
-	if (nextunit > numunits) {
-		printf("ERROR: Partitions appear to extend beyond end of device!\n");
-	}
-	if (nextunit < numunits) {
-		printf("  Unpartitioned space: %d bytes\n"
-				"    virtualUnits  = %d\n"
-				"    firstUnit     = %d\n"
-				"    lastUnit      = %d\n",
-				(numunits - nextunit) * unitsize, numunits - nextunit,
-				nextunit, numunits - 1);
-	}
-}
-
-
-int main(int argc, char **argv)
-{
-	int ret, i, mhblock, unitsize, block;
-	unsigned int nblocks[4], npart;
-	unsigned int totblocks;
-	struct INFTLPartition *ip;
-	unsigned char *oobbuf;
-	struct mtd_oob_buf oob;
-	char line[20];
-	int mhoffs;
-	struct INFTLMediaHeader *mh2;
-
-	if (argc < 2) {
-		printf(
-				"Usage: %s <mtddevice> [<size1> [<size2> [<size3> [<size4]]]]\n"
-				"  Sizes are in device units (run with no sizes to show unitsize and current\n"
-				"  partitions).  Last size = 0 means go to end of device.\n",
-				PROGRAM_NAME);
-		return 1;
-	}
-
-	npart = argc - 2;
-	if (npart > 4) {
-		printf("Max 4 partitions allowed.\n");
-		return 1;
-	}
-
-	for (i = 0; i < npart; i++) {
-		nblocks[i] = strtoul(argv[2+i], NULL, 0);
-		if (i && !nblocks[i-1]) {
-			printf("No sizes allowed after 0\n");
-			return 1;
-		}
-	}
-
-	// Open and size the device
-	if ((fd = open(argv[1], O_RDWR)) < 0) {
-		perror("Open flash device");
-		return 1;
-	}
-
-	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
-		perror("ioctl(MEMGETINFO)");
-		return 1;
-	}
-
-	printf("Device size is %d bytes.  Erasesize is %d bytes.\n",
-			meminfo.size, meminfo.erasesize);
-
-	buf = malloc(meminfo.erasesize);
-	oobbuf = malloc((meminfo.erasesize / meminfo.writesize) * meminfo.oobsize);
-	if (!buf || !oobbuf) {
-		printf("Can't malloc block buffer\n");
-		return 1;
-	}
-	oob.length = meminfo.oobsize;
-
-	mh = (struct INFTLMediaHeader *) buf;
-
-	for (mhblock = 0; mhblock < MAXSCAN; mhblock++) {
-		if ((ret = pread(fd, buf, meminfo.erasesize, mhblock * meminfo.erasesize)) < 0) {
-			if (errno == EBADMSG) {
-				printf("ECC error at eraseblock %d\n", mhblock);
-				continue;
-			}
-			perror("Read eraseblock");
-			return 1;
-		}
-		if (ret != meminfo.erasesize) {
-			printf("Short read!\n");
-			return 1;
-		}
-		if (!strcmp("BNAND", mh->bootRecordID)) break;
-	}
-	if (mhblock >= MAXSCAN) {
-		printf("Unable to find INFTL Media Header\n");
-		return 1;
-	}
-	printf("Found INFTL Media Header at block %d:\n", mhblock);
-	mhoffs = mhblock * meminfo.erasesize;
-
-	oob.ptr = oobbuf;
-	oob.start = mhoffs;
-	for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
-		if (ioctl(fd, MEMREADOOB, &oob)) {
-			perror("ioctl(MEMREADOOB)");
-			return 1;
-		}
-		oob.start += meminfo.writesize;
-		oob.ptr += meminfo.oobsize;
-	}
-
-	show_header(mhoffs);
-
-	if (!npart)
-		return 0;
-
-	printf("\n-------------------------------------------------------------------------\n");
-
-	unitsize = meminfo.erasesize >> le32_to_cpu(mh->BlockMultiplierBits);
-	totblocks = meminfo.size / unitsize;
-	block = mhoffs / unitsize;
-	block++;
-
-	mh->NoOfBDTLPartitions = 0;
-	mh->NoOfBinaryPartitions = npart;
-
-	for (i = 0; i < npart; i++) {
-		ip = &(mh->Partitions[i]);
-		ip->firstUnit = cpu_to_le32(block);
-		if (!nblocks[i])
-			nblocks[i] = totblocks - block;
-		ip->virtualUnits = cpu_to_le32(nblocks[i]);
-		block += nblocks[i];
-		ip->lastUnit = cpu_to_le32(block-1);
-		ip->spareUnits = 0;
-		ip->flags = cpu_to_le32(INFTL_BINARY);
-	}
-	if (block > totblocks) {
-		printf("Requested partitions extend beyond end of device.\n");
-		return 1;
-	}
-	ip->flags = cpu_to_le32(INFTL_BINARY | INFTL_LAST);
-
-	/* update the spare as well */
-	mh2 = (struct INFTLMediaHeader *) (buf + 4096);
-	memcpy((void *) mh2, (void *) mh, sizeof(struct INFTLMediaHeader));
-
-	printf("\nProposed new Media Header:\n");
-	show_header(mhoffs);
-
-	printf("\nReady to update device.  Type 'yes' to proceed, anything else to abort: ");
-	fgets(line, sizeof(line), stdin);
-	if (strcmp("yes\n", line))
-		return 0;
-	printf("Updating MediaHeader...\n");
-
-	erase.start = mhoffs;
-	erase.length = meminfo.erasesize;
-	if (ioctl(fd, MEMERASE, &erase)) {
-		perror("ioctl(MEMERASE)");
-		printf("Your MediaHeader may be hosed.  UHOH!\n");
-		return 1;
-	}
-
-	oob.ptr = oobbuf;
-	oob.start = mhoffs;
-	for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
-		memset(oob.ptr, 0xff, 6); // clear ECC.
-		if (ioctl(fd, MEMWRITEOOB, &oob)) {
-			perror("ioctl(MEMWRITEOOB)");
-			printf("Your MediaHeader may be hosed.  UHOH!\n");
-			return 1;
-		}
-		if ((ret = pwrite(fd, buf, meminfo.writesize, oob.start)) < 0) {
-			perror("Write page");
-			printf("Your MediaHeader may be hosed.  UHOH!\n");
-			return 1;
-		}
-		if (ret != meminfo.writesize) {
-			printf("Short write!\n");
-			printf("Your MediaHeader may be hosed.  UHOH!\n");
-			return 1;
-		}
-
-		oob.start += meminfo.writesize;
-		oob.ptr += meminfo.oobsize;
-		buf += meminfo.writesize;
-	}
-
-	printf("Success.  REBOOT or unload the diskonchip module to update partitions!\n");
-	return 0;
-}
diff --git a/fectest.c b/fectest.c
deleted file mode 100644
index fd577f3..0000000
--- a/fectest.c
+++ /dev/null
@@ -1,91 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "mcast_image.h"
-#include <crc32.h>
-
-#define ERASE_SIZE 131072
-#define NR_PKTS ((ERASE_SIZE + PKT_SIZE - 1) / PKT_SIZE)
-#define DROPS 8
-
-int main(void)
-{
-	int i, j;
-	unsigned char buf[NR_PKTS * PKT_SIZE];
-	unsigned char pktbuf[(NR_PKTS + DROPS) * PKT_SIZE];
-	struct fec_parms *fec;
-	unsigned char *srcs[NR_PKTS];
-	unsigned char *pkt[NR_PKTS + DROPS];
-	int pktnr[NR_PKTS + DROPS];
-	struct timeval then, now;
-
-	srand(3453);
-	for (i=0; i < sizeof(buf); i++)
-		if (i < ERASE_SIZE)
-			buf[i] = rand();
-		else
-			buf[i] = 0;
-
-	for (i=0; i < NR_PKTS + DROPS; i++)
-		srcs[i] = buf + (i * PKT_SIZE);
-
-	for (i=0; i < NR_PKTS + DROPS; i++) {
-		pkt[i] = malloc(PKT_SIZE);
-		pktnr[i] = -1;
-	}
-	fec = fec_new(NR_PKTS, NR_PKTS + DROPS);
-	if (!fec) {
-		printf("fec_init() failed\n");
-		exit(1);
-	}
-	j = 0;
-	for (i=0; i < NR_PKTS + DROPS; i++) {
-#if 1
-		if (i == 27  || i == 40  || i == 44 || i == 45 || i == 56 )
-			continue;
-#endif
-		if (i == 69 || i == 93 || i == 103)
-			continue;
-		fec_encode(fec, srcs, pkt[j], i, PKT_SIZE);
-		pktnr[j] = i;
-		j++;
-	}
-	gettimeofday(&then, NULL);
-	if (fec_decode(fec, pkt, pktnr, PKT_SIZE)) {
-		printf("Decode failed\n");
-		exit(1);
-	}
-
-	for (i=0; i < NR_PKTS; i++)
-		memcpy(pktbuf + (i*PKT_SIZE), pkt[i], PKT_SIZE);
-	gettimeofday(&now, NULL);
-	now.tv_sec -= then.tv_sec;
-	now.tv_usec -= then.tv_usec;
-	if (now.tv_usec < 0) {
-		now.tv_usec += 1000000;
-		now.tv_sec--;
-	}
-
-	if (memcmp(pktbuf, buf, ERASE_SIZE)) {
-		int fd;
-		printf("Compare failed\n");
-		fd = open("before", O_WRONLY|O_TRUNC|O_CREAT, 0644);
-		if (fd >= 0)
-			write(fd, buf, ERASE_SIZE);
-		close(fd);
-		fd = open("after", O_WRONLY|O_TRUNC|O_CREAT, 0644);
-		if (fd >= 0)
-			write(fd, pktbuf, ERASE_SIZE);
-
-		exit(1);
-	}
-
-	printf("Decoded in %ld.%06lds\n", now.tv_sec, now.tv_usec);
-	return 0;
-}
diff --git a/flash-utils/flash_erase.c b/flash-utils/flash_erase.c
new file mode 100644
index 0000000..933373a
--- /dev/null
+++ b/flash-utils/flash_erase.c
@@ -0,0 +1,295 @@
+/* flash_erase.c -- erase MTD devices
+
+   Copyright (C) 2000 Arcom Control System Ltd
+   Copyright (C) 2010 Mike Frysinger <vapier at gentoo.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; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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
+ */
+
+#define PROGRAM_NAME "flash_erase"
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <common.h>
+#include <crc32.h>
+#include <libmtd.h>
+
+#include <mtd/mtd-user.h>
+#include <mtd/jffs2-user.h>
+
+static const char *mtd_device;
+
+static int quiet;		/* true -- don't output progress */
+static int jffs2;		/* format for jffs2 usage */
+static int noskipbad;		/* do not skip bad blocks */
+static int unlock;		/* unlock sectors before erasing */
+
+static struct jffs2_unknown_node cleanmarker;
+int target_endian = __BYTE_ORDER;
+
+static void show_progress(struct mtd_dev_info *mtd, off_t start, int eb,
+			  int eb_start, int eb_cnt)
+{
+	bareverbose(!quiet, "\rErasing %d Kibyte @ %"PRIxoff_t" -- %2i %% complete ",
+		mtd->eb_size / 1024, start, ((eb - eb_start) * 100) / eb_cnt);
+	fflush(stdout);
+}
+
+static void display_help (void)
+{
+	printf("Usage: %s [options] MTD_DEVICE <start offset> <block count>\n"
+			"Erase blocks of the specified MTD device.\n"
+			"Specify a count of 0 to erase to end of device.\n"
+			"\n"
+			"  -j, --jffs2       format the device for jffs2\n"
+			"  -N, --noskipbad   don't skip bad blocks\n"
+			"  -u, --unlock      unlock sectors before erasing\n"
+			"  -q, --quiet       do not display progress messages\n"
+			"      --silent      same as --quiet\n"
+			"      --help        display this help and exit\n"
+			"      --version     output version information and exit\n",
+			PROGRAM_NAME);
+}
+
+static void display_version (void)
+{
+	printf("%1$s version " VERSION "\n"
+			"\n"
+			"Copyright (C) 2000 Arcom Control Systems Ltd\n"
+			"\n"
+			"%1$s comes with NO WARRANTY\n"
+			"to the extent permitted by law.\n"
+			"\n"
+			"You may redistribute copies of %1$s\n"
+			"under the terms of the GNU General Public Licence.\n"
+			"See the file `COPYING' for more information.\n",
+			PROGRAM_NAME);
+}
+
+int main(int argc, char *argv[])
+{
+	libmtd_t mtd_desc;
+	struct mtd_dev_info mtd;
+	int fd, clmpos = 0, clmlen = 8;
+	unsigned long long start;
+	unsigned int eb, eb_start, eb_cnt;
+	bool isNAND;
+	int error = 0;
+	off_t offset = 0;
+
+	/*
+	 * Process user arguments
+	 */
+	for (;;) {
+		int option_index = 0;
+		static const char *short_options = "jNqu";
+		static const struct option long_options[] = {
+			{"help", no_argument, 0, 0},
+			{"version", no_argument, 0, 0},
+			{"jffs2", no_argument, 0, 'j'},
+			{"noskipbad", no_argument, 0, 'N'},
+			{"quiet", no_argument, 0, 'q'},
+			{"silent", no_argument, 0, 'q'},
+			{"unlock", no_argument, 0, 'u'},
+
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+		case 0:
+			switch (option_index) {
+			case 0:
+				display_help();
+				return 0;
+			case 1:
+				display_version();
+				return 0;
+			}
+			break;
+		case 'j':
+			jffs2 = 1;
+			break;
+		case 'N':
+			noskipbad = 1;
+			break;
+		case 'q':
+			quiet = 1;
+			break;
+		case 'u':
+			unlock = 1;
+			break;
+		case '?':
+			error = 1;
+			break;
+		}
+	}
+	switch (argc - optind) {
+	case 3:
+		mtd_device = argv[optind];
+		start = simple_strtoull(argv[optind + 1], &error);
+		eb_cnt = simple_strtoul(argv[optind + 2], &error);
+		break;
+	default:
+	case 0:
+		errmsg("no MTD device specified");
+	case 1:
+		errmsg("no start erase block specified");
+	case 2:
+		errmsg("no erase block count specified");
+		error = 1;
+		break;
+	}
+	if (error)
+		return errmsg("Try `--help' for more information");
+
+	/*
+	 * Locate MTD and prepare for erasure
+	 */
+	mtd_desc = libmtd_open();
+	if (mtd_desc == NULL)
+		return errmsg("can't initialize libmtd");
+
+	if ((fd = open(mtd_device, O_RDWR)) < 0)
+		return sys_errmsg("%s", mtd_device);
+
+	if (mtd_get_dev_info(mtd_desc, mtd_device, &mtd) < 0)
+		return errmsg("mtd_get_dev_info failed");
+
+	if (jffs2 && mtd.type == MTD_MLCNANDFLASH)
+		return errmsg("JFFS2 cannot support MLC NAND.");
+
+	eb_start = start / mtd.eb_size;
+
+	isNAND = mtd.type == MTD_NANDFLASH || mtd.type == MTD_MLCNANDFLASH;
+
+	if (jffs2) {
+		cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
+		cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
+		if (!isNAND)
+			cleanmarker.totlen = cpu_to_je32(sizeof(cleanmarker));
+		else {
+			struct nand_oobinfo oobinfo;
+
+			if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0)
+				return sys_errmsg("%s: unable to get NAND oobinfo", mtd_device);
+
+			/* Check for autoplacement */
+			if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
+				/* Get the position of the free bytes */
+				if (!oobinfo.oobfree[0][1])
+					return errmsg(" Eeep. Autoplacement selected and no empty space in oob");
+				clmpos = oobinfo.oobfree[0][0];
+				clmlen = oobinfo.oobfree[0][1];
+				if (clmlen > 8)
+					clmlen = 8;
+			} else {
+				/* Legacy mode */
+				switch (mtd.oob_size) {
+					case 8:
+						clmpos = 6;
+						clmlen = 2;
+						break;
+					case 16:
+						clmpos = 8;
+						clmlen = 8;
+						break;
+					case 64:
+						clmpos = 16;
+						clmlen = 8;
+						break;
+				}
+			}
+			cleanmarker.totlen = cpu_to_je32(8);
+		}
+		cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(cleanmarker) - 4));
+	}
+
+	/*
+	 * Now do the actual erasing of the MTD device
+	 */
+	if (eb_cnt == 0)
+		eb_cnt = (mtd.size / mtd.eb_size) - eb_start;
+
+	for (eb = eb_start; eb < eb_start + eb_cnt; eb++) {
+		offset = (off_t)eb * mtd.eb_size;
+
+		if (!noskipbad) {
+			int ret = mtd_is_bad(&mtd, fd, eb);
+			if (ret > 0) {
+				verbose(!quiet, "Skipping bad block at %08"PRIxoff_t, offset);
+				continue;
+			} else if (ret < 0) {
+				if (errno == EOPNOTSUPP) {
+					noskipbad = 1;
+					if (isNAND)
+						return errmsg("%s: Bad block check not available", mtd_device);
+				} else
+					return sys_errmsg("%s: MTD get bad block failed", mtd_device);
+			}
+		}
+
+		show_progress(&mtd, offset, eb, eb_start, eb_cnt);
+
+		if (unlock) {
+			if (mtd_unlock(&mtd, fd, eb) != 0) {
+				sys_errmsg("%s: MTD unlock failure", mtd_device);
+				continue;
+			}
+		}
+
+		if (mtd_erase(mtd_desc, &mtd, fd, eb) != 0) {
+			sys_errmsg("%s: MTD Erase failure", mtd_device);
+			continue;
+		}
+
+		/* format for JFFS2 ? */
+		if (!jffs2)
+			continue;
+
+		/* write cleanmarker */
+		if (isNAND) {
+			if (mtd_write_oob(mtd_desc, &mtd, fd, (uint64_t)offset + clmpos, clmlen, &cleanmarker) != 0) {
+				sys_errmsg("%s: MTD writeoob failure", mtd_device);
+				continue;
+			}
+		} else {
+			if (pwrite(fd, &cleanmarker, sizeof(cleanmarker), (loff_t)offset) != sizeof(cleanmarker)) {
+				sys_errmsg("%s: MTD write failure", mtd_device);
+				continue;
+			}
+		}
+		verbose(!quiet, " Cleanmarker written at %"PRIxoff_t, offset);
+	}
+	show_progress(&mtd, offset, eb, eb_start, eb_cnt);
+	bareverbose(!quiet, "\n");
+
+	return 0;
+}
diff --git a/flash-utils/flash_eraseall b/flash-utils/flash_eraseall
new file mode 100755
index 0000000..c5539b3
--- /dev/null
+++ b/flash-utils/flash_eraseall
@@ -0,0 +1,4 @@
+#!/bin/sh
+echo "${0##*/} has been replaced by \`flash_erase <mtddev> 0 0\`; please use it" 1>&2
+[ $# -ne 0 ] && set -- "$@" 0 0
+exec flash_erase "$@"
diff --git a/flash-utils/flash_lock.c b/flash-utils/flash_lock.c
new file mode 100644
index 0000000..33f76c7
--- /dev/null
+++ b/flash-utils/flash_lock.c
@@ -0,0 +1,8 @@
+/*
+ * flash_{lock,unlock}
+ *
+ * utilities for locking/unlocking sectors of flash devices
+ */
+
+#define PROGRAM_NAME "flash_lock"
+#include "flash_unlock.c"
diff --git a/flash-utils/flash_otp_dump.c b/flash-utils/flash_otp_dump.c
new file mode 100644
index 0000000..f0c0fb9
--- /dev/null
+++ b/flash-utils/flash_otp_dump.c
@@ -0,0 +1,56 @@
+/*
+ * flash_otp_dump.c -- display One-Time-Programm data
+ */
+
+#define PROGRAM_NAME "flash_otp_dump"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc,char *argv[])
+{
+	int fd, val, i, offset, ret;
+	unsigned char buf[16];
+
+	if (argc != 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) {
+		fprintf(stderr,"Usage: %s [ -f | -u ] <device>\n", PROGRAM_NAME);
+		return EINVAL;
+	}
+
+	fd = open(argv[2], O_RDONLY);
+	if (fd < 0) {
+		perror(argv[2]);
+		return errno;
+	}
+
+	val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER;
+	ret = ioctl(fd, OTPSELECT, &val);
+	if (ret < 0) {
+		perror("OTPSELECT");
+		return errno;
+	}
+
+	printf("OTP %s data for %s\n",
+			argv[1][1] == 'f' ? "factory" : "user", argv[2]);
+	offset = 0;
+	while ((ret = read(fd, buf, sizeof(buf)))) {
+		if (ret < 0) {
+			perror("read()");
+			return errno;
+		}
+		printf("0x%04x:", offset);
+		for (i = 0; i < ret; i++)
+			printf(" %02x", buf[i]);
+		printf("\n");
+		offset += ret;
+	}
+
+	close(fd);
+	return 0;
+}
diff --git a/flash-utils/flash_otp_info.c b/flash-utils/flash_otp_info.c
new file mode 100644
index 0000000..2061797
--- /dev/null
+++ b/flash-utils/flash_otp_info.c
@@ -0,0 +1,65 @@
+/*
+ * flash_otp_info.c -- print info about One-Time-Programm data
+ */
+
+#define PROGRAM_NAME "flash_otp_info"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc,char *argv[])
+{
+	int fd, val, i, ret;
+
+	if (argc != 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) {
+		fprintf(stderr,"Usage: %s [ -f | -u ] <device>\n", PROGRAM_NAME);
+		return EINVAL;
+	}
+
+	fd = open(argv[2], O_RDONLY);
+	if (fd < 0) {
+		perror(argv[2]);
+		return errno;
+	}
+
+	val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER;
+	ret = ioctl(fd, OTPSELECT, &val);
+	if (ret < 0) {
+		perror("OTPSELECT");
+		return errno;
+	}
+
+	ret = ioctl(fd, OTPGETREGIONCOUNT, &val);
+	if (ret < 0) {
+		perror("OTPGETREGIONCOUNT");
+		return errno;
+	}
+
+	printf("Number of OTP %s blocks on %s: %d\n",
+			argv[1][1] == 'f' ? "factory" : "user", argv[2], val);
+
+	if (val > 0) {
+		struct otp_info info[val];
+
+		ret = ioctl(fd, OTPGETREGIONINFO, &info);
+		if (ret	< 0) {
+			perror("OTPGETREGIONCOUNT");
+			return errno;
+		}
+
+		for (i = 0; i < val; i++)
+			printf("block %2d:  offset = 0x%04x  "
+					"size = %2d bytes  %s\n",
+					i, info[i].start, info[i].length,
+					info[i].locked ? "[locked]" : "[unlocked]");
+	}
+
+	close(fd);
+	return 0;
+}
diff --git a/flash-utils/flash_otp_lock.c b/flash-utils/flash_otp_lock.c
new file mode 100644
index 0000000..3c39a2d
--- /dev/null
+++ b/flash-utils/flash_otp_lock.c
@@ -0,0 +1,72 @@
+/*
+ * flash_otp_lock.c -- lock area of One-Time-Program data
+ */
+
+#define PROGRAM_NAME "flash_otp_lock"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <mtd/mtd-user.h>
+#include "common.h"
+
+int main(int argc,char *argv[])
+{
+	int fd, val, ret, offset, size;
+	char *p;
+
+	if (argc != 5 || strcmp(argv[1], "-u")) {
+		fprintf(stderr, "Usage: %s -u <device> <offset> <size>\n", PROGRAM_NAME);
+		fprintf(stderr, "offset and size must match on OTP region boundaries\n");
+		fprintf(stderr, "CAUTION! ONCE LOCKED, OTP REGIONS CAN'T BE UNLOCKED!\n");
+		return EINVAL;
+	}
+
+	fd = open(argv[2], O_WRONLY);
+	if (fd < 0) {
+		perror(argv[2]);
+		return errno;
+	}
+
+	val = MTD_OTP_USER;
+	ret = ioctl(fd, OTPSELECT, &val);
+	if (ret < 0) {
+		perror("OTPSELECT");
+		return errno;
+	}
+
+	offset = strtoul(argv[3], &p, 0);
+	if (argv[3][0] == 0 || *p != 0) {
+		fprintf(stderr, "%s: bad offset value\n", PROGRAM_NAME);
+		return ERANGE;
+	}
+
+	size = strtoul(argv[4], &p, 0);
+	if (argv[4][0] == 0 || *p != 0) {
+		fprintf(stderr, "%s: bad size value\n", PROGRAM_NAME);
+		return ERANGE;
+	}
+
+	printf("About to lock OTP user data on %s from 0x%x to 0x%x\n",
+			argv[2], offset, offset + size);
+	if (prompt("Are you sure?", false)) {
+		struct otp_info info;
+		info.start = offset;
+		info.length = size;
+		ret = ioctl(fd, OTPLOCK, &info);
+		if (ret	< 0) {
+			perror("OTPLOCK");
+			return errno;
+		}
+		printf("Done.\n");
+	} else {
+		printf("Aborted\n");
+	}
+
+	return 0;
+}
diff --git a/flash-utils/flash_otp_write.c b/flash-utils/flash_otp_write.c
new file mode 100644
index 0000000..111318d
--- /dev/null
+++ b/flash-utils/flash_otp_write.c
@@ -0,0 +1,122 @@
+/*
+ * flash_otp_write.c -- write One-Time-Program data
+ */
+
+#define PROGRAM_NAME "flash_otp_write"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <common.h>
+#include <mtd/mtd-user.h>
+
+ssize_t xread(int fd, void *buf, size_t count)
+{
+	ssize_t ret, done = 0;
+
+retry:
+	ret = read(fd, buf + done, count - done);
+	if (ret < 0)
+		return ret;
+
+	done += ret;
+
+	if (ret == 0 /* EOF */ || done == count)
+		return done;
+	else
+		goto retry;
+}
+
+int main(int argc,char *argv[])
+{
+	int fd, val, ret, size, wrote, len;
+	mtd_info_t mtdInfo;
+	off_t offset;
+	char *p, buf[2048];
+
+	if (argc != 4 || strcmp(argv[1], "-u")) {
+		fprintf(stderr, "Usage: %s -u <device> <offset>\n", PROGRAM_NAME);
+		fprintf(stderr, "the raw data to write should be provided on stdin\n");
+		fprintf(stderr, "CAUTION! ONCE SET TO 0, OTP DATA BITS CAN'T BE ERASED!\n");
+		return EINVAL;
+	}
+
+	fd = open(argv[2], O_WRONLY);
+	if (fd < 0) {
+		perror(argv[2]);
+		return errno;
+	}
+
+	val = MTD_OTP_USER;
+	ret = ioctl(fd, OTPSELECT, &val);
+	if (ret < 0) {
+		perror("OTPSELECT");
+		return errno;
+	}
+
+	if (ioctl(fd, MEMGETINFO, &mtdInfo)) {
+		perror("MEMGETINFO");
+		return errno;
+	}
+
+	offset = (off_t)strtoull(argv[3], &p, 0);
+	if (argv[3][0] == 0 || *p != 0) {
+		fprintf(stderr, "%s: bad offset value\n", PROGRAM_NAME);
+		return ERANGE;
+	}
+
+	if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+		perror("lseek()");
+		return errno;
+	}
+
+	printf("Writing OTP user data on %s at offset 0x%"PRIxoff_t"\n", argv[2], offset);
+
+	if (mtd_type_is_nand_user(&mtdInfo))
+		len = mtdInfo.writesize;
+	else
+		len = 256;
+
+	if (len > sizeof(buf)) {
+		printf("huh, writesize (%d) bigger than buffer (%zu)\n",
+				len, sizeof(buf));
+		return ENOMEM;
+	}
+
+	wrote = 0;
+	while ((size = xread(0, buf, len))) {
+		if (size < 0) {
+			perror("read()");
+			return errno;
+		}
+		p = buf;
+		while (size > 0) {
+			if (mtd_type_is_nand_user(&mtdInfo)) {
+				/* Fill remain buffers with 0xff */
+				memset(buf + size, 0xff, mtdInfo.writesize - size);
+				size = mtdInfo.writesize;
+			}
+			ret = write(fd, p, size);
+			if (ret < 0) {
+				perror("write()");
+				return errno;
+			}
+			if (ret == 0) {
+				printf("write() returned 0 after writing %d bytes\n", wrote);
+				return 0;
+			}
+			p += ret;
+			wrote += ret;
+			size -= ret;
+		}
+	}
+
+	printf("Wrote %d bytes of OTP user data\n", wrote);
+	return 0;
+}
diff --git a/flash-utils/flash_unlock.c b/flash-utils/flash_unlock.c
new file mode 100644
index 0000000..1cc8c2f
--- /dev/null
+++ b/flash-utils/flash_unlock.c
@@ -0,0 +1,90 @@
+/*
+ * flash_{lock,unlock}
+ *
+ * utilities for locking/unlocking sectors of flash devices
+ */
+
+#ifndef PROGRAM_NAME
+#define PROGRAM_NAME "flash_unlock"
+#define FLASH_MSG    "unlock"
+#define FLASH_UNLOCK 1
+#else
+#define FLASH_MSG    "lock"
+#define FLASH_UNLOCK 0
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <string.h>
+
+#include "common.h"
+#include <mtd/mtd-user.h>
+
+static void usage(int status)
+{
+	fprintf(status ? stderr : stdout,
+		"Usage: %s <mtd device> [offset] [block count]\n\n"
+		"If offset is not specified, it defaults to 0.\n"
+		"If block count is not specified, it defaults to all blocks.\n",
+		PROGRAM_NAME);
+	exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+	int fd, request;
+	struct mtd_info_user mtdInfo;
+	struct erase_info_user mtdLockInfo;
+	int count;
+	const char *dev;
+
+	/* Parse command line options */
+	if (argc < 2 || argc > 4)
+		usage(1);
+	if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
+		usage(0);
+
+	dev = argv[1];
+
+	/* Get the device info to compare to command line sizes */
+	fd = open(dev, O_RDWR);
+	if (fd < 0)
+		sys_errmsg_die("could not open: %s", dev);
+
+	if (ioctl(fd, MEMGETINFO, &mtdInfo))
+		sys_errmsg_die("could not get mtd info: %s", dev);
+
+	/* Make sure user options are valid */
+	if (argc > 2)
+		mtdLockInfo.start = strtol(argv[2], NULL, 0);
+	else
+		mtdLockInfo.start = 0;
+	if (mtdLockInfo.start > mtdInfo.size)
+		errmsg_die("%#x is beyond device size %#x",
+			mtdLockInfo.start, mtdInfo.size);
+
+	if (argc > 3) {
+		count = strtol(argv[3], NULL, 0);
+		if (count == -1)
+			mtdLockInfo.length = mtdInfo.size;
+		else
+			mtdLockInfo.length = mtdInfo.erasesize * count;
+	} else
+		mtdLockInfo.length = mtdInfo.size;
+	if (mtdLockInfo.start + mtdLockInfo.length > mtdInfo.size)
+		errmsg_die("range is more than device supports: %#x + %#x > %#x",
+			mtdLockInfo.start, mtdLockInfo.length, mtdInfo.size);
+
+	/* Finally do the operation */
+	request = FLASH_UNLOCK ? MEMUNLOCK : MEMLOCK;
+	if (ioctl(fd, request, &mtdLockInfo))
+		sys_errmsg_die("could not %s device: %s\n",
+			FLASH_MSG, dev);
+
+	return 0;
+}
diff --git a/flash-utils/flashcp.c b/flash-utils/flashcp.c
new file mode 100644
index 0000000..86334ac
--- /dev/null
+++ b/flash-utils/flashcp.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2d3D, Inc.
+ * Written by Abraham vd Merwe <abraham at 2d3d.co.za>
+ * All rights reserved.
+ *
+ * Renamed to flashcp.c to avoid conflicts with fcp from fsh package
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	  notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	  notice, this list of conditions and the following disclaimer in the
+ *	  documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ *	  may be used to endorse or promote products derived from this software
+ *	  without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define PROGRAM_NAME "flashcp"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <mtd/mtd-user.h>
+#include <getopt.h>
+
+typedef int bool;
+#define true 1
+#define false 0
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+/* for debugging purposes only */
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(fmt,args...) { log_printf (LOG_ERROR,"%d: ",__LINE__); log_printf (LOG_ERROR,fmt,## args); }
+#else
+#undef DEBUG
+#define DEBUG(fmt,args...)
+#endif
+
+#define KB(x) ((x) / 1024)
+#define PERCENTAGE(x,total) (((x) * 100) / (total))
+
+/* size of read/write buffer */
+#define BUFSIZE (10 * 1024)
+
+/* cmd-line flags */
+#define FLAG_NONE		0x00
+#define FLAG_VERBOSE	0x01
+#define FLAG_HELP		0x02
+#define FLAG_FILENAME	0x04
+#define FLAG_DEVICE		0x08
+
+/* error levels */
+#define LOG_NORMAL	1
+#define LOG_ERROR	2
+
+static void log_printf (int level,const char *fmt, ...)
+{
+	FILE *fp = level == LOG_NORMAL ? stdout : stderr;
+	va_list ap;
+	va_start (ap,fmt);
+	vfprintf (fp,fmt,ap);
+	va_end (ap);
+	fflush (fp);
+}
+
+static void showusage(bool error)
+{
+	int level = error ? LOG_ERROR : LOG_NORMAL;
+
+	log_printf (level,
+			"\n"
+			"Flash Copy - Written by Abraham van der Merwe <abraham at 2d3d.co.za>\n"
+			"\n"
+			"usage: %1$s [ -v | --verbose ] <filename> <device>\n"
+			"       %1$s -h | --help\n"
+			"\n"
+			"   -h | --help      Show this help message\n"
+			"   -v | --verbose   Show progress reports\n"
+			"   <filename>       File which you want to copy to flash\n"
+			"   <device>         Flash device to write to (e.g. /dev/mtd0, /dev/mtd1, etc.)\n"
+			"\n",
+			PROGRAM_NAME);
+
+	exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+static int safe_open (const char *pathname,int flags)
+{
+	int fd;
+
+	fd = open (pathname,flags);
+	if (fd < 0)
+	{
+		log_printf (LOG_ERROR,"While trying to open %s",pathname);
+		if (flags & O_RDWR)
+			log_printf (LOG_ERROR," for read/write access");
+		else if (flags & O_RDONLY)
+			log_printf (LOG_ERROR," for read access");
+		else if (flags & O_WRONLY)
+			log_printf (LOG_ERROR," for write access");
+		log_printf (LOG_ERROR,": %m\n");
+		exit (EXIT_FAILURE);
+	}
+
+	return (fd);
+}
+
+static void safe_read (int fd,const char *filename,void *buf,size_t count,bool verbose)
+{
+	ssize_t result;
+
+	result = read (fd,buf,count);
+	if (count != result)
+	{
+		if (verbose) log_printf (LOG_NORMAL,"\n");
+		if (result < 0)
+		{
+			log_printf (LOG_ERROR,"While reading data from %s: %m\n",filename);
+			exit (EXIT_FAILURE);
+		}
+		log_printf (LOG_ERROR,"Short read count returned while reading from %s\n",filename);
+		exit (EXIT_FAILURE);
+	}
+}
+
+static void safe_rewind (int fd,const char *filename)
+{
+	if (lseek (fd,0L,SEEK_SET) < 0)
+	{
+		log_printf (LOG_ERROR,"While seeking to start of %s: %m\n",filename);
+		exit (EXIT_FAILURE);
+	}
+}
+
+/******************************************************************************/
+
+static int dev_fd = -1,fil_fd = -1;
+
+static void cleanup (void)
+{
+	if (dev_fd > 0) close (dev_fd);
+	if (fil_fd > 0) close (fil_fd);
+}
+
+int main (int argc,char *argv[])
+{
+	const char *filename = NULL,*device = NULL;
+	int i,flags = FLAG_NONE;
+	ssize_t result;
+	size_t size,written;
+	struct mtd_info_user mtd;
+	struct erase_info_user erase;
+	struct stat filestat;
+	unsigned char src[BUFSIZE],dest[BUFSIZE];
+
+	/*********************
+	 * parse cmd-line
+	 *****************/
+
+	for (;;) {
+		int option_index = 0;
+		static const char *short_options = "hv";
+		static const struct option long_options[] = {
+			{"help", no_argument, 0, 'h'},
+			{"verbose", no_argument, 0, 'v'},
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF) {
+			break;
+		}
+
+		switch (c) {
+			case 'h':
+				flags |= FLAG_HELP;
+				DEBUG("Got FLAG_HELP\n");
+				break;
+			case 'v':
+				flags |= FLAG_VERBOSE;
+				DEBUG("Got FLAG_VERBOSE\n");
+				break;
+			default:
+				DEBUG("Unknown parameter: %s\n",argv[option_index]);
+				showusage(true);
+		}
+	}
+	if (optind+2 == argc) {
+		flags |= FLAG_FILENAME;
+		filename = argv[optind];
+		DEBUG("Got filename: %s\n",filename);
+
+		flags |= FLAG_DEVICE;
+		device = argv[optind+1];
+		DEBUG("Got device: %s\n",device);
+	}
+
+	if (flags & FLAG_HELP || device == NULL)
+		showusage(flags != FLAG_HELP);
+
+	atexit (cleanup);
+
+	/* get some info about the flash device */
+	dev_fd = safe_open (device,O_SYNC | O_RDWR);
+	if (ioctl (dev_fd,MEMGETINFO,&mtd) < 0)
+	{
+		DEBUG("ioctl(): %m\n");
+		log_printf (LOG_ERROR,"This doesn't seem to be a valid MTD flash device!\n");
+		exit (EXIT_FAILURE);
+	}
+
+	/* get some info about the file we want to copy */
+	fil_fd = safe_open (filename,O_RDONLY);
+	if (fstat (fil_fd,&filestat) < 0)
+	{
+		log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename);
+		exit (EXIT_FAILURE);
+	}
+
+	/* does it fit into the device/partition? */
+	if (filestat.st_size > mtd.size)
+	{
+		log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device);
+		exit (EXIT_FAILURE);
+	}
+
+	/*****************************************************
+	 * erase enough blocks so that we can write the file *
+	 *****************************************************/
+
+#warning "Check for smaller erase regions"
+
+	erase.start = 0;
+	erase.length = (filestat.st_size + mtd.erasesize - 1) / mtd.erasesize;
+	erase.length *= mtd.erasesize;
+
+	if (flags & FLAG_VERBOSE)
+	{
+		/* if the user wants verbose output, erase 1 block at a time and show him/her what's going on */
+		int blocks = erase.length / mtd.erasesize;
+		erase.length = mtd.erasesize;
+		log_printf (LOG_NORMAL,"Erasing blocks: 0/%d (0%%)",blocks);
+		for (i = 1; i <= blocks; i++)
+		{
+			log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks));
+			if (ioctl (dev_fd,MEMERASE,&erase) < 0)
+			{
+				log_printf (LOG_NORMAL,"\n");
+				log_printf (LOG_ERROR,
+						"While erasing blocks 0x%.8x-0x%.8x on %s: %m\n",
+						(unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
+				exit (EXIT_FAILURE);
+			}
+			erase.start += mtd.erasesize;
+		}
+		log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (100%%)\n",blocks,blocks);
+	}
+	else
+	{
+		/* if not, erase the whole chunk in one shot */
+		if (ioctl (dev_fd,MEMERASE,&erase) < 0)
+		{
+			log_printf (LOG_ERROR,
+					"While erasing blocks from 0x%.8x-0x%.8x on %s: %m\n",
+					(unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
+			exit (EXIT_FAILURE);
+		}
+	}
+	DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size);
+
+	/**********************************
+	 * write the entire file to flash *
+	 **********************************/
+
+	if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%luk (0%%)",KB (filestat.st_size));
+	size = filestat.st_size;
+	i = BUFSIZE;
+	written = 0;
+	while (size)
+	{
+		if (size < BUFSIZE) i = size;
+		if (flags & FLAG_VERBOSE)
+			log_printf (LOG_NORMAL,"\rWriting data: %dk/%luk (%lu%%)",
+					KB (written + i),
+					KB (filestat.st_size),
+					PERCENTAGE (written + i,filestat.st_size));
+
+		/* read from filename */
+		safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
+
+		/* write to device */
+		result = write (dev_fd,src,i);
+		if (i != result)
+		{
+			if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n");
+			if (result < 0)
+			{
+				log_printf (LOG_ERROR,
+						"While writing data to 0x%.8x-0x%.8x on %s: %m\n",
+						written,written + i,device);
+				exit (EXIT_FAILURE);
+			}
+			log_printf (LOG_ERROR,
+					"Short write count returned while writing to x%.8x-0x%.8x on %s: %d/%lu bytes written to flash\n",
+					written,written + i,device,written + result,filestat.st_size);
+			exit (EXIT_FAILURE);
+		}
+
+		written += i;
+		size -= i;
+	}
+	if (flags & FLAG_VERBOSE)
+		log_printf (LOG_NORMAL,
+				"\rWriting data: %luk/%luk (100%%)\n",
+				KB (filestat.st_size),
+				KB (filestat.st_size));
+	DEBUG("Wrote %d / %luk bytes\n",written,filestat.st_size);
+
+	/**********************************
+	 * verify that flash == file data *
+	 **********************************/
+
+	safe_rewind (fil_fd,filename);
+	safe_rewind (dev_fd,device);
+	size = filestat.st_size;
+	i = BUFSIZE;
+	written = 0;
+	if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%luk (0%%)",KB (filestat.st_size));
+	while (size)
+	{
+		if (size < BUFSIZE) i = size;
+		if (flags & FLAG_VERBOSE)
+			log_printf (LOG_NORMAL,
+					"\rVerifying data: %dk/%luk (%lu%%)",
+					KB (written + i),
+					KB (filestat.st_size),
+					PERCENTAGE (written + i,filestat.st_size));
+
+		/* read from filename */
+		safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
+
+		/* read from device */
+		safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE);
+
+		/* compare buffers */
+		if (memcmp (src,dest,i))
+		{
+			log_printf (LOG_ERROR,
+					"File does not seem to match flash data. First mismatch at 0x%.8x-0x%.8x\n",
+					written,written + i);
+			exit (EXIT_FAILURE);
+		}
+
+		written += i;
+		size -= i;
+	}
+	if (flags & FLAG_VERBOSE)
+		log_printf (LOG_NORMAL,
+				"\rVerifying data: %luk/%luk (100%%)\n",
+				KB (filestat.st_size),
+				KB (filestat.st_size));
+	DEBUG("Verified %d / %luk bytes\n",written,filestat.st_size);
+
+	exit (EXIT_SUCCESS);
+}
diff --git a/flash_erase.c b/flash_erase.c
deleted file mode 100644
index 933373a..0000000
--- a/flash_erase.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/* flash_erase.c -- erase MTD devices
-
-   Copyright (C) 2000 Arcom Control System Ltd
-   Copyright (C) 2010 Mike Frysinger <vapier at gentoo.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; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   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
- */
-
-#define PROGRAM_NAME "flash_erase"
-
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <stdint.h>
-#include <getopt.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-
-#include <common.h>
-#include <crc32.h>
-#include <libmtd.h>
-
-#include <mtd/mtd-user.h>
-#include <mtd/jffs2-user.h>
-
-static const char *mtd_device;
-
-static int quiet;		/* true -- don't output progress */
-static int jffs2;		/* format for jffs2 usage */
-static int noskipbad;		/* do not skip bad blocks */
-static int unlock;		/* unlock sectors before erasing */
-
-static struct jffs2_unknown_node cleanmarker;
-int target_endian = __BYTE_ORDER;
-
-static void show_progress(struct mtd_dev_info *mtd, off_t start, int eb,
-			  int eb_start, int eb_cnt)
-{
-	bareverbose(!quiet, "\rErasing %d Kibyte @ %"PRIxoff_t" -- %2i %% complete ",
-		mtd->eb_size / 1024, start, ((eb - eb_start) * 100) / eb_cnt);
-	fflush(stdout);
-}
-
-static void display_help (void)
-{
-	printf("Usage: %s [options] MTD_DEVICE <start offset> <block count>\n"
-			"Erase blocks of the specified MTD device.\n"
-			"Specify a count of 0 to erase to end of device.\n"
-			"\n"
-			"  -j, --jffs2       format the device for jffs2\n"
-			"  -N, --noskipbad   don't skip bad blocks\n"
-			"  -u, --unlock      unlock sectors before erasing\n"
-			"  -q, --quiet       do not display progress messages\n"
-			"      --silent      same as --quiet\n"
-			"      --help        display this help and exit\n"
-			"      --version     output version information and exit\n",
-			PROGRAM_NAME);
-}
-
-static void display_version (void)
-{
-	printf("%1$s version " VERSION "\n"
-			"\n"
-			"Copyright (C) 2000 Arcom Control Systems Ltd\n"
-			"\n"
-			"%1$s comes with NO WARRANTY\n"
-			"to the extent permitted by law.\n"
-			"\n"
-			"You may redistribute copies of %1$s\n"
-			"under the terms of the GNU General Public Licence.\n"
-			"See the file `COPYING' for more information.\n",
-			PROGRAM_NAME);
-}
-
-int main(int argc, char *argv[])
-{
-	libmtd_t mtd_desc;
-	struct mtd_dev_info mtd;
-	int fd, clmpos = 0, clmlen = 8;
-	unsigned long long start;
-	unsigned int eb, eb_start, eb_cnt;
-	bool isNAND;
-	int error = 0;
-	off_t offset = 0;
-
-	/*
-	 * Process user arguments
-	 */
-	for (;;) {
-		int option_index = 0;
-		static const char *short_options = "jNqu";
-		static const struct option long_options[] = {
-			{"help", no_argument, 0, 0},
-			{"version", no_argument, 0, 0},
-			{"jffs2", no_argument, 0, 'j'},
-			{"noskipbad", no_argument, 0, 'N'},
-			{"quiet", no_argument, 0, 'q'},
-			{"silent", no_argument, 0, 'q'},
-			{"unlock", no_argument, 0, 'u'},
-
-			{0, 0, 0, 0},
-		};
-
-		int c = getopt_long(argc, argv, short_options,
-				long_options, &option_index);
-		if (c == EOF)
-			break;
-
-		switch (c) {
-		case 0:
-			switch (option_index) {
-			case 0:
-				display_help();
-				return 0;
-			case 1:
-				display_version();
-				return 0;
-			}
-			break;
-		case 'j':
-			jffs2 = 1;
-			break;
-		case 'N':
-			noskipbad = 1;
-			break;
-		case 'q':
-			quiet = 1;
-			break;
-		case 'u':
-			unlock = 1;
-			break;
-		case '?':
-			error = 1;
-			break;
-		}
-	}
-	switch (argc - optind) {
-	case 3:
-		mtd_device = argv[optind];
-		start = simple_strtoull(argv[optind + 1], &error);
-		eb_cnt = simple_strtoul(argv[optind + 2], &error);
-		break;
-	default:
-	case 0:
-		errmsg("no MTD device specified");
-	case 1:
-		errmsg("no start erase block specified");
-	case 2:
-		errmsg("no erase block count specified");
-		error = 1;
-		break;
-	}
-	if (error)
-		return errmsg("Try `--help' for more information");
-
-	/*
-	 * Locate MTD and prepare for erasure
-	 */
-	mtd_desc = libmtd_open();
-	if (mtd_desc == NULL)
-		return errmsg("can't initialize libmtd");
-
-	if ((fd = open(mtd_device, O_RDWR)) < 0)
-		return sys_errmsg("%s", mtd_device);
-
-	if (mtd_get_dev_info(mtd_desc, mtd_device, &mtd) < 0)
-		return errmsg("mtd_get_dev_info failed");
-
-	if (jffs2 && mtd.type == MTD_MLCNANDFLASH)
-		return errmsg("JFFS2 cannot support MLC NAND.");
-
-	eb_start = start / mtd.eb_size;
-
-	isNAND = mtd.type == MTD_NANDFLASH || mtd.type == MTD_MLCNANDFLASH;
-
-	if (jffs2) {
-		cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
-		cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
-		if (!isNAND)
-			cleanmarker.totlen = cpu_to_je32(sizeof(cleanmarker));
-		else {
-			struct nand_oobinfo oobinfo;
-
-			if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0)
-				return sys_errmsg("%s: unable to get NAND oobinfo", mtd_device);
-
-			/* Check for autoplacement */
-			if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
-				/* Get the position of the free bytes */
-				if (!oobinfo.oobfree[0][1])
-					return errmsg(" Eeep. Autoplacement selected and no empty space in oob");
-				clmpos = oobinfo.oobfree[0][0];
-				clmlen = oobinfo.oobfree[0][1];
-				if (clmlen > 8)
-					clmlen = 8;
-			} else {
-				/* Legacy mode */
-				switch (mtd.oob_size) {
-					case 8:
-						clmpos = 6;
-						clmlen = 2;
-						break;
-					case 16:
-						clmpos = 8;
-						clmlen = 8;
-						break;
-					case 64:
-						clmpos = 16;
-						clmlen = 8;
-						break;
-				}
-			}
-			cleanmarker.totlen = cpu_to_je32(8);
-		}
-		cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(cleanmarker) - 4));
-	}
-
-	/*
-	 * Now do the actual erasing of the MTD device
-	 */
-	if (eb_cnt == 0)
-		eb_cnt = (mtd.size / mtd.eb_size) - eb_start;
-
-	for (eb = eb_start; eb < eb_start + eb_cnt; eb++) {
-		offset = (off_t)eb * mtd.eb_size;
-
-		if (!noskipbad) {
-			int ret = mtd_is_bad(&mtd, fd, eb);
-			if (ret > 0) {
-				verbose(!quiet, "Skipping bad block at %08"PRIxoff_t, offset);
-				continue;
-			} else if (ret < 0) {
-				if (errno == EOPNOTSUPP) {
-					noskipbad = 1;
-					if (isNAND)
-						return errmsg("%s: Bad block check not available", mtd_device);
-				} else
-					return sys_errmsg("%s: MTD get bad block failed", mtd_device);
-			}
-		}
-
-		show_progress(&mtd, offset, eb, eb_start, eb_cnt);
-
-		if (unlock) {
-			if (mtd_unlock(&mtd, fd, eb) != 0) {
-				sys_errmsg("%s: MTD unlock failure", mtd_device);
-				continue;
-			}
-		}
-
-		if (mtd_erase(mtd_desc, &mtd, fd, eb) != 0) {
-			sys_errmsg("%s: MTD Erase failure", mtd_device);
-			continue;
-		}
-
-		/* format for JFFS2 ? */
-		if (!jffs2)
-			continue;
-
-		/* write cleanmarker */
-		if (isNAND) {
-			if (mtd_write_oob(mtd_desc, &mtd, fd, (uint64_t)offset + clmpos, clmlen, &cleanmarker) != 0) {
-				sys_errmsg("%s: MTD writeoob failure", mtd_device);
-				continue;
-			}
-		} else {
-			if (pwrite(fd, &cleanmarker, sizeof(cleanmarker), (loff_t)offset) != sizeof(cleanmarker)) {
-				sys_errmsg("%s: MTD write failure", mtd_device);
-				continue;
-			}
-		}
-		verbose(!quiet, " Cleanmarker written at %"PRIxoff_t, offset);
-	}
-	show_progress(&mtd, offset, eb, eb_start, eb_cnt);
-	bareverbose(!quiet, "\n");
-
-	return 0;
-}
diff --git a/flash_eraseall b/flash_eraseall
deleted file mode 100755
index c5539b3..0000000
--- a/flash_eraseall
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-echo "${0##*/} has been replaced by \`flash_erase <mtddev> 0 0\`; please use it" 1>&2
-[ $# -ne 0 ] && set -- "$@" 0 0
-exec flash_erase "$@"
diff --git a/flash_lock.c b/flash_lock.c
deleted file mode 100644
index 33f76c7..0000000
--- a/flash_lock.c
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * flash_{lock,unlock}
- *
- * utilities for locking/unlocking sectors of flash devices
- */
-
-#define PROGRAM_NAME "flash_lock"
-#include "flash_unlock.c"
diff --git a/flash_otp_dump.c b/flash_otp_dump.c
deleted file mode 100644
index f0c0fb9..0000000
--- a/flash_otp_dump.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * flash_otp_dump.c -- display One-Time-Programm data
- */
-
-#define PROGRAM_NAME "flash_otp_dump"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-
-#include <mtd/mtd-user.h>
-
-int main(int argc,char *argv[])
-{
-	int fd, val, i, offset, ret;
-	unsigned char buf[16];
-
-	if (argc != 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) {
-		fprintf(stderr,"Usage: %s [ -f | -u ] <device>\n", PROGRAM_NAME);
-		return EINVAL;
-	}
-
-	fd = open(argv[2], O_RDONLY);
-	if (fd < 0) {
-		perror(argv[2]);
-		return errno;
-	}
-
-	val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER;
-	ret = ioctl(fd, OTPSELECT, &val);
-	if (ret < 0) {
-		perror("OTPSELECT");
-		return errno;
-	}
-
-	printf("OTP %s data for %s\n",
-			argv[1][1] == 'f' ? "factory" : "user", argv[2]);
-	offset = 0;
-	while ((ret = read(fd, buf, sizeof(buf)))) {
-		if (ret < 0) {
-			perror("read()");
-			return errno;
-		}
-		printf("0x%04x:", offset);
-		for (i = 0; i < ret; i++)
-			printf(" %02x", buf[i]);
-		printf("\n");
-		offset += ret;
-	}
-
-	close(fd);
-	return 0;
-}
diff --git a/flash_otp_info.c b/flash_otp_info.c
deleted file mode 100644
index 2061797..0000000
--- a/flash_otp_info.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * flash_otp_info.c -- print info about One-Time-Programm data
- */
-
-#define PROGRAM_NAME "flash_otp_info"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-
-#include <mtd/mtd-user.h>
-
-int main(int argc,char *argv[])
-{
-	int fd, val, i, ret;
-
-	if (argc != 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) {
-		fprintf(stderr,"Usage: %s [ -f | -u ] <device>\n", PROGRAM_NAME);
-		return EINVAL;
-	}
-
-	fd = open(argv[2], O_RDONLY);
-	if (fd < 0) {
-		perror(argv[2]);
-		return errno;
-	}
-
-	val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER;
-	ret = ioctl(fd, OTPSELECT, &val);
-	if (ret < 0) {
-		perror("OTPSELECT");
-		return errno;
-	}
-
-	ret = ioctl(fd, OTPGETREGIONCOUNT, &val);
-	if (ret < 0) {
-		perror("OTPGETREGIONCOUNT");
-		return errno;
-	}
-
-	printf("Number of OTP %s blocks on %s: %d\n",
-			argv[1][1] == 'f' ? "factory" : "user", argv[2], val);
-
-	if (val > 0) {
-		struct otp_info info[val];
-
-		ret = ioctl(fd, OTPGETREGIONINFO, &info);
-		if (ret	< 0) {
-			perror("OTPGETREGIONCOUNT");
-			return errno;
-		}
-
-		for (i = 0; i < val; i++)
-			printf("block %2d:  offset = 0x%04x  "
-					"size = %2d bytes  %s\n",
-					i, info[i].start, info[i].length,
-					info[i].locked ? "[locked]" : "[unlocked]");
-	}
-
-	close(fd);
-	return 0;
-}
diff --git a/flash_otp_lock.c b/flash_otp_lock.c
deleted file mode 100644
index 3c39a2d..0000000
--- a/flash_otp_lock.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * flash_otp_lock.c -- lock area of One-Time-Program data
- */
-
-#define PROGRAM_NAME "flash_otp_lock"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-
-#include <mtd/mtd-user.h>
-#include "common.h"
-
-int main(int argc,char *argv[])
-{
-	int fd, val, ret, offset, size;
-	char *p;
-
-	if (argc != 5 || strcmp(argv[1], "-u")) {
-		fprintf(stderr, "Usage: %s -u <device> <offset> <size>\n", PROGRAM_NAME);
-		fprintf(stderr, "offset and size must match on OTP region boundaries\n");
-		fprintf(stderr, "CAUTION! ONCE LOCKED, OTP REGIONS CAN'T BE UNLOCKED!\n");
-		return EINVAL;
-	}
-
-	fd = open(argv[2], O_WRONLY);
-	if (fd < 0) {
-		perror(argv[2]);
-		return errno;
-	}
-
-	val = MTD_OTP_USER;
-	ret = ioctl(fd, OTPSELECT, &val);
-	if (ret < 0) {
-		perror("OTPSELECT");
-		return errno;
-	}
-
-	offset = strtoul(argv[3], &p, 0);
-	if (argv[3][0] == 0 || *p != 0) {
-		fprintf(stderr, "%s: bad offset value\n", PROGRAM_NAME);
-		return ERANGE;
-	}
-
-	size = strtoul(argv[4], &p, 0);
-	if (argv[4][0] == 0 || *p != 0) {
-		fprintf(stderr, "%s: bad size value\n", PROGRAM_NAME);
-		return ERANGE;
-	}
-
-	printf("About to lock OTP user data on %s from 0x%x to 0x%x\n",
-			argv[2], offset, offset + size);
-	if (prompt("Are you sure?", false)) {
-		struct otp_info info;
-		info.start = offset;
-		info.length = size;
-		ret = ioctl(fd, OTPLOCK, &info);
-		if (ret	< 0) {
-			perror("OTPLOCK");
-			return errno;
-		}
-		printf("Done.\n");
-	} else {
-		printf("Aborted\n");
-	}
-
-	return 0;
-}
diff --git a/flash_otp_write.c b/flash_otp_write.c
deleted file mode 100644
index 111318d..0000000
--- a/flash_otp_write.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * flash_otp_write.c -- write One-Time-Program data
- */
-
-#define PROGRAM_NAME "flash_otp_write"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-
-#include <common.h>
-#include <mtd/mtd-user.h>
-
-ssize_t xread(int fd, void *buf, size_t count)
-{
-	ssize_t ret, done = 0;
-
-retry:
-	ret = read(fd, buf + done, count - done);
-	if (ret < 0)
-		return ret;
-
-	done += ret;
-
-	if (ret == 0 /* EOF */ || done == count)
-		return done;
-	else
-		goto retry;
-}
-
-int main(int argc,char *argv[])
-{
-	int fd, val, ret, size, wrote, len;
-	mtd_info_t mtdInfo;
-	off_t offset;
-	char *p, buf[2048];
-
-	if (argc != 4 || strcmp(argv[1], "-u")) {
-		fprintf(stderr, "Usage: %s -u <device> <offset>\n", PROGRAM_NAME);
-		fprintf(stderr, "the raw data to write should be provided on stdin\n");
-		fprintf(stderr, "CAUTION! ONCE SET TO 0, OTP DATA BITS CAN'T BE ERASED!\n");
-		return EINVAL;
-	}
-
-	fd = open(argv[2], O_WRONLY);
-	if (fd < 0) {
-		perror(argv[2]);
-		return errno;
-	}
-
-	val = MTD_OTP_USER;
-	ret = ioctl(fd, OTPSELECT, &val);
-	if (ret < 0) {
-		perror("OTPSELECT");
-		return errno;
-	}
-
-	if (ioctl(fd, MEMGETINFO, &mtdInfo)) {
-		perror("MEMGETINFO");
-		return errno;
-	}
-
-	offset = (off_t)strtoull(argv[3], &p, 0);
-	if (argv[3][0] == 0 || *p != 0) {
-		fprintf(stderr, "%s: bad offset value\n", PROGRAM_NAME);
-		return ERANGE;
-	}
-
-	if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
-		perror("lseek()");
-		return errno;
-	}
-
-	printf("Writing OTP user data on %s at offset 0x%"PRIxoff_t"\n", argv[2], offset);
-
-	if (mtd_type_is_nand_user(&mtdInfo))
-		len = mtdInfo.writesize;
-	else
-		len = 256;
-
-	if (len > sizeof(buf)) {
-		printf("huh, writesize (%d) bigger than buffer (%zu)\n",
-				len, sizeof(buf));
-		return ENOMEM;
-	}
-
-	wrote = 0;
-	while ((size = xread(0, buf, len))) {
-		if (size < 0) {
-			perror("read()");
-			return errno;
-		}
-		p = buf;
-		while (size > 0) {
-			if (mtd_type_is_nand_user(&mtdInfo)) {
-				/* Fill remain buffers with 0xff */
-				memset(buf + size, 0xff, mtdInfo.writesize - size);
-				size = mtdInfo.writesize;
-			}
-			ret = write(fd, p, size);
-			if (ret < 0) {
-				perror("write()");
-				return errno;
-			}
-			if (ret == 0) {
-				printf("write() returned 0 after writing %d bytes\n", wrote);
-				return 0;
-			}
-			p += ret;
-			wrote += ret;
-			size -= ret;
-		}
-	}
-
-	printf("Wrote %d bytes of OTP user data\n", wrote);
-	return 0;
-}
diff --git a/flash_unlock.c b/flash_unlock.c
deleted file mode 100644
index 1cc8c2f..0000000
--- a/flash_unlock.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * flash_{lock,unlock}
- *
- * utilities for locking/unlocking sectors of flash devices
- */
-
-#ifndef PROGRAM_NAME
-#define PROGRAM_NAME "flash_unlock"
-#define FLASH_MSG    "unlock"
-#define FLASH_UNLOCK 1
-#else
-#define FLASH_MSG    "lock"
-#define FLASH_UNLOCK 0
-#endif
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/ioctl.h>
-#include <sys/mount.h>
-#include <string.h>
-
-#include "common.h"
-#include <mtd/mtd-user.h>
-
-static void usage(int status)
-{
-	fprintf(status ? stderr : stdout,
-		"Usage: %s <mtd device> [offset] [block count]\n\n"
-		"If offset is not specified, it defaults to 0.\n"
-		"If block count is not specified, it defaults to all blocks.\n",
-		PROGRAM_NAME);
-	exit(status);
-}
-
-int main(int argc, char *argv[])
-{
-	int fd, request;
-	struct mtd_info_user mtdInfo;
-	struct erase_info_user mtdLockInfo;
-	int count;
-	const char *dev;
-
-	/* Parse command line options */
-	if (argc < 2 || argc > 4)
-		usage(1);
-	if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
-		usage(0);
-
-	dev = argv[1];
-
-	/* Get the device info to compare to command line sizes */
-	fd = open(dev, O_RDWR);
-	if (fd < 0)
-		sys_errmsg_die("could not open: %s", dev);
-
-	if (ioctl(fd, MEMGETINFO, &mtdInfo))
-		sys_errmsg_die("could not get mtd info: %s", dev);
-
-	/* Make sure user options are valid */
-	if (argc > 2)
-		mtdLockInfo.start = strtol(argv[2], NULL, 0);
-	else
-		mtdLockInfo.start = 0;
-	if (mtdLockInfo.start > mtdInfo.size)
-		errmsg_die("%#x is beyond device size %#x",
-			mtdLockInfo.start, mtdInfo.size);
-
-	if (argc > 3) {
-		count = strtol(argv[3], NULL, 0);
-		if (count == -1)
-			mtdLockInfo.length = mtdInfo.size;
-		else
-			mtdLockInfo.length = mtdInfo.erasesize * count;
-	} else
-		mtdLockInfo.length = mtdInfo.size;
-	if (mtdLockInfo.start + mtdLockInfo.length > mtdInfo.size)
-		errmsg_die("range is more than device supports: %#x + %#x > %#x",
-			mtdLockInfo.start, mtdLockInfo.length, mtdInfo.size);
-
-	/* Finally do the operation */
-	request = FLASH_UNLOCK ? MEMUNLOCK : MEMLOCK;
-	if (ioctl(fd, request, &mtdLockInfo))
-		sys_errmsg_die("could not %s device: %s\n",
-			FLASH_MSG, dev);
-
-	return 0;
-}
diff --git a/flashcp.c b/flashcp.c
deleted file mode 100644
index 86334ac..0000000
--- a/flashcp.c
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (c) 2d3D, Inc.
- * Written by Abraham vd Merwe <abraham at 2d3d.co.za>
- * All rights reserved.
- *
- * Renamed to flashcp.c to avoid conflicts with fcp from fsh package
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *	  notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *	  notice, this list of conditions and the following disclaimer in the
- *	  documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the names of other contributors
- *	  may be used to endorse or promote products derived from this software
- *	  without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define PROGRAM_NAME "flashcp"
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <mtd/mtd-user.h>
-#include <getopt.h>
-
-typedef int bool;
-#define true 1
-#define false 0
-
-#define EXIT_FAILURE 1
-#define EXIT_SUCCESS 0
-
-/* for debugging purposes only */
-#ifdef DEBUG
-#undef DEBUG
-#define DEBUG(fmt,args...) { log_printf (LOG_ERROR,"%d: ",__LINE__); log_printf (LOG_ERROR,fmt,## args); }
-#else
-#undef DEBUG
-#define DEBUG(fmt,args...)
-#endif
-
-#define KB(x) ((x) / 1024)
-#define PERCENTAGE(x,total) (((x) * 100) / (total))
-
-/* size of read/write buffer */
-#define BUFSIZE (10 * 1024)
-
-/* cmd-line flags */
-#define FLAG_NONE		0x00
-#define FLAG_VERBOSE	0x01
-#define FLAG_HELP		0x02
-#define FLAG_FILENAME	0x04
-#define FLAG_DEVICE		0x08
-
-/* error levels */
-#define LOG_NORMAL	1
-#define LOG_ERROR	2
-
-static void log_printf (int level,const char *fmt, ...)
-{
-	FILE *fp = level == LOG_NORMAL ? stdout : stderr;
-	va_list ap;
-	va_start (ap,fmt);
-	vfprintf (fp,fmt,ap);
-	va_end (ap);
-	fflush (fp);
-}
-
-static void showusage(bool error)
-{
-	int level = error ? LOG_ERROR : LOG_NORMAL;
-
-	log_printf (level,
-			"\n"
-			"Flash Copy - Written by Abraham van der Merwe <abraham at 2d3d.co.za>\n"
-			"\n"
-			"usage: %1$s [ -v | --verbose ] <filename> <device>\n"
-			"       %1$s -h | --help\n"
-			"\n"
-			"   -h | --help      Show this help message\n"
-			"   -v | --verbose   Show progress reports\n"
-			"   <filename>       File which you want to copy to flash\n"
-			"   <device>         Flash device to write to (e.g. /dev/mtd0, /dev/mtd1, etc.)\n"
-			"\n",
-			PROGRAM_NAME);
-
-	exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
-}
-
-static int safe_open (const char *pathname,int flags)
-{
-	int fd;
-
-	fd = open (pathname,flags);
-	if (fd < 0)
-	{
-		log_printf (LOG_ERROR,"While trying to open %s",pathname);
-		if (flags & O_RDWR)
-			log_printf (LOG_ERROR," for read/write access");
-		else if (flags & O_RDONLY)
-			log_printf (LOG_ERROR," for read access");
-		else if (flags & O_WRONLY)
-			log_printf (LOG_ERROR," for write access");
-		log_printf (LOG_ERROR,": %m\n");
-		exit (EXIT_FAILURE);
-	}
-
-	return (fd);
-}
-
-static void safe_read (int fd,const char *filename,void *buf,size_t count,bool verbose)
-{
-	ssize_t result;
-
-	result = read (fd,buf,count);
-	if (count != result)
-	{
-		if (verbose) log_printf (LOG_NORMAL,"\n");
-		if (result < 0)
-		{
-			log_printf (LOG_ERROR,"While reading data from %s: %m\n",filename);
-			exit (EXIT_FAILURE);
-		}
-		log_printf (LOG_ERROR,"Short read count returned while reading from %s\n",filename);
-		exit (EXIT_FAILURE);
-	}
-}
-
-static void safe_rewind (int fd,const char *filename)
-{
-	if (lseek (fd,0L,SEEK_SET) < 0)
-	{
-		log_printf (LOG_ERROR,"While seeking to start of %s: %m\n",filename);
-		exit (EXIT_FAILURE);
-	}
-}
-
-/******************************************************************************/
-
-static int dev_fd = -1,fil_fd = -1;
-
-static void cleanup (void)
-{
-	if (dev_fd > 0) close (dev_fd);
-	if (fil_fd > 0) close (fil_fd);
-}
-
-int main (int argc,char *argv[])
-{
-	const char *filename = NULL,*device = NULL;
-	int i,flags = FLAG_NONE;
-	ssize_t result;
-	size_t size,written;
-	struct mtd_info_user mtd;
-	struct erase_info_user erase;
-	struct stat filestat;
-	unsigned char src[BUFSIZE],dest[BUFSIZE];
-
-	/*********************
-	 * parse cmd-line
-	 *****************/
-
-	for (;;) {
-		int option_index = 0;
-		static const char *short_options = "hv";
-		static const struct option long_options[] = {
-			{"help", no_argument, 0, 'h'},
-			{"verbose", no_argument, 0, 'v'},
-			{0, 0, 0, 0},
-		};
-
-		int c = getopt_long(argc, argv, short_options,
-				long_options, &option_index);
-		if (c == EOF) {
-			break;
-		}
-
-		switch (c) {
-			case 'h':
-				flags |= FLAG_HELP;
-				DEBUG("Got FLAG_HELP\n");
-				break;
-			case 'v':
-				flags |= FLAG_VERBOSE;
-				DEBUG("Got FLAG_VERBOSE\n");
-				break;
-			default:
-				DEBUG("Unknown parameter: %s\n",argv[option_index]);
-				showusage(true);
-		}
-	}
-	if (optind+2 == argc) {
-		flags |= FLAG_FILENAME;
-		filename = argv[optind];
-		DEBUG("Got filename: %s\n",filename);
-
-		flags |= FLAG_DEVICE;
-		device = argv[optind+1];
-		DEBUG("Got device: %s\n",device);
-	}
-
-	if (flags & FLAG_HELP || device == NULL)
-		showusage(flags != FLAG_HELP);
-
-	atexit (cleanup);
-
-	/* get some info about the flash device */
-	dev_fd = safe_open (device,O_SYNC | O_RDWR);
-	if (ioctl (dev_fd,MEMGETINFO,&mtd) < 0)
-	{
-		DEBUG("ioctl(): %m\n");
-		log_printf (LOG_ERROR,"This doesn't seem to be a valid MTD flash device!\n");
-		exit (EXIT_FAILURE);
-	}
-
-	/* get some info about the file we want to copy */
-	fil_fd = safe_open (filename,O_RDONLY);
-	if (fstat (fil_fd,&filestat) < 0)
-	{
-		log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename);
-		exit (EXIT_FAILURE);
-	}
-
-	/* does it fit into the device/partition? */
-	if (filestat.st_size > mtd.size)
-	{
-		log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device);
-		exit (EXIT_FAILURE);
-	}
-
-	/*****************************************************
-	 * erase enough blocks so that we can write the file *
-	 *****************************************************/
-
-#warning "Check for smaller erase regions"
-
-	erase.start = 0;
-	erase.length = (filestat.st_size + mtd.erasesize - 1) / mtd.erasesize;
-	erase.length *= mtd.erasesize;
-
-	if (flags & FLAG_VERBOSE)
-	{
-		/* if the user wants verbose output, erase 1 block at a time and show him/her what's going on */
-		int blocks = erase.length / mtd.erasesize;
-		erase.length = mtd.erasesize;
-		log_printf (LOG_NORMAL,"Erasing blocks: 0/%d (0%%)",blocks);
-		for (i = 1; i <= blocks; i++)
-		{
-			log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks));
-			if (ioctl (dev_fd,MEMERASE,&erase) < 0)
-			{
-				log_printf (LOG_NORMAL,"\n");
-				log_printf (LOG_ERROR,
-						"While erasing blocks 0x%.8x-0x%.8x on %s: %m\n",
-						(unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
-				exit (EXIT_FAILURE);
-			}
-			erase.start += mtd.erasesize;
-		}
-		log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (100%%)\n",blocks,blocks);
-	}
-	else
-	{
-		/* if not, erase the whole chunk in one shot */
-		if (ioctl (dev_fd,MEMERASE,&erase) < 0)
-		{
-			log_printf (LOG_ERROR,
-					"While erasing blocks from 0x%.8x-0x%.8x on %s: %m\n",
-					(unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
-			exit (EXIT_FAILURE);
-		}
-	}
-	DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size);
-
-	/**********************************
-	 * write the entire file to flash *
-	 **********************************/
-
-	if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%luk (0%%)",KB (filestat.st_size));
-	size = filestat.st_size;
-	i = BUFSIZE;
-	written = 0;
-	while (size)
-	{
-		if (size < BUFSIZE) i = size;
-		if (flags & FLAG_VERBOSE)
-			log_printf (LOG_NORMAL,"\rWriting data: %dk/%luk (%lu%%)",
-					KB (written + i),
-					KB (filestat.st_size),
-					PERCENTAGE (written + i,filestat.st_size));
-
-		/* read from filename */
-		safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
-
-		/* write to device */
-		result = write (dev_fd,src,i);
-		if (i != result)
-		{
-			if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n");
-			if (result < 0)
-			{
-				log_printf (LOG_ERROR,
-						"While writing data to 0x%.8x-0x%.8x on %s: %m\n",
-						written,written + i,device);
-				exit (EXIT_FAILURE);
-			}
-			log_printf (LOG_ERROR,
-					"Short write count returned while writing to x%.8x-0x%.8x on %s: %d/%lu bytes written to flash\n",
-					written,written + i,device,written + result,filestat.st_size);
-			exit (EXIT_FAILURE);
-		}
-
-		written += i;
-		size -= i;
-	}
-	if (flags & FLAG_VERBOSE)
-		log_printf (LOG_NORMAL,
-				"\rWriting data: %luk/%luk (100%%)\n",
-				KB (filestat.st_size),
-				KB (filestat.st_size));
-	DEBUG("Wrote %d / %luk bytes\n",written,filestat.st_size);
-
-	/**********************************
-	 * verify that flash == file data *
-	 **********************************/
-
-	safe_rewind (fil_fd,filename);
-	safe_rewind (dev_fd,device);
-	size = filestat.st_size;
-	i = BUFSIZE;
-	written = 0;
-	if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%luk (0%%)",KB (filestat.st_size));
-	while (size)
-	{
-		if (size < BUFSIZE) i = size;
-		if (flags & FLAG_VERBOSE)
-			log_printf (LOG_NORMAL,
-					"\rVerifying data: %dk/%luk (%lu%%)",
-					KB (written + i),
-					KB (filestat.st_size),
-					PERCENTAGE (written + i,filestat.st_size));
-
-		/* read from filename */
-		safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
-
-		/* read from device */
-		safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE);
-
-		/* compare buffers */
-		if (memcmp (src,dest,i))
-		{
-			log_printf (LOG_ERROR,
-					"File does not seem to match flash data. First mismatch at 0x%.8x-0x%.8x\n",
-					written,written + i);
-			exit (EXIT_FAILURE);
-		}
-
-		written += i;
-		size -= i;
-	}
-	if (flags & FLAG_VERBOSE)
-		log_printf (LOG_NORMAL,
-				"\rVerifying data: %luk/%luk (100%%)\n",
-				KB (filestat.st_size),
-				KB (filestat.st_size));
-	DEBUG("Verified %d / %luk bytes\n",written,filestat.st_size);
-
-	exit (EXIT_SUCCESS);
-}
diff --git a/ftl_check.c b/ftl_check.c
deleted file mode 100644
index 0eada8f..0000000
--- a/ftl_check.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/* Ported to MTD system.
- * Based on:
- */
-/*======================================================================
-
-  Utility to create an FTL partition in a memory region
-
-  ftl_check.c 1.10 1999/10/25 20:01:35
-
-  The contents of this file are subject to the Mozilla Public
-  License Version 1.1 (the "License"); you may not use this file
-  except in compliance with the License. You may obtain a copy of
-  the License at http://www.mozilla.org/MPL/
-
-  Software distributed under the License is distributed on an "AS
-  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  implied. See the License for the specific language governing
-  rights and limitations under the License.
-
-  The initial developer of the original code is David A. Hinds
-  <dhinds at pcmcia.sourceforge.org>.  Portions created by David A. Hinds
-  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-
-  Alternatively, the contents of this file may be used under the
-  terms of the GNU Public License version 2 (the "GPL"), in which
-  case the provisions of the GPL are applicable instead of the
-  above.  If you wish to allow the use of your version of this file
-  only under the terms of the GPL and not to allow others to use
-  your version of this file under the MPL, indicate your decision
-  by deleting the provisions above and replace them with the notice
-  and other provisions required by the GPL.  If you do not delete
-  the provisions above, a recipient may use your version of this
-  file under either the MPL or the GPL.
-
-  ======================================================================*/
-
-#define PROGRAM_NAME "ftl_check"
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-
-#include <mtd/mtd-user.h>
-#include <mtd/ftl-user.h>
-#include <mtd_swab.h>
-
-#include "common.h"
-
-/*====================================================================*/
-
-static void print_size(u_int s)
-{
-	if ((s > 0x100000) && ((s % 0x100000) == 0))
-		printf("%d mb", s / 0x100000);
-	else if ((s > 0x400) && ((s % 0x400) == 0))
-		printf("%d kb", s / 0x400);
-	else
-		printf("%d bytes", s);
-}
-
-/*====================================================================*/
-
-static void check_partition(int fd)
-{
-	mtd_info_t mtd;
-	erase_unit_header_t hdr, hdr2;
-	off_t i;
-	u_int j, nbam, *bam;
-	int control, data, free, deleted;
-
-	/* Get partition size, block size */
-	if (ioctl(fd, MEMGETINFO, &mtd) != 0) {
-		perror("get info failed");
-		return;
-	}
-
-	printf("Memory region info:\n");
-	printf("  Region size = ");
-	print_size(mtd.size);
-	printf("  Erase block size = ");
-	print_size(mtd.erasesize);
-	printf("\n\n");
-
-	for (i = 0; i < mtd.size/mtd.erasesize; i++) {
-		if (lseek(fd, (i * mtd.erasesize), SEEK_SET) == -1) {
-			perror("seek failed");
-			break;
-		}
-		read(fd, &hdr, sizeof(hdr));
-		if ((le32_to_cpu(hdr.FormattedSize) > 0) &&
-				(le32_to_cpu(hdr.FormattedSize) <= mtd.size) &&
-				(le16_to_cpu(hdr.NumEraseUnits) > 0) &&
-				(le16_to_cpu(hdr.NumEraseUnits) <= mtd.size/mtd.erasesize))
-			break;
-	}
-	if (i == mtd.size/mtd.erasesize) {
-		fprintf(stderr, "No valid erase unit headers!\n");
-		return;
-	}
-
-	printf("Partition header:\n");
-	printf("  Formatted size = ");
-	print_size(le32_to_cpu(hdr.FormattedSize));
-	printf(", erase units = %d, transfer units = %d\n",
-			le16_to_cpu(hdr.NumEraseUnits), hdr.NumTransferUnits);
-	printf("  Erase unit size = ");
-	print_size(1 << hdr.EraseUnitSize);
-	printf(", virtual block size = ");
-	print_size(1 << hdr.BlockSize);
-	printf("\n");
-
-	/* Create basic block allocation table for control blocks */
-	nbam = (mtd.erasesize >> hdr.BlockSize);
-	bam = malloc(nbam * sizeof(u_int));
-
-	for (i = 0; i < le16_to_cpu(hdr.NumEraseUnits); i++) {
-		if (lseek(fd, (i << hdr.EraseUnitSize), SEEK_SET) == -1) {
-			perror("seek failed");
-			break;
-		}
-		if (read(fd, &hdr2, sizeof(hdr2)) == -1) {
-			perror("read failed");
-			break;
-		}
-		printf("\nErase unit %"PRIdoff_t":\n", i);
-		if ((hdr2.FormattedSize != hdr.FormattedSize) ||
-				(hdr2.NumEraseUnits != hdr.NumEraseUnits) ||
-				(hdr2.SerialNumber != hdr.SerialNumber))
-			printf("  Erase unit header is corrupt.\n");
-		else if (le16_to_cpu(hdr2.LogicalEUN) == 0xffff)
-			printf("  Transfer unit, erase count = %d\n", le32_to_cpu(hdr2.EraseCount));
-		else {
-			printf("  Logical unit %d, erase count = %d\n",
-					le16_to_cpu(hdr2.LogicalEUN), le32_to_cpu(hdr2.EraseCount));
-			if (lseek(fd, (i << hdr.EraseUnitSize)+le32_to_cpu(hdr.BAMOffset),
-						SEEK_SET) == -1) {
-				perror("seek failed");
-				break;
-			}
-			if (read(fd, bam, nbam * sizeof(u_int)) == -1) {
-				perror("read failed");
-				break;
-			}
-			free = deleted = control = data = 0;
-			for (j = 0; j < nbam; j++) {
-				if (BLOCK_FREE(le32_to_cpu(bam[j])))
-					free++;
-				else if (BLOCK_DELETED(le32_to_cpu(bam[j])))
-					deleted++;
-				else switch (BLOCK_TYPE(le32_to_cpu(bam[j]))) {
-					case BLOCK_CONTROL: control++; break;
-					case BLOCK_DATA: data++; break;
-					default: break;
-				}
-			}
-			printf("  Block allocation: %d control, %d data, %d free,"
-					" %d deleted\n", control, data, free, deleted);
-		}
-	}
-} /* format_partition */
-
-/* Show usage information */
-void showusage(void)
-{
-	fprintf(stderr, "usage: %s device\n", PROGRAM_NAME);
-}
-
-/*====================================================================*/
-
-int main(int argc, char *argv[])
-{
-	int optch, errflg, fd;
-	struct stat buf;
-
-	errflg = 0;
-	while ((optch = getopt(argc, argv, "h")) != -1) {
-		switch (optch) {
-			case 'h':
-				errflg = 1; break;
-			default:
-				errflg = -1; break;
-		}
-	}
-	if (errflg || (optind != argc-1)) {
-		showusage();
-		exit(errflg > 0 ? 0 : EXIT_FAILURE);
-	}
-
-	if (stat(argv[optind], &buf) != 0) {
-		perror("status check failed");
-		exit(EXIT_FAILURE);
-	}
-	if (!(buf.st_mode & S_IFCHR)) {
-		fprintf(stderr, "%s is not a character special device\n",
-				argv[optind]);
-		exit(EXIT_FAILURE);
-	}
-	fd = open(argv[optind], O_RDONLY);
-	if (fd == -1) {
-		perror("open failed");
-		exit(EXIT_FAILURE);
-	}
-
-	check_partition(fd);
-	close(fd);
-
-	exit(EXIT_SUCCESS);
-	return 0;
-}
diff --git a/ftl_format.c b/ftl_format.c
deleted file mode 100644
index b58677f..0000000
--- a/ftl_format.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/* Ported to MTD system.
- * Based on:
- */
-/*======================================================================
-
-  Utility to create an FTL partition in a memory region
-
-  ftl_format.c 1.13 1999/10/25 20:01:35
-
-  The contents of this file are subject to the Mozilla Public
-  License Version 1.1 (the "License"); you may not use this file
-  except in compliance with the License. You may obtain a copy of
-  the License at http://www.mozilla.org/MPL/
-
-  Software distributed under the License is distributed on an "AS
-  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  implied. See the License for the specific language governing
-  rights and limitations under the License.
-
-  The initial developer of the original code is David A. Hinds
-  <dhinds at pcmcia.sourceforge.org>.  Portions created by David A. Hinds
-  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-
-  Alternatively, the contents of this file may be used under the
-  terms of the GNU Public License version 2 (the "GPL"), in which
-  case the provisions of the GPL are applicable instead of the
-  above.  If you wish to allow the use of your version of this file
-  only under the terms of the GPL and not to allow others to use
-  your version of this file under the MPL, indicate your decision
-  by deleting the provisions above and replace them with the notice
-  and other provisions required by the GPL.  If you do not delete
-  the provisions above, a recipient may use your version of this
-  file under either the MPL or the GPL.
-
-  ======================================================================*/
-
-#define PROGRAM_NAME "ftl_format"
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <time.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-
-#include <mtd/mtd-user.h>
-#include <mtd/ftl-user.h>
-#include <mtd_swab.h>
-#include "common.h"
-
-/*====================================================================*/
-
-static void print_size(u_int s)
-{
-	if ((s > 0x100000) && ((s % 0x100000) == 0))
-		printf("%d mb", s / 0x100000);
-	else if ((s > 0x400) && ((s % 0x400) == 0))
-		printf("%d kb", s / 0x400);
-	else
-		printf("%d bytes", s);
-}
-
-/*====================================================================*/
-
-static const char LinkTarget[] = {
-	0x13, 0x03, 'C', 'I', 'S'
-};
-static const char DataOrg[] = {
-	0x46, 0x39, 0x00, 'F', 'T', 'L', '1', '0', '0', 0x00
-};
-
-static void build_header(erase_unit_header_t *hdr, u_int RegionSize,
-		u_int BlockSize, u_int Spare, int Reserve,
-		u_int BootSize)
-{
-	u_int i, BootUnits, nbam, __FormattedSize;
-
-	/* Default everything to the erased state */
-	memset(hdr, 0xff, sizeof(*hdr));
-	memcpy(hdr->LinkTargetTuple, LinkTarget, 5);
-	memcpy(hdr->DataOrgTuple, DataOrg, 10);
-	hdr->EndTuple[0] = hdr->EndTuple[1] = 0xff;
-	BootSize = (BootSize + (BlockSize-1)) & ~(BlockSize-1);
-	BootUnits = BootSize / BlockSize;
-
-	/* We only support 512-byte blocks */
-	hdr->BlockSize = 9;
-	hdr->EraseUnitSize = 0;
-	for (i = BlockSize; i > 1; i >>= 1)
-		hdr->EraseUnitSize++;
-	hdr->EraseCount = cpu_to_le32(0);
-	hdr->FirstPhysicalEUN = cpu_to_le16(BootUnits);
-	hdr->NumEraseUnits = cpu_to_le16((RegionSize - BootSize) >> hdr->EraseUnitSize);
-	hdr->NumTransferUnits = Spare;
-	__FormattedSize = RegionSize - ((Spare + BootUnits) << hdr->EraseUnitSize);
-	/* Leave a little bit of space between the CIS and BAM */
-	hdr->BAMOffset = cpu_to_le32(0x80);
-	/* Adjust size to account for BAM space */
-	nbam = ((1 << (hdr->EraseUnitSize - hdr->BlockSize)) * sizeof(u_int)
-			+ le32_to_cpu(hdr->BAMOffset) + (1 << hdr->BlockSize) - 1) >> hdr->BlockSize;
-
-	__FormattedSize -=
-		(le16_to_cpu(hdr->NumEraseUnits) - Spare) * (nbam << hdr->BlockSize);
-	__FormattedSize -= ((__FormattedSize * Reserve / 100) & ~0xfff);
-
-	hdr->FormattedSize = cpu_to_le32(__FormattedSize);
-
-	/* hdr->FirstVMAddress defaults to erased state */
-	hdr->NumVMPages = cpu_to_le16(0);
-	hdr->Flags = 0;
-	/* hdr->Code defaults to erased state */
-	hdr->SerialNumber = cpu_to_le32(time(NULL));
-	/* hdr->AltEUHOffset defaults to erased state */
-
-} /* build_header */
-
-/*====================================================================*/
-
-static int format_partition(int fd, int quiet, int interrogate,
-		u_int spare, int reserve, u_int bootsize)
-{
-	mtd_info_t mtd;
-	erase_info_t erase;
-	erase_unit_header_t hdr;
-	u_int step, lun, i, nbam, *bam;
-
-	/* Get partition size, block size */
-	if (ioctl(fd, MEMGETINFO, &mtd) != 0) {
-		perror("get info failed");
-		return -1;
-	}
-
-#if 0
-	/* Intel Series 100 Flash: skip first block */
-	if ((region.JedecMfr == 0x89) && (region.JedecInfo == 0xaa) &&
-			(bootsize == 0)) {
-		if (!quiet)
-			printf("Skipping first block to protect CIS info...\n");
-		bootsize = 1;
-	}
-#endif
-
-	/* Create header */
-	build_header(&hdr, mtd.size, mtd.erasesize,
-			spare, reserve, bootsize);
-
-	if (!quiet) {
-		printf("Partition size = ");
-		print_size(mtd.size);
-		printf(", erase unit size = ");
-		print_size(mtd.erasesize);
-		printf(", %d transfer units\n", spare);
-		if (bootsize != 0) {
-			print_size(le16_to_cpu(hdr.FirstPhysicalEUN) << hdr.EraseUnitSize);
-			printf(" allocated for boot image\n");
-		}
-		printf("Reserved %d%%, formatted size = ", reserve);
-		print_size(le32_to_cpu(hdr.FormattedSize));
-		printf("\n");
-		fflush(stdout);
-	}
-
-	if (interrogate)
-		if (!prompt("This will destroy all data on the target device. Confirm?", false))
-			return -1;
-
-	/* Create basic block allocation table for control blocks */
-	nbam = ((mtd.erasesize >> hdr.BlockSize) * sizeof(u_int)
-			+ le32_to_cpu(hdr.BAMOffset) + (1 << hdr.BlockSize) - 1) >> hdr.BlockSize;
-	bam = malloc(nbam * sizeof(u_int));
-	for (i = 0; i < nbam; i++)
-		bam[i] = cpu_to_le32(BLOCK_CONTROL);
-
-	/* Erase partition */
-	if (!quiet) {
-		printf("Erasing all blocks...\n");
-		fflush(stdout);
-	}
-	erase.length = mtd.erasesize;
-	erase.start = mtd.erasesize * le16_to_cpu(hdr.FirstPhysicalEUN);
-	for (i = 0; i < le16_to_cpu(hdr.NumEraseUnits); i++) {
-		if (ioctl(fd, MEMERASE, &erase) < 0) {
-			if (!quiet) {
-				putchar('\n');
-				fflush(stdout);
-			}
-			perror("block erase failed");
-			return -1;
-		}
-		erase.start += erase.length;
-		if (!quiet) {
-			if (mtd.size <= 0x800000) {
-				if (erase.start % 0x100000) {
-					if (!(erase.start % 0x20000)) putchar('-');
-				}
-				else putchar('+');
-			}
-			else {
-				if (erase.start % 0x800000) {
-					if (!(erase.start % 0x100000)) putchar('+');
-				}
-				else putchar('*');
-			}
-			fflush(stdout);
-		}
-	}
-	if (!quiet) putchar('\n');
-
-	/* Prepare erase units */
-	if (!quiet) {
-		printf("Writing erase unit headers...\n");
-		fflush(stdout);
-	}
-	lun = 0;
-	/* Distribute transfer units over the entire region */
-	step = spare ? (le16_to_cpu(hdr.NumEraseUnits) / spare) : (le16_to_cpu(hdr.NumEraseUnits) + 1);
-	for (i = 0; i < le16_to_cpu(hdr.NumEraseUnits); i++) {
-		off_t ofs = (off_t) (i + le16_to_cpu(hdr.FirstPhysicalEUN)) << hdr.EraseUnitSize;
-		if (lseek(fd, ofs, SEEK_SET) == -1) {
-			perror("seek failed");
-			break;
-		}
-		/* Is this a transfer unit? */
-		if (((i+1) % step) == 0)
-			hdr.LogicalEUN = cpu_to_le16(0xffff);
-		else {
-			hdr.LogicalEUN = cpu_to_le16(lun);
-			lun++;
-		}
-		if (write(fd, &hdr, sizeof(hdr)) == -1) {
-			perror("write failed");
-			break;
-		}
-		if (lseek(fd, ofs + le32_to_cpu(hdr.BAMOffset), SEEK_SET) == -1) {
-			perror("seek failed");
-			break;
-		}
-		if (write(fd, bam, nbam * sizeof(u_int)) == -1) {
-			perror("write failed");
-			break;
-		}
-	}
-	if (i < le16_to_cpu(hdr.NumEraseUnits))
-		return -1;
-	else
-		return 0;
-} /* format_partition */
-
-/*====================================================================*/
-
-int main(int argc, char *argv[])
-{
-	int quiet, interrogate, reserve;
-	int optch, errflg, fd, ret;
-	u_int spare, bootsize;
-	char *s;
-	extern char *optarg;
-	struct stat buf;
-
-	quiet = 0;
-	interrogate = 0;
-	spare = 1;
-	reserve = 5;
-	errflg = 0;
-	bootsize = 0;
-
-	while ((optch = getopt(argc, argv, "qir:s:b:")) != -1) {
-		switch (optch) {
-			case 'q':
-				quiet = 1; break;
-			case 'i':
-				interrogate = 1; break;
-			case 's':
-				spare = strtoul(optarg, NULL, 0); break;
-			case 'r':
-				reserve = strtoul(optarg, NULL, 0); break;
-			case 'b':
-				bootsize = strtoul(optarg, &s, 0);
-				if ((*s == 'k') || (*s == 'K'))
-					bootsize *= 1024;
-				break;
-			default:
-				errflg = 1; break;
-		}
-	}
-	if (errflg || (optind != argc-1)) {
-		fprintf(stderr, "usage: %s [-q] [-i] [-s spare-blocks]"
-				" [-r reserve-percent] [-b bootsize] device\n", PROGRAM_NAME);
-		exit(EXIT_FAILURE);
-	}
-
-	if (stat(argv[optind], &buf) != 0) {
-		perror("status check failed");
-		exit(EXIT_FAILURE);
-	}
-	if (!(buf.st_mode & S_IFCHR)) {
-		fprintf(stderr, "%s is not a character special device\n",
-				argv[optind]);
-		exit(EXIT_FAILURE);
-	}
-	fd = open(argv[optind], O_RDWR);
-	if (fd == -1) {
-		perror("open failed");
-		exit(EXIT_FAILURE);
-	}
-
-	ret = format_partition(fd, quiet, interrogate, spare, reserve,
-			bootsize);
-	if (!quiet) {
-		if (ret)
-			printf("format failed.\n");
-		else
-			printf("format successful.\n");
-	}
-	close(fd);
-
-	exit((ret) ? EXIT_FAILURE : EXIT_SUCCESS);
-	return 0;
-}
diff --git a/jffs-dump.c b/jffs-dump.c
deleted file mode 100644
index 3176469..0000000
--- a/jffs-dump.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Dump JFFS filesystem.
- * Useful when it buggers up.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-#include "common.h"
-
-#define BLOCK_SIZE 1024
-#define JFFS_MAGIC 0x34383931 /* "1984" */
-#define JFFS_MAX_NAME_LEN 256
-#define JFFS_MIN_INO 1
-#define JFFS_TRACE_INDENT 4
-#define JFFS_ALIGN_SIZE 4
-#define MAX_CHUNK_SIZE 32768
-
-/* How many padding bytes should be inserted between two chunks of data
-   on the flash?  */
-#define JFFS_GET_PAD_BYTES(size) ((JFFS_ALIGN_SIZE                     \
-			- ((uint32_t)(size) % JFFS_ALIGN_SIZE)) \
-		% JFFS_ALIGN_SIZE)
-
-#define JFFS_EMPTY_BITMASK 0xffffffff
-#define JFFS_MAGIC_BITMASK 0x34383931
-#define JFFS_DIRTY_BITMASK 0x00000000
-
-struct jffs_raw_inode
-{
-	uint32_t magic;    /* A constant magic number.  */
-	uint32_t ino;      /* Inode number.  */
-	uint32_t pino;     /* Parent's inode number.  */
-	uint32_t version;  /* Version number.  */
-	uint32_t mode;     /* file_type, mode  */
-	uint16_t uid;
-	uint16_t gid;
-	uint32_t atime;
-	uint32_t mtime;
-	uint32_t ctime;
-	uint32_t offset;     /* Where to begin to write.  */
-	uint32_t dsize;      /* Size of the file data.  */
-	uint32_t rsize;      /* How much are going to be replaced?  */
-	uint8_t nsize;       /* Name length.  */
-	uint8_t nlink;       /* Number of links.  */
-	uint8_t spare : 6;   /* For future use.  */
-	uint8_t rename : 1;  /* Is this a special rename?  */
-	uint8_t deleted : 1; /* Has this file been deleted?  */
-	uint8_t accurate;    /* The inode is obsolete if accurate == 0.  */
-	uint32_t dchksum;    /* Checksum for the data.  */
-	uint16_t nchksum;    /* Checksum for the name.  */
-	uint16_t chksum;     /* Checksum for the raw_inode.  */
-};
-
-
-struct jffs_file
-{
-	struct jffs_raw_inode inode;
-	char *name;
-	unsigned char *data;
-};
-
-
-char *root_directory_name = NULL;
-int fs_pos = 0;
-int verbose = 0;
-
-#define ENDIAN_HOST   0
-#define ENDIAN_BIG    1
-#define ENDIAN_LITTLE 2
-int endian = ENDIAN_HOST;
-
-static uint32_t jffs_checksum(void *data, int size);
-void jffs_print_trace(const char *path, int depth);
-int make_root_dir(FILE *fs, int first_ino, const char *root_dir_path,
-		int depth);
-void write_file(struct jffs_file *f, FILE *fs, struct stat st);
-void read_data(struct jffs_file *f, const char *path, int offset);
-int mkfs(FILE *fs, const char *path, int ino, int parent, int depth);
-
-
-	static uint32_t
-jffs_checksum(void *data, int size)
-{
-	uint32_t sum = 0;
-	uint8_t *ptr = (uint8_t *)data;
-
-	while (size-- > 0)
-	{
-		sum += *ptr++;
-	}
-
-	return sum;
-}
-
-
-	void
-jffs_print_trace(const char *path, int depth)
-{
-	int path_len = strlen(path);
-	int out_pos = depth * JFFS_TRACE_INDENT;
-	int pos = path_len - 1;
-	char *out = (char *)alloca(depth * JFFS_TRACE_INDENT + path_len + 1);
-
-	if (verbose >= 2)
-	{
-		fprintf(stderr, "jffs_print_trace(): path: \"%s\"\n", path);
-	}
-
-	if (!out) {
-		fprintf(stderr, "jffs_print_trace(): Allocation failed.\n");
-		fprintf(stderr, " path: \"%s\"\n", path);
-		fprintf(stderr, "depth: %d\n", depth);
-		exit(1);
-	}
-
-	memset(out, ' ', depth * JFFS_TRACE_INDENT);
-
-	if (path[pos] == '/')
-	{
-		pos--;
-	}
-	while (path[pos] && (path[pos] != '/'))
-	{
-		pos--;
-	}
-	for (pos++; path[pos] && (path[pos] != '/'); pos++)
-	{
-		out[out_pos++] = path[pos];
-	}
-	out[out_pos] = '\0';
-	fprintf(stderr, "%s\n", out);
-}
-
-
-/* Print the contents of a raw inode.  */
-	void
-jffs_print_raw_inode(struct jffs_raw_inode *raw_inode)
-{
-	fprintf(stdout, "jffs_raw_inode: inode number: %u, version %u\n", raw_inode->ino, raw_inode->version);
-	fprintf(stdout, "{\n");
-	fprintf(stdout, "        0x%08x, /* magic  */\n", raw_inode->magic);
-	fprintf(stdout, "        0x%08x, /* ino  */\n", raw_inode->ino);
-	fprintf(stdout, "        0x%08x, /* pino  */\n", raw_inode->pino);
-	fprintf(stdout, "        0x%08x, /* version  */\n", raw_inode->version);
-	fprintf(stdout, "        0x%08x, /* mode  */\n", raw_inode->mode);
-	fprintf(stdout, "        0x%04x,     /* uid  */\n", raw_inode->uid);
-	fprintf(stdout, "        0x%04x,     /* gid  */\n", raw_inode->gid);
-	fprintf(stdout, "        0x%08x, /* atime  */\n", raw_inode->atime);
-	fprintf(stdout, "        0x%08x, /* mtime  */\n", raw_inode->mtime);
-	fprintf(stdout, "        0x%08x, /* ctime  */\n", raw_inode->ctime);
-	fprintf(stdout, "        0x%08x, /* offset  */\n", raw_inode->offset);
-	fprintf(stdout, "        0x%08x, /* dsize  */\n", raw_inode->dsize);
-	fprintf(stdout, "        0x%08x, /* rsize  */\n", raw_inode->rsize);
-	fprintf(stdout, "        0x%02x,       /* nsize  */\n", raw_inode->nsize);
-	fprintf(stdout, "        0x%02x,       /* nlink  */\n", raw_inode->nlink);
-	fprintf(stdout, "        0x%02x,       /* spare  */\n",
-			raw_inode->spare);
-	fprintf(stdout, "        %u,          /* rename  */\n",
-			raw_inode->rename);
-	fprintf(stdout, "        %u,          /* deleted  */\n",
-			raw_inode->deleted);
-	fprintf(stdout, "        0x%02x,       /* accurate  */\n",
-			raw_inode->accurate);
-	fprintf(stdout, "        0x%08x, /* dchksum  */\n", raw_inode->dchksum);
-	fprintf(stdout, "        0x%04x,     /* nchksum  */\n", raw_inode->nchksum);
-	fprintf(stdout, "        0x%04x,     /* chksum  */\n", raw_inode->chksum);
-	fprintf(stdout, "}\n");
-}
-
-static void write_val32(uint32_t *adr, uint32_t val)
-{
-	switch(endian) {
-		case ENDIAN_HOST:
-			*adr = val;
-			break;
-		case ENDIAN_LITTLE:
-			*adr = __cpu_to_le32(val);
-			break;
-		case ENDIAN_BIG:
-			*adr = __cpu_to_be32(val);
-			break;
-	}
-}
-
-static void write_val16(uint16_t *adr, uint16_t val)
-{
-	switch(endian) {
-		case ENDIAN_HOST:
-			*adr = val;
-			break;
-		case ENDIAN_LITTLE:
-			*adr = __cpu_to_le16(val);
-			break;
-		case ENDIAN_BIG:
-			*adr = __cpu_to_be16(val);
-			break;
-	}
-}
-
-static uint32_t read_val32(uint32_t *adr)
-{
-	uint32_t val;
-
-	switch(endian) {
-		case ENDIAN_HOST:
-			val = *adr;
-			break;
-		case ENDIAN_LITTLE:
-			val = __le32_to_cpu(*adr);
-			break;
-		case ENDIAN_BIG:
-			val = __be32_to_cpu(*adr);
-			break;
-	}
-	return val;
-}
-
-static uint16_t read_val16(uint16_t *adr)
-{
-	uint16_t val;
-
-	switch(endian) {
-		case ENDIAN_HOST:
-			val = *adr;
-			break;
-		case ENDIAN_LITTLE:
-			val = __le16_to_cpu(*adr);
-			break;
-		case ENDIAN_BIG:
-			val = __be16_to_cpu(*adr);
-			break;
-	}
-	return val;
-}
-
-	int
-main(int argc, char **argv)
-{
-	int fs;
-	struct stat sb;
-	uint32_t wordbuf;
-	off_t pos = 0;
-	off_t end;
-	struct jffs_raw_inode ino;
-	unsigned char namebuf[4096];
-	int myino = -1;
-
-	if (argc < 2) {
-		printf("no filesystem given\n");
-		exit(1);
-	}
-
-	fs = open(argv[1], O_RDONLY);
-	if (fs < 0) {
-		perror("open");
-		exit(1);
-	}
-
-	if (argc > 2) {
-		myino = atol(argv[2]);
-		printf("Printing ino #%d\n" , myino);
-	}
-
-	if (fstat(fs, &sb) < 0) {
-		perror("stat");
-		close(fs);
-		exit(1);
-	}
-	end = sb.st_size;
-
-	while (pos < end) {
-		if (pread(fs, &wordbuf, 4, pos) < 0) {
-			perror("pread");
-			exit(1);
-		}
-
-		switch(wordbuf) {
-			case JFFS_EMPTY_BITMASK:
-				//			printf("0xff started at 0x%lx\n", pos);
-				for (; pos < end && wordbuf == JFFS_EMPTY_BITMASK; pos += 4) {
-					if (pread(fs, &wordbuf, 4, pos) < 0) {
-						perror("pread");
-						exit(1);
-					}
-				}
-				if (pos < end)
-					pos -= 4;
-				//			printf("0xff ended at 0x%lx\n", pos);
-				continue;
-
-			case JFFS_DIRTY_BITMASK:
-				//			printf("0x00 started at 0x%lx\n", pos);
-				for (; pos < end && wordbuf == JFFS_DIRTY_BITMASK; pos += 4) {
-					if (pread(fs, &wordbuf, 4, pos) < 0) {
-						perror("pread");
-						exit(1);
-					}
-				}
-				if (pos < end)
-					pos -=4;
-				//			printf("0x00 ended at 0x%lx\n", pos);
-				continue;
-
-			default:
-				printf("Argh. Dirty memory at 0x%lx\n", pos);
-				//			file_hexdump(fs, pos, 128);
-				for (pos += 4; pos < end; pos += 4) {
-					if (pread(fs, &wordbuf, 4, pos) < 0) {
-						perror("pread");
-						exit(1);
-					}
-					if (wordbuf == JFFS_MAGIC_BITMASK)
-						break;
-				}
-
-			case JFFS_MAGIC_BITMASK:
-				if (pread(fs, &ino, sizeof(ino), pos) < 0) {
-					perror("pread");
-					exit(1);
-				}
-				if (myino == -1 || ino.ino == myino) {
-					printf("Magic found at 0x%lx\n", pos);
-					jffs_print_raw_inode(&ino);
-				}
-				pos += sizeof(ino);
-
-				if (myino == -1 || ino.ino == myino) {
-					if (ino.nsize) {
-						if (pread(fs, namebuf, min(ino.nsize, 4095), pos) < 0) {
-							perror("pread");
-							exit(1);
-						}
-						if (ino.nsize < 4095)
-							namebuf[ino.nsize] = 0;
-						else
-							namebuf[4095] = 0;
-						printf("Name: \"%s\"\n", namebuf);
-					} else {
-						printf("No Name\n");
-					}
-				}
-				pos += (ino.nsize + 3) & ~3;
-
-				pos += (ino.dsize + 3) & ~3;
-		}
-
-
-
-	}
-}
diff --git a/jffs2dump.c b/jffs2dump.c
deleted file mode 100644
index f8b8ac7..0000000
--- a/jffs2dump.c
+++ /dev/null
@@ -1,805 +0,0 @@
-/*
- *  dumpjffs2.c
- *
- *  Copyright (C) 2003 Thomas Gleixner (tglx at linutronix.de)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Overview:
- *   This utility dumps the contents of a binary JFFS2 image
- *
- *
- * Bug/ToDo:
- */
-
-#define PROGRAM_NAME "jffs2dump"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <asm/types.h>
-#include <dirent.h>
-#include <mtd/jffs2-user.h>
-#include <endian.h>
-#include <byteswap.h>
-#include <getopt.h>
-#include <crc32.h>
-#include "summary.h"
-#include "common.h"
-
-#define PAD(x) (((x)+3)&~3)
-
-/* For outputting a byte-swapped version of the input image. */
-#define cnv_e32(x) ((jint32_t){bswap_32(x.v32)})
-#define cnv_e16(x) ((jint16_t){bswap_16(x.v16)})
-
-#define t32_backwards(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?bswap_32(__b):__b; })
-#define cpu_to_e32(x) ((jint32_t){t32_backwards(x)})
-
-// Global variables
-long	imglen;		// length of image
-char	*data;		// image data
-
-void display_help (void)
-{
-	printf("Usage: %s [OPTION]... INPUTFILE\n"
-	       "Dump the contents of a binary JFFS2 image.\n\n"
-	       "     --help                   display this help and exit\n"
-	       "     --version                display version information and exit\n"
-	       " -b, --bigendian              image is big endian\n"
-	       " -l, --littleendian           image is little endian\n"
-	       " -c, --content                dump image contents\n"
-	       " -e, --endianconvert=FNAME    convert image endianness, output to file fname\n"
-	       " -r, --recalccrc              recalc name and data crc on endian conversion\n"
-	       " -d, --datsize=LEN            size of data chunks, when oob data in binary image (NAND only)\n"
-	       " -o, --oobsize=LEN            size of oob data chunk in binary image (NAND only)\n"
-	       " -v, --verbose                verbose output\n",
-	       PROGRAM_NAME);
-	exit(0);
-}
-
-void display_version (void)
-{
-	printf("%1$s " VERSION "\n"
-			"\n"
-			"Copyright (C) 2003 Thomas Gleixner \n"
-			"\n"
-			"%1$s comes with NO WARRANTY\n"
-			"to the extent permitted by law.\n"
-			"\n"
-			"You may redistribute copies of %1$s\n"
-			"under the terms of the GNU General Public Licence.\n"
-			"See the file `COPYING' for more information.\n",
-			PROGRAM_NAME);
-	exit(0);
-}
-
-// Option variables
-
-int 	verbose;		// verbose output
-char 	*img;			// filename of image
-int	dumpcontent;		// dump image content
-int	target_endian = __BYTE_ORDER;	// image endianess
-int	convertendian;		// convert endianness
-int	recalccrc;		// recalc name and data crc's on endian conversion
-char	cnvfile[256];		// filename for conversion output
-int	datsize;		// Size of data chunks, when oob data is inside the binary image
-int	oobsize;		// Size of oob chunks, when oob data is inside the binary image
-
-void process_options (int argc, char *argv[])
-{
-	int error = 0;
-
-	for (;;) {
-		int option_index = 0;
-		static const char *short_options = "blce:rd:o:v";
-		static const struct option long_options[] = {
-			{"help", no_argument, 0, 0},
-			{"version", no_argument, 0, 0},
-			{"bigendian", no_argument, 0, 'b'},
-			{"littleendian", no_argument, 0, 'l'},
-			{"content", no_argument, 0, 'c'},
-			{"endianconvert", required_argument, 0, 'e'},
-			{"datsize", required_argument, 0, 'd'},
-			{"oobsize", required_argument, 0, 'o'},
-			{"recalccrc", required_argument, 0, 'r'},
-			{"verbose", no_argument, 0, 'v'},
-			{0, 0, 0, 0},
-		};
-
-		int c = getopt_long(argc, argv, short_options,
-				long_options, &option_index);
-		if (c == EOF) {
-			break;
-		}
-
-		switch (c) {
-			case 0:
-				switch (option_index) {
-					case 0:
-						display_help();
-						break;
-					case 1:
-						display_version();
-						break;
-				}
-				break;
-			case 'v':
-				verbose = 1;
-				break;
-			case 'b':
-				target_endian = __BIG_ENDIAN;
-				break;
-			case 'l':
-				target_endian = __LITTLE_ENDIAN;
-				break;
-			case 'c':
-				dumpcontent = 1;
-				break;
-			case 'd':
-				datsize = atoi(optarg);
-				break;
-			case 'o':
-				oobsize = atoi(optarg);
-				break;
-			case 'e':
-				convertendian = 1;
-				strcpy (cnvfile, optarg);
-				break;
-			case 'r':
-				recalccrc = 1;
-				break;
-			case '?':
-				error = 1;
-				break;
-		}
-	}
-
-	if ((argc - optind) != 1 || error)
-		display_help ();
-
-	img = argv[optind];
-}
-
-
-/*
- *	Dump image contents
- */
-void do_dumpcontent (void)
-{
-	char			*p = data, *p_free_begin;
-	union jffs2_node_union 	*node;
-	int			empty = 0, dirty = 0;
-	char			name[256];
-	uint32_t		crc;
-	uint16_t		type;
-	int			bitchbitmask = 0;
-	int			obsolete;
-
-	p_free_begin = NULL;
-	while ( p < (data + imglen)) {
-		node = (union jffs2_node_union*) p;
-
-		/* Skip empty space */
-		if (!p_free_begin)
-			p_free_begin = p;
-		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
-			p += 4;
-			empty += 4;
-			continue;
-		}
-
-		if (p != p_free_begin)
-			printf("Empty space found from 0x%08zx to 0x%08zx\n", p_free_begin-data, p-data);
-		p_free_begin = NULL;
-
-		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
-			if (!bitchbitmask++)
-				printf ("Wrong bitmask  at  0x%08zx, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
-			p += 4;
-			dirty += 4;
-			continue;
-		}
-		bitchbitmask = 0;
-
-		type = je16_to_cpu(node->u.nodetype);
-		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
-			obsolete = 1;
-			type |= JFFS2_NODE_ACCURATE;
-		} else
-			obsolete = 0;
-		/* Set accurate for CRC check */
-		node->u.nodetype = cpu_to_je16(type);
-
-		crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
-		if (crc != je32_to_cpu (node->u.hdr_crc)) {
-			printf ("Wrong hdr_crc  at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc);
-			p += 4;
-			dirty += 4;
-			continue;
-		}
-
-		switch(je16_to_cpu(node->u.nodetype)) {
-
-			case JFFS2_NODETYPE_INODE:
-				printf ("%8s Inode      node at 0x%08zx, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
-						obsolete ? "Obsolete" : "",
-						p - data, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
-						je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
-						je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
-
-				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
-				if (crc != je32_to_cpu (node->i.node_crc)) {
-					printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.node_crc), crc);
-					p += PAD(je32_to_cpu (node->i.totlen));
-					dirty += PAD(je32_to_cpu (node->i.totlen));;
-					continue;
-				}
-
-				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
-				if (crc != je32_to_cpu(node->i.data_crc)) {
-					printf ("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.data_crc), crc);
-					p += PAD(je32_to_cpu (node->i.totlen));
-					dirty += PAD(je32_to_cpu (node->i.totlen));;
-					continue;
-				}
-
-				p += PAD(je32_to_cpu (node->i.totlen));
-				break;
-
-			case JFFS2_NODETYPE_DIRENT:
-				memcpy (name, node->d.name, node->d.nsize);
-				name [node->d.nsize] = 0x0;
-				printf ("%8s Dirent     node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
-						obsolete ? "Obsolete" : "",
-						p - data, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
-						je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
-						node->d.nsize, name);
-
-				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
-				if (crc != je32_to_cpu (node->d.node_crc)) {
-					printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.node_crc), crc);
-					p += PAD(je32_to_cpu (node->d.totlen));
-					dirty += PAD(je32_to_cpu (node->d.totlen));;
-					continue;
-				}
-
-				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
-				if (crc != je32_to_cpu(node->d.name_crc)) {
-					printf ("Wrong name_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.name_crc), crc);
-					p += PAD(je32_to_cpu (node->d.totlen));
-					dirty += PAD(je32_to_cpu (node->d.totlen));;
-					continue;
-				}
-
-				p += PAD(je32_to_cpu (node->d.totlen));
-				break;
-
-			case JFFS2_NODETYPE_XATTR:
-				memcpy(name, node->x.data, node->x.name_len);
-				name[node->x.name_len] = '\x00';
-				printf ("%8s Xattr      node at 0x%08zx, totlen 0x%08x, xid   %5d, version %5d, name_len   %3d, name %s\n",
-						obsolete ? "Obsolete" : "",
-						p - data,
-						je32_to_cpu (node->x.totlen),
-						je32_to_cpu (node->x.xid),
-						je32_to_cpu (node->x.version),
-						node->x.name_len,
-						name);
-
-				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_xattr) - sizeof (node->x.node_crc));
-				if (crc != je32_to_cpu (node->x.node_crc)) {
-					printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->x.node_crc), crc);
-					p += PAD(je32_to_cpu (node->x.totlen));
-					dirty += PAD(je32_to_cpu (node->x.totlen));
-					continue;
-				}
-
-				crc = mtd_crc32 (0, p + sizeof (struct jffs2_raw_xattr), node->x.name_len + je16_to_cpu (node->x.value_len) + 1);
-				if (crc != je32_to_cpu (node->x.data_crc)) {
-					printf ("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->x.data_crc), crc);
-					p += PAD(je32_to_cpu (node->x.totlen));
-					dirty += PAD(je32_to_cpu (node->x.totlen));
-					continue;
-				}
-				p += PAD(je32_to_cpu (node->x.totlen));
-				break;
-
-			case JFFS2_NODETYPE_XREF:
-				printf ("%8s Xref       node at 0x%08zx, totlen 0x%08x, xid   %5d, xseqno  %5d, #ino  %8d\n",
-						obsolete ? "Obsolete" : "",
-						p - data,
-						je32_to_cpu (node->r.totlen),
-						je32_to_cpu (node->r.xid),
-						je32_to_cpu (node->r.xseqno),
-						je32_to_cpu (node->r.ino));
-				p += PAD(je32_to_cpu (node->r.totlen));
-				break;
-
-			case JFFS2_NODETYPE_SUMMARY: {
-
-											 int i;
-											 struct jffs2_sum_marker * sm;
-
-											 printf("%8s Inode Sum  node at 0x%08zx, totlen 0x%08x, sum_num  %5d, cleanmarker size %5d\n",
-													 obsolete ? "Obsolete" : "",
-													 p - data,
-													 je32_to_cpu (node->s.totlen),
-													 je32_to_cpu (node->s.sum_num),
-													 je32_to_cpu (node->s.cln_mkr));
-
-											 crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_summary) - 8);
-											 if (crc != je32_to_cpu (node->s.node_crc)) {
-												 printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.node_crc), crc);
-												 p += PAD(je32_to_cpu (node->s.totlen));
-												 dirty += PAD(je32_to_cpu (node->s.totlen));;
-												 continue;
-											 }
-
-											 crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_summary),  je32_to_cpu (node->s.totlen) - sizeof(struct jffs2_raw_summary));
-											 if (crc != je32_to_cpu(node->s.sum_crc)) {
-												 printf ("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.sum_crc), crc);
-												 p += PAD(je32_to_cpu (node->s.totlen));
-												 dirty += PAD(je32_to_cpu (node->s.totlen));;
-												 continue;
-											 }
-
-											 if (verbose) {
-												 void *sp;
-												 sp = (p + sizeof(struct jffs2_raw_summary));
-
-												 for(i=0; i<je32_to_cpu(node->s.sum_num); i++) {
-
-													 switch(je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
-														 case JFFS2_NODETYPE_INODE : {
-
-																						 struct jffs2_sum_inode_flash *spi;
-																						 spi = sp;
-
-																						 printf ("%14s #ino  %5d,  version %5d, offset 0x%08x, totlen 0x%08x\n",
-																								 "",
-																								 je32_to_cpu (spi->inode),
-																								 je32_to_cpu (spi->version),
-																								 je32_to_cpu (spi->offset),
-																								 je32_to_cpu (spi->totlen));
-
-																						 sp += JFFS2_SUMMARY_INODE_SIZE;
-																						 break;
-																					 }
-
-														 case JFFS2_NODETYPE_DIRENT : {
-
-																						  char name[255];
-																						  struct jffs2_sum_dirent_flash *spd;
-																						  spd = sp;
-
-																						  memcpy(name,spd->name,spd->nsize);
-																						  name [spd->nsize] = 0x0;
-
-																						  printf ("%14s dirent offset 0x%08x, totlen 0x%08x, #pino  %5d,  version %5d, #ino  %8d, nsize %8d, name %s \n",
-																								  "",
-																								  je32_to_cpu (spd->offset),
-																								  je32_to_cpu (spd->totlen),
-																								  je32_to_cpu (spd->pino),
-																								  je32_to_cpu (spd->version),
-																								  je32_to_cpu (spd->ino),
-																								  spd->nsize,
-																								  name);
-
-																						  sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
-																						  break;
-																					  }
-
-														 case JFFS2_NODETYPE_XATTR : {
-																						  struct jffs2_sum_xattr_flash *spx;
-																						  spx = sp;
-																						  printf ("%14s Xattr  offset 0x%08x, totlen 0x%08x, version %5d, #xid %8d\n",
-																								  "",
-																								  je32_to_cpu (spx->offset),
-																								  je32_to_cpu (spx->totlen),
-																								  je32_to_cpu (spx->version),
-																								  je32_to_cpu (spx->xid));
-																						  sp += JFFS2_SUMMARY_XATTR_SIZE;
-																						  break;
-																					  }
-
-														 case JFFS2_NODETYPE_XREF : {
-																						  struct jffs2_sum_xref_flash *spr;
-																						  spr = sp;
-																						  printf ("%14s Xref   offset 0x%08x\n",
-																								  "",
-																								  je32_to_cpu (spr->offset));
-																						  sp += JFFS2_SUMMARY_XREF_SIZE;
-																						  break;
-																					  }
-
-														 default :
-																					  printf("Unknown summary node!\n");
-																					  break;
-													 }
-												 }
-
-												 sm = (struct jffs2_sum_marker *) ((char *)p + je32_to_cpu(node->s.totlen) - sizeof(struct jffs2_sum_marker));
-
-												 printf("%14s Sum Node Offset  0x%08x, Magic 0x%08x, Padded size 0x%08x\n",
-														 "",
-														 je32_to_cpu(sm->offset),
-														 je32_to_cpu(sm->magic),
-														 je32_to_cpu(node->s.padded));
-											 }
-
-											 p += PAD(je32_to_cpu (node->s.totlen));
-											 break;
-										 }
-
-			case JFFS2_NODETYPE_CLEANMARKER:
-										 if (verbose) {
-											 printf ("%8s Cleanmarker     at 0x%08zx, totlen 0x%08x\n",
-													 obsolete ? "Obsolete" : "",
-													 p - data, je32_to_cpu (node->u.totlen));
-										 }
-										 p += PAD(je32_to_cpu (node->u.totlen));
-										 break;
-
-			case JFFS2_NODETYPE_PADDING:
-										 if (verbose) {
-											 printf ("%8s Padding    node at 0x%08zx, totlen 0x%08x\n",
-													 obsolete ? "Obsolete" : "",
-													 p - data, je32_to_cpu (node->u.totlen));
-										 }
-										 p += PAD(je32_to_cpu (node->u.totlen));
-										 break;
-
-			case 0xffff:
-										 p += 4;
-										 empty += 4;
-										 break;
-
-			default:
-										 if (verbose) {
-											 printf ("%8s Unknown    node at 0x%08zx, totlen 0x%08x\n",
-													 obsolete ? "Obsolete" : "",
-													 p - data, je32_to_cpu (node->u.totlen));
-										 }
-										 p += PAD(je32_to_cpu (node->u.totlen));
-										 dirty += PAD(je32_to_cpu (node->u.totlen));
-
-		}
-	}
-
-	if (verbose)
-		printf ("Empty space: %d, dirty space: %d\n", empty, dirty);
-}
-
-/*
- *	Convert endianess
- */
-void do_endianconvert (void)
-{
-	char			*p = data;
-	union jffs2_node_union 	*node, newnode;
-	int			fd, len;
-	jint32_t		mode;
-	uint32_t		crc;
-
-	fd = open (cnvfile, O_WRONLY | O_CREAT, 0644);
-	if (fd < 0) {
-		fprintf (stderr, "Cannot open / create file: %s\n", cnvfile);
-		return;
-	}
-
-	while ( p < (data + imglen)) {
-		node = (union jffs2_node_union*) p;
-
-		/* Skip empty space */
-		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
-			write (fd, p, 4);
-			p += 4;
-			continue;
-		}
-
-		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
-			printf ("Wrong bitmask  at  0x%08zx, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
-			newnode.u.magic = cnv_e16 (node->u.magic);
-			newnode.u.nodetype = cnv_e16 (node->u.nodetype);
-			write (fd, &newnode, 4);
-			p += 4;
-			continue;
-		}
-
-		crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
-		if (crc != je32_to_cpu (node->u.hdr_crc)) {
-			printf ("Wrong hdr_crc  at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc);
-		}
-
-		switch(je16_to_cpu(node->u.nodetype)) {
-
-			case JFFS2_NODETYPE_INODE:
-
-				newnode.i.magic = cnv_e16 (node->i.magic);
-				newnode.i.nodetype = cnv_e16 (node->i.nodetype);
-				newnode.i.totlen = cnv_e32 (node->i.totlen);
-				newnode.i.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
-				newnode.i.ino = cnv_e32 (node->i.ino);
-				newnode.i.version = cnv_e32 (node->i.version);
-				mode.v32 = node->i.mode.m;
-				mode = cnv_e32 (mode);
-				newnode.i.mode.m = mode.v32;
-				newnode.i.uid = cnv_e16 (node->i.uid);
-				newnode.i.gid = cnv_e16 (node->i.gid);
-				newnode.i.isize = cnv_e32 (node->i.isize);
-				newnode.i.atime = cnv_e32 (node->i.atime);
-				newnode.i.mtime = cnv_e32 (node->i.mtime);
-				newnode.i.ctime = cnv_e32 (node->i.ctime);
-				newnode.i.offset = cnv_e32 (node->i.offset);
-				newnode.i.csize = cnv_e32 (node->i.csize);
-				newnode.i.dsize = cnv_e32 (node->i.dsize);
-				newnode.i.compr = node->i.compr;
-				newnode.i.usercompr = node->i.usercompr;
-				newnode.i.flags = cnv_e16 (node->i.flags);
-				if (recalccrc) {
-					len = je32_to_cpu(node->i.csize);
-					newnode.i.data_crc = cpu_to_e32 ( mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), len));
-				} else
-					newnode.i.data_crc = cnv_e32 (node->i.data_crc);
-
-				newnode.i.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_inode) - 8));
-
-				write (fd, &newnode, sizeof (struct jffs2_raw_inode));
-				write (fd, p + sizeof (struct jffs2_raw_inode), PAD (je32_to_cpu (node->i.totlen) -  sizeof (struct jffs2_raw_inode)));
-
-				p += PAD(je32_to_cpu (node->i.totlen));
-				break;
-
-			case JFFS2_NODETYPE_DIRENT:
-				newnode.d.magic = cnv_e16 (node->d.magic);
-				newnode.d.nodetype = cnv_e16 (node->d.nodetype);
-				newnode.d.totlen = cnv_e32 (node->d.totlen);
-				newnode.d.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
-				newnode.d.pino = cnv_e32 (node->d.pino);
-				newnode.d.version = cnv_e32 (node->d.version);
-				newnode.d.ino = cnv_e32 (node->d.ino);
-				newnode.d.mctime = cnv_e32 (node->d.mctime);
-				newnode.d.nsize = node->d.nsize;
-				newnode.d.type = node->d.type;
-				newnode.d.unused[0] = node->d.unused[0];
-				newnode.d.unused[1] = node->d.unused[1];
-				newnode.d.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_dirent) - 8));
-				if (recalccrc)
-					newnode.d.name_crc = cpu_to_e32 ( mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize));
-				else
-					newnode.d.name_crc = cnv_e32 (node->d.name_crc);
-
-				write (fd, &newnode, sizeof (struct jffs2_raw_dirent));
-				write (fd, p + sizeof (struct jffs2_raw_dirent), PAD (je32_to_cpu (node->d.totlen) -  sizeof (struct jffs2_raw_dirent)));
-				p += PAD(je32_to_cpu (node->d.totlen));
-				break;
-
-			case JFFS2_NODETYPE_XATTR:
-				newnode.x.magic = cnv_e16 (node->x.magic);
-				newnode.x.nodetype = cnv_e16 (node->x.nodetype);
-				newnode.x.totlen = cnv_e32 (node->x.totlen);
-				newnode.x.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
-				newnode.x.xid = cnv_e32 (node->x.xid);
-				newnode.x.version = cnv_e32 (node->x.version);
-				newnode.x.xprefix = node->x.xprefix;
-				newnode.x.name_len = node->x.name_len;
-				newnode.x.value_len = cnv_e16 (node->x.value_len);
-				if (recalccrc)
-					newnode.x.data_crc = cpu_to_e32 (mtd_crc32 (0, p + sizeof (struct jffs2_raw_xattr), node->x.name_len + je16_to_cpu (node->x.value_len) + 1));
-				else
-					newnode.x.data_crc = cnv_e32 (node->x.data_crc);
-				newnode.x.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_xattr) - sizeof (newnode.x.node_crc)));
-
-				write (fd, &newnode, sizeof (struct jffs2_raw_xattr));
-				write (fd, p + sizeof (struct jffs2_raw_xattr), PAD (je32_to_cpu (node->d.totlen) -  sizeof (struct jffs2_raw_xattr)));
-				p += PAD(je32_to_cpu (node->x.totlen));
-				break;
-
-			case JFFS2_NODETYPE_XREF:
-				newnode.r.magic = cnv_e16 (node->r.magic);
-				newnode.r.nodetype = cnv_e16 (node->r.nodetype);
-				newnode.r.totlen = cnv_e32 (node->r.totlen);
-				newnode.r.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - sizeof (newnode.r.hdr_crc)));
-				newnode.r.ino = cnv_e32 (node->r.ino);
-				newnode.r.xid = cnv_e32 (node->r.xid);
-				newnode.r.xseqno = cnv_e32 (node->r.xseqno);
-				newnode.r.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_xref) - sizeof (newnode.r.node_crc)));
-				p += PAD(je32_to_cpu (node->x.totlen));
-				break;
-
-			case JFFS2_NODETYPE_CLEANMARKER:
-			case JFFS2_NODETYPE_PADDING:
-				newnode.u.magic = cnv_e16 (node->u.magic);
-				newnode.u.nodetype = cnv_e16 (node->u.nodetype);
-				newnode.u.totlen = cnv_e32 (node->u.totlen);
-				newnode.u.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
-
-				write (fd, &newnode, sizeof (struct jffs2_unknown_node));
-				len = PAD(je32_to_cpu (node->u.totlen) - sizeof (struct jffs2_unknown_node));
-				if (len > 0)
-					write (fd, p + sizeof (struct jffs2_unknown_node), len);
-
-				p += PAD(je32_to_cpu (node->u.totlen));
-				break;
-
-			case JFFS2_NODETYPE_SUMMARY : {
-											  struct jffs2_sum_marker *sm_ptr;
-											  int i,sum_len;
-											  int counter = 0;
-
-											  newnode.s.magic = cnv_e16 (node->s.magic);
-											  newnode.s.nodetype = cnv_e16 (node->s.nodetype);
-											  newnode.s.totlen = cnv_e32 (node->s.totlen);
-											  newnode.s.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
-											  newnode.s.sum_num = cnv_e32 (node->s.sum_num);
-											  newnode.s.cln_mkr = cnv_e32 (node->s.cln_mkr);
-											  newnode.s.padded = cnv_e32 (node->s.padded);
-
-											  newnode.s.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_summary) - 8));
-
-											  // summary header
-											  p += sizeof (struct jffs2_raw_summary);
-
-											  // summary data
-											  sum_len = je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary) - sizeof (struct jffs2_sum_marker);
-
-											  for (i=0; i<je32_to_cpu (node->s.sum_num); i++) {
-												  union jffs2_sum_flash *fl_ptr;
-
-												  fl_ptr = (union jffs2_sum_flash *) p;
-
-												  switch (je16_to_cpu (fl_ptr->u.nodetype)) {
-													  case JFFS2_NODETYPE_INODE:
-
-														  fl_ptr->i.nodetype = cnv_e16 (fl_ptr->i.nodetype);
-														  fl_ptr->i.inode = cnv_e32 (fl_ptr->i.inode);
-														  fl_ptr->i.version = cnv_e32 (fl_ptr->i.version);
-														  fl_ptr->i.offset = cnv_e32 (fl_ptr->i.offset);
-														  fl_ptr->i.totlen = cnv_e32 (fl_ptr->i.totlen);
-														  p += sizeof (struct jffs2_sum_inode_flash);
-														  counter += sizeof (struct jffs2_sum_inode_flash);
-														  break;
-
-													  case JFFS2_NODETYPE_DIRENT:
-														  fl_ptr->d.nodetype = cnv_e16 (fl_ptr->d.nodetype);
-														  fl_ptr->d.totlen = cnv_e32 (fl_ptr->d.totlen);
-														  fl_ptr->d.offset = cnv_e32 (fl_ptr->d.offset);
-														  fl_ptr->d.pino = cnv_e32 (fl_ptr->d.pino);
-														  fl_ptr->d.version = cnv_e32 (fl_ptr->d.version);
-														  fl_ptr->d.ino = cnv_e32 (fl_ptr->d.ino);
-														  p += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
-														  counter += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
-														  break;
-
-													  case JFFS2_NODETYPE_XATTR:
-														  fl_ptr->x.nodetype = cnv_e16 (fl_ptr->x.nodetype);
-														  fl_ptr->x.xid = cnv_e32 (fl_ptr->x.xid);
-														  fl_ptr->x.version = cnv_e32 (fl_ptr->x.version);
-														  fl_ptr->x.offset = cnv_e32 (fl_ptr->x.offset);
-														  fl_ptr->x.totlen = cnv_e32 (fl_ptr->x.totlen);
-														  p += sizeof (struct jffs2_sum_xattr_flash);
-														  counter += sizeof (struct jffs2_sum_xattr_flash);
-														  break;
-
-													  case JFFS2_NODETYPE_XREF:
-														  fl_ptr->r.nodetype = cnv_e16 (fl_ptr->r.nodetype);
-														  fl_ptr->r.offset = cnv_e32 (fl_ptr->r.offset);
-														  p += sizeof (struct jffs2_sum_xref_flash);
-														  counter += sizeof (struct jffs2_sum_xref_flash);
-														  break;
-
-													  default :
-														  printf("Unknown node in summary information!!! nodetype(%x)\n", je16_to_cpu (fl_ptr->u.nodetype));
-														  exit(EXIT_FAILURE);
-														  break;
-												  }
-
-											  }
-
-											  //pad
-											  p += sum_len - counter;
-
-											  // summary marker
-											  sm_ptr = (struct jffs2_sum_marker *) p;
-											  sm_ptr->offset = cnv_e32 (sm_ptr->offset);
-											  sm_ptr->magic = cnv_e32 (sm_ptr->magic);
-											  p += sizeof (struct jffs2_sum_marker);
-
-											  // generate new crc on sum data
-											  newnode.s.sum_crc = cpu_to_e32 ( mtd_crc32(0, ((char *) node) + sizeof (struct jffs2_raw_summary),
-														  je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary)));
-
-											  // write out new node header
-											  write(fd, &newnode, sizeof (struct jffs2_raw_summary));
-											  // write out new summary data
-											  write(fd, &node->s.sum, sum_len + sizeof (struct jffs2_sum_marker));
-
-											  break;
-										  }
-
-			case 0xffff:
-										  write (fd, p, 4);
-										  p += 4;
-										  break;
-
-			default:
-										  printf ("Unknown node type: 0x%04x at 0x%08zx, totlen 0x%08x\n", je16_to_cpu (node->u.nodetype), p - data, je32_to_cpu (node->u.totlen));
-										  p += PAD(je32_to_cpu (node->u.totlen));
-
-		}
-	}
-
-	close (fd);
-
-}
-
-/*
- * Main program
- */
-int main(int argc, char **argv)
-{
-	int fd;
-
-	process_options(argc, argv);
-
-	/* Open the input file */
-	if ((fd = open(img, O_RDONLY)) == -1) {
-		perror("open input file");
-		exit(1);
-	}
-
-	// get image length
-	imglen = lseek(fd, 0, SEEK_END);
-	lseek (fd, 0, SEEK_SET);
-
-	data = malloc (imglen);
-	if (!data) {
-		perror("out of memory");
-		close (fd);
-		exit(1);
-	}
-
-	if (datsize && oobsize) {
-		int  idx = 0;
-		long len = imglen;
-		uint8_t oob[oobsize];
-		printf ("Peeling data out of combined data/oob image\n");
-		while (len) {
-			// read image data
-			read (fd, &data[idx], datsize);
-			read (fd, oob, oobsize);
-			idx += datsize;
-			imglen -= oobsize;
-			len -= datsize + oobsize;
-		}
-
-	} else {
-		// read image data
-		read (fd, data, imglen);
-	}
-	// Close the input file
-	close(fd);
-
-	if (dumpcontent)
-		do_dumpcontent ();
-
-	if (convertendian)
-		do_endianconvert ();
-
-	// free memory
-	free (data);
-
-	// Return happy
-	exit (0);
-}
diff --git a/jffs2reader.c b/jffs2reader.c
deleted file mode 100644
index a62da9a..0000000
--- a/jffs2reader.c
+++ /dev/null
@@ -1,918 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * jffs2reader v0.0.18 A jffs2 image reader
- *
- * Copyright (c) 2001 Jari Kirma <Jari.Kirma at hut.fi>
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the author be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any
- * purpose, including commercial applications, and to alter it and
- * redistribute it freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must
- * not claim that you wrote the original software. If you use this
- * software in a product, an acknowledgment in the product
- * documentation would be appreciated but is not required.
- *
- * 2. Altered source versions must be plainly marked as such, and must
- * not be misrepresented as being the original software.
- *
- * 3. This notice may not be removed or altered from any source
- * distribution.
- *
- *
- *********
- *  This code was altered September 2001
- *  Changes are Copyright (c) Erik Andersen <andersen at codepoet.org>
- *
- * In compliance with (2) above, this is hereby marked as an altered
- * version of this software.  It has been altered as follows:
- *      *) Listing a directory now mimics the behavior of 'ls -l'
- *      *) Support for recursive listing has been added
- *      *) Without options, does a recursive 'ls' on the whole filesystem
- *      *) option parsing now uses getopt()
- *      *) Now uses printf, and error messages go to stderr.
- *      *) The copyright notice has been cleaned up and reformatted
- *      *) The code has been reformatted
- *      *) Several twisty code paths have been fixed so I can understand them.
- *  -Erik, 1 September 2001
- *
- *      *) Made it show major/minor numbers for device nodes
- *      *) Made it show symlink targets
- *  -Erik, 13 September 2001
- */
-
-
-/*
-TODO:
-
-- Add CRC checking code to places marked with XXX.
-- Add support for other node compression types.
-
-- Test with real life images.
-- Maybe port into bootloader.
- */
-
-/*
-BUGS:
-
-- Doesn't check CRC checksums.
- */
-
-#define PROGRAM_NAME "jffs2reader"
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <zlib.h>
-
-#include "mtd/jffs2-user.h"
-#include "common.h"
-
-#define SCRATCH_SIZE (5*1024*1024)
-
-/* macro to avoid "lvalue required as left operand of assignment" error */
-#define ADD_BYTES(p, n)		((p) = (typeof(p))((char *)(p) + (n)))
-
-#define DIRENT_INO(dirent) ((dirent) !=NULL ? je32_to_cpu((dirent)->ino) : 0)
-#define DIRENT_PINO(dirent) ((dirent) !=NULL ? je32_to_cpu((dirent)->pino) : 0)
-
-struct dir {
-	struct dir *next;
-	uint8_t type;
-	uint8_t nsize;
-	uint32_t ino;
-	char name[256];
-};
-
-int target_endian = __BYTE_ORDER;
-
-void putblock(char *, size_t, size_t *, struct jffs2_raw_inode *);
-struct dir *putdir(struct dir *, struct jffs2_raw_dirent *);
-void printdir(char *o, size_t size, struct dir *d, const char *path,
-		int recurse, int want_ctime);
-void freedir(struct dir *);
-
-struct jffs2_raw_inode *find_raw_inode(char *o, size_t size, uint32_t ino);
-struct jffs2_raw_dirent *resolvedirent(char *, size_t, uint32_t, uint32_t,
-		char *, uint8_t);
-struct jffs2_raw_dirent *resolvename(char *, size_t, uint32_t, char *, uint8_t);
-struct jffs2_raw_dirent *resolveinode(char *, size_t, uint32_t);
-
-struct jffs2_raw_dirent *resolvepath0(char *, size_t, uint32_t, const char *,
-		uint32_t *, int);
-struct jffs2_raw_dirent *resolvepath(char *, size_t, uint32_t, const char *,
-		uint32_t *);
-
-void lsdir(char *, size_t, const char *, int, int);
-void catfile(char *, size_t, char *, char *, size_t, size_t *);
-
-int main(int, char **);
-
-/* writes file node into buffer, to the proper position. */
-/* reading all valid nodes in version order reconstructs the file. */
-
-/*
-   b       - buffer
-   bsize   - buffer size
-   rsize   - result size
-   n       - node
- */
-
-void putblock(char *b, size_t bsize, size_t * rsize,
-		struct jffs2_raw_inode *n)
-{
-	uLongf dlen = je32_to_cpu(n->dsize);
-
-	if (je32_to_cpu(n->isize) > bsize || (je32_to_cpu(n->offset) + dlen) > bsize)
-		errmsg_die("File does not fit into buffer!");
-
-	if (*rsize < je32_to_cpu(n->isize))
-		bzero(b + *rsize, je32_to_cpu(n->isize) - *rsize);
-
-	switch (n->compr) {
-		case JFFS2_COMPR_ZLIB:
-			uncompress((Bytef *) b + je32_to_cpu(n->offset), &dlen,
-					(Bytef *) ((char *) n) + sizeof(struct jffs2_raw_inode),
-					(uLongf) je32_to_cpu(n->csize));
-			break;
-
-		case JFFS2_COMPR_NONE:
-			memcpy(b + je32_to_cpu(n->offset),
-					((char *) n) + sizeof(struct jffs2_raw_inode), dlen);
-			break;
-
-		case JFFS2_COMPR_ZERO:
-			bzero(b + je32_to_cpu(n->offset), dlen);
-			break;
-
-			/* [DYN]RUBIN support required! */
-
-		default:
-			errmsg_die("Unsupported compression method!");
-	}
-
-	*rsize = je32_to_cpu(n->isize);
-}
-
-/* adds/removes directory node into dir struct. */
-/* reading all valid nodes in version order reconstructs the directory. */
-
-/*
-   dd      - directory struct being processed
-   n       - node
-
-   return value: directory struct value replacing dd
- */
-
-struct dir *putdir(struct dir *dd, struct jffs2_raw_dirent *n)
-{
-	struct dir *o, *d, *p;
-
-	o = dd;
-
-	if (je32_to_cpu(n->ino)) {
-		if (dd == NULL) {
-			d = xmalloc(sizeof(struct dir));
-			d->type = n->type;
-			memcpy(d->name, n->name, n->nsize);
-			d->nsize = n->nsize;
-			d->ino = je32_to_cpu(n->ino);
-			d->next = NULL;
-
-			return d;
-		}
-
-		while (1) {
-			if (n->nsize == dd->nsize &&
-					!memcmp(n->name, dd->name, n->nsize)) {
-				dd->type = n->type;
-				dd->ino = je32_to_cpu(n->ino);
-
-				return o;
-			}
-
-			if (dd->next == NULL) {
-				dd->next = xmalloc(sizeof(struct dir));
-				dd->next->type = n->type;
-				memcpy(dd->next->name, n->name, n->nsize);
-				dd->next->nsize = n->nsize;
-				dd->next->ino = je32_to_cpu(n->ino);
-				dd->next->next = NULL;
-
-				return o;
-			}
-
-			dd = dd->next;
-		}
-	} else {
-		if (dd == NULL)
-			return NULL;
-
-		if (n->nsize == dd->nsize && !memcmp(n->name, dd->name, n->nsize)) {
-			d = dd->next;
-			free(dd);
-			return d;
-		}
-
-		while (1) {
-			p = dd;
-			dd = dd->next;
-
-			if (dd == NULL)
-				return o;
-
-			if (n->nsize == dd->nsize &&
-					!memcmp(n->name, dd->name, n->nsize)) {
-				p->next = dd->next;
-				free(dd);
-
-				return o;
-			}
-		}
-	}
-}
-
-
-#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
-#define TYPECHAR(mode)  ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
-
-/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
-static const mode_t SBIT[] = {
-	0, 0, S_ISUID,
-	0, 0, S_ISGID,
-	0, 0, S_ISVTX
-};
-
-/* The 9 mode bits to test */
-static const mode_t MBIT[] = {
-	S_IRUSR, S_IWUSR, S_IXUSR,
-	S_IRGRP, S_IWGRP, S_IXGRP,
-	S_IROTH, S_IWOTH, S_IXOTH
-};
-
-static const char MODE1[] = "rwxrwxrwx";
-static const char MODE0[] = "---------";
-static const char SMODE1[] = "..s..s..t";
-static const char SMODE0[] = "..S..S..T";
-
-/*
- * Return the standard ls-like mode string from a file mode.
- * This is static and so is overwritten on each call.
- */
-const char *mode_string(int mode)
-{
-	static char buf[12];
-
-	int i;
-
-	buf[0] = TYPECHAR(mode);
-	for (i = 0; i < 9; i++) {
-		if (mode & SBIT[i])
-			buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
-		else
-			buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
-	}
-	return buf;
-}
-
-/* prints contents of directory structure */
-
-/*
-   d       - dir struct
- */
-
-void printdir(char *o, size_t size, struct dir *d, const char *path, int recurse,
-		int want_ctime)
-{
-	char m;
-	char *filetime;
-	time_t age;
-	struct jffs2_raw_inode *ri;
-	jint32_t mode;
-
-	if (!path)
-		return;
-	if (strlen(path) == 1 && *path == '/')
-		path++;
-
-	while (d != NULL) {
-		switch (d->type) {
-			case DT_REG:
-				m = ' ';
-				break;
-
-			case DT_FIFO:
-				m = '|';
-				break;
-
-			case DT_CHR:
-				m = ' ';
-				break;
-
-			case DT_BLK:
-				m = ' ';
-				break;
-
-			case DT_DIR:
-				m = '/';
-				break;
-
-			case DT_LNK:
-				m = ' ';
-				break;
-
-			case DT_SOCK:
-				m = '=';
-				break;
-
-			default:
-				m = '?';
-		}
-		ri = find_raw_inode(o, size, d->ino);
-		if (!ri) {
-			warnmsg("bug: raw_inode missing!");
-			d = d->next;
-			continue;
-		}
-
-		filetime = ctime((const time_t *) &(ri->ctime));
-		age = time(NULL) - je32_to_cpu(ri->ctime);
-		mode.v32 = ri->mode.m;
-		printf("%s %-4d %-8d %-8d ", mode_string(je32_to_cpu(mode)),
-				1, je16_to_cpu(ri->uid), je16_to_cpu(ri->gid));
-		if ( d->type==DT_BLK || d->type==DT_CHR ) {
-			dev_t rdev;
-			size_t devsize;
-			putblock((char*)&rdev, sizeof(rdev), &devsize, ri);
-			printf("%4d, %3d ", major(rdev), minor(rdev));
-		} else {
-			printf("%9ld ", (long)je32_to_cpu(ri->dsize));
-		}
-		d->name[d->nsize]='\0';
-		if (want_ctime) {
-			if (age < 3600L * 24 * 365 / 2 && age > -15 * 60)
-				/* hh:mm if less than 6 months old */
-				printf("%6.6s %5.5s ", filetime + 4, filetime + 11);
-			else
-				printf("%6.6s %4.4s ", filetime + 4, filetime + 20);
-		}
-		printf("%s/%s%c", path, d->name, m);
-		if (d->type == DT_LNK) {
-			char symbuf[1024];
-			size_t symsize;
-			putblock(symbuf, sizeof(symbuf), &symsize, ri);
-			symbuf[symsize] = 0;
-			printf(" -> %s", symbuf);
-		}
-		printf("\n");
-
-		if (d->type == DT_DIR && recurse) {
-			char *tmp;
-			tmp = xmalloc(BUFSIZ);
-			sprintf(tmp, "%s/%s", path, d->name);
-			lsdir(o, size, tmp, recurse, want_ctime);	/* Go recursive */
-			free(tmp);
-		}
-
-		d = d->next;
-	}
-}
-
-/* frees memory used by directory structure */
-
-/*
-   d       - dir struct
- */
-
-void freedir(struct dir *d)
-{
-	struct dir *t;
-
-	while (d != NULL) {
-		t = d->next;
-		free(d);
-		d = t;
-	}
-}
-
-/* collects directory/file nodes in version order. */
-
-/*
-   f       - file flag.
-   if zero, collect file, compare ino to inode
-   otherwise, collect directory, compare ino to parent inode
-   o       - filesystem image pointer
-   size    - size of filesystem image
-   ino     - inode to compare against. see f.
-
-   return value: a jffs2_raw_inode that corresponds the the specified
-   inode, or NULL
- */
-
-struct jffs2_raw_inode *find_raw_inode(char *o, size_t size, uint32_t ino)
-{
-	/* aligned! */
-	union jffs2_node_union *n;
-	union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
-	union jffs2_node_union *lr;	/* last block position */
-	union jffs2_node_union *mp = NULL;	/* minimum position */
-
-	uint32_t vmin, vmint, vmaxt, vmax, vcur, v;
-
-	vmin = 0;					/* next to read */
-	vmax = ~((uint32_t) 0);		/* last to read */
-	vmint = ~((uint32_t) 0);
-	vmaxt = 0;					/* found maximum */
-	vcur = 0;					/* XXX what is smallest version number used? */
-	/* too low version number can easily result excess log rereading */
-
-	n = (union jffs2_node_union *) o;
-	lr = n;
-
-	do {
-		while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
-			ADD_BYTES(n, 4);
-
-		if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
-			if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_INODE &&
-				je32_to_cpu(n->i.ino) == ino && (v = je32_to_cpu(n->i.version)) > vcur) {
-				/* XXX crc check */
-
-				if (vmaxt < v)
-					vmaxt = v;
-				if (vmint > v) {
-					vmint = v;
-					mp = n;
-				}
-
-				if (v == (vcur + 1))
-					return (&(n->i));
-			}
-
-			ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
-		} else
-			n = (union jffs2_node_union *) o;	/* we're at the end, rewind to the beginning */
-
-		if (lr == n) {			/* whole loop since last read */
-			vmax = vmaxt;
-			vmin = vmint;
-			vmint = ~((uint32_t) 0);
-
-			if (vcur < vmax && vcur < vmin)
-				return (&(mp->i));
-		}
-	} while (vcur < vmax);
-
-	return NULL;
-}
-
-/* collects dir struct for selected inode */
-
-/*
-   o       - filesystem image pointer
-   size    - size of filesystem image
-   pino    - inode of the specified directory
-   d       - input directory structure
-
-   return value: result directory structure, replaces d.
- */
-
-struct dir *collectdir(char *o, size_t size, uint32_t ino, struct dir *d)
-{
-	/* aligned! */
-	union jffs2_node_union *n;
-	union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
-	union jffs2_node_union *lr;	/* last block position */
-	union jffs2_node_union *mp = NULL;	/* minimum position */
-
-	uint32_t vmin, vmint, vmaxt, vmax, vcur, v;
-
-	vmin = 0;					/* next to read */
-	vmax = ~((uint32_t) 0);		/* last to read */
-	vmint = ~((uint32_t) 0);
-	vmaxt = 0;					/* found maximum */
-	vcur = 0;					/* XXX what is smallest version number used? */
-	/* too low version number can easily result excess log rereading */
-
-	n = (union jffs2_node_union *) o;
-	lr = n;
-
-	do {
-		while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
-			ADD_BYTES(n, 4);
-
-		if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
-			if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_DIRENT &&
-				je32_to_cpu(n->d.pino) == ino && (v = je32_to_cpu(n->d.version)) > vcur) {
-				/* XXX crc check */
-
-				if (vmaxt < v)
-					vmaxt = v;
-				if (vmint > v) {
-					vmint = v;
-					mp = n;
-				}
-
-				if (v == (vcur + 1)) {
-					d = putdir(d, &(n->d));
-
-					lr = n;
-					vcur++;
-					vmint = ~((uint32_t) 0);
-				}
-			}
-
-			ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
-		} else
-			n = (union jffs2_node_union *) o;	/* we're at the end, rewind to the beginning */
-
-		if (lr == n) {			/* whole loop since last read */
-			vmax = vmaxt;
-			vmin = vmint;
-			vmint = ~((uint32_t) 0);
-
-			if (vcur < vmax && vcur < vmin) {
-				d = putdir(d, &(mp->d));
-
-				lr = n =
-					(union jffs2_node_union *) (((char *) mp) +
-							((je32_to_cpu(mp->u.totlen) + 3) & ~3));
-
-				vcur = vmin;
-			}
-		}
-	} while (vcur < vmax);
-
-	return d;
-}
-
-
-
-/* resolve dirent based on criteria */
-
-/*
-   o       - filesystem image pointer
-   size    - size of filesystem image
-   ino     - if zero, ignore,
-   otherwise compare against dirent inode
-   pino    - if zero, ingore,
-   otherwise compare against parent inode
-   and use name and nsize as extra criteria
-   name    - name of wanted dirent, used if pino!=0
-   nsize   - length of name of wanted dirent, used if pino!=0
-
-   return value: pointer to relevant dirent structure in
-   filesystem image or NULL
- */
-
-struct jffs2_raw_dirent *resolvedirent(char *o, size_t size,
-		uint32_t ino, uint32_t pino,
-		char *name, uint8_t nsize)
-{
-	/* aligned! */
-	union jffs2_node_union *n;
-	union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
-
-	struct jffs2_raw_dirent *dd = NULL;
-
-	uint32_t vmax, v;
-
-	if (!pino && ino <= 1)
-		return dd;
-
-	vmax = 0;
-
-	n = (union jffs2_node_union *) o;
-
-	do {
-		while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
-			ADD_BYTES(n, 4);
-
-		if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
-			if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_DIRENT &&
-					(!ino || je32_to_cpu(n->d.ino) == ino) &&
-					(v = je32_to_cpu(n->d.version)) > vmax &&
-					(!pino || (je32_to_cpu(n->d.pino) == pino &&
-							   nsize == n->d.nsize &&
-							   !memcmp(name, n->d.name, nsize)))) {
-				/* XXX crc check */
-
-				if (vmax < v) {
-					vmax = v;
-					dd = &(n->d);
-				}
-			}
-
-			ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
-		} else
-			return dd;
-	} while (1);
-}
-
-/* resolve name under certain parent inode to dirent */
-
-/*
-   o       - filesystem image pointer
-   size    - size of filesystem image
-   pino    - requested parent inode
-   name    - name of wanted dirent
-   nsize   - length of name of wanted dirent
-
-   return value: pointer to relevant dirent structure in
-   filesystem image or NULL
- */
-
-struct jffs2_raw_dirent *resolvename(char *o, size_t size, uint32_t pino,
-		char *name, uint8_t nsize)
-{
-	return resolvedirent(o, size, 0, pino, name, nsize);
-}
-
-/* resolve inode to dirent */
-
-/*
-   o       - filesystem image pointer
-   size    - size of filesystem image
-   ino     - compare against dirent inode
-
-   return value: pointer to relevant dirent structure in
-   filesystem image or NULL
- */
-
-struct jffs2_raw_dirent *resolveinode(char *o, size_t size, uint32_t ino)
-{
-	return resolvedirent(o, size, ino, 0, NULL, 0);
-}
-
-/* resolve slash-style path into dirent and inode.
-   slash as first byte marks absolute path (root=inode 1).
-   . and .. are resolved properly, and symlinks are followed.
- */
-
-/*
-   o       - filesystem image pointer
-   size    - size of filesystem image
-   ino     - root inode, used if path is relative
-   p       - path to be resolved
-   inos    - result inode, zero if failure
-   recc    - recursion count, to detect symlink loops
-
-   return value: pointer to dirent struct in file system image.
-   note that root directory doesn't have dirent struct
-   (return value is NULL), but it has inode (*inos=1)
- */
-
-struct jffs2_raw_dirent *resolvepath0(char *o, size_t size, uint32_t ino,
-		const char *p, uint32_t * inos, int recc)
-{
-	struct jffs2_raw_dirent *dir = NULL;
-
-	int d = 1;
-	uint32_t tino;
-
-	char *next;
-
-	char *path, *pp;
-
-	char symbuf[1024];
-	size_t symsize;
-
-	if (recc > 16) {
-		/* probably symlink loop */
-		*inos = 0;
-		return NULL;
-	}
-
-	pp = path = xstrdup(p);
-
-	if (*path == '/') {
-		path++;
-		ino = 1;
-	}
-
-	if (ino > 1) {
-		dir = resolveinode(o, size, ino);
-
-		ino = DIRENT_INO(dir);
-	}
-
-	next = path - 1;
-
-	while (ino && next != NULL && next[1] != 0 && d) {
-		path = next + 1;
-		next = strchr(path, '/');
-
-		if (next != NULL)
-			*next = 0;
-
-		if (*path == '.' && path[1] == 0)
-			continue;
-		if (*path == '.' && path[1] == '.' && path[2] == 0) {
-			if (DIRENT_PINO(dir) == 1) {
-				ino = 1;
-				dir = NULL;
-			} else {
-				dir = resolveinode(o, size, DIRENT_PINO(dir));
-				ino = DIRENT_INO(dir);
-			}
-
-			continue;
-		}
-
-		dir = resolvename(o, size, ino, path, (uint8_t) strlen(path));
-
-		if (DIRENT_INO(dir) == 0 ||
-				(next != NULL &&
-				 !(dir->type == DT_DIR || dir->type == DT_LNK))) {
-			free(pp);
-
-			*inos = 0;
-
-			return NULL;
-		}
-
-		if (dir->type == DT_LNK) {
-			struct jffs2_raw_inode *ri;
-			ri = find_raw_inode(o, size, DIRENT_INO(dir));
-			putblock(symbuf, sizeof(symbuf), &symsize, ri);
-			symbuf[symsize] = 0;
-
-			tino = ino;
-			ino = 0;
-
-			dir = resolvepath0(o, size, tino, symbuf, &ino, ++recc);
-
-			if (dir != NULL && next != NULL &&
-					!(dir->type == DT_DIR || dir->type == DT_LNK)) {
-				free(pp);
-
-				*inos = 0;
-				return NULL;
-			}
-		}
-		if (dir != NULL)
-			ino = DIRENT_INO(dir);
-	}
-
-	free(pp);
-
-	*inos = ino;
-
-	return dir;
-}
-
-/* resolve slash-style path into dirent and inode.
-   slash as first byte marks absolute path (root=inode 1).
-   . and .. are resolved properly, and symlinks are followed.
- */
-
-/*
-   o       - filesystem image pointer
-   size    - size of filesystem image
-   ino     - root inode, used if path is relative
-   p       - path to be resolved
-   inos    - result inode, zero if failure
-
-   return value: pointer to dirent struct in file system image.
-   note that root directory doesn't have dirent struct
-   (return value is NULL), but it has inode (*inos=1)
- */
-
-struct jffs2_raw_dirent *resolvepath(char *o, size_t size, uint32_t ino,
-		const char *p, uint32_t * inos)
-{
-	return resolvepath0(o, size, ino, p, inos, 0);
-}
-
-/* lists files on directory specified by path */
-
-/*
-   o       - filesystem image pointer
-   size    - size of filesystem image
-   p       - path to be resolved
- */
-
-void lsdir(char *o, size_t size, const char *path, int recurse, int want_ctime)
-{
-	struct jffs2_raw_dirent *dd;
-	struct dir *d = NULL;
-
-	uint32_t ino;
-
-	dd = resolvepath(o, size, 1, path, &ino);
-
-	if (ino == 0 ||
-			(dd == NULL && ino == 0) || (dd != NULL && dd->type != DT_DIR))
-		errmsg_die("%s: No such file or directory", path);
-
-	d = collectdir(o, size, ino, d);
-	printdir(o, size, d, path, recurse, want_ctime);
-	freedir(d);
-}
-
-/* writes file specified by path to the buffer */
-
-/*
-   o       - filesystem image pointer
-   size    - size of filesystem image
-   p       - path to be resolved
-   b       - file buffer
-   bsize   - file buffer size
-   rsize   - file result size
- */
-
-void catfile(char *o, size_t size, char *path, char *b, size_t bsize,
-		size_t * rsize)
-{
-	struct jffs2_raw_dirent *dd;
-	struct jffs2_raw_inode *ri;
-	uint32_t ino;
-
-	dd = resolvepath(o, size, 1, path, &ino);
-
-	if (ino == 0)
-		errmsg_die("%s: No such file or directory", path);
-
-	if (dd == NULL || dd->type != DT_REG)
-		errmsg_die("%s: Not a regular file", path);
-
-	ri = find_raw_inode(o, size, ino);
-	putblock(b, bsize, rsize, ri);
-
-	write(1, b, *rsize);
-}
-
-/* usage example */
-
-int main(int argc, char **argv)
-{
-	int fd, opt, recurse = 0, want_ctime = 0;
-	struct stat st;
-
-	char *scratch, *dir = NULL, *file = NULL;
-	size_t ssize = 0;
-
-	char *buf;
-
-	while ((opt = getopt(argc, argv, "rd:f:t")) > 0) {
-		switch (opt) {
-			case 'd':
-				dir = optarg;
-				break;
-			case 'f':
-				file = optarg;
-				break;
-			case 'r':
-				recurse++;
-				break;
-			case 't':
-				want_ctime++;
-				break;
-			default:
-				fprintf(stderr,
-						"Usage: %s <image> [-d|-f] < path >\n",
-						PROGRAM_NAME);
-				exit(EXIT_FAILURE);
-		}
-	}
-
-	fd = open(argv[optind], O_RDONLY);
-	if (fd == -1)
-		sys_errmsg_die("%s", argv[optind]);
-
-	if (fstat(fd, &st))
-		sys_errmsg_die("%s", argv[optind]);
-
-	buf = xmalloc((size_t) st.st_size);
-
-	if (read(fd, buf, st.st_size) != (ssize_t) st.st_size)
-		sys_errmsg_die("%s", argv[optind]);
-
-	if (dir)
-		lsdir(buf, st.st_size, dir, recurse, want_ctime);
-
-	if (file) {
-		scratch = xmalloc(SCRATCH_SIZE);
-
-		catfile(buf, st.st_size, file, scratch, SCRATCH_SIZE, &ssize);
-		free(scratch);
-	}
-
-	if (!dir && !file)
-		lsdir(buf, st.st_size, "/", 1, want_ctime);
-
-
-	free(buf);
-	exit(EXIT_SUCCESS);
-}
diff --git a/jffsX-utils/compr.c b/jffsX-utils/compr.c
new file mode 100644
index 0000000..cb4432e
--- /dev/null
+++ b/jffsX-utils/compr.c
@@ -0,0 +1,538 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004 Ferenc Havasi <havasi at inf.u-szeged.hu>,
+ *                    University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory
+ * in the jffs2 directory.
+ */
+
+#include "compr.h"
+#include <string.h>
+#include <stdlib.h>
+#include <linux/jffs2.h>
+
+#define FAVOUR_LZO_PERCENT 80
+
+extern int page_size;
+
+/* LIST IMPLEMENTATION (from linux/list.h) */
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void __list_add(struct list_head *new,
+		struct list_head *prev,
+		struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = (void *) 0;
+	entry->prev = (void *) 0;
+}
+
+#define list_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#define list_for_each_entry(pos, head, member)                          \
+	for (pos = list_entry((head)->next, typeof(*pos), member);      \
+			&pos->member != (head);                                    \
+			pos = list_entry(pos->member.next, typeof(*pos), member))
+
+
+/* Available compressors are on this list */
+static LIST_HEAD(jffs2_compressor_list);
+
+/* Actual compression mode */
+static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
+
+void jffs2_set_compression_mode(int mode)
+{
+	jffs2_compression_mode = mode;
+}
+
+int jffs2_get_compression_mode(void)
+{
+	return jffs2_compression_mode;
+}
+
+/* Statistics for blocks stored without compression */
+static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
+
+/* Compression test stuffs */
+
+static int jffs2_compression_check = 0;
+
+static unsigned char *jffs2_compression_check_buf = NULL;
+
+void jffs2_compression_check_set(int yesno)
+{
+	jffs2_compression_check = yesno;
+}
+
+int jffs2_compression_check_get(void)
+{
+	return jffs2_compression_check;
+}
+
+static int jffs2_error_cnt = 0;
+
+int jffs2_compression_check_errorcnt_get(void)
+{
+	return jffs2_error_cnt;
+}
+
+#define JFFS2_BUFFER_FILL 0x55
+
+/* Called before compression (if compression_check is setted) to prepare
+   the buffer for buffer overflow test */
+static void jffs2_decompression_test_prepare(unsigned char *buf, int size)
+{
+	memset(buf,JFFS2_BUFFER_FILL,size+1);
+}
+
+/* Called after compression (if compression_check is setted) to test the result */
+static void jffs2_decompression_test(struct jffs2_compressor *compr,
+		unsigned char *data_in, unsigned char *output_buf,
+		uint32_t cdatalen, uint32_t datalen, uint32_t buf_size)
+{
+	uint32_t i;
+
+	/* buffer overflow test */
+	for (i=buf_size;i>cdatalen;i--) {
+		if (output_buf[i]!=JFFS2_BUFFER_FILL) {
+			fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. "
+					"(bs=%d csize=%d b[%d]=%d)\n", compr->name,
+					buf_size, cdatalen, i, (int)(output_buf[i]));
+			jffs2_error_cnt++;
+			return;
+		}
+	}
+	/* allocing temporary buffer for decompression */
+	if (!jffs2_compression_check_buf) {
+		jffs2_compression_check_buf = malloc(page_size);
+		if (!jffs2_compression_check_buf) {
+			fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n");
+			jffs2_compression_check = 0;
+			return;
+		}
+	}
+	/* decompressing */
+	if (!compr->decompress) {
+		fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name);
+		jffs2_error_cnt++;
+		return;
+	}
+	if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen)) {
+		fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name);
+		jffs2_error_cnt++;
+	}
+	/* validate decompression */
+	else {
+		for (i=0;i<datalen;i++) {
+			if (data_in[i]!=jffs2_compression_check_buf[i]) {
+				fprintf(stderr,"JFFS2 compression check: data mismatch at %s (pos %d).\n", compr->name, i);
+				jffs2_error_cnt++;
+				break;
+			}
+		}
+	}
+}
+
+/*
+ * Return 1 to use this compression
+ */
+static int jffs2_is_best_compression(struct jffs2_compressor *this,
+		struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
+{
+	switch (jffs2_compression_mode) {
+	case JFFS2_COMPR_MODE_SIZE:
+		if (bestsize > size)
+			return 1;
+		return 0;
+	case JFFS2_COMPR_MODE_FAVOURLZO:
+		if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size))
+			return 1;
+		if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
+			return 1;
+		if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
+			return 1;
+		if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
+			return 1;
+
+		return 0;
+	}
+	/* Shouldn't happen */
+	return 0;
+}
+
+/* jffs2_compress:
+ * @data: Pointer to uncompressed data
+ * @cdata: Pointer to returned pointer to buffer for compressed data
+ * @datalen: On entry, holds the amount of data available for compression.
+ *	On exit, expected to hold the amount of data actually compressed.
+ * @cdatalen: On entry, holds the amount of space available for compressed
+ *	data. On exit, expected to hold the actual size of the compressed
+ *	data.
+ *
+ * Returns: Lower byte to be stored with data indicating compression type used.
+ * Zero is used to show that the data could not be compressed - the
+ * compressed version was actually larger than the original.
+ * Upper byte will be used later. (soon)
+ *
+ * If the cdata buffer isn't large enough to hold all the uncompressed data,
+ * jffs2_compress should compress as much as will fit, and should set
+ * *datalen accordingly to show the amount of data which were compressed.
+ */
+uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out,
+		uint32_t *datalen, uint32_t *cdatalen)
+{
+	int ret = JFFS2_COMPR_NONE;
+	int compr_ret;
+	struct jffs2_compressor *this, *best=NULL;
+	unsigned char *output_buf = NULL, *tmp_buf;
+	uint32_t orig_slen, orig_dlen;
+	uint32_t best_slen=0, best_dlen=0;
+
+	switch (jffs2_compression_mode) {
+		case JFFS2_COMPR_MODE_NONE:
+			break;
+		case JFFS2_COMPR_MODE_PRIORITY:
+			orig_slen = *datalen;
+			orig_dlen = *cdatalen;
+			output_buf = malloc(orig_dlen+jffs2_compression_check);
+			if (!output_buf) {
+				fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n");
+				goto out;
+			}
+			list_for_each_entry(this, &jffs2_compressor_list, list) {
+				/* Skip decompress-only backwards-compatibility and disabled modules */
+				if ((!this->compress)||(this->disabled))
+					continue;
+
+				this->usecount++;
+
+				if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
+					jffs2_decompression_test_prepare(output_buf, orig_dlen);
+
+				*datalen  = orig_slen;
+				*cdatalen = orig_dlen;
+				compr_ret = this->compress(data_in, output_buf, datalen, cdatalen);
+				this->usecount--;
+				if (!compr_ret) {
+					ret = this->compr;
+					this->stat_compr_blocks++;
+					this->stat_compr_orig_size += *datalen;
+					this->stat_compr_new_size  += *cdatalen;
+					if (jffs2_compression_check)
+						jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, orig_dlen);
+					break;
+				}
+			}
+			if (ret == JFFS2_COMPR_NONE) free(output_buf);
+			break;
+		case JFFS2_COMPR_MODE_FAVOURLZO:
+		case JFFS2_COMPR_MODE_SIZE:
+			orig_slen = *datalen;
+			orig_dlen = *cdatalen;
+			list_for_each_entry(this, &jffs2_compressor_list, list) {
+				uint32_t needed_buf_size;
+
+				if (jffs2_compression_mode == JFFS2_COMPR_MODE_FAVOURLZO)
+					needed_buf_size = orig_slen + jffs2_compression_check;
+				else
+					needed_buf_size = orig_dlen + jffs2_compression_check;
+
+				/* Skip decompress-only backwards-compatibility and disabled modules */
+				if ((!this->compress)||(this->disabled))
+					continue;
+				/* Allocating memory for output buffer if necessary */
+				if ((this->compr_buf_size < needed_buf_size) && (this->compr_buf)) {
+					free(this->compr_buf);
+					this->compr_buf_size=0;
+					this->compr_buf=NULL;
+				}
+				if (!this->compr_buf) {
+					tmp_buf = malloc(needed_buf_size);
+					if (!tmp_buf) {
+						fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
+						continue;
+					}
+					else {
+						this->compr_buf = tmp_buf;
+						this->compr_buf_size = orig_dlen;
+					}
+				}
+				this->usecount++;
+				if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
+					jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size);
+				*datalen  = orig_slen;
+				*cdatalen = orig_dlen;
+				compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
+				this->usecount--;
+				if (!compr_ret) {
+					if (jffs2_compression_check)
+						jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, this->compr_buf_size);
+					if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
+								&& (*cdatalen < *datalen)) {
+						best_dlen = *cdatalen;
+						best_slen = *datalen;
+						best = this;
+					}
+				}
+			}
+			if (best_dlen) {
+				*cdatalen = best_dlen;
+				*datalen  = best_slen;
+				output_buf = best->compr_buf;
+				best->compr_buf = NULL;
+				best->compr_buf_size = 0;
+				best->stat_compr_blocks++;
+				best->stat_compr_orig_size += best_slen;
+				best->stat_compr_new_size  += best_dlen;
+				ret = best->compr;
+			}
+			break;
+		default:
+			fprintf(stderr,"mkfs.jffs2: unknown compression mode.\n");
+	}
+out:
+	if (ret == JFFS2_COMPR_NONE) {
+		*cpage_out = data_in;
+		*datalen = *cdatalen;
+		none_stat_compr_blocks++;
+		none_stat_compr_size += *datalen;
+	}
+	else {
+		*cpage_out = output_buf;
+	}
+	return ret;
+}
+
+
+int jffs2_register_compressor(struct jffs2_compressor *comp)
+{
+	struct jffs2_compressor *this;
+
+	if (!comp->name) {
+		fprintf(stderr,"NULL compressor name at registering JFFS2 compressor. Failed.\n");
+		return -1;
+	}
+	comp->compr_buf_size=0;
+	comp->compr_buf=NULL;
+	comp->usecount=0;
+	comp->stat_compr_orig_size=0;
+	comp->stat_compr_new_size=0;
+	comp->stat_compr_blocks=0;
+	comp->stat_decompr_blocks=0;
+
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		if (this->priority < comp->priority) {
+			list_add(&comp->list, this->list.prev);
+			goto out;
+		}
+	}
+	list_add_tail(&comp->list, &jffs2_compressor_list);
+out:
+	return 0;
+}
+
+int jffs2_unregister_compressor(struct jffs2_compressor *comp)
+{
+
+	if (comp->usecount) {
+		fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n");
+		return -1;
+	}
+	list_del(&comp->list);
+
+	return 0;
+}
+
+#define JFFS2_STAT_BUF_SIZE 16000
+
+char *jffs2_list_compressors(void)
+{
+	struct jffs2_compressor *this;
+	char *buf, *act_buf;
+
+	act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
+		if ((this->disabled)||(!this->compress))
+			act_buf += sprintf(act_buf,"disabled");
+		else
+			act_buf += sprintf(act_buf,"enabled");
+		act_buf += sprintf(act_buf,"\n");
+	}
+	return buf;
+}
+
+char *jffs2_stats(void)
+{
+	struct jffs2_compressor *this;
+	char *buf, *act_buf;
+
+	act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
+
+	act_buf += sprintf(act_buf,"Compression mode: ");
+	switch (jffs2_compression_mode) {
+		case JFFS2_COMPR_MODE_NONE:
+			act_buf += sprintf(act_buf,"none");
+			break;
+		case JFFS2_COMPR_MODE_PRIORITY:
+			act_buf += sprintf(act_buf,"priority");
+			break;
+		case JFFS2_COMPR_MODE_SIZE:
+			act_buf += sprintf(act_buf,"size");
+			break;
+		case JFFS2_COMPR_MODE_FAVOURLZO:
+			act_buf += sprintf(act_buf, "favourlzo");
+			break;
+		default:
+			act_buf += sprintf(act_buf, "unknown");
+			break;
+	}
+	act_buf += sprintf(act_buf,"\nCompressors:\n");
+	act_buf += sprintf(act_buf,"%10s             ","none");
+	act_buf += sprintf(act_buf,"compr: %d blocks (%d)  decompr: %d blocks\n", none_stat_compr_blocks,
+			none_stat_compr_size, none_stat_decompr_blocks);
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		act_buf += sprintf(act_buf,"%10s (prio:%d) ",this->name,this->priority);
+		if ((this->disabled)||(!this->compress))
+			act_buf += sprintf(act_buf,"- ");
+		else
+			act_buf += sprintf(act_buf,"+ ");
+		act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks,
+				this->stat_compr_new_size, this->stat_compr_orig_size,
+				this->stat_decompr_blocks);
+		act_buf += sprintf(act_buf,"\n");
+	}
+	return buf;
+}
+
+int jffs2_set_compression_mode_name(const char *name)
+{
+	if (!strcmp("none",name)) {
+		jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+		return 0;
+	}
+	if (!strcmp("priority",name)) {
+		jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
+		return 0;
+	}
+	if (!strcmp("size",name)) {
+		jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
+		return 0;
+	}
+	if (!strcmp("favourlzo", name)) {
+		jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
+		return 0;
+	}
+
+	return 1;
+}
+
+static int jffs2_compressor_Xable(const char *name, int disabled)
+{
+	struct jffs2_compressor *this;
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		if (!strcmp(this->name, name)) {
+			this->disabled = disabled;
+			return 0;
+		}
+	}
+	return 1;
+}
+
+int jffs2_enable_compressor_name(const char *name)
+{
+	return jffs2_compressor_Xable(name, 0);
+}
+
+int jffs2_disable_compressor_name(const char *name)
+{
+	return jffs2_compressor_Xable(name, 1);
+}
+
+int jffs2_set_compressor_priority(const char *name, int priority)
+{
+	struct jffs2_compressor *this,*comp;
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		if (!strcmp(this->name, name)) {
+			this->priority = priority;
+			comp = this;
+			goto reinsert;
+		}
+	}
+	fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name);
+	return 1;
+reinsert:
+	/* list is sorted in the order of priority, so if
+	   we change it we have to reinsert it into the
+	   good place */
+	list_del(&comp->list);
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		if (this->priority < comp->priority) {
+			list_add(&comp->list, this->list.prev);
+			return 0;
+		}
+	}
+	list_add_tail(&comp->list, &jffs2_compressor_list);
+	return 0;
+}
+
+
+int jffs2_compressors_init(void)
+{
+#ifdef CONFIG_JFFS2_ZLIB
+	jffs2_zlib_init();
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+	jffs2_rtime_init();
+#endif
+#ifdef CONFIG_JFFS2_LZO
+	jffs2_lzo_init();
+#endif
+	return 0;
+}
+
+int jffs2_compressors_exit(void)
+{
+#ifdef CONFIG_JFFS2_RTIME
+	jffs2_rtime_exit();
+#endif
+#ifdef CONFIG_JFFS2_ZLIB
+	jffs2_zlib_exit();
+#endif
+#ifdef CONFIG_JFFS2_LZO
+	jffs2_lzo_exit();
+#endif
+	return 0;
+}
diff --git a/jffsX-utils/compr.h b/jffsX-utils/compr.h
new file mode 100644
index 0000000..a21e935
--- /dev/null
+++ b/jffsX-utils/compr.h
@@ -0,0 +1,119 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004 Ferenc Havasi <havasi at inf.u-szeged.hu>,
+ *                    University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in the
+ * jffs2 directory.
+ */
+
+#ifndef __JFFS2_COMPR_H__
+#define __JFFS2_COMPR_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "linux/jffs2.h"
+
+#define CONFIG_JFFS2_ZLIB
+#define CONFIG_JFFS2_RTIME
+#define CONFIG_JFFS2_LZO
+
+#define JFFS2_RUBINMIPS_PRIORITY 10
+#define JFFS2_DYNRUBIN_PRIORITY  20
+#define JFFS2_RTIME_PRIORITY     50
+#define JFFS2_ZLIB_PRIORITY      60
+#define JFFS2_LZO_PRIORITY       80
+
+#define JFFS2_COMPR_MODE_NONE       0
+#define JFFS2_COMPR_MODE_PRIORITY   1
+#define JFFS2_COMPR_MODE_SIZE       2
+#define JFFS2_COMPR_MODE_FAVOURLZO  3
+
+#define kmalloc(a,b)                malloc(a)
+#define kfree(a)                    free(a)
+#ifndef GFP_KERNEL
+#define GFP_KERNEL                  0
+#endif
+
+#define vmalloc(a)                  malloc(a)
+#define vfree(a)                    free(a)
+
+#define printk(...)                 fprintf(stderr,__VA_ARGS__)
+
+#define KERN_EMERG
+#define KERN_ALERT
+#define KERN_CRIT
+#define KERN_ERR
+#define KERN_WARNING
+#define KERN_NOTICE
+#define KERN_INFO
+#define KERN_DEBUG
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+void jffs2_set_compression_mode(int mode);
+int jffs2_get_compression_mode(void);
+int jffs2_set_compression_mode_name(const char *mode_name);
+
+int jffs2_enable_compressor_name(const char *name);
+int jffs2_disable_compressor_name(const char *name);
+
+int jffs2_set_compressor_priority(const char *name, int priority);
+
+struct jffs2_compressor {
+	struct list_head list;
+	int priority;             /* used by prirority comr. mode */
+	const char *name;
+	char compr;               /* JFFS2_COMPR_XXX */
+	int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
+			uint32_t *srclen, uint32_t *destlen);
+	int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
+			uint32_t cdatalen, uint32_t datalen);
+	int usecount;
+	int disabled;             /* if seted the compressor won't compress */
+	unsigned char *compr_buf; /* used by size compr. mode */
+	uint32_t compr_buf_size;  /* used by size compr. mode */
+	uint32_t stat_compr_orig_size;
+	uint32_t stat_compr_new_size;
+	uint32_t stat_compr_blocks;
+	uint32_t stat_decompr_blocks;
+};
+
+int jffs2_register_compressor(struct jffs2_compressor *comp);
+int jffs2_unregister_compressor(struct jffs2_compressor *comp);
+
+int jffs2_compressors_init(void);
+int jffs2_compressors_exit(void);
+
+uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out,
+		uint32_t *datalen, uint32_t *cdatalen);
+
+/* If it is setted, a decompress will be called after every compress */
+void jffs2_compression_check_set(int yesno);
+int jffs2_compression_check_get(void);
+int jffs2_compression_check_errorcnt_get(void);
+
+char *jffs2_list_compressors(void);
+char *jffs2_stats(void);
+
+/* Compressor modules */
+
+/* These functions will be called by jffs2_compressors_init/exit */
+#ifdef CONFIG_JFFS2_ZLIB
+int jffs2_zlib_init(void);
+void jffs2_zlib_exit(void);
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+int jffs2_rtime_init(void);
+void jffs2_rtime_exit(void);
+#endif
+#ifdef CONFIG_JFFS2_LZO
+int jffs2_lzo_init(void);
+void jffs2_lzo_exit(void);
+#endif
+
+#endif /* __JFFS2_COMPR_H__ */
diff --git a/jffsX-utils/compr_lzo.c b/jffsX-utils/compr_lzo.c
new file mode 100644
index 0000000..d2e2afc
--- /dev/null
+++ b/jffsX-utils/compr_lzo.c
@@ -0,0 +1,135 @@
+/*
+ * JFFS2 LZO Compression Interface.
+ *
+ * Copyright (C) 2007 Nokia Corporation. All rights reserved.
+ *
+ * Author: Richard Purdie <rpurdie at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef WITHOUT_LZO
+#include <asm/types.h>
+#include <linux/jffs2.h>
+#include <lzo/lzo1x.h>
+#include "compr.h"
+
+extern int page_size;
+
+static void *lzo_mem;
+static void *lzo_compress_buf;
+
+/*
+ * Note about LZO compression.
+ *
+ * We want to use the _999_ compression routine which gives better compression
+ * rates at the expense of time. Decompression time is unaffected. We might as
+ * well use the standard lzo library routines for this but they will overflow
+ * the destination buffer since they don't check the destination size.
+ *
+ * We therefore compress to a temporary buffer and copy if it will fit.
+ *
+ */
+static int jffs2_lzo_cmpr(unsigned char *data_in, unsigned char *cpage_out,
+			  uint32_t *sourcelen, uint32_t *dstlen)
+{
+	lzo_uint compress_size;
+	int ret;
+
+	ret = lzo1x_999_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem);
+
+	if (ret != LZO_E_OK)
+		return -1;
+
+	if (compress_size > *dstlen)
+		return -1;
+
+	memcpy(cpage_out, lzo_compress_buf, compress_size);
+	*dstlen = compress_size;
+
+	return 0;
+}
+
+static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out,
+				 uint32_t srclen, uint32_t destlen)
+{
+	int ret;
+	lzo_uint dl;
+
+	ret = lzo1x_decompress_safe(data_in,srclen,cpage_out,&dl,NULL);
+
+	if (ret != LZO_E_OK || dl != destlen)
+		return -1;
+
+	return 0;
+}
+
+static struct jffs2_compressor jffs2_lzo_comp = {
+	.priority = JFFS2_LZO_PRIORITY,
+	.name = "lzo",
+	.compr = JFFS2_COMPR_LZO,
+	.compress = &jffs2_lzo_cmpr,
+	.decompress = &jffs2_lzo_decompress,
+	.disabled = 1,
+};
+
+int jffs2_lzo_init(void)
+{
+	int ret;
+
+	lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
+	if (!lzo_mem)
+		return -1;
+
+	/* Worse case LZO compression size from their FAQ */
+	lzo_compress_buf = malloc(page_size + (page_size / 16) + 64 + 3);
+	if (!lzo_compress_buf) {
+		free(lzo_mem);
+		return -1;
+	}
+
+	ret = jffs2_register_compressor(&jffs2_lzo_comp);
+	if (ret < 0) {
+		free(lzo_compress_buf);
+		free(lzo_mem);
+	}
+
+	return ret;
+}
+
+void jffs2_lzo_exit(void)
+{
+	jffs2_unregister_compressor(&jffs2_lzo_comp);
+	free(lzo_compress_buf);
+	free(lzo_mem);
+}
+
+#else
+
+int jffs2_lzo_init(void)
+{
+	return 0;
+}
+
+void jffs2_lzo_exit(void)
+{
+}
+
+#endif
diff --git a/jffsX-utils/compr_rtime.c b/jffsX-utils/compr_rtime.c
new file mode 100644
index 0000000..f24379d
--- /dev/null
+++ b/jffsX-utils/compr_rtime.c
@@ -0,0 +1,119 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by Arjan van de Ven <arjanv at redhat.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * Very simple lz77-ish encoder.
+ *
+ * Theory of operation: Both encoder and decoder have a list of "last
+ * occurrences" for every possible source-value; after sending the
+ * first source-byte, the second byte indicated the "run" length of
+ * matches
+ *
+ * The algorithm is intended to only send "whole bytes", no bit-messing.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "compr.h"
+
+/* _compress returns the compressed size, -1 if bigger */
+static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
+		uint32_t *sourcelen, uint32_t *dstlen)
+{
+	short positions[256];
+	int outpos = 0;
+	int pos=0;
+
+	memset(positions,0,sizeof(positions));
+
+	while (pos < (*sourcelen) && outpos+2 <= (*dstlen)) {
+		int backpos, runlen=0;
+		unsigned char value;
+
+		value = data_in[pos];
+
+		cpage_out[outpos++] = data_in[pos++];
+
+		backpos = positions[value];
+		positions[value]=pos;
+
+		while ((backpos < pos) && (pos < (*sourcelen)) &&
+				(data_in[pos]==data_in[backpos++]) && (runlen<255)) {
+			pos++;
+			runlen++;
+		}
+		cpage_out[outpos++] = runlen;
+	}
+
+	if (outpos >= pos) {
+		/* We failed */
+		return -1;
+	}
+
+	/* Tell the caller how much we managed to compress, and how much space it took */
+	*sourcelen = pos;
+	*dstlen = outpos;
+	return 0;
+}
+
+
+static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
+		__attribute__((unused)) uint32_t srclen, uint32_t destlen)
+{
+	short positions[256];
+	int outpos = 0;
+	int pos=0;
+
+	memset(positions,0,sizeof(positions));
+
+	while (outpos<destlen) {
+		unsigned char value;
+		int backoffs;
+		int repeat;
+
+		value = data_in[pos++];
+		cpage_out[outpos++] = value; /* first the verbatim copied byte */
+		repeat = data_in[pos++];
+		backoffs = positions[value];
+
+		positions[value]=outpos;
+		if (repeat) {
+			if (backoffs + repeat >= outpos) {
+				while(repeat) {
+					cpage_out[outpos++] = cpage_out[backoffs++];
+					repeat--;
+				}
+			} else {
+				memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat);
+				outpos+=repeat;
+			}
+		}
+	}
+	return 0;
+}
+
+
+static struct jffs2_compressor jffs2_rtime_comp = {
+	.priority = JFFS2_RTIME_PRIORITY,
+	.name = "rtime",
+	.disabled = 0,
+	.compr = JFFS2_COMPR_RTIME,
+	.compress = &jffs2_rtime_compress,
+	.decompress = &jffs2_rtime_decompress,
+};
+
+int jffs2_rtime_init(void)
+{
+	return jffs2_register_compressor(&jffs2_rtime_comp);
+}
+
+void jffs2_rtime_exit(void)
+{
+	jffs2_unregister_compressor(&jffs2_rtime_comp);
+}
diff --git a/jffsX-utils/compr_zlib.c b/jffsX-utils/compr_zlib.c
new file mode 100644
index 0000000..1f94628
--- /dev/null
+++ b/jffsX-utils/compr_zlib.c
@@ -0,0 +1,148 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2 at cambridge.redhat.com>
+ *
+ * The original JFFS, from which the design for JFFS2 was derived,
+ * was designed and implemented by Axis Communications AB.
+ *
+ * The contents of this file are subject to the Red Hat eCos Public
+ * License Version 1.1 (the "Licence"); you may not use this file
+ * except in compliance with the Licence.  You may obtain a copy of
+ * the Licence at http://www.redhat.com/
+ *
+ * Software distributed under the Licence is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing rights and
+ * limitations under the Licence.
+ *
+ * The Original Code is JFFS2 - Journalling Flash File System, version 2
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the RHEPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the RHEPL or the GPL.
+ */
+
+#define PROGRAM_NAME "compr_zlib"
+
+#include <stdint.h>
+#define crc32 __zlib_crc32
+#include <zlib.h>
+#undef crc32
+#include <stdio.h>
+#include <asm/types.h>
+#include <linux/jffs2.h>
+#include "common.h"
+#include "compr.h"
+
+/* Plan: call deflate() with avail_in == *sourcelen,
+   avail_out = *dstlen - 12 and flush == Z_FINISH.
+   If it doesn't manage to finish,	call it again with
+   avail_in == 0 and avail_out set to the remaining 12
+   bytes for it to clean up.
+Q: Is 12 bytes sufficient?
+ */
+#define STREAM_END_SPACE 12
+
+static int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
+		uint32_t *sourcelen, uint32_t *dstlen)
+{
+	z_stream strm;
+	int ret;
+
+	if (*dstlen <= STREAM_END_SPACE)
+		return -1;
+
+	strm.zalloc = (void *)0;
+	strm.zfree = (void *)0;
+
+	if (Z_OK != deflateInit(&strm, 3)) {
+		return -1;
+	}
+	strm.next_in = data_in;
+	strm.total_in = 0;
+
+	strm.next_out = cpage_out;
+	strm.total_out = 0;
+
+	while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) {
+		strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE);
+		strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
+		ret = deflate(&strm, Z_PARTIAL_FLUSH);
+		if (ret != Z_OK) {
+			deflateEnd(&strm);
+			return -1;
+		}
+	}
+	strm.avail_out += STREAM_END_SPACE;
+	strm.avail_in = 0;
+	ret = deflate(&strm, Z_FINISH);
+	if (ret != Z_STREAM_END) {
+		deflateEnd(&strm);
+		return -1;
+	}
+	deflateEnd(&strm);
+
+	if (strm.total_out >= strm.total_in)
+		return -1;
+
+
+	*dstlen = strm.total_out;
+	*sourcelen = strm.total_in;
+	return 0;
+}
+
+static int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+		uint32_t srclen, uint32_t destlen)
+{
+	z_stream strm;
+	int ret;
+
+	strm.zalloc = (void *)0;
+	strm.zfree = (void *)0;
+
+	if (Z_OK != inflateInit(&strm)) {
+		return 1;
+	}
+	strm.next_in = data_in;
+	strm.avail_in = srclen;
+	strm.total_in = 0;
+
+	strm.next_out = cpage_out;
+	strm.avail_out = destlen;
+	strm.total_out = 0;
+
+	while((ret = inflate(&strm, Z_FINISH)) == Z_OK)
+		;
+
+	inflateEnd(&strm);
+	return 0;
+}
+
+static struct jffs2_compressor jffs2_zlib_comp = {
+	.priority = JFFS2_ZLIB_PRIORITY,
+	.name = "zlib",
+	.disabled = 0,
+	.compr = JFFS2_COMPR_ZLIB,
+	.compress = &jffs2_zlib_compress,
+	.decompress = &jffs2_zlib_decompress,
+};
+
+int jffs2_zlib_init(void)
+{
+	return jffs2_register_compressor(&jffs2_zlib_comp);
+}
+
+void jffs2_zlib_exit(void)
+{
+	jffs2_unregister_compressor(&jffs2_zlib_comp);
+}
diff --git a/jffsX-utils/device_table.txt b/jffsX-utils/device_table.txt
new file mode 100644
index 0000000..394a62b
--- /dev/null
+++ b/jffsX-utils/device_table.txt
@@ -0,0 +1,128 @@
+# This is a sample device table file for use with mkfs.jffs2.  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.
+#
+# 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 entried apply only to device special
+# file.
+
+# 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".
+# 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
+#
+# Have fun
+# -Erik Andersen <andersen at 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 --git a/jffsX-utils/jffs-dump.c b/jffsX-utils/jffs-dump.c
new file mode 100644
index 0000000..3176469
--- /dev/null
+++ b/jffsX-utils/jffs-dump.c
@@ -0,0 +1,359 @@
+/*
+ * Dump JFFS filesystem.
+ * Useful when it buggers up.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#include "common.h"
+
+#define BLOCK_SIZE 1024
+#define JFFS_MAGIC 0x34383931 /* "1984" */
+#define JFFS_MAX_NAME_LEN 256
+#define JFFS_MIN_INO 1
+#define JFFS_TRACE_INDENT 4
+#define JFFS_ALIGN_SIZE 4
+#define MAX_CHUNK_SIZE 32768
+
+/* How many padding bytes should be inserted between two chunks of data
+   on the flash?  */
+#define JFFS_GET_PAD_BYTES(size) ((JFFS_ALIGN_SIZE                     \
+			- ((uint32_t)(size) % JFFS_ALIGN_SIZE)) \
+		% JFFS_ALIGN_SIZE)
+
+#define JFFS_EMPTY_BITMASK 0xffffffff
+#define JFFS_MAGIC_BITMASK 0x34383931
+#define JFFS_DIRTY_BITMASK 0x00000000
+
+struct jffs_raw_inode
+{
+	uint32_t magic;    /* A constant magic number.  */
+	uint32_t ino;      /* Inode number.  */
+	uint32_t pino;     /* Parent's inode number.  */
+	uint32_t version;  /* Version number.  */
+	uint32_t mode;     /* file_type, mode  */
+	uint16_t uid;
+	uint16_t gid;
+	uint32_t atime;
+	uint32_t mtime;
+	uint32_t ctime;
+	uint32_t offset;     /* Where to begin to write.  */
+	uint32_t dsize;      /* Size of the file data.  */
+	uint32_t rsize;      /* How much are going to be replaced?  */
+	uint8_t nsize;       /* Name length.  */
+	uint8_t nlink;       /* Number of links.  */
+	uint8_t spare : 6;   /* For future use.  */
+	uint8_t rename : 1;  /* Is this a special rename?  */
+	uint8_t deleted : 1; /* Has this file been deleted?  */
+	uint8_t accurate;    /* The inode is obsolete if accurate == 0.  */
+	uint32_t dchksum;    /* Checksum for the data.  */
+	uint16_t nchksum;    /* Checksum for the name.  */
+	uint16_t chksum;     /* Checksum for the raw_inode.  */
+};
+
+
+struct jffs_file
+{
+	struct jffs_raw_inode inode;
+	char *name;
+	unsigned char *data;
+};
+
+
+char *root_directory_name = NULL;
+int fs_pos = 0;
+int verbose = 0;
+
+#define ENDIAN_HOST   0
+#define ENDIAN_BIG    1
+#define ENDIAN_LITTLE 2
+int endian = ENDIAN_HOST;
+
+static uint32_t jffs_checksum(void *data, int size);
+void jffs_print_trace(const char *path, int depth);
+int make_root_dir(FILE *fs, int first_ino, const char *root_dir_path,
+		int depth);
+void write_file(struct jffs_file *f, FILE *fs, struct stat st);
+void read_data(struct jffs_file *f, const char *path, int offset);
+int mkfs(FILE *fs, const char *path, int ino, int parent, int depth);
+
+
+	static uint32_t
+jffs_checksum(void *data, int size)
+{
+	uint32_t sum = 0;
+	uint8_t *ptr = (uint8_t *)data;
+
+	while (size-- > 0)
+	{
+		sum += *ptr++;
+	}
+
+	return sum;
+}
+
+
+	void
+jffs_print_trace(const char *path, int depth)
+{
+	int path_len = strlen(path);
+	int out_pos = depth * JFFS_TRACE_INDENT;
+	int pos = path_len - 1;
+	char *out = (char *)alloca(depth * JFFS_TRACE_INDENT + path_len + 1);
+
+	if (verbose >= 2)
+	{
+		fprintf(stderr, "jffs_print_trace(): path: \"%s\"\n", path);
+	}
+
+	if (!out) {
+		fprintf(stderr, "jffs_print_trace(): Allocation failed.\n");
+		fprintf(stderr, " path: \"%s\"\n", path);
+		fprintf(stderr, "depth: %d\n", depth);
+		exit(1);
+	}
+
+	memset(out, ' ', depth * JFFS_TRACE_INDENT);
+
+	if (path[pos] == '/')
+	{
+		pos--;
+	}
+	while (path[pos] && (path[pos] != '/'))
+	{
+		pos--;
+	}
+	for (pos++; path[pos] && (path[pos] != '/'); pos++)
+	{
+		out[out_pos++] = path[pos];
+	}
+	out[out_pos] = '\0';
+	fprintf(stderr, "%s\n", out);
+}
+
+
+/* Print the contents of a raw inode.  */
+	void
+jffs_print_raw_inode(struct jffs_raw_inode *raw_inode)
+{
+	fprintf(stdout, "jffs_raw_inode: inode number: %u, version %u\n", raw_inode->ino, raw_inode->version);
+	fprintf(stdout, "{\n");
+	fprintf(stdout, "        0x%08x, /* magic  */\n", raw_inode->magic);
+	fprintf(stdout, "        0x%08x, /* ino  */\n", raw_inode->ino);
+	fprintf(stdout, "        0x%08x, /* pino  */\n", raw_inode->pino);
+	fprintf(stdout, "        0x%08x, /* version  */\n", raw_inode->version);
+	fprintf(stdout, "        0x%08x, /* mode  */\n", raw_inode->mode);
+	fprintf(stdout, "        0x%04x,     /* uid  */\n", raw_inode->uid);
+	fprintf(stdout, "        0x%04x,     /* gid  */\n", raw_inode->gid);
+	fprintf(stdout, "        0x%08x, /* atime  */\n", raw_inode->atime);
+	fprintf(stdout, "        0x%08x, /* mtime  */\n", raw_inode->mtime);
+	fprintf(stdout, "        0x%08x, /* ctime  */\n", raw_inode->ctime);
+	fprintf(stdout, "        0x%08x, /* offset  */\n", raw_inode->offset);
+	fprintf(stdout, "        0x%08x, /* dsize  */\n", raw_inode->dsize);
+	fprintf(stdout, "        0x%08x, /* rsize  */\n", raw_inode->rsize);
+	fprintf(stdout, "        0x%02x,       /* nsize  */\n", raw_inode->nsize);
+	fprintf(stdout, "        0x%02x,       /* nlink  */\n", raw_inode->nlink);
+	fprintf(stdout, "        0x%02x,       /* spare  */\n",
+			raw_inode->spare);
+	fprintf(stdout, "        %u,          /* rename  */\n",
+			raw_inode->rename);
+	fprintf(stdout, "        %u,          /* deleted  */\n",
+			raw_inode->deleted);
+	fprintf(stdout, "        0x%02x,       /* accurate  */\n",
+			raw_inode->accurate);
+	fprintf(stdout, "        0x%08x, /* dchksum  */\n", raw_inode->dchksum);
+	fprintf(stdout, "        0x%04x,     /* nchksum  */\n", raw_inode->nchksum);
+	fprintf(stdout, "        0x%04x,     /* chksum  */\n", raw_inode->chksum);
+	fprintf(stdout, "}\n");
+}
+
+static void write_val32(uint32_t *adr, uint32_t val)
+{
+	switch(endian) {
+		case ENDIAN_HOST:
+			*adr = val;
+			break;
+		case ENDIAN_LITTLE:
+			*adr = __cpu_to_le32(val);
+			break;
+		case ENDIAN_BIG:
+			*adr = __cpu_to_be32(val);
+			break;
+	}
+}
+
+static void write_val16(uint16_t *adr, uint16_t val)
+{
+	switch(endian) {
+		case ENDIAN_HOST:
+			*adr = val;
+			break;
+		case ENDIAN_LITTLE:
+			*adr = __cpu_to_le16(val);
+			break;
+		case ENDIAN_BIG:
+			*adr = __cpu_to_be16(val);
+			break;
+	}
+}
+
+static uint32_t read_val32(uint32_t *adr)
+{
+	uint32_t val;
+
+	switch(endian) {
+		case ENDIAN_HOST:
+			val = *adr;
+			break;
+		case ENDIAN_LITTLE:
+			val = __le32_to_cpu(*adr);
+			break;
+		case ENDIAN_BIG:
+			val = __be32_to_cpu(*adr);
+			break;
+	}
+	return val;
+}
+
+static uint16_t read_val16(uint16_t *adr)
+{
+	uint16_t val;
+
+	switch(endian) {
+		case ENDIAN_HOST:
+			val = *adr;
+			break;
+		case ENDIAN_LITTLE:
+			val = __le16_to_cpu(*adr);
+			break;
+		case ENDIAN_BIG:
+			val = __be16_to_cpu(*adr);
+			break;
+	}
+	return val;
+}
+
+	int
+main(int argc, char **argv)
+{
+	int fs;
+	struct stat sb;
+	uint32_t wordbuf;
+	off_t pos = 0;
+	off_t end;
+	struct jffs_raw_inode ino;
+	unsigned char namebuf[4096];
+	int myino = -1;
+
+	if (argc < 2) {
+		printf("no filesystem given\n");
+		exit(1);
+	}
+
+	fs = open(argv[1], O_RDONLY);
+	if (fs < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	if (argc > 2) {
+		myino = atol(argv[2]);
+		printf("Printing ino #%d\n" , myino);
+	}
+
+	if (fstat(fs, &sb) < 0) {
+		perror("stat");
+		close(fs);
+		exit(1);
+	}
+	end = sb.st_size;
+
+	while (pos < end) {
+		if (pread(fs, &wordbuf, 4, pos) < 0) {
+			perror("pread");
+			exit(1);
+		}
+
+		switch(wordbuf) {
+			case JFFS_EMPTY_BITMASK:
+				//			printf("0xff started at 0x%lx\n", pos);
+				for (; pos < end && wordbuf == JFFS_EMPTY_BITMASK; pos += 4) {
+					if (pread(fs, &wordbuf, 4, pos) < 0) {
+						perror("pread");
+						exit(1);
+					}
+				}
+				if (pos < end)
+					pos -= 4;
+				//			printf("0xff ended at 0x%lx\n", pos);
+				continue;
+
+			case JFFS_DIRTY_BITMASK:
+				//			printf("0x00 started at 0x%lx\n", pos);
+				for (; pos < end && wordbuf == JFFS_DIRTY_BITMASK; pos += 4) {
+					if (pread(fs, &wordbuf, 4, pos) < 0) {
+						perror("pread");
+						exit(1);
+					}
+				}
+				if (pos < end)
+					pos -=4;
+				//			printf("0x00 ended at 0x%lx\n", pos);
+				continue;
+
+			default:
+				printf("Argh. Dirty memory at 0x%lx\n", pos);
+				//			file_hexdump(fs, pos, 128);
+				for (pos += 4; pos < end; pos += 4) {
+					if (pread(fs, &wordbuf, 4, pos) < 0) {
+						perror("pread");
+						exit(1);
+					}
+					if (wordbuf == JFFS_MAGIC_BITMASK)
+						break;
+				}
+
+			case JFFS_MAGIC_BITMASK:
+				if (pread(fs, &ino, sizeof(ino), pos) < 0) {
+					perror("pread");
+					exit(1);
+				}
+				if (myino == -1 || ino.ino == myino) {
+					printf("Magic found at 0x%lx\n", pos);
+					jffs_print_raw_inode(&ino);
+				}
+				pos += sizeof(ino);
+
+				if (myino == -1 || ino.ino == myino) {
+					if (ino.nsize) {
+						if (pread(fs, namebuf, min(ino.nsize, 4095), pos) < 0) {
+							perror("pread");
+							exit(1);
+						}
+						if (ino.nsize < 4095)
+							namebuf[ino.nsize] = 0;
+						else
+							namebuf[4095] = 0;
+						printf("Name: \"%s\"\n", namebuf);
+					} else {
+						printf("No Name\n");
+					}
+				}
+				pos += (ino.nsize + 3) & ~3;
+
+				pos += (ino.dsize + 3) & ~3;
+		}
+
+
+
+	}
+}
diff --git a/jffsX-utils/jffs2dump.c b/jffsX-utils/jffs2dump.c
new file mode 100644
index 0000000..f8b8ac7
--- /dev/null
+++ b/jffsX-utils/jffs2dump.c
@@ -0,0 +1,805 @@
+/*
+ *  dumpjffs2.c
+ *
+ *  Copyright (C) 2003 Thomas Gleixner (tglx at linutronix.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Overview:
+ *   This utility dumps the contents of a binary JFFS2 image
+ *
+ *
+ * Bug/ToDo:
+ */
+
+#define PROGRAM_NAME "jffs2dump"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <asm/types.h>
+#include <dirent.h>
+#include <mtd/jffs2-user.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <getopt.h>
+#include <crc32.h>
+#include "summary.h"
+#include "common.h"
+
+#define PAD(x) (((x)+3)&~3)
+
+/* For outputting a byte-swapped version of the input image. */
+#define cnv_e32(x) ((jint32_t){bswap_32(x.v32)})
+#define cnv_e16(x) ((jint16_t){bswap_16(x.v16)})
+
+#define t32_backwards(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?bswap_32(__b):__b; })
+#define cpu_to_e32(x) ((jint32_t){t32_backwards(x)})
+
+// Global variables
+long	imglen;		// length of image
+char	*data;		// image data
+
+void display_help (void)
+{
+	printf("Usage: %s [OPTION]... INPUTFILE\n"
+	       "Dump the contents of a binary JFFS2 image.\n\n"
+	       "     --help                   display this help and exit\n"
+	       "     --version                display version information and exit\n"
+	       " -b, --bigendian              image is big endian\n"
+	       " -l, --littleendian           image is little endian\n"
+	       " -c, --content                dump image contents\n"
+	       " -e, --endianconvert=FNAME    convert image endianness, output to file fname\n"
+	       " -r, --recalccrc              recalc name and data crc on endian conversion\n"
+	       " -d, --datsize=LEN            size of data chunks, when oob data in binary image (NAND only)\n"
+	       " -o, --oobsize=LEN            size of oob data chunk in binary image (NAND only)\n"
+	       " -v, --verbose                verbose output\n",
+	       PROGRAM_NAME);
+	exit(0);
+}
+
+void display_version (void)
+{
+	printf("%1$s " VERSION "\n"
+			"\n"
+			"Copyright (C) 2003 Thomas Gleixner \n"
+			"\n"
+			"%1$s comes with NO WARRANTY\n"
+			"to the extent permitted by law.\n"
+			"\n"
+			"You may redistribute copies of %1$s\n"
+			"under the terms of the GNU General Public Licence.\n"
+			"See the file `COPYING' for more information.\n",
+			PROGRAM_NAME);
+	exit(0);
+}
+
+// Option variables
+
+int 	verbose;		// verbose output
+char 	*img;			// filename of image
+int	dumpcontent;		// dump image content
+int	target_endian = __BYTE_ORDER;	// image endianess
+int	convertendian;		// convert endianness
+int	recalccrc;		// recalc name and data crc's on endian conversion
+char	cnvfile[256];		// filename for conversion output
+int	datsize;		// Size of data chunks, when oob data is inside the binary image
+int	oobsize;		// Size of oob chunks, when oob data is inside the binary image
+
+void process_options (int argc, char *argv[])
+{
+	int error = 0;
+
+	for (;;) {
+		int option_index = 0;
+		static const char *short_options = "blce:rd:o:v";
+		static const struct option long_options[] = {
+			{"help", no_argument, 0, 0},
+			{"version", no_argument, 0, 0},
+			{"bigendian", no_argument, 0, 'b'},
+			{"littleendian", no_argument, 0, 'l'},
+			{"content", no_argument, 0, 'c'},
+			{"endianconvert", required_argument, 0, 'e'},
+			{"datsize", required_argument, 0, 'd'},
+			{"oobsize", required_argument, 0, 'o'},
+			{"recalccrc", required_argument, 0, 'r'},
+			{"verbose", no_argument, 0, 'v'},
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF) {
+			break;
+		}
+
+		switch (c) {
+			case 0:
+				switch (option_index) {
+					case 0:
+						display_help();
+						break;
+					case 1:
+						display_version();
+						break;
+				}
+				break;
+			case 'v':
+				verbose = 1;
+				break;
+			case 'b':
+				target_endian = __BIG_ENDIAN;
+				break;
+			case 'l':
+				target_endian = __LITTLE_ENDIAN;
+				break;
+			case 'c':
+				dumpcontent = 1;
+				break;
+			case 'd':
+				datsize = atoi(optarg);
+				break;
+			case 'o':
+				oobsize = atoi(optarg);
+				break;
+			case 'e':
+				convertendian = 1;
+				strcpy (cnvfile, optarg);
+				break;
+			case 'r':
+				recalccrc = 1;
+				break;
+			case '?':
+				error = 1;
+				break;
+		}
+	}
+
+	if ((argc - optind) != 1 || error)
+		display_help ();
+
+	img = argv[optind];
+}
+
+
+/*
+ *	Dump image contents
+ */
+void do_dumpcontent (void)
+{
+	char			*p = data, *p_free_begin;
+	union jffs2_node_union 	*node;
+	int			empty = 0, dirty = 0;
+	char			name[256];
+	uint32_t		crc;
+	uint16_t		type;
+	int			bitchbitmask = 0;
+	int			obsolete;
+
+	p_free_begin = NULL;
+	while ( p < (data + imglen)) {
+		node = (union jffs2_node_union*) p;
+
+		/* Skip empty space */
+		if (!p_free_begin)
+			p_free_begin = p;
+		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+			p += 4;
+			empty += 4;
+			continue;
+		}
+
+		if (p != p_free_begin)
+			printf("Empty space found from 0x%08zx to 0x%08zx\n", p_free_begin-data, p-data);
+		p_free_begin = NULL;
+
+		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
+			if (!bitchbitmask++)
+				printf ("Wrong bitmask  at  0x%08zx, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
+			p += 4;
+			dirty += 4;
+			continue;
+		}
+		bitchbitmask = 0;
+
+		type = je16_to_cpu(node->u.nodetype);
+		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+			obsolete = 1;
+			type |= JFFS2_NODE_ACCURATE;
+		} else
+			obsolete = 0;
+		/* Set accurate for CRC check */
+		node->u.nodetype = cpu_to_je16(type);
+
+		crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+		if (crc != je32_to_cpu (node->u.hdr_crc)) {
+			printf ("Wrong hdr_crc  at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc);
+			p += 4;
+			dirty += 4;
+			continue;
+		}
+
+		switch(je16_to_cpu(node->u.nodetype)) {
+
+			case JFFS2_NODETYPE_INODE:
+				printf ("%8s Inode      node at 0x%08zx, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+						obsolete ? "Obsolete" : "",
+						p - data, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+						je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
+						je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
+				if (crc != je32_to_cpu (node->i.node_crc)) {
+					printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.node_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					dirty += PAD(je32_to_cpu (node->i.totlen));;
+					continue;
+				}
+
+				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
+				if (crc != je32_to_cpu(node->i.data_crc)) {
+					printf ("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.data_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					dirty += PAD(je32_to_cpu (node->i.totlen));;
+					continue;
+				}
+
+				p += PAD(je32_to_cpu (node->i.totlen));
+				break;
+
+			case JFFS2_NODETYPE_DIRENT:
+				memcpy (name, node->d.name, node->d.nsize);
+				name [node->d.nsize] = 0x0;
+				printf ("%8s Dirent     node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
+						obsolete ? "Obsolete" : "",
+						p - data, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+						je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
+						node->d.nsize, name);
+
+				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
+				if (crc != je32_to_cpu (node->d.node_crc)) {
+					printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.node_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					dirty += PAD(je32_to_cpu (node->d.totlen));;
+					continue;
+				}
+
+				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
+				if (crc != je32_to_cpu(node->d.name_crc)) {
+					printf ("Wrong name_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.name_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					dirty += PAD(je32_to_cpu (node->d.totlen));;
+					continue;
+				}
+
+				p += PAD(je32_to_cpu (node->d.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XATTR:
+				memcpy(name, node->x.data, node->x.name_len);
+				name[node->x.name_len] = '\x00';
+				printf ("%8s Xattr      node at 0x%08zx, totlen 0x%08x, xid   %5d, version %5d, name_len   %3d, name %s\n",
+						obsolete ? "Obsolete" : "",
+						p - data,
+						je32_to_cpu (node->x.totlen),
+						je32_to_cpu (node->x.xid),
+						je32_to_cpu (node->x.version),
+						node->x.name_len,
+						name);
+
+				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_xattr) - sizeof (node->x.node_crc));
+				if (crc != je32_to_cpu (node->x.node_crc)) {
+					printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->x.node_crc), crc);
+					p += PAD(je32_to_cpu (node->x.totlen));
+					dirty += PAD(je32_to_cpu (node->x.totlen));
+					continue;
+				}
+
+				crc = mtd_crc32 (0, p + sizeof (struct jffs2_raw_xattr), node->x.name_len + je16_to_cpu (node->x.value_len) + 1);
+				if (crc != je32_to_cpu (node->x.data_crc)) {
+					printf ("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->x.data_crc), crc);
+					p += PAD(je32_to_cpu (node->x.totlen));
+					dirty += PAD(je32_to_cpu (node->x.totlen));
+					continue;
+				}
+				p += PAD(je32_to_cpu (node->x.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XREF:
+				printf ("%8s Xref       node at 0x%08zx, totlen 0x%08x, xid   %5d, xseqno  %5d, #ino  %8d\n",
+						obsolete ? "Obsolete" : "",
+						p - data,
+						je32_to_cpu (node->r.totlen),
+						je32_to_cpu (node->r.xid),
+						je32_to_cpu (node->r.xseqno),
+						je32_to_cpu (node->r.ino));
+				p += PAD(je32_to_cpu (node->r.totlen));
+				break;
+
+			case JFFS2_NODETYPE_SUMMARY: {
+
+											 int i;
+											 struct jffs2_sum_marker * sm;
+
+											 printf("%8s Inode Sum  node at 0x%08zx, totlen 0x%08x, sum_num  %5d, cleanmarker size %5d\n",
+													 obsolete ? "Obsolete" : "",
+													 p - data,
+													 je32_to_cpu (node->s.totlen),
+													 je32_to_cpu (node->s.sum_num),
+													 je32_to_cpu (node->s.cln_mkr));
+
+											 crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_summary) - 8);
+											 if (crc != je32_to_cpu (node->s.node_crc)) {
+												 printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.node_crc), crc);
+												 p += PAD(je32_to_cpu (node->s.totlen));
+												 dirty += PAD(je32_to_cpu (node->s.totlen));;
+												 continue;
+											 }
+
+											 crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_summary),  je32_to_cpu (node->s.totlen) - sizeof(struct jffs2_raw_summary));
+											 if (crc != je32_to_cpu(node->s.sum_crc)) {
+												 printf ("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.sum_crc), crc);
+												 p += PAD(je32_to_cpu (node->s.totlen));
+												 dirty += PAD(je32_to_cpu (node->s.totlen));;
+												 continue;
+											 }
+
+											 if (verbose) {
+												 void *sp;
+												 sp = (p + sizeof(struct jffs2_raw_summary));
+
+												 for(i=0; i<je32_to_cpu(node->s.sum_num); i++) {
+
+													 switch(je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
+														 case JFFS2_NODETYPE_INODE : {
+
+																						 struct jffs2_sum_inode_flash *spi;
+																						 spi = sp;
+
+																						 printf ("%14s #ino  %5d,  version %5d, offset 0x%08x, totlen 0x%08x\n",
+																								 "",
+																								 je32_to_cpu (spi->inode),
+																								 je32_to_cpu (spi->version),
+																								 je32_to_cpu (spi->offset),
+																								 je32_to_cpu (spi->totlen));
+
+																						 sp += JFFS2_SUMMARY_INODE_SIZE;
+																						 break;
+																					 }
+
+														 case JFFS2_NODETYPE_DIRENT : {
+
+																						  char name[255];
+																						  struct jffs2_sum_dirent_flash *spd;
+																						  spd = sp;
+
+																						  memcpy(name,spd->name,spd->nsize);
+																						  name [spd->nsize] = 0x0;
+
+																						  printf ("%14s dirent offset 0x%08x, totlen 0x%08x, #pino  %5d,  version %5d, #ino  %8d, nsize %8d, name %s \n",
+																								  "",
+																								  je32_to_cpu (spd->offset),
+																								  je32_to_cpu (spd->totlen),
+																								  je32_to_cpu (spd->pino),
+																								  je32_to_cpu (spd->version),
+																								  je32_to_cpu (spd->ino),
+																								  spd->nsize,
+																								  name);
+
+																						  sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
+																						  break;
+																					  }
+
+														 case JFFS2_NODETYPE_XATTR : {
+																						  struct jffs2_sum_xattr_flash *spx;
+																						  spx = sp;
+																						  printf ("%14s Xattr  offset 0x%08x, totlen 0x%08x, version %5d, #xid %8d\n",
+																								  "",
+																								  je32_to_cpu (spx->offset),
+																								  je32_to_cpu (spx->totlen),
+																								  je32_to_cpu (spx->version),
+																								  je32_to_cpu (spx->xid));
+																						  sp += JFFS2_SUMMARY_XATTR_SIZE;
+																						  break;
+																					  }
+
+														 case JFFS2_NODETYPE_XREF : {
+																						  struct jffs2_sum_xref_flash *spr;
+																						  spr = sp;
+																						  printf ("%14s Xref   offset 0x%08x\n",
+																								  "",
+																								  je32_to_cpu (spr->offset));
+																						  sp += JFFS2_SUMMARY_XREF_SIZE;
+																						  break;
+																					  }
+
+														 default :
+																					  printf("Unknown summary node!\n");
+																					  break;
+													 }
+												 }
+
+												 sm = (struct jffs2_sum_marker *) ((char *)p + je32_to_cpu(node->s.totlen) - sizeof(struct jffs2_sum_marker));
+
+												 printf("%14s Sum Node Offset  0x%08x, Magic 0x%08x, Padded size 0x%08x\n",
+														 "",
+														 je32_to_cpu(sm->offset),
+														 je32_to_cpu(sm->magic),
+														 je32_to_cpu(node->s.padded));
+											 }
+
+											 p += PAD(je32_to_cpu (node->s.totlen));
+											 break;
+										 }
+
+			case JFFS2_NODETYPE_CLEANMARKER:
+										 if (verbose) {
+											 printf ("%8s Cleanmarker     at 0x%08zx, totlen 0x%08x\n",
+													 obsolete ? "Obsolete" : "",
+													 p - data, je32_to_cpu (node->u.totlen));
+										 }
+										 p += PAD(je32_to_cpu (node->u.totlen));
+										 break;
+
+			case JFFS2_NODETYPE_PADDING:
+										 if (verbose) {
+											 printf ("%8s Padding    node at 0x%08zx, totlen 0x%08x\n",
+													 obsolete ? "Obsolete" : "",
+													 p - data, je32_to_cpu (node->u.totlen));
+										 }
+										 p += PAD(je32_to_cpu (node->u.totlen));
+										 break;
+
+			case 0xffff:
+										 p += 4;
+										 empty += 4;
+										 break;
+
+			default:
+										 if (verbose) {
+											 printf ("%8s Unknown    node at 0x%08zx, totlen 0x%08x\n",
+													 obsolete ? "Obsolete" : "",
+													 p - data, je32_to_cpu (node->u.totlen));
+										 }
+										 p += PAD(je32_to_cpu (node->u.totlen));
+										 dirty += PAD(je32_to_cpu (node->u.totlen));
+
+		}
+	}
+
+	if (verbose)
+		printf ("Empty space: %d, dirty space: %d\n", empty, dirty);
+}
+
+/*
+ *	Convert endianess
+ */
+void do_endianconvert (void)
+{
+	char			*p = data;
+	union jffs2_node_union 	*node, newnode;
+	int			fd, len;
+	jint32_t		mode;
+	uint32_t		crc;
+
+	fd = open (cnvfile, O_WRONLY | O_CREAT, 0644);
+	if (fd < 0) {
+		fprintf (stderr, "Cannot open / create file: %s\n", cnvfile);
+		return;
+	}
+
+	while ( p < (data + imglen)) {
+		node = (union jffs2_node_union*) p;
+
+		/* Skip empty space */
+		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+			write (fd, p, 4);
+			p += 4;
+			continue;
+		}
+
+		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
+			printf ("Wrong bitmask  at  0x%08zx, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
+			newnode.u.magic = cnv_e16 (node->u.magic);
+			newnode.u.nodetype = cnv_e16 (node->u.nodetype);
+			write (fd, &newnode, 4);
+			p += 4;
+			continue;
+		}
+
+		crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+		if (crc != je32_to_cpu (node->u.hdr_crc)) {
+			printf ("Wrong hdr_crc  at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc);
+		}
+
+		switch(je16_to_cpu(node->u.nodetype)) {
+
+			case JFFS2_NODETYPE_INODE:
+
+				newnode.i.magic = cnv_e16 (node->i.magic);
+				newnode.i.nodetype = cnv_e16 (node->i.nodetype);
+				newnode.i.totlen = cnv_e32 (node->i.totlen);
+				newnode.i.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+				newnode.i.ino = cnv_e32 (node->i.ino);
+				newnode.i.version = cnv_e32 (node->i.version);
+				mode.v32 = node->i.mode.m;
+				mode = cnv_e32 (mode);
+				newnode.i.mode.m = mode.v32;
+				newnode.i.uid = cnv_e16 (node->i.uid);
+				newnode.i.gid = cnv_e16 (node->i.gid);
+				newnode.i.isize = cnv_e32 (node->i.isize);
+				newnode.i.atime = cnv_e32 (node->i.atime);
+				newnode.i.mtime = cnv_e32 (node->i.mtime);
+				newnode.i.ctime = cnv_e32 (node->i.ctime);
+				newnode.i.offset = cnv_e32 (node->i.offset);
+				newnode.i.csize = cnv_e32 (node->i.csize);
+				newnode.i.dsize = cnv_e32 (node->i.dsize);
+				newnode.i.compr = node->i.compr;
+				newnode.i.usercompr = node->i.usercompr;
+				newnode.i.flags = cnv_e16 (node->i.flags);
+				if (recalccrc) {
+					len = je32_to_cpu(node->i.csize);
+					newnode.i.data_crc = cpu_to_e32 ( mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), len));
+				} else
+					newnode.i.data_crc = cnv_e32 (node->i.data_crc);
+
+				newnode.i.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_inode) - 8));
+
+				write (fd, &newnode, sizeof (struct jffs2_raw_inode));
+				write (fd, p + sizeof (struct jffs2_raw_inode), PAD (je32_to_cpu (node->i.totlen) -  sizeof (struct jffs2_raw_inode)));
+
+				p += PAD(je32_to_cpu (node->i.totlen));
+				break;
+
+			case JFFS2_NODETYPE_DIRENT:
+				newnode.d.magic = cnv_e16 (node->d.magic);
+				newnode.d.nodetype = cnv_e16 (node->d.nodetype);
+				newnode.d.totlen = cnv_e32 (node->d.totlen);
+				newnode.d.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+				newnode.d.pino = cnv_e32 (node->d.pino);
+				newnode.d.version = cnv_e32 (node->d.version);
+				newnode.d.ino = cnv_e32 (node->d.ino);
+				newnode.d.mctime = cnv_e32 (node->d.mctime);
+				newnode.d.nsize = node->d.nsize;
+				newnode.d.type = node->d.type;
+				newnode.d.unused[0] = node->d.unused[0];
+				newnode.d.unused[1] = node->d.unused[1];
+				newnode.d.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_dirent) - 8));
+				if (recalccrc)
+					newnode.d.name_crc = cpu_to_e32 ( mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize));
+				else
+					newnode.d.name_crc = cnv_e32 (node->d.name_crc);
+
+				write (fd, &newnode, sizeof (struct jffs2_raw_dirent));
+				write (fd, p + sizeof (struct jffs2_raw_dirent), PAD (je32_to_cpu (node->d.totlen) -  sizeof (struct jffs2_raw_dirent)));
+				p += PAD(je32_to_cpu (node->d.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XATTR:
+				newnode.x.magic = cnv_e16 (node->x.magic);
+				newnode.x.nodetype = cnv_e16 (node->x.nodetype);
+				newnode.x.totlen = cnv_e32 (node->x.totlen);
+				newnode.x.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+				newnode.x.xid = cnv_e32 (node->x.xid);
+				newnode.x.version = cnv_e32 (node->x.version);
+				newnode.x.xprefix = node->x.xprefix;
+				newnode.x.name_len = node->x.name_len;
+				newnode.x.value_len = cnv_e16 (node->x.value_len);
+				if (recalccrc)
+					newnode.x.data_crc = cpu_to_e32 (mtd_crc32 (0, p + sizeof (struct jffs2_raw_xattr), node->x.name_len + je16_to_cpu (node->x.value_len) + 1));
+				else
+					newnode.x.data_crc = cnv_e32 (node->x.data_crc);
+				newnode.x.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_xattr) - sizeof (newnode.x.node_crc)));
+
+				write (fd, &newnode, sizeof (struct jffs2_raw_xattr));
+				write (fd, p + sizeof (struct jffs2_raw_xattr), PAD (je32_to_cpu (node->d.totlen) -  sizeof (struct jffs2_raw_xattr)));
+				p += PAD(je32_to_cpu (node->x.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XREF:
+				newnode.r.magic = cnv_e16 (node->r.magic);
+				newnode.r.nodetype = cnv_e16 (node->r.nodetype);
+				newnode.r.totlen = cnv_e32 (node->r.totlen);
+				newnode.r.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - sizeof (newnode.r.hdr_crc)));
+				newnode.r.ino = cnv_e32 (node->r.ino);
+				newnode.r.xid = cnv_e32 (node->r.xid);
+				newnode.r.xseqno = cnv_e32 (node->r.xseqno);
+				newnode.r.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_xref) - sizeof (newnode.r.node_crc)));
+				p += PAD(je32_to_cpu (node->x.totlen));
+				break;
+
+			case JFFS2_NODETYPE_CLEANMARKER:
+			case JFFS2_NODETYPE_PADDING:
+				newnode.u.magic = cnv_e16 (node->u.magic);
+				newnode.u.nodetype = cnv_e16 (node->u.nodetype);
+				newnode.u.totlen = cnv_e32 (node->u.totlen);
+				newnode.u.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+
+				write (fd, &newnode, sizeof (struct jffs2_unknown_node));
+				len = PAD(je32_to_cpu (node->u.totlen) - sizeof (struct jffs2_unknown_node));
+				if (len > 0)
+					write (fd, p + sizeof (struct jffs2_unknown_node), len);
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case JFFS2_NODETYPE_SUMMARY : {
+											  struct jffs2_sum_marker *sm_ptr;
+											  int i,sum_len;
+											  int counter = 0;
+
+											  newnode.s.magic = cnv_e16 (node->s.magic);
+											  newnode.s.nodetype = cnv_e16 (node->s.nodetype);
+											  newnode.s.totlen = cnv_e32 (node->s.totlen);
+											  newnode.s.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+											  newnode.s.sum_num = cnv_e32 (node->s.sum_num);
+											  newnode.s.cln_mkr = cnv_e32 (node->s.cln_mkr);
+											  newnode.s.padded = cnv_e32 (node->s.padded);
+
+											  newnode.s.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_summary) - 8));
+
+											  // summary header
+											  p += sizeof (struct jffs2_raw_summary);
+
+											  // summary data
+											  sum_len = je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary) - sizeof (struct jffs2_sum_marker);
+
+											  for (i=0; i<je32_to_cpu (node->s.sum_num); i++) {
+												  union jffs2_sum_flash *fl_ptr;
+
+												  fl_ptr = (union jffs2_sum_flash *) p;
+
+												  switch (je16_to_cpu (fl_ptr->u.nodetype)) {
+													  case JFFS2_NODETYPE_INODE:
+
+														  fl_ptr->i.nodetype = cnv_e16 (fl_ptr->i.nodetype);
+														  fl_ptr->i.inode = cnv_e32 (fl_ptr->i.inode);
+														  fl_ptr->i.version = cnv_e32 (fl_ptr->i.version);
+														  fl_ptr->i.offset = cnv_e32 (fl_ptr->i.offset);
+														  fl_ptr->i.totlen = cnv_e32 (fl_ptr->i.totlen);
+														  p += sizeof (struct jffs2_sum_inode_flash);
+														  counter += sizeof (struct jffs2_sum_inode_flash);
+														  break;
+
+													  case JFFS2_NODETYPE_DIRENT:
+														  fl_ptr->d.nodetype = cnv_e16 (fl_ptr->d.nodetype);
+														  fl_ptr->d.totlen = cnv_e32 (fl_ptr->d.totlen);
+														  fl_ptr->d.offset = cnv_e32 (fl_ptr->d.offset);
+														  fl_ptr->d.pino = cnv_e32 (fl_ptr->d.pino);
+														  fl_ptr->d.version = cnv_e32 (fl_ptr->d.version);
+														  fl_ptr->d.ino = cnv_e32 (fl_ptr->d.ino);
+														  p += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
+														  counter += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
+														  break;
+
+													  case JFFS2_NODETYPE_XATTR:
+														  fl_ptr->x.nodetype = cnv_e16 (fl_ptr->x.nodetype);
+														  fl_ptr->x.xid = cnv_e32 (fl_ptr->x.xid);
+														  fl_ptr->x.version = cnv_e32 (fl_ptr->x.version);
+														  fl_ptr->x.offset = cnv_e32 (fl_ptr->x.offset);
+														  fl_ptr->x.totlen = cnv_e32 (fl_ptr->x.totlen);
+														  p += sizeof (struct jffs2_sum_xattr_flash);
+														  counter += sizeof (struct jffs2_sum_xattr_flash);
+														  break;
+
+													  case JFFS2_NODETYPE_XREF:
+														  fl_ptr->r.nodetype = cnv_e16 (fl_ptr->r.nodetype);
+														  fl_ptr->r.offset = cnv_e32 (fl_ptr->r.offset);
+														  p += sizeof (struct jffs2_sum_xref_flash);
+														  counter += sizeof (struct jffs2_sum_xref_flash);
+														  break;
+
+													  default :
+														  printf("Unknown node in summary information!!! nodetype(%x)\n", je16_to_cpu (fl_ptr->u.nodetype));
+														  exit(EXIT_FAILURE);
+														  break;
+												  }
+
+											  }
+
+											  //pad
+											  p += sum_len - counter;
+
+											  // summary marker
+											  sm_ptr = (struct jffs2_sum_marker *) p;
+											  sm_ptr->offset = cnv_e32 (sm_ptr->offset);
+											  sm_ptr->magic = cnv_e32 (sm_ptr->magic);
+											  p += sizeof (struct jffs2_sum_marker);
+
+											  // generate new crc on sum data
+											  newnode.s.sum_crc = cpu_to_e32 ( mtd_crc32(0, ((char *) node) + sizeof (struct jffs2_raw_summary),
+														  je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary)));
+
+											  // write out new node header
+											  write(fd, &newnode, sizeof (struct jffs2_raw_summary));
+											  // write out new summary data
+											  write(fd, &node->s.sum, sum_len + sizeof (struct jffs2_sum_marker));
+
+											  break;
+										  }
+
+			case 0xffff:
+										  write (fd, p, 4);
+										  p += 4;
+										  break;
+
+			default:
+										  printf ("Unknown node type: 0x%04x at 0x%08zx, totlen 0x%08x\n", je16_to_cpu (node->u.nodetype), p - data, je32_to_cpu (node->u.totlen));
+										  p += PAD(je32_to_cpu (node->u.totlen));
+
+		}
+	}
+
+	close (fd);
+
+}
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+	int fd;
+
+	process_options(argc, argv);
+
+	/* Open the input file */
+	if ((fd = open(img, O_RDONLY)) == -1) {
+		perror("open input file");
+		exit(1);
+	}
+
+	// get image length
+	imglen = lseek(fd, 0, SEEK_END);
+	lseek (fd, 0, SEEK_SET);
+
+	data = malloc (imglen);
+	if (!data) {
+		perror("out of memory");
+		close (fd);
+		exit(1);
+	}
+
+	if (datsize && oobsize) {
+		int  idx = 0;
+		long len = imglen;
+		uint8_t oob[oobsize];
+		printf ("Peeling data out of combined data/oob image\n");
+		while (len) {
+			// read image data
+			read (fd, &data[idx], datsize);
+			read (fd, oob, oobsize);
+			idx += datsize;
+			imglen -= oobsize;
+			len -= datsize + oobsize;
+		}
+
+	} else {
+		// read image data
+		read (fd, data, imglen);
+	}
+	// Close the input file
+	close(fd);
+
+	if (dumpcontent)
+		do_dumpcontent ();
+
+	if (convertendian)
+		do_endianconvert ();
+
+	// free memory
+	free (data);
+
+	// Return happy
+	exit (0);
+}
diff --git a/jffsX-utils/jffs2reader.c b/jffsX-utils/jffs2reader.c
new file mode 100644
index 0000000..a62da9a
--- /dev/null
+++ b/jffsX-utils/jffs2reader.c
@@ -0,0 +1,918 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * jffs2reader v0.0.18 A jffs2 image reader
+ *
+ * Copyright (c) 2001 Jari Kirma <Jari.Kirma at hut.fi>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose, including commercial applications, and to alter it and
+ * redistribute it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ * not claim that you wrote the original software. If you use this
+ * software in a product, an acknowledgment in the product
+ * documentation would be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must
+ * not be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ *
+ *********
+ *  This code was altered September 2001
+ *  Changes are Copyright (c) Erik Andersen <andersen at codepoet.org>
+ *
+ * In compliance with (2) above, this is hereby marked as an altered
+ * version of this software.  It has been altered as follows:
+ *      *) Listing a directory now mimics the behavior of 'ls -l'
+ *      *) Support for recursive listing has been added
+ *      *) Without options, does a recursive 'ls' on the whole filesystem
+ *      *) option parsing now uses getopt()
+ *      *) Now uses printf, and error messages go to stderr.
+ *      *) The copyright notice has been cleaned up and reformatted
+ *      *) The code has been reformatted
+ *      *) Several twisty code paths have been fixed so I can understand them.
+ *  -Erik, 1 September 2001
+ *
+ *      *) Made it show major/minor numbers for device nodes
+ *      *) Made it show symlink targets
+ *  -Erik, 13 September 2001
+ */
+
+
+/*
+TODO:
+
+- Add CRC checking code to places marked with XXX.
+- Add support for other node compression types.
+
+- Test with real life images.
+- Maybe port into bootloader.
+ */
+
+/*
+BUGS:
+
+- Doesn't check CRC checksums.
+ */
+
+#define PROGRAM_NAME "jffs2reader"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <zlib.h>
+
+#include "mtd/jffs2-user.h"
+#include "common.h"
+
+#define SCRATCH_SIZE (5*1024*1024)
+
+/* macro to avoid "lvalue required as left operand of assignment" error */
+#define ADD_BYTES(p, n)		((p) = (typeof(p))((char *)(p) + (n)))
+
+#define DIRENT_INO(dirent) ((dirent) !=NULL ? je32_to_cpu((dirent)->ino) : 0)
+#define DIRENT_PINO(dirent) ((dirent) !=NULL ? je32_to_cpu((dirent)->pino) : 0)
+
+struct dir {
+	struct dir *next;
+	uint8_t type;
+	uint8_t nsize;
+	uint32_t ino;
+	char name[256];
+};
+
+int target_endian = __BYTE_ORDER;
+
+void putblock(char *, size_t, size_t *, struct jffs2_raw_inode *);
+struct dir *putdir(struct dir *, struct jffs2_raw_dirent *);
+void printdir(char *o, size_t size, struct dir *d, const char *path,
+		int recurse, int want_ctime);
+void freedir(struct dir *);
+
+struct jffs2_raw_inode *find_raw_inode(char *o, size_t size, uint32_t ino);
+struct jffs2_raw_dirent *resolvedirent(char *, size_t, uint32_t, uint32_t,
+		char *, uint8_t);
+struct jffs2_raw_dirent *resolvename(char *, size_t, uint32_t, char *, uint8_t);
+struct jffs2_raw_dirent *resolveinode(char *, size_t, uint32_t);
+
+struct jffs2_raw_dirent *resolvepath0(char *, size_t, uint32_t, const char *,
+		uint32_t *, int);
+struct jffs2_raw_dirent *resolvepath(char *, size_t, uint32_t, const char *,
+		uint32_t *);
+
+void lsdir(char *, size_t, const char *, int, int);
+void catfile(char *, size_t, char *, char *, size_t, size_t *);
+
+int main(int, char **);
+
+/* writes file node into buffer, to the proper position. */
+/* reading all valid nodes in version order reconstructs the file. */
+
+/*
+   b       - buffer
+   bsize   - buffer size
+   rsize   - result size
+   n       - node
+ */
+
+void putblock(char *b, size_t bsize, size_t * rsize,
+		struct jffs2_raw_inode *n)
+{
+	uLongf dlen = je32_to_cpu(n->dsize);
+
+	if (je32_to_cpu(n->isize) > bsize || (je32_to_cpu(n->offset) + dlen) > bsize)
+		errmsg_die("File does not fit into buffer!");
+
+	if (*rsize < je32_to_cpu(n->isize))
+		bzero(b + *rsize, je32_to_cpu(n->isize) - *rsize);
+
+	switch (n->compr) {
+		case JFFS2_COMPR_ZLIB:
+			uncompress((Bytef *) b + je32_to_cpu(n->offset), &dlen,
+					(Bytef *) ((char *) n) + sizeof(struct jffs2_raw_inode),
+					(uLongf) je32_to_cpu(n->csize));
+			break;
+
+		case JFFS2_COMPR_NONE:
+			memcpy(b + je32_to_cpu(n->offset),
+					((char *) n) + sizeof(struct jffs2_raw_inode), dlen);
+			break;
+
+		case JFFS2_COMPR_ZERO:
+			bzero(b + je32_to_cpu(n->offset), dlen);
+			break;
+
+			/* [DYN]RUBIN support required! */
+
+		default:
+			errmsg_die("Unsupported compression method!");
+	}
+
+	*rsize = je32_to_cpu(n->isize);
+}
+
+/* adds/removes directory node into dir struct. */
+/* reading all valid nodes in version order reconstructs the directory. */
+
+/*
+   dd      - directory struct being processed
+   n       - node
+
+   return value: directory struct value replacing dd
+ */
+
+struct dir *putdir(struct dir *dd, struct jffs2_raw_dirent *n)
+{
+	struct dir *o, *d, *p;
+
+	o = dd;
+
+	if (je32_to_cpu(n->ino)) {
+		if (dd == NULL) {
+			d = xmalloc(sizeof(struct dir));
+			d->type = n->type;
+			memcpy(d->name, n->name, n->nsize);
+			d->nsize = n->nsize;
+			d->ino = je32_to_cpu(n->ino);
+			d->next = NULL;
+
+			return d;
+		}
+
+		while (1) {
+			if (n->nsize == dd->nsize &&
+					!memcmp(n->name, dd->name, n->nsize)) {
+				dd->type = n->type;
+				dd->ino = je32_to_cpu(n->ino);
+
+				return o;
+			}
+
+			if (dd->next == NULL) {
+				dd->next = xmalloc(sizeof(struct dir));
+				dd->next->type = n->type;
+				memcpy(dd->next->name, n->name, n->nsize);
+				dd->next->nsize = n->nsize;
+				dd->next->ino = je32_to_cpu(n->ino);
+				dd->next->next = NULL;
+
+				return o;
+			}
+
+			dd = dd->next;
+		}
+	} else {
+		if (dd == NULL)
+			return NULL;
+
+		if (n->nsize == dd->nsize && !memcmp(n->name, dd->name, n->nsize)) {
+			d = dd->next;
+			free(dd);
+			return d;
+		}
+
+		while (1) {
+			p = dd;
+			dd = dd->next;
+
+			if (dd == NULL)
+				return o;
+
+			if (n->nsize == dd->nsize &&
+					!memcmp(n->name, dd->name, n->nsize)) {
+				p->next = dd->next;
+				free(dd);
+
+				return o;
+			}
+		}
+	}
+}
+
+
+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
+#define TYPECHAR(mode)  ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+
+/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
+static const mode_t SBIT[] = {
+	0, 0, S_ISUID,
+	0, 0, S_ISGID,
+	0, 0, S_ISVTX
+};
+
+/* The 9 mode bits to test */
+static const mode_t MBIT[] = {
+	S_IRUSR, S_IWUSR, S_IXUSR,
+	S_IRGRP, S_IWGRP, S_IXGRP,
+	S_IROTH, S_IWOTH, S_IXOTH
+};
+
+static const char MODE1[] = "rwxrwxrwx";
+static const char MODE0[] = "---------";
+static const char SMODE1[] = "..s..s..t";
+static const char SMODE0[] = "..S..S..T";
+
+/*
+ * Return the standard ls-like mode string from a file mode.
+ * This is static and so is overwritten on each call.
+ */
+const char *mode_string(int mode)
+{
+	static char buf[12];
+
+	int i;
+
+	buf[0] = TYPECHAR(mode);
+	for (i = 0; i < 9; i++) {
+		if (mode & SBIT[i])
+			buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
+		else
+			buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
+	}
+	return buf;
+}
+
+/* prints contents of directory structure */
+
+/*
+   d       - dir struct
+ */
+
+void printdir(char *o, size_t size, struct dir *d, const char *path, int recurse,
+		int want_ctime)
+{
+	char m;
+	char *filetime;
+	time_t age;
+	struct jffs2_raw_inode *ri;
+	jint32_t mode;
+
+	if (!path)
+		return;
+	if (strlen(path) == 1 && *path == '/')
+		path++;
+
+	while (d != NULL) {
+		switch (d->type) {
+			case DT_REG:
+				m = ' ';
+				break;
+
+			case DT_FIFO:
+				m = '|';
+				break;
+
+			case DT_CHR:
+				m = ' ';
+				break;
+
+			case DT_BLK:
+				m = ' ';
+				break;
+
+			case DT_DIR:
+				m = '/';
+				break;
+
+			case DT_LNK:
+				m = ' ';
+				break;
+
+			case DT_SOCK:
+				m = '=';
+				break;
+
+			default:
+				m = '?';
+		}
+		ri = find_raw_inode(o, size, d->ino);
+		if (!ri) {
+			warnmsg("bug: raw_inode missing!");
+			d = d->next;
+			continue;
+		}
+
+		filetime = ctime((const time_t *) &(ri->ctime));
+		age = time(NULL) - je32_to_cpu(ri->ctime);
+		mode.v32 = ri->mode.m;
+		printf("%s %-4d %-8d %-8d ", mode_string(je32_to_cpu(mode)),
+				1, je16_to_cpu(ri->uid), je16_to_cpu(ri->gid));
+		if ( d->type==DT_BLK || d->type==DT_CHR ) {
+			dev_t rdev;
+			size_t devsize;
+			putblock((char*)&rdev, sizeof(rdev), &devsize, ri);
+			printf("%4d, %3d ", major(rdev), minor(rdev));
+		} else {
+			printf("%9ld ", (long)je32_to_cpu(ri->dsize));
+		}
+		d->name[d->nsize]='\0';
+		if (want_ctime) {
+			if (age < 3600L * 24 * 365 / 2 && age > -15 * 60)
+				/* hh:mm if less than 6 months old */
+				printf("%6.6s %5.5s ", filetime + 4, filetime + 11);
+			else
+				printf("%6.6s %4.4s ", filetime + 4, filetime + 20);
+		}
+		printf("%s/%s%c", path, d->name, m);
+		if (d->type == DT_LNK) {
+			char symbuf[1024];
+			size_t symsize;
+			putblock(symbuf, sizeof(symbuf), &symsize, ri);
+			symbuf[symsize] = 0;
+			printf(" -> %s", symbuf);
+		}
+		printf("\n");
+
+		if (d->type == DT_DIR && recurse) {
+			char *tmp;
+			tmp = xmalloc(BUFSIZ);
+			sprintf(tmp, "%s/%s", path, d->name);
+			lsdir(o, size, tmp, recurse, want_ctime);	/* Go recursive */
+			free(tmp);
+		}
+
+		d = d->next;
+	}
+}
+
+/* frees memory used by directory structure */
+
+/*
+   d       - dir struct
+ */
+
+void freedir(struct dir *d)
+{
+	struct dir *t;
+
+	while (d != NULL) {
+		t = d->next;
+		free(d);
+		d = t;
+	}
+}
+
+/* collects directory/file nodes in version order. */
+
+/*
+   f       - file flag.
+   if zero, collect file, compare ino to inode
+   otherwise, collect directory, compare ino to parent inode
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   ino     - inode to compare against. see f.
+
+   return value: a jffs2_raw_inode that corresponds the the specified
+   inode, or NULL
+ */
+
+struct jffs2_raw_inode *find_raw_inode(char *o, size_t size, uint32_t ino)
+{
+	/* aligned! */
+	union jffs2_node_union *n;
+	union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
+	union jffs2_node_union *lr;	/* last block position */
+	union jffs2_node_union *mp = NULL;	/* minimum position */
+
+	uint32_t vmin, vmint, vmaxt, vmax, vcur, v;
+
+	vmin = 0;					/* next to read */
+	vmax = ~((uint32_t) 0);		/* last to read */
+	vmint = ~((uint32_t) 0);
+	vmaxt = 0;					/* found maximum */
+	vcur = 0;					/* XXX what is smallest version number used? */
+	/* too low version number can easily result excess log rereading */
+
+	n = (union jffs2_node_union *) o;
+	lr = n;
+
+	do {
+		while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
+			ADD_BYTES(n, 4);
+
+		if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
+			if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_INODE &&
+				je32_to_cpu(n->i.ino) == ino && (v = je32_to_cpu(n->i.version)) > vcur) {
+				/* XXX crc check */
+
+				if (vmaxt < v)
+					vmaxt = v;
+				if (vmint > v) {
+					vmint = v;
+					mp = n;
+				}
+
+				if (v == (vcur + 1))
+					return (&(n->i));
+			}
+
+			ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
+		} else
+			n = (union jffs2_node_union *) o;	/* we're at the end, rewind to the beginning */
+
+		if (lr == n) {			/* whole loop since last read */
+			vmax = vmaxt;
+			vmin = vmint;
+			vmint = ~((uint32_t) 0);
+
+			if (vcur < vmax && vcur < vmin)
+				return (&(mp->i));
+		}
+	} while (vcur < vmax);
+
+	return NULL;
+}
+
+/* collects dir struct for selected inode */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   pino    - inode of the specified directory
+   d       - input directory structure
+
+   return value: result directory structure, replaces d.
+ */
+
+struct dir *collectdir(char *o, size_t size, uint32_t ino, struct dir *d)
+{
+	/* aligned! */
+	union jffs2_node_union *n;
+	union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
+	union jffs2_node_union *lr;	/* last block position */
+	union jffs2_node_union *mp = NULL;	/* minimum position */
+
+	uint32_t vmin, vmint, vmaxt, vmax, vcur, v;
+
+	vmin = 0;					/* next to read */
+	vmax = ~((uint32_t) 0);		/* last to read */
+	vmint = ~((uint32_t) 0);
+	vmaxt = 0;					/* found maximum */
+	vcur = 0;					/* XXX what is smallest version number used? */
+	/* too low version number can easily result excess log rereading */
+
+	n = (union jffs2_node_union *) o;
+	lr = n;
+
+	do {
+		while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
+			ADD_BYTES(n, 4);
+
+		if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
+			if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_DIRENT &&
+				je32_to_cpu(n->d.pino) == ino && (v = je32_to_cpu(n->d.version)) > vcur) {
+				/* XXX crc check */
+
+				if (vmaxt < v)
+					vmaxt = v;
+				if (vmint > v) {
+					vmint = v;
+					mp = n;
+				}
+
+				if (v == (vcur + 1)) {
+					d = putdir(d, &(n->d));
+
+					lr = n;
+					vcur++;
+					vmint = ~((uint32_t) 0);
+				}
+			}
+
+			ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
+		} else
+			n = (union jffs2_node_union *) o;	/* we're at the end, rewind to the beginning */
+
+		if (lr == n) {			/* whole loop since last read */
+			vmax = vmaxt;
+			vmin = vmint;
+			vmint = ~((uint32_t) 0);
+
+			if (vcur < vmax && vcur < vmin) {
+				d = putdir(d, &(mp->d));
+
+				lr = n =
+					(union jffs2_node_union *) (((char *) mp) +
+							((je32_to_cpu(mp->u.totlen) + 3) & ~3));
+
+				vcur = vmin;
+			}
+		}
+	} while (vcur < vmax);
+
+	return d;
+}
+
+
+
+/* resolve dirent based on criteria */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   ino     - if zero, ignore,
+   otherwise compare against dirent inode
+   pino    - if zero, ingore,
+   otherwise compare against parent inode
+   and use name and nsize as extra criteria
+   name    - name of wanted dirent, used if pino!=0
+   nsize   - length of name of wanted dirent, used if pino!=0
+
+   return value: pointer to relevant dirent structure in
+   filesystem image or NULL
+ */
+
+struct jffs2_raw_dirent *resolvedirent(char *o, size_t size,
+		uint32_t ino, uint32_t pino,
+		char *name, uint8_t nsize)
+{
+	/* aligned! */
+	union jffs2_node_union *n;
+	union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
+
+	struct jffs2_raw_dirent *dd = NULL;
+
+	uint32_t vmax, v;
+
+	if (!pino && ino <= 1)
+		return dd;
+
+	vmax = 0;
+
+	n = (union jffs2_node_union *) o;
+
+	do {
+		while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
+			ADD_BYTES(n, 4);
+
+		if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
+			if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_DIRENT &&
+					(!ino || je32_to_cpu(n->d.ino) == ino) &&
+					(v = je32_to_cpu(n->d.version)) > vmax &&
+					(!pino || (je32_to_cpu(n->d.pino) == pino &&
+							   nsize == n->d.nsize &&
+							   !memcmp(name, n->d.name, nsize)))) {
+				/* XXX crc check */
+
+				if (vmax < v) {
+					vmax = v;
+					dd = &(n->d);
+				}
+			}
+
+			ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
+		} else
+			return dd;
+	} while (1);
+}
+
+/* resolve name under certain parent inode to dirent */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   pino    - requested parent inode
+   name    - name of wanted dirent
+   nsize   - length of name of wanted dirent
+
+   return value: pointer to relevant dirent structure in
+   filesystem image or NULL
+ */
+
+struct jffs2_raw_dirent *resolvename(char *o, size_t size, uint32_t pino,
+		char *name, uint8_t nsize)
+{
+	return resolvedirent(o, size, 0, pino, name, nsize);
+}
+
+/* resolve inode to dirent */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   ino     - compare against dirent inode
+
+   return value: pointer to relevant dirent structure in
+   filesystem image or NULL
+ */
+
+struct jffs2_raw_dirent *resolveinode(char *o, size_t size, uint32_t ino)
+{
+	return resolvedirent(o, size, ino, 0, NULL, 0);
+}
+
+/* resolve slash-style path into dirent and inode.
+   slash as first byte marks absolute path (root=inode 1).
+   . and .. are resolved properly, and symlinks are followed.
+ */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   ino     - root inode, used if path is relative
+   p       - path to be resolved
+   inos    - result inode, zero if failure
+   recc    - recursion count, to detect symlink loops
+
+   return value: pointer to dirent struct in file system image.
+   note that root directory doesn't have dirent struct
+   (return value is NULL), but it has inode (*inos=1)
+ */
+
+struct jffs2_raw_dirent *resolvepath0(char *o, size_t size, uint32_t ino,
+		const char *p, uint32_t * inos, int recc)
+{
+	struct jffs2_raw_dirent *dir = NULL;
+
+	int d = 1;
+	uint32_t tino;
+
+	char *next;
+
+	char *path, *pp;
+
+	char symbuf[1024];
+	size_t symsize;
+
+	if (recc > 16) {
+		/* probably symlink loop */
+		*inos = 0;
+		return NULL;
+	}
+
+	pp = path = xstrdup(p);
+
+	if (*path == '/') {
+		path++;
+		ino = 1;
+	}
+
+	if (ino > 1) {
+		dir = resolveinode(o, size, ino);
+
+		ino = DIRENT_INO(dir);
+	}
+
+	next = path - 1;
+
+	while (ino && next != NULL && next[1] != 0 && d) {
+		path = next + 1;
+		next = strchr(path, '/');
+
+		if (next != NULL)
+			*next = 0;
+
+		if (*path == '.' && path[1] == 0)
+			continue;
+		if (*path == '.' && path[1] == '.' && path[2] == 0) {
+			if (DIRENT_PINO(dir) == 1) {
+				ino = 1;
+				dir = NULL;
+			} else {
+				dir = resolveinode(o, size, DIRENT_PINO(dir));
+				ino = DIRENT_INO(dir);
+			}
+
+			continue;
+		}
+
+		dir = resolvename(o, size, ino, path, (uint8_t) strlen(path));
+
+		if (DIRENT_INO(dir) == 0 ||
+				(next != NULL &&
+				 !(dir->type == DT_DIR || dir->type == DT_LNK))) {
+			free(pp);
+
+			*inos = 0;
+
+			return NULL;
+		}
+
+		if (dir->type == DT_LNK) {
+			struct jffs2_raw_inode *ri;
+			ri = find_raw_inode(o, size, DIRENT_INO(dir));
+			putblock(symbuf, sizeof(symbuf), &symsize, ri);
+			symbuf[symsize] = 0;
+
+			tino = ino;
+			ino = 0;
+
+			dir = resolvepath0(o, size, tino, symbuf, &ino, ++recc);
+
+			if (dir != NULL && next != NULL &&
+					!(dir->type == DT_DIR || dir->type == DT_LNK)) {
+				free(pp);
+
+				*inos = 0;
+				return NULL;
+			}
+		}
+		if (dir != NULL)
+			ino = DIRENT_INO(dir);
+	}
+
+	free(pp);
+
+	*inos = ino;
+
+	return dir;
+}
+
+/* resolve slash-style path into dirent and inode.
+   slash as first byte marks absolute path (root=inode 1).
+   . and .. are resolved properly, and symlinks are followed.
+ */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   ino     - root inode, used if path is relative
+   p       - path to be resolved
+   inos    - result inode, zero if failure
+
+   return value: pointer to dirent struct in file system image.
+   note that root directory doesn't have dirent struct
+   (return value is NULL), but it has inode (*inos=1)
+ */
+
+struct jffs2_raw_dirent *resolvepath(char *o, size_t size, uint32_t ino,
+		const char *p, uint32_t * inos)
+{
+	return resolvepath0(o, size, ino, p, inos, 0);
+}
+
+/* lists files on directory specified by path */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   p       - path to be resolved
+ */
+
+void lsdir(char *o, size_t size, const char *path, int recurse, int want_ctime)
+{
+	struct jffs2_raw_dirent *dd;
+	struct dir *d = NULL;
+
+	uint32_t ino;
+
+	dd = resolvepath(o, size, 1, path, &ino);
+
+	if (ino == 0 ||
+			(dd == NULL && ino == 0) || (dd != NULL && dd->type != DT_DIR))
+		errmsg_die("%s: No such file or directory", path);
+
+	d = collectdir(o, size, ino, d);
+	printdir(o, size, d, path, recurse, want_ctime);
+	freedir(d);
+}
+
+/* writes file specified by path to the buffer */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   p       - path to be resolved
+   b       - file buffer
+   bsize   - file buffer size
+   rsize   - file result size
+ */
+
+void catfile(char *o, size_t size, char *path, char *b, size_t bsize,
+		size_t * rsize)
+{
+	struct jffs2_raw_dirent *dd;
+	struct jffs2_raw_inode *ri;
+	uint32_t ino;
+
+	dd = resolvepath(o, size, 1, path, &ino);
+
+	if (ino == 0)
+		errmsg_die("%s: No such file or directory", path);
+
+	if (dd == NULL || dd->type != DT_REG)
+		errmsg_die("%s: Not a regular file", path);
+
+	ri = find_raw_inode(o, size, ino);
+	putblock(b, bsize, rsize, ri);
+
+	write(1, b, *rsize);
+}
+
+/* usage example */
+
+int main(int argc, char **argv)
+{
+	int fd, opt, recurse = 0, want_ctime = 0;
+	struct stat st;
+
+	char *scratch, *dir = NULL, *file = NULL;
+	size_t ssize = 0;
+
+	char *buf;
+
+	while ((opt = getopt(argc, argv, "rd:f:t")) > 0) {
+		switch (opt) {
+			case 'd':
+				dir = optarg;
+				break;
+			case 'f':
+				file = optarg;
+				break;
+			case 'r':
+				recurse++;
+				break;
+			case 't':
+				want_ctime++;
+				break;
+			default:
+				fprintf(stderr,
+						"Usage: %s <image> [-d|-f] < path >\n",
+						PROGRAM_NAME);
+				exit(EXIT_FAILURE);
+		}
+	}
+
+	fd = open(argv[optind], O_RDONLY);
+	if (fd == -1)
+		sys_errmsg_die("%s", argv[optind]);
+
+	if (fstat(fd, &st))
+		sys_errmsg_die("%s", argv[optind]);
+
+	buf = xmalloc((size_t) st.st_size);
+
+	if (read(fd, buf, st.st_size) != (ssize_t) st.st_size)
+		sys_errmsg_die("%s", argv[optind]);
+
+	if (dir)
+		lsdir(buf, st.st_size, dir, recurse, want_ctime);
+
+	if (file) {
+		scratch = xmalloc(SCRATCH_SIZE);
+
+		catfile(buf, st.st_size, file, scratch, SCRATCH_SIZE, &ssize);
+		free(scratch);
+	}
+
+	if (!dir && !file)
+		lsdir(buf, st.st_size, "/", 1, want_ctime);
+
+
+	free(buf);
+	exit(EXIT_SUCCESS);
+}
diff --git a/jffsX-utils/mkfs.jffs2.1 b/jffsX-utils/mkfs.jffs2.1
new file mode 100644
index 0000000..7c57ddc
--- /dev/null
+++ b/jffsX-utils/mkfs.jffs2.1
@@ -0,0 +1,268 @@
+.TH MKFS.JFFS2 1
+.SH NAME
+mkfs.jffs2 \- Create a JFFS2 file system image from directory
+.SH SYNOPSIS
+.B mkfs.jffs2
+[
+.B -p,--pad[=SIZE]
+]
+[
+.B -r,-d,--root
+.I directory
+]
+[
+.B -s,--pagesize=SIZE
+]
+[
+.B -e,--eraseblock=SIZE
+]
+[
+.B -c,--cleanmarker=SIZE
+]
+[
+.B -n,--no-cleanmarkers
+]
+[
+.B -o,--output
+.I image.jffs2
+]
+[
+.B -l,--little-endian
+]
+[
+.B -b,--big-endian
+]
+[
+.B -D,--devtable=FILE
+]
+[
+.B -f,--faketime
+]
+[
+.B -q,--squash
+]
+[
+.B -U,--squash-uids
+]
+[
+.B -P,--squash-perms
+]
+[
+.B --with-xattr
+]
+[
+.B --with-selinux
+]
+[
+.B --with-posix-acl
+]
+[
+.B -m,--compression-mode=MODE
+]
+[
+.B -x,--disable-compressor=NAME
+]
+[
+.B -X,--enable-compressor=NAME
+]
+[
+.B -y,--compressor-priority=PRIORITY:NAME
+]
+[
+.B -L,--list-compressors
+]
+[
+.B -t,--test-compression
+]
+[
+.B -h,--help
+]
+[
+.B -v,--verbose
+]
+[
+.B -V,--version
+]
+[
+.B -i,--incremental
+.I image.jffs2
+]
+
+.SH DESCRIPTION
+The program
+.B mkfs.jffs2
+creates a JFFS2 (Second Journalling Flash File System) file system
+image and writes the resulting image to the file specified by the
+.B -o
+option or by default to the standard output, unless the standard
+output is a terminal device in which case mkfs.jffs2 will abort.
+
+The file system image is created using the files and directories
+contained in the directory specified by the option
+.B -r
+or the present directory, if the
+.B -r
+option is not specified.
+
+Each block of the files to be placed into the file system image
+are compressed using one of the available compressors depending
+on the selected compression mode.
+
+File systems are created with the same endianness as the host,
+unless the
+.B -b
+or
+.B -l
+options are specified.  JFFS2 driver in the 2.4 Linux kernel only
+supported images having the same endianness as the CPU. As of 2.5.48,
+the kernel can be changed with a #define to accept images of the
+non-native endianness. Full bi-endian support in the kernel is not
+planned.
+
+It is unlikely that JFFS2 images are useful except in conjuction
+with the MTD (Memory Technology Device) drivers in the Linux
+kernel, since the JFFS2 file system driver in the kernel requires
+MTD devices.
+.SH OPTIONS
+Options that take SIZE arguments can be specified as either
+decimal (e.g., 65536), octal (0200000), or hexidecimal (0x1000).
+.TP
+.B -p, --pad[=SIZE]
+Pad output to SIZE bytes with 0xFF.  If SIZE is not specified,
+the output is padded to the end of the final erase block.
+.TP
+.B -r, -d, --root=DIR
+Build file system from directory DIR.  The default is the current
+directory.
+.TP
+.B -s, --pagesize=SIZE
+Use page size SIZE.  The default is 4 KiB.  This size is the
+maximum size of a data node.  Set according to target system's memory
+management page size (NOTE: this is NOT related to NAND page size).
+.TP
+.B -e, --eraseblock=SIZE
+Use erase block size SIZE.  The default is 64 KiB.  If you use a erase
+block size different than the erase block size of the target MTD
+device, JFFS2 may not perform optimally. If the SIZE specified is
+below 4096, the units are assumed to be KiB.
+.TP
+.B -c, --cleanmarker=SIZE
+Write \'CLEANMARKER\' nodes with the size specified. It is not
+normally appropriate to specify a size other than the default 12
+bytes.
+.TP
+.B -n, --no-cleanmarkers
+Do not write \'CLEANMARKER\' nodes to the beginning of each erase
+block. This option can be useful for creating JFFS2 images for
+use on NAND flash, and for creating images which are to be used
+on a variety of hardware with differing eraseblock sizes.
+.TP
+.B -o, --output=FILE
+Write JFFS2 image to file FILE.  Default is the standard output.
+.TP
+.B -l, --little-endian
+Create a little-endian JFFS2 image.  Default is to make an image
+with the same endianness as the host.
+.TP
+.B -b, --big-endian
+Create a big-endian JFFS2 image.  Default is to make an image
+with the same endianness as the host.
+.TP
+.B -D, --devtable=FILE
+Use the named FILE as a device table file, for including devices and
+changing permissions in the created image when the user does not have
+appropriate permissions to create them on the file system used as
+source.
+.TP
+.B -f, --faketime
+Change all file timestamps to \'0\' for regression testing.
+.TP
+.B -q, --squash
+Squash permissions and owners, making all files be owned by root and
+removing write permission for \'group\' and \'other\'.
+.TP
+.B -U, --squash-uids
+Squash owners making all files be owned by root.
+.TP
+.B -P, --squash-perms
+Squash permissions, removing write permission for \'group\' and \'other\'.
+.TP
+.B --with-xattr
+Enables xattr, stuff all xattr entries into jffs2 image file.
+.TP
+.B --with-selinux
+Enables xattr, stuff only SELinux Labels into jffs2 image file.
+.TP
+.B --with-posix-acl
+Enable xattr, stuff only POSIX ACL entries into jffs2 image file.
+.TP
+.B -m, --compression-mode=MODE
+Set the default compression mode. The default mode is
+.B priority
+which tries the compressors in a predefinied order and chooses the first
+successful one. The alternatives are:
+.B none
+(mkfs will not compress) and
+.B size
+(mkfs will try all compressor and chooses the one which have the smallest result).
+.TP
+.B -x, --disable-compressor=NAME
+Disable a compressor. Use
+.B -L
+to see the list of the available compressors and their default states.
+.TP
+.B -X, --enable-compressor=NAME
+Enable a compressor. Use
+.B -L
+to see the list of the available compressors and their default states.
+.TP
+.B -y, --compressor-priority=PRIORITY:NAME
+Set the priority of a compressor. Use
+.B -L
+to see the list of the available compressors and their default priority.
+Priorities are used by priority compression mode.
+.TP
+.B -L, --list-compressors
+Show the list of the available compressors and their states.
+.TP
+.B -t, --test-compression
+Call decompress after every compress - and compare the result with the original data -, and
+some other check.
+.TP
+.B -h, --help
+Display help text.
+.TP
+.B -v, --verbose
+Verbose operation.
+.TP
+.B -V, --version
+Display version information.
+.TP
+.B -i, --incremental=FILE
+Generate an appendage image for FILE. If FILE is written to flash and flash
+is appended with the output, then it seems as if it was one thing.
+
+.SH LIMITATIONS
+The format and grammar of the device table file does not allow it to
+create symbolic links when the symbolic links are not already present
+in the root working directory.
+
+However, symbolic links may be specified in the device table file
+using the \fIl\fR type for the purposes of setting their permissions
+and ownership.
+.SH BUGS
+JFFS2 limits device major and minor numbers to 8 bits each.  Some
+consider this a bug.
+
+.B mkfs.jffs2
+does not properly handle hard links in the input directory structure.
+Currently, hard linked files will be expanded to multiple identical
+files in the output image.
+.SH AUTHORS
+David Woodhouse
+.br
+Manual page written by David Schleef <ds at schleef.org>
+.SH SEE ALSO
+.BR mkfs (8),
+.BR mkfs.jffs (1),
+.BR fakeroot (1)
diff --git a/jffsX-utils/mkfs.jffs2.c b/jffsX-utils/mkfs.jffs2.c
new file mode 100644
index 0000000..f09c0b2
--- /dev/null
+++ b/jffsX-utils/mkfs.jffs2.c
@@ -0,0 +1,1805 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Build a JFFS2 image in a file, from a given directory tree.
+ *
+ * Copyright 2001, 2002 Red Hat, Inc.
+ *           2001 David A. Schleef <ds at lineo.com>
+ *           2002 Axis Communications AB
+ *           2001, 2002 Erik Andersen <andersen at codepoet.org>
+ *           2004 University of Szeged, Hungary
+ *           2006 KaiGai Kohei <kaigai at ak.jp.nec.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ *
+ * Cross-endian support added by David Schleef <ds at schleef.org>.
+ *
+ * Major architectural rewrite by Erik Andersen <andersen at codepoet.org>
+ * to allow support for making hard links (though hard links support is
+ * not yet implemented), and for munging file permissions and ownership
+ * on the fly using --faketime, --squash, --devtable.   And I plugged a
+ * few memory leaks, adjusted the error handling and fixed some little
+ * nits here and there.
+ *
+ * I also added a sample device table file.  See device_table.txt
+ *  -Erik, September 2001
+ *
+ * Cleanmarkers support added by Axis Communications AB
+ *
+ * Rewritten again.  Cleanly separated host and target filsystem
+ * activities (mainly so I can reuse all the host handling stuff as I
+ * rewrite other mkfs utils).  Added a verbose option to list types
+ * and attributes as files are added to the file system.  Major cleanup
+ * and scrubbing of the code so it can be read, understood, and
+ * modified by mere mortals.
+ *
+ *  -Erik, November 2002
+ */
+
+#define PROGRAM_NAME "mkfs.jffs2"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <libgen.h>
+#include <ctype.h>
+#include <time.h>
+#include <getopt.h>
+#ifndef WITHOUT_XATTR
+#include <sys/xattr.h>
+#include <sys/acl.h>
+#endif
+#include <byteswap.h>
+#include <crc32.h>
+#include <inttypes.h>
+
+#include "rbtree.h"
+#include "common.h"
+
+/* Do not use the weird XPG version of basename */
+#undef basename
+
+//#define DMALLOC
+//#define mkfs_debug_msg    errmsg
+#define mkfs_debug_msg(a...)	{ }
+
+#define PAD(x) (((x)+3)&~3)
+
+struct filesystem_entry {
+	char *name;					/* Name of this directory (think basename) */
+	char *path;					/* Path of this directory (think dirname) */
+	char *fullname;				/* Full name of this directory (i.e. path+name) */
+	char *hostname;				/* Full path to this file on the host filesystem */
+	uint32_t ino;				/* Inode number of this file in JFFS2 */
+	struct stat sb;				/* Stores directory permissions and whatnot */
+	char *link;					/* Target a symlink points to. */
+	struct filesystem_entry *parent;	/* Parent directory */
+	struct filesystem_entry *prev;	/* Only relevant to non-directories */
+	struct filesystem_entry *next;	/* Only relevant to non-directories */
+	struct filesystem_entry *files;	/* Only relevant to directories */
+	struct rb_node hardlink_rb;
+};
+
+struct rb_root hardlinks;
+static int out_fd = -1;
+static int in_fd = -1;
+static char default_rootdir[] = ".";
+static char *rootdir = default_rootdir;
+static int verbose = 0;
+static int squash_uids = 0;
+static int squash_perms = 0;
+static int fake_times = 0;
+int target_endian = __BYTE_ORDER;
+
+uint32_t find_hardlink(struct filesystem_entry *e)
+{
+	struct filesystem_entry *f;
+	struct rb_node **n = &hardlinks.rb_node;
+	struct rb_node *parent = NULL;
+
+	while (*n) {
+		parent = *n;
+		f = rb_entry(parent, struct filesystem_entry, hardlink_rb);
+
+		if ((f->sb.st_dev < e->sb.st_dev) ||
+		    (f->sb.st_dev == e->sb.st_dev &&
+		     f->sb.st_ino < e->sb.st_ino))
+			n = &parent->rb_left;
+		else if ((f->sb.st_dev > e->sb.st_dev) ||
+			 (f->sb.st_dev == e->sb.st_dev &&
+			  f->sb.st_ino > e->sb.st_ino)) {
+			n = &parent->rb_right;
+		} else
+			return f->ino;
+	}
+
+	rb_link_node(&e->hardlink_rb, parent, n);
+	rb_insert_color(&e->hardlink_rb, &hardlinks);
+	return 0;
+}
+
+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) {
+			sys_errmsg("%s:%s", PROGRAM_NAME, path);
+			return NULL;
+		}
+	}
+	while (bufsize < readsize + 1);
+
+	buf[readsize] = '\0';
+
+	return buf;
+}
+static FILE *xfopen(const char *path, const char *mode)
+{
+	FILE *fp;
+	if ((fp = fopen(path, mode)) == NULL)
+		sys_errmsg_die("%s", path);
+	return fp;
+}
+
+static struct filesystem_entry *find_filesystem_entry(
+		struct filesystem_entry *dir, char *fullname, uint32_t type)
+{
+	struct filesystem_entry *e = dir;
+
+	if (S_ISDIR(dir->sb.st_mode)) {
+		/* If this is the first call, and we actually want this
+		 * directory, then return it now */
+		if (strcmp(fullname, e->fullname) == 0)
+			return e;
+
+		e = dir->files;
+	}
+	while (e) {
+		if (S_ISDIR(e->sb.st_mode)) {
+			int len = strlen(e->fullname);
+
+			/* Check if we are a parent of the correct path */
+			if (strncmp(e->fullname, fullname, len) == 0) {
+				/* Is this an _exact_ match? */
+				if (strcmp(fullname, e->fullname) == 0) {
+					return (e);
+				}
+				/* Looks like we found a parent of the correct path */
+				if (fullname[len] == '/') {
+					if (e->files) {
+						return (find_filesystem_entry (e, fullname, type));
+					} else {
+						return NULL;
+					}
+				}
+			}
+		} else {
+			if (strcmp(fullname, e->fullname) == 0) {
+				return (e);
+			}
+		}
+		e = e->next;
+	}
+	return (NULL);
+}
+
+static struct filesystem_entry *add_host_filesystem_entry(const char *name,
+		const char *path, unsigned long uid, unsigned long gid,
+		unsigned long mode, dev_t rdev, struct filesystem_entry *parent)
+{
+	int status;
+	char *tmp;
+	struct stat sb;
+	time_t timestamp = time(NULL);
+	struct filesystem_entry *entry;
+
+	memset(&sb, 0, sizeof(struct stat));
+	status = lstat(path, &sb);
+
+	if (status >= 0) {
+		/* It is ok for some types of files to not exit on disk (such as
+		 * device nodes), but if they _do_ exist the specified mode had
+		 * better match the actual file or strange things will happen.... */
+		if ((mode & S_IFMT) != (sb.st_mode & S_IFMT)) {
+			errmsg_die ("%s: file type does not match specified type!", path);
+		}
+		timestamp = sb.st_mtime;
+	} else {
+		/* If this is a regular file, it _must_ exist on disk */
+		if ((mode & S_IFMT) == S_IFREG) {
+			errmsg_die("%s: does not exist!", path);
+		}
+	}
+
+	/* Squash all permissions so files are owned by root, all
+	 * timestamps are _right now_, and file permissions
+	 * have group and other write removed */
+	if (squash_uids) {
+		uid = gid = 0;
+	}
+	if (squash_perms) {
+		if (!S_ISLNK(mode)) {
+			mode &= ~(S_IWGRP | S_IWOTH);
+			mode &= ~(S_ISUID | S_ISGID);
+		}
+	}
+	if (fake_times) {
+		timestamp = 0;
+	}
+
+	entry = xcalloc(1, sizeof(struct filesystem_entry));
+
+	entry->hostname = xstrdup(path);
+	entry->fullname = xstrdup(name);
+	tmp = xstrdup(name);
+	entry->name = xstrdup(basename(tmp));
+	free(tmp);
+	tmp = xstrdup(name);
+	entry->path = xstrdup(dirname(tmp));
+	free(tmp);
+
+	entry->sb.st_ino = sb.st_ino;
+	entry->sb.st_dev = sb.st_dev;
+	entry->sb.st_nlink = sb.st_nlink;
+
+	entry->sb.st_uid = uid;
+	entry->sb.st_gid = gid;
+	entry->sb.st_mode = mode;
+	entry->sb.st_rdev = rdev;
+	entry->sb.st_atime = entry->sb.st_ctime =
+		entry->sb.st_mtime = timestamp;
+	if (S_ISREG(mode)) {
+		entry->sb.st_size = sb.st_size;
+	}
+	if (S_ISLNK(mode)) {
+		entry->link = xreadlink(path);
+		entry->sb.st_size = strlen(entry->link);
+	}
+
+	/* This happens only for root */
+	if (!parent)
+		return (entry);
+
+	/* Hook the file into the parent directory */
+	entry->parent = parent;
+	if (!parent->files) {
+		parent->files = entry;
+	} else {
+		struct filesystem_entry *prev;
+		for (prev = parent->files; prev->next; prev = prev->next);
+		prev->next = entry;
+		entry->prev = prev;
+	}
+
+	return (entry);
+}
+
+static struct filesystem_entry *recursive_add_host_directory(
+		struct filesystem_entry *parent, const char *targetpath,
+		const char *hostpath)
+{
+	int i, n;
+	struct stat sb;
+	char *hpath, *tpath;
+	struct dirent *dp, **namelist;
+	struct filesystem_entry *entry;
+
+
+	if (lstat(hostpath, &sb)) {
+		sys_errmsg_die("%s", hostpath);
+	}
+
+	entry = add_host_filesystem_entry(targetpath, hostpath,
+			sb.st_uid, sb.st_gid, sb.st_mode, 0, parent);
+
+	n = scandir(hostpath, &namelist, 0, alphasort);
+	if (n < 0) {
+		sys_errmsg_die("opening directory %s", hostpath);
+	}
+
+	for (i=0; i<n; i++)
+	{
+		dp = namelist[i];
+		if (dp->d_name[0] == '.' && (dp->d_name[1] == 0 ||
+					(dp->d_name[1] == '.' &&  dp->d_name[2] == 0)))
+		{
+			free(dp);
+			continue;
+		}
+
+		xasprintf(&hpath, "%s/%s", hostpath, dp->d_name);
+		if (lstat(hpath, &sb)) {
+			sys_errmsg_die("%s", hpath);
+		}
+		if (strcmp(targetpath, "/") == 0) {
+			xasprintf(&tpath, "%s%s", targetpath, dp->d_name);
+		} else {
+			xasprintf(&tpath, "%s/%s", targetpath, dp->d_name);
+		}
+
+		switch (sb.st_mode & S_IFMT) {
+			case S_IFDIR:
+				recursive_add_host_directory(entry, tpath, hpath);
+				break;
+
+			case S_IFREG:
+			case S_IFSOCK:
+			case S_IFIFO:
+			case S_IFLNK:
+			case S_IFCHR:
+			case S_IFBLK:
+				add_host_filesystem_entry(tpath, hpath, sb.st_uid,
+						sb.st_gid, sb.st_mode, sb.st_rdev, entry);
+				break;
+
+			default:
+				errmsg("Unknown file type %o for %s", sb.st_mode, hpath);
+				break;
+		}
+		free(dp);
+		free(hpath);
+		free(tpath);
+	}
+	free(namelist);
+	return (entry);
+}
+
+/* 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(struct filesystem_entry *root, char *line)
+{
+	char *hostpath;
+	char type, *name = NULL, *tmp, *dir;
+	unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
+	unsigned long start = 0, increment = 1, count = 0;
+	struct filesystem_entry *parent, *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, "/")) {
+		errmsg_die("Device table entries require absolute paths");
+	}
+
+	xasprintf(&hostpath, "%s%s", rootdir, name);
+
+	/* 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;
+		case 'l':
+			mode |= S_IFLNK;
+			break;
+		default:
+			errmsg_die("Unsupported file type '%c'", type);
+	}
+	entry = find_filesystem_entry(root, name, mode);
+	if (entry && !(count > 0 && (type == 'c' || type == 'b'))) {
+		/* Ok, we just need to fixup the existing entry
+		 * and we will be all done... */
+		entry->sb.st_uid = uid;
+		entry->sb.st_gid = gid;
+		entry->sb.st_mode = mode;
+		if (major && minor) {
+			entry->sb.st_rdev = makedev(major, minor);
+		}
+	} else {
+		/* If parent is NULL (happens with device table entries),
+		 * try and find our parent now) */
+		tmp = xstrdup(name);
+		dir = dirname(tmp);
+		parent = find_filesystem_entry(root, dir, S_IFDIR);
+		free(tmp);
+		if (parent == NULL) {
+			errmsg ("skipping device_table entry '%s': no parent directory!", name);
+			free(name);
+			free(hostpath);
+			return 1;
+		}
+
+		switch (type) {
+			case 'd':
+				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+				break;
+			case 'f':
+				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+				break;
+			case 'p':
+				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+				break;
+			case 'c':
+			case 'b':
+				if (count > 0) {
+					dev_t rdev;
+					unsigned long i;
+					char *dname, *hpath;
+
+					for (i = start; i < (start + count); i++) {
+						xasprintf(&dname, "%s%lu", name, i);
+						xasprintf(&hpath, "%s/%s%lu", rootdir, name, i);
+						rdev = makedev(major, minor + (i - start) * increment);
+						add_host_filesystem_entry(dname, hpath, uid, gid,
+								mode, rdev, parent);
+						free(dname);
+						free(hpath);
+					}
+				} else {
+					dev_t rdev = makedev(major, minor);
+					add_host_filesystem_entry(name, hostpath, uid, gid,
+							mode, rdev, parent);
+				}
+				break;
+			default:
+				errmsg_die("Unsupported file type '%c'", type);
+		}
+	}
+	free(name);
+	free(hostpath);
+	return 0;
+}
+
+static int parse_device_table(struct filesystem_entry *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;
+}
+
+static void cleanup(struct filesystem_entry *dir)
+{
+	struct filesystem_entry *e, *prev;
+
+	e = dir->files;
+	while (e) {
+		if (e->name)
+			free(e->name);
+		if (e->path)
+			free(e->path);
+		if (e->fullname)
+			free(e->fullname);
+		e->next = NULL;
+		e->name = NULL;
+		e->path = NULL;
+		e->fullname = NULL;
+		e->prev = NULL;
+		prev = e;
+		if (S_ISDIR(e->sb.st_mode)) {
+			cleanup(e);
+		}
+		e = e->next;
+		free(prev);
+	}
+}
+
+/* Here is where we do the actual creation of the file system */
+#include "mtd/jffs2-user.h"
+
+#define JFFS2_MAX_FILE_SIZE 0xFFFFFFFF
+#ifndef JFFS2_MAX_SYMLINK_LEN
+#define JFFS2_MAX_SYMLINK_LEN 254
+#endif
+
+static uint32_t ino = 0;
+static uint8_t *file_buffer = NULL;		/* file buffer contains the actual erase block*/
+static int out_ofs = 0;
+static int erase_block_size = 65536;
+static int pad_fs_size = 0;
+static int add_cleanmarkers = 1;
+static struct jffs2_unknown_node cleanmarker;
+static int cleanmarker_size = sizeof(cleanmarker);
+static unsigned char ffbuf[16] =
+{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+/* We set this at start of main() using sysconf(), -1 means we don't know */
+/* When building an fs for non-native systems, use --pagesize=SIZE option */
+int page_size = -1;
+
+#include "compr.h"
+
+static void full_write(int fd, const void *buf, int len)
+{
+	int ret;
+
+	while (len > 0) {
+		ret = write(fd, buf, len);
+
+		if (ret < 0)
+			sys_errmsg_die("write");
+
+		if (ret == 0)
+			sys_errmsg_die("write returned zero");
+
+		len -= ret;
+		buf += ret;
+		out_ofs += ret;
+	}
+}
+
+static void padblock(void)
+{
+	while (out_ofs % erase_block_size) {
+		full_write(out_fd, ffbuf, min(sizeof(ffbuf),
+					erase_block_size - (out_ofs % erase_block_size)));
+	}
+}
+
+static void pad(int req)
+{
+	while (req) {
+		if (req > sizeof(ffbuf)) {
+			full_write(out_fd, ffbuf, sizeof(ffbuf));
+			req -= sizeof(ffbuf);
+		} else {
+			full_write(out_fd, ffbuf, req);
+			req = 0;
+		}
+	}
+}
+
+static inline void padword(void)
+{
+	if (out_ofs % 4) {
+		full_write(out_fd, ffbuf, 4 - (out_ofs % 4));
+	}
+}
+
+static inline void pad_block_if_less_than(int req)
+{
+	if (add_cleanmarkers) {
+		if ((out_ofs % erase_block_size) == 0) {
+			full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
+			pad(cleanmarker_size - sizeof(cleanmarker));
+			padword();
+		}
+	}
+	if ((out_ofs % erase_block_size) + req > erase_block_size) {
+		padblock();
+	}
+	if (add_cleanmarkers) {
+		if ((out_ofs % erase_block_size) == 0) {
+			full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
+			pad(cleanmarker_size - sizeof(cleanmarker));
+			padword();
+		}
+	}
+}
+
+static void write_dirent(struct filesystem_entry *e)
+{
+	char *name = e->name;
+	struct jffs2_raw_dirent rd;
+	struct stat *statbuf = &(e->sb);
+	static uint32_t version = 0;
+
+	memset(&rd, 0, sizeof(rd));
+
+	rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+	rd.totlen = cpu_to_je32(sizeof(rd) + strlen(name));
+	rd.hdr_crc = cpu_to_je32(mtd_crc32(0, &rd,
+				sizeof(struct jffs2_unknown_node) - 4));
+	rd.pino = cpu_to_je32((e->parent) ? e->parent->ino : 1);
+	rd.version = cpu_to_je32(version++);
+	rd.ino = cpu_to_je32(e->ino);
+	rd.mctime = cpu_to_je32(statbuf->st_mtime);
+	rd.nsize = strlen(name);
+	rd.type = IFTODT(statbuf->st_mode);
+	//rd.unused[0] = 0;
+	//rd.unused[1] = 0;
+	rd.node_crc = cpu_to_je32(mtd_crc32(0, &rd, sizeof(rd) - 8));
+	rd.name_crc = cpu_to_je32(mtd_crc32(0, name, strlen(name)));
+
+	pad_block_if_less_than(sizeof(rd) + rd.nsize);
+	full_write(out_fd, &rd, sizeof(rd));
+	full_write(out_fd, name, rd.nsize);
+	padword();
+}
+
+static unsigned int write_regular_file(struct filesystem_entry *e)
+{
+	int fd, len;
+	uint32_t ver;
+	unsigned int offset;
+	unsigned char *buf, *cbuf, *wbuf;
+	struct jffs2_raw_inode ri;
+	struct stat *statbuf;
+	unsigned int totcomp = 0;
+
+	statbuf = &(e->sb);
+	if (statbuf->st_size >= JFFS2_MAX_FILE_SIZE) {
+		errmsg("Skipping file \"%s\" too large.", e->path);
+		return -1;
+	}
+	fd = open(e->hostname, O_RDONLY);
+	if (fd == -1) {
+		sys_errmsg_die("%s: open file", e->hostname);
+	}
+
+	e->ino = ++ino;
+	mkfs_debug_msg("writing file '%s'  ino=%lu  parent_ino=%lu",
+			e->name, (unsigned long) e->ino,
+			(unsigned long) e->parent->ino);
+	write_dirent(e);
+
+	buf = xmalloc(page_size);
+	cbuf = NULL;
+
+	ver = 0;
+	offset = 0;
+
+	memset(&ri, 0, sizeof(ri));
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+
+	ri.ino = cpu_to_je32(e->ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(statbuf->st_size);
+
+	while ((len = read(fd, buf, page_size))) {
+		unsigned char *tbuf = buf;
+
+		if (len < 0) {
+			sys_errmsg_die("read");
+		}
+
+		while (len) {
+			uint32_t dsize, space;
+			uint16_t compression;
+
+			pad_block_if_less_than(sizeof(ri) + JFFS2_MIN_DATA_LEN);
+
+			dsize = len;
+			space =
+				erase_block_size - (out_ofs % erase_block_size) -
+				sizeof(ri);
+			if (space > dsize)
+				space = dsize;
+
+			compression = jffs2_compress(tbuf, &cbuf, &dsize, &space);
+
+			ri.compr = compression & 0xff;
+			ri.usercompr = (compression >> 8) & 0xff;
+
+			if (ri.compr) {
+				wbuf = cbuf;
+			} else {
+				wbuf = tbuf;
+				dsize = space;
+			}
+
+			ri.totlen = cpu_to_je32(sizeof(ri) + space);
+			ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
+						&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+			ri.version = cpu_to_je32(++ver);
+			ri.offset = cpu_to_je32(offset);
+			ri.csize = cpu_to_je32(space);
+			ri.dsize = cpu_to_je32(dsize);
+			ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
+			ri.data_crc = cpu_to_je32(mtd_crc32(0, wbuf, space));
+
+			full_write(out_fd, &ri, sizeof(ri));
+			totcomp += sizeof(ri);
+			full_write(out_fd, wbuf, space);
+			totcomp += space;
+			padword();
+
+			if (tbuf != cbuf) {
+				free(cbuf);
+				cbuf = NULL;
+			}
+
+			tbuf += dsize;
+			len -= dsize;
+			offset += dsize;
+
+		}
+	}
+	if (!je32_to_cpu(ri.version)) {
+		/* Was empty file */
+		pad_block_if_less_than(sizeof(ri));
+
+		ri.version = cpu_to_je32(++ver);
+		ri.totlen = cpu_to_je32(sizeof(ri));
+		ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
+					&ri, sizeof(struct jffs2_unknown_node) - 4));
+		ri.csize = cpu_to_je32(0);
+		ri.dsize = cpu_to_je32(0);
+		ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
+
+		full_write(out_fd, &ri, sizeof(ri));
+		padword();
+	}
+	free(buf);
+	close(fd);
+	return totcomp;
+}
+
+static void write_symlink(struct filesystem_entry *e)
+{
+	int len;
+	struct stat *statbuf;
+	struct jffs2_raw_inode ri;
+
+	statbuf = &(e->sb);
+	e->ino = ++ino;
+	mkfs_debug_msg("writing symlink '%s'  ino=%lu  parent_ino=%lu",
+			e->name, (unsigned long) e->ino,
+			(unsigned long) e->parent->ino);
+	write_dirent(e);
+
+	len = strlen(e->link);
+	if (len > JFFS2_MAX_SYMLINK_LEN) {
+		errmsg("symlink too large. Truncated to %d chars.",
+				JFFS2_MAX_SYMLINK_LEN);
+		len = JFFS2_MAX_SYMLINK_LEN;
+	}
+
+	memset(&ri, 0, sizeof(ri));
+
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri.totlen = cpu_to_je32(sizeof(ri) + len);
+	ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
+				&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+	ri.ino = cpu_to_je32(e->ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(statbuf->st_size);
+	ri.version = cpu_to_je32(1);
+	ri.csize = cpu_to_je32(len);
+	ri.dsize = cpu_to_je32(len);
+	ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
+	ri.data_crc = cpu_to_je32(mtd_crc32(0, e->link, len));
+
+	pad_block_if_less_than(sizeof(ri) + len);
+	full_write(out_fd, &ri, sizeof(ri));
+	full_write(out_fd, e->link, len);
+	padword();
+}
+
+static void write_pipe(struct filesystem_entry *e)
+{
+	struct stat *statbuf;
+	struct jffs2_raw_inode ri;
+
+	statbuf = &(e->sb);
+	e->ino = ++ino;
+	if (S_ISDIR(statbuf->st_mode)) {
+		mkfs_debug_msg("writing dir '%s'  ino=%lu  parent_ino=%lu",
+				e->name, (unsigned long) e->ino,
+				(unsigned long) (e->parent) ? e->parent->ino : 1);
+	}
+	write_dirent(e);
+
+	memset(&ri, 0, sizeof(ri));
+
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri.totlen = cpu_to_je32(sizeof(ri));
+	ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
+				&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+	ri.ino = cpu_to_je32(e->ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(0);
+	ri.version = cpu_to_je32(1);
+	ri.csize = cpu_to_je32(0);
+	ri.dsize = cpu_to_je32(0);
+	ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
+	ri.data_crc = cpu_to_je32(0);
+
+	pad_block_if_less_than(sizeof(ri));
+	full_write(out_fd, &ri, sizeof(ri));
+	padword();
+}
+
+static void write_special_file(struct filesystem_entry *e)
+{
+	jint16_t kdev;
+	struct stat *statbuf;
+	struct jffs2_raw_inode ri;
+
+	statbuf = &(e->sb);
+	e->ino = ++ino;
+	write_dirent(e);
+
+	kdev = cpu_to_je16((major(statbuf->st_rdev) << 8) +
+			minor(statbuf->st_rdev));
+
+	memset(&ri, 0, sizeof(ri));
+
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri.totlen = cpu_to_je32(sizeof(ri) + sizeof(kdev));
+	ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
+				&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+	ri.ino = cpu_to_je32(e->ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(statbuf->st_size);
+	ri.version = cpu_to_je32(1);
+	ri.csize = cpu_to_je32(sizeof(kdev));
+	ri.dsize = cpu_to_je32(sizeof(kdev));
+	ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
+	ri.data_crc = cpu_to_je32(mtd_crc32(0, &kdev, sizeof(kdev)));
+
+	pad_block_if_less_than(sizeof(ri) + sizeof(kdev));
+	full_write(out_fd, &ri, sizeof(ri));
+	full_write(out_fd, &kdev, sizeof(kdev));
+	padword();
+}
+
+#ifndef WITHOUT_XATTR
+typedef struct xattr_entry {
+	struct xattr_entry *next;
+	uint32_t xid;
+	int xprefix;
+	char *xname;
+	char *xvalue;
+	int name_len;
+	int value_len;
+} xattr_entry_t;
+
+#define XATTR_BUFFER_SIZE		(64 * 1024)	/* 64KB */
+static uint32_t enable_xattr = 0;
+static uint32_t highest_xid = 0;
+static uint32_t highest_xseqno = 0;
+
+static struct {
+	int xprefix;
+	const char *string;
+	int length;
+} xprefix_tbl[] = {
+	{ JFFS2_XPREFIX_USER, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN },
+	{ JFFS2_XPREFIX_SECURITY, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
+	{ JFFS2_XPREFIX_ACL_ACCESS, POSIX_ACL_XATTR_ACCESS, POSIX_ACL_XATTR_ACCESS_LEN },
+	{ JFFS2_XPREFIX_ACL_DEFAULT, POSIX_ACL_XATTR_DEFAULT, POSIX_ACL_XATTR_DEFAULT_LEN },
+	{ JFFS2_XPREFIX_TRUSTED, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN },
+	{ 0, NULL, 0 }
+};
+
+static void formalize_posix_acl(void *xvalue, int *value_len)
+{
+	struct posix_acl_xattr_header *pacl_header;
+	struct posix_acl_xattr_entry *pent, *plim;
+	struct jffs2_acl_header *jacl_header;
+	struct jffs2_acl_entry *jent;
+	struct jffs2_acl_entry_short *jent_s;
+	char buffer[XATTR_BUFFER_SIZE];
+	int offset = 0;
+
+	pacl_header = xvalue;;
+	pent = pacl_header->a_entries;
+	plim = xvalue + *value_len;
+
+	jacl_header = (struct jffs2_acl_header *)buffer;
+	offset += sizeof(struct jffs2_acl_header);
+	jacl_header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
+
+	while (pent < plim) {
+		switch(le16_to_cpu(pent->e_tag)) {
+			case ACL_USER_OBJ:
+			case ACL_GROUP_OBJ:
+			case ACL_MASK:
+			case ACL_OTHER:
+				jent_s = (struct jffs2_acl_entry_short *)(buffer + offset);
+				offset += sizeof(struct jffs2_acl_entry_short);
+				jent_s->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
+				jent_s->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
+				break;
+			case ACL_USER:
+			case ACL_GROUP:
+				jent = (struct jffs2_acl_entry *)(buffer + offset);
+				offset += sizeof(struct jffs2_acl_entry);
+				jent->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
+				jent->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
+				jent->e_id = cpu_to_je32(le32_to_cpu(pent->e_id));
+				break;
+			default:
+				printf("%04x : Unknown XATTR entry tag.\n", le16_to_cpu(pent->e_tag));
+				exit(1);
+		}
+		pent++;
+	}
+	if (offset > *value_len) {
+		printf("Length of JFFS2 ACL expression(%u) is longer than general one(%u).\n",
+				offset, *value_len);
+		exit(1);
+	}
+	memcpy(xvalue, buffer, offset);
+	*value_len = offset;
+}
+
+static xattr_entry_t *create_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
+{
+	xattr_entry_t *xe;
+	struct jffs2_raw_xattr rx;
+	int name_len;
+
+	/* create xattr entry */
+	name_len = strlen(xname);
+	xe = xcalloc(1, sizeof(xattr_entry_t) + name_len + 1 + value_len);
+	xe->next = NULL;
+	xe->xid = ++highest_xid;
+	xe->xprefix = xprefix;
+	xe->xname = ((char *)xe) + sizeof(xattr_entry_t);
+	xe->xvalue = xe->xname + name_len + 1;
+	xe->name_len = name_len;
+	xe->value_len = value_len;
+	strcpy(xe->xname, xname);
+	memcpy(xe->xvalue, xvalue, value_len);
+
+	/* write xattr node */
+	memset(&rx, 0, sizeof(rx));
+	rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
+	rx.totlen = cpu_to_je32(PAD(sizeof(rx) + xe->name_len + 1 + xe->value_len));
+	rx.hdr_crc = cpu_to_je32(mtd_crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
+
+	rx.xid = cpu_to_je32(xe->xid);
+	rx.version = cpu_to_je32(1);	/* initial version */
+	rx.xprefix = xprefix;
+	rx.name_len = xe->name_len;
+	rx.value_len = cpu_to_je16(xe->value_len);
+	rx.data_crc = cpu_to_je32(mtd_crc32(0, xe->xname, xe->name_len + 1 + xe->value_len));
+	rx.node_crc = cpu_to_je32(mtd_crc32(0, &rx, sizeof(rx) - 4));
+
+	pad_block_if_less_than(sizeof(rx) + xe->name_len + 1 + xe->value_len);
+	full_write(out_fd, &rx, sizeof(rx));
+	full_write(out_fd, xe->xname, xe->name_len + 1 + xe->value_len);
+	padword();
+
+	return xe;
+}
+
+#define XATTRENTRY_HASHSIZE	57
+static xattr_entry_t *find_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
+{
+	static xattr_entry_t **xentry_hash = NULL;
+	xattr_entry_t *xe;
+	int index, name_len;
+
+	/* create hash table */
+	if (!xentry_hash)
+		xentry_hash = xcalloc(1, sizeof(xe) * XATTRENTRY_HASHSIZE);
+
+	if (xprefix == JFFS2_XPREFIX_ACL_ACCESS
+			|| xprefix == JFFS2_XPREFIX_ACL_DEFAULT)
+		formalize_posix_acl(xvalue, &value_len);
+
+	name_len = strlen(xname);
+	index = (mtd_crc32(0, xname, name_len) ^ mtd_crc32(0, xvalue, value_len)) % XATTRENTRY_HASHSIZE;
+	for (xe = xentry_hash[index]; xe; xe = xe->next) {
+		if (xe->xprefix == xprefix
+				&& xe->value_len == value_len
+				&& !strcmp(xe->xname, xname)
+				&& !memcmp(xe->xvalue, xvalue, value_len))
+			break;
+	}
+	if (!xe) {
+		xe = create_xattr_entry(xprefix, xname, xvalue, value_len);
+		xe->next = xentry_hash[index];
+		xentry_hash[index] = xe;
+	}
+	return xe;
+}
+
+static void write_xattr_entry(struct filesystem_entry *e)
+{
+	struct jffs2_raw_xref ref;
+	struct xattr_entry *xe;
+	char xlist[XATTR_BUFFER_SIZE], xvalue[XATTR_BUFFER_SIZE];
+	char *xname;
+	const char *prefix_str;
+	int i, xprefix, prefix_len;
+	int list_sz, offset, name_len, value_len;
+
+	if (!enable_xattr)
+		return;
+
+	list_sz = llistxattr(e->hostname, xlist, XATTR_BUFFER_SIZE);
+	if (list_sz < 0) {
+		if (verbose)
+			printf("llistxattr('%s') = %d : %s\n",
+					e->hostname, errno, strerror(errno));
+		return;
+	}
+
+	for (offset = 0; offset < list_sz; offset += name_len) {
+		xname = xlist + offset;
+		name_len = strlen(xname) + 1;
+
+		for (i = 0; (xprefix = xprefix_tbl[i].xprefix); i++) {
+			prefix_str = xprefix_tbl[i].string;
+			prefix_len = xprefix_tbl[i].length;
+			if (prefix_str[prefix_len - 1] == '.') {
+				if (!strncmp(xname, prefix_str, prefix_len - 1))
+					break;
+			} else {
+				if (!strcmp(xname, prefix_str))
+					break;
+			}
+		}
+		if (!xprefix) {
+			if (verbose)
+				printf("%s: xattr '%s' is not supported.\n",
+						e->hostname, xname);
+			continue;
+		}
+		if ((enable_xattr & (1 << xprefix)) == 0)
+			continue;
+
+		value_len = lgetxattr(e->hostname, xname, xvalue, XATTR_BUFFER_SIZE);
+		if (value_len < 0) {
+			if (verbose)
+				printf("lgetxattr('%s', '%s') = %d : %s\n",
+						e->hostname, xname, errno, strerror(errno));
+			continue;
+		}
+		xe = find_xattr_entry(xprefix, xname + prefix_len, xvalue, value_len);
+		if (!xe) {
+			if (verbose)
+				printf("%s : xattr '%s' was ignored.\n",
+						e->hostname, xname);
+			continue;
+		}
+
+		memset(&ref, 0, sizeof(ref));
+		ref.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+		ref.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF);
+		ref.totlen = cpu_to_je32(sizeof(ref));
+		ref.hdr_crc = cpu_to_je32(mtd_crc32(0, &ref, sizeof(struct jffs2_unknown_node) - 4));
+		ref.ino = cpu_to_je32(e->ino);
+		ref.xid = cpu_to_je32(xe->xid);
+		ref.xseqno = cpu_to_je32(highest_xseqno += 2);
+		ref.node_crc = cpu_to_je32(mtd_crc32(0, &ref, sizeof(ref) - 4));
+
+		pad_block_if_less_than(sizeof(ref));
+		full_write(out_fd, &ref, sizeof(ref));
+		padword();
+	}
+}
+
+#else /* WITHOUT_XATTR */
+#define write_xattr_entry(x)
+#endif
+
+static void recursive_populate_directory(struct filesystem_entry *dir)
+{
+	struct filesystem_entry *e;
+	unsigned int wrote;
+
+	if (verbose) {
+		printf("%s\n", dir->fullname);
+	}
+	write_xattr_entry(dir);		/* for '/' */
+
+	e = dir->files;
+	while (e) {
+		if (e->sb.st_nlink >= 1 &&
+		    (e->ino = find_hardlink(e))) {
+
+			write_dirent(e);
+			if (verbose) {
+				printf("\tL %04o %9lu             %5d:%-3d %s\n",
+				       e->sb.st_mode & ~S_IFMT, (unsigned long) e->ino,
+				       (int) (e->sb.st_uid), (int) (e->sb.st_gid),
+				       e->name);
+			}
+		} else switch (e->sb.st_mode & S_IFMT) {
+			case S_IFDIR:
+				if (verbose) {
+					printf("\td %04o %9" PRIdoff_t "             %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+							(int) (e->sb.st_uid), (int) (e->sb.st_gid),
+							e->name);
+				}
+				write_pipe(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFSOCK:
+				if (verbose) {
+					printf("\ts %04o %9" PRIdoff_t "             %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+				}
+				write_pipe(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFIFO:
+				if (verbose) {
+					printf("\tp %04o %9" PRIdoff_t "             %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+				}
+				write_pipe(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFCHR:
+				if (verbose) {
+					printf("\tc %04o %4d,%4d             %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
+							minor(e->sb.st_rdev), (int) e->sb.st_uid,
+							(int) e->sb.st_gid, e->name);
+				}
+				write_special_file(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFBLK:
+				if (verbose) {
+					printf("\tb %04o %4d,%4d             %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
+							minor(e->sb.st_rdev), (int) e->sb.st_uid,
+							(int) e->sb.st_gid, e->name);
+				}
+				write_special_file(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFLNK:
+				if (verbose) {
+					printf("\tl %04o %9" PRIdoff_t "             %5d:%-3d %s -> %s\n",
+							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name,
+							e->link);
+				}
+				write_symlink(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFREG:
+				wrote = write_regular_file(e);
+				write_xattr_entry(e);
+				if (verbose) {
+					printf("\tf %04o %9" PRIdoff_t " (%9u) %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, e->sb.st_size, wrote,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+				}
+				break;
+			default:
+				errmsg("Unknown mode %o for %s", e->sb.st_mode,
+						e->fullname);
+				break;
+		}
+		e = e->next;
+	}
+
+	e = dir->files;
+	while (e) {
+		if (S_ISDIR(e->sb.st_mode)) {
+			if (e->files) {
+				recursive_populate_directory(e);
+			} else if (verbose) {
+				printf("%s\n", e->fullname);
+			}
+		}
+		e = e->next;
+	}
+}
+
+static void create_target_filesystem(struct filesystem_entry *root)
+{
+	cleanmarker.magic    = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
+	cleanmarker.totlen   = cpu_to_je32(cleanmarker_size);
+	cleanmarker.hdr_crc  = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
+
+	if (ino == 0)
+		ino = 1;
+
+	root->ino = 1;
+	recursive_populate_directory(root);
+
+	if (pad_fs_size == -1) {
+		padblock();
+	} else {
+		if (pad_fs_size && add_cleanmarkers){
+			padblock();
+			while (out_ofs < pad_fs_size) {
+				full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
+				pad(cleanmarker_size - sizeof(cleanmarker));
+				padblock();
+			}
+		} else {
+			while (out_ofs < pad_fs_size) {
+				full_write(out_fd, ffbuf, min(sizeof(ffbuf), pad_fs_size - out_ofs));
+			}
+
+		}
+	}
+}
+
+static struct option long_options[] = {
+	{"pad", 2, NULL, 'p'},
+	{"root", 1, NULL, 'r'},
+	{"pagesize", 1, NULL, 's'},
+	{"eraseblock", 1, NULL, 'e'},
+	{"output", 1, NULL, 'o'},
+	{"help", 0, NULL, 'h'},
+	{"verbose", 0, NULL, 'v'},
+	{"version", 0, NULL, 'V'},
+	{"big-endian", 0, NULL, 'b'},
+	{"little-endian", 0, NULL, 'l'},
+	{"no-cleanmarkers", 0, NULL, 'n'},
+	{"cleanmarker", 1, NULL, 'c'},
+	{"squash", 0, NULL, 'q'},
+	{"squash-uids", 0, NULL, 'U'},
+	{"squash-perms", 0, NULL, 'P'},
+	{"faketime", 0, NULL, 'f'},
+	{"devtable", 1, NULL, 'D'},
+	{"compression-mode", 1, NULL, 'm'},
+	{"disable-compressor", 1, NULL, 'x'},
+	{"enable-compressor", 1, NULL, 'X'},
+	{"test-compression", 0, NULL, 't'},
+	{"compressor-priority", 1, NULL, 'y'},
+	{"incremental", 1, NULL, 'i'},
+#ifndef WITHOUT_XATTR
+	{"with-xattr", 0, NULL, 1000 },
+	{"with-selinux", 0, NULL, 1001 },
+	{"with-posix-acl", 0, NULL, 1002 },
+#endif
+	{NULL, 0, NULL, 0}
+};
+
+static const char helptext[] =
+"Usage: mkfs.jffs2 [OPTIONS]\n"
+"Make a JFFS2 file system image from an existing directory tree\n\n"
+"Options:\n"
+"  -p, --pad[=SIZE]        Pad output to SIZE bytes with 0xFF. If SIZE is\n"
+"                          not specified, the output is padded to the end of\n"
+"                          the final erase block\n"
+"  -r, -d, --root=DIR      Build file system from directory DIR (default: cwd)\n"
+"  -s, --pagesize=SIZE     Use page size (max data node size) SIZE.\n"
+"                          Set according to target system's memory management\n"
+"                          page size (default: 4KiB)\n"
+"  -e, --eraseblock=SIZE   Use erase block size SIZE (default: 64KiB)\n"
+"  -c, --cleanmarker=SIZE  Size of cleanmarker (default 12)\n"
+"  -m, --compr-mode=MODE   Select compression mode (default: priority)\n"
+"  -x, --disable-compressor=COMPRESSOR_NAME\n"
+"                          Disable a compressor\n"
+"  -X, --enable-compressor=COMPRESSOR_NAME\n"
+"                          Enable a compressor\n"
+"  -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME\n"
+"                          Set the priority of a compressor\n"
+"  -L, --list-compressors  Show the list of the available compressors\n"
+"  -t, --test-compression  Call decompress and compare with the original (for test)\n"
+"  -n, --no-cleanmarkers   Don't add a cleanmarker to every eraseblock\n"
+"  -o, --output=FILE       Output to FILE (default: stdout)\n"
+"  -l, --little-endian     Create a little-endian filesystem\n"
+"  -b, --big-endian        Create a big-endian filesystem\n"
+"  -D, --devtable=FILE     Use the named FILE as a device table file\n"
+"  -f, --faketime          Change all file times to '0' for regression testing\n"
+"  -q, --squash            Squash permissions and owners making all files be owned by root\n"
+"  -U, --squash-uids       Squash owners making all files be owned by root\n"
+"  -P, --squash-perms      Squash permissions on all files\n"
+#ifndef WITHOUT_XATTR
+"      --with-xattr        stuff all xattr entries into image\n"
+"      --with-selinux      stuff only SELinux Labels into jffs2 image\n"
+"      --with-posix-acl    stuff only POSIX ACL entries into jffs2 image\n"
+#endif
+"  -h, --help              Display this help text\n"
+"  -v, --verbose           Verbose operation\n"
+"  -V, --version           Display version information\n"
+"  -i, --incremental=FILE  Parse FILE and generate appendage output for it\n\n";
+
+static const char revtext[] = "1.60";
+
+int load_next_block() {
+
+	int ret;
+	ret = read(in_fd, file_buffer, erase_block_size);
+
+	if(verbose)
+		printf("Load next block : %d bytes read\n",ret);
+
+	return ret;
+}
+
+void process_buffer(int inp_size) {
+	uint8_t		*p = file_buffer;
+	union jffs2_node_union 	*node;
+	uint16_t	type;
+	int		bitchbitmask = 0;
+	int		obsolete;
+
+	char	name[256];
+
+	while ( p < (file_buffer + inp_size)) {
+
+		node = (union jffs2_node_union *) p;
+
+		/* Skip empty space */
+		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+			p += 4;
+			continue;
+		}
+
+		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
+			if (!bitchbitmask++)
+				printf ("Wrong bitmask  at  0x%08zx, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic));
+			p += 4;
+			continue;
+		}
+
+		bitchbitmask = 0;
+
+		type = je16_to_cpu(node->u.nodetype);
+		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+			obsolete = 1;
+			type |= JFFS2_NODE_ACCURATE;
+		} else
+			obsolete = 0;
+
+		node->u.nodetype = cpu_to_je16(type);
+
+		switch(je16_to_cpu(node->u.nodetype)) {
+
+			case JFFS2_NODETYPE_INODE:
+				if(verbose)
+					printf ("%8s Inode      node at 0x%08zx, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+							obsolete ? "Obsolete" : "",
+							p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+							je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
+							je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+				if ( je32_to_cpu (node->i.ino) > ino )
+					ino = je32_to_cpu (node->i.ino);
+
+				p += PAD(je32_to_cpu (node->i.totlen));
+				break;
+
+			case JFFS2_NODETYPE_DIRENT:
+				memcpy (name, node->d.name, node->d.nsize);
+				name [node->d.nsize] = 0x0;
+
+				if(verbose)
+					printf ("%8s Dirent     node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
+							obsolete ? "Obsolete" : "",
+							p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+							je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
+							node->d.nsize, name);
+
+				p += PAD(je32_to_cpu (node->d.totlen));
+				break;
+
+			case JFFS2_NODETYPE_CLEANMARKER:
+				if (verbose) {
+					printf ("%8s Cleanmarker     at 0x%08zx, totlen 0x%08x\n",
+							obsolete ? "Obsolete" : "",
+							p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case JFFS2_NODETYPE_PADDING:
+				if (verbose) {
+					printf ("%8s Padding    node at 0x%08zx, totlen 0x%08x\n",
+							obsolete ? "Obsolete" : "",
+							p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case 0xffff:
+				p += 4;
+				break;
+
+			default:
+				if (verbose) {
+					printf ("%8s Unknown    node at 0x%08zx, totlen 0x%08x\n",
+							obsolete ? "Obsolete" : "",
+							p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+		}
+	}
+}
+
+void parse_image(){
+	int ret;
+
+	file_buffer = xmalloc(erase_block_size);
+
+	while ((ret = load_next_block())) {
+		process_buffer(ret);
+	}
+
+	if (file_buffer)
+		free(file_buffer);
+
+	close(in_fd);
+}
+
+int main(int argc, char **argv)
+{
+	int c, opt;
+	char *cwd;
+	struct stat sb;
+	FILE *devtable = NULL;
+	struct filesystem_entry *root;
+	char *compr_name = NULL;
+	int compr_prior  = -1;
+	int warn_page_size = 0;
+
+	page_size = sysconf(_SC_PAGESIZE);
+	if (page_size < 0) /* System doesn't know so ... */
+		page_size = 4096; /* ... we make an educated guess */
+	if (page_size != 4096)
+		warn_page_size = 1; /* warn user if page size not 4096 */
+
+	jffs2_compressors_init();
+
+	while ((opt = getopt_long(argc, argv,
+					"D:d:r:s:o:qUPfh?vVe:lbp::nc:m:x:X:Lty:i:", long_options, &c)) >= 0)
+	{
+		switch (opt) {
+			case 'D':
+				devtable = xfopen(optarg, "r");
+				if (fstat(fileno(devtable), &sb) < 0)
+					sys_errmsg_die("%s", optarg);
+				if (sb.st_size < 10)
+					errmsg_die("%s: not a proper device table file", optarg);
+				break;
+
+			case 'r':
+			case 'd':	/* for compatibility with mkfs.jffs, genext2fs, etc... */
+				if (rootdir != default_rootdir) {
+					errmsg_die("root directory specified more than once");
+				}
+				rootdir = xstrdup(optarg);
+				break;
+
+			case 's':
+				page_size = strtol(optarg, NULL, 0);
+				warn_page_size = 0; /* set by user, so don't need to warn */
+				break;
+
+			case 'o':
+				if (out_fd != -1) {
+					errmsg_die("output filename specified more than once");
+				}
+				out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
+				if (out_fd == -1) {
+					sys_errmsg_die("open output file");
+				}
+				break;
+
+			case 'q':
+				squash_uids = 1;
+				squash_perms = 1;
+				break;
+
+			case 'U':
+				squash_uids = 1;
+				break;
+
+			case 'P':
+				squash_perms = 1;
+				break;
+
+			case 'f':
+				fake_times = 1;
+				break;
+
+			case 'h':
+			case '?':
+				errmsg_die("%s", helptext);
+
+			case 'v':
+				verbose = 1;
+				break;
+
+			case 'V':
+				errmsg_die("revision %s\n", revtext);
+
+			case 'e': {
+						  char *next;
+						  unsigned units = 0;
+						  erase_block_size = strtol(optarg, &next, 0);
+						  if (!erase_block_size)
+							  errmsg_die("Unrecognisable erase size\n");
+
+						  if (*next) {
+							  if (!strcmp(next, "KiB")) {
+								  units = 1024;
+							  } else if (!strcmp(next, "MiB")) {
+								  units = 1024 * 1024;
+							  } else {
+								  errmsg_die("Unknown units in erasesize\n");
+							  }
+						  } else {
+							  if (erase_block_size < 0x1000)
+								  units = 1024;
+							  else
+								  units = 1;
+						  }
+						  erase_block_size *= units;
+
+						  /* If it's less than 8KiB, they're not allowed */
+						  if (erase_block_size < 0x2000) {
+							  fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n",
+									  erase_block_size);
+							  erase_block_size = 0x2000;
+						  }
+						  break;
+					  }
+
+			case 'l':
+					  target_endian = __LITTLE_ENDIAN;
+					  break;
+
+			case 'b':
+					  target_endian = __BIG_ENDIAN;
+					  break;
+
+			case 'p':
+					  if (optarg)
+						  pad_fs_size = strtol(optarg, NULL, 0);
+					  else
+						  pad_fs_size = -1;
+					  break;
+			case 'n':
+					  add_cleanmarkers = 0;
+					  break;
+			case 'c':
+					  cleanmarker_size = strtol(optarg, NULL, 0);
+					  if (cleanmarker_size < sizeof(cleanmarker)) {
+						  errmsg_die("cleanmarker size must be >= 12");
+					  }
+					  if (cleanmarker_size >= erase_block_size) {
+						  errmsg_die("cleanmarker size must be < eraseblock size");
+					  }
+					  break;
+			case 'm':
+					  if (jffs2_set_compression_mode_name(optarg)) {
+						  errmsg_die("Unknown compression mode %s", optarg);
+					  }
+					  break;
+			case 'x':
+					  if (jffs2_disable_compressor_name(optarg)) {
+						  errmsg_die("Unknown compressor name %s",optarg);
+					  }
+					  break;
+			case 'X':
+					  if (jffs2_enable_compressor_name(optarg)) {
+						  errmsg_die("Unknown compressor name %s",optarg);
+					  }
+					  break;
+			case 'L':
+					  errmsg_die("\n%s",jffs2_list_compressors());
+					  break;
+			case 't':
+					  jffs2_compression_check_set(1);
+					  break;
+			case 'y':
+					  compr_name = xmalloc(strlen(optarg));
+					  sscanf(optarg,"%d:%s",&compr_prior,compr_name);
+					  if ((compr_prior>=0)&&(compr_name)) {
+						  if (jffs2_set_compressor_priority(compr_name, compr_prior))
+							  exit(EXIT_FAILURE);
+					  }
+					  else {
+						  errmsg_die("Cannot parse %s",optarg);
+					  }
+					  free(compr_name);
+					  break;
+			case 'i':
+					  if (in_fd != -1) {
+						  errmsg_die("(incremental) filename specified more than once");
+					  }
+					  in_fd = open(optarg, O_RDONLY);
+					  if (in_fd == -1) {
+						  sys_errmsg_die("cannot open (incremental) file");
+					  }
+					  break;
+#ifndef WITHOUT_XATTR
+			case 1000:	/* --with-xattr  */
+					  enable_xattr |= (1 << JFFS2_XPREFIX_USER)
+						  | (1 << JFFS2_XPREFIX_SECURITY)
+						  | (1 << JFFS2_XPREFIX_ACL_ACCESS)
+						  | (1 << JFFS2_XPREFIX_ACL_DEFAULT)
+						  | (1 << JFFS2_XPREFIX_TRUSTED);
+					  break;
+			case 1001:	/*  --with-selinux  */
+					  enable_xattr |= (1 << JFFS2_XPREFIX_SECURITY);
+					  break;
+			case 1002:	/*  --with-posix-acl  */
+					  enable_xattr |= (1 << JFFS2_XPREFIX_ACL_ACCESS)
+						  | (1 << JFFS2_XPREFIX_ACL_DEFAULT);
+					  break;
+#endif
+		}
+	}
+	if (warn_page_size) {
+		errmsg("Page size for this system is by default %d", page_size);
+		errmsg("Use the --pagesize=SIZE option if this is not what you want");
+	}
+	if (out_fd == -1) {
+		if (isatty(1)) {
+			errmsg_die("%s", helptext);
+		}
+		out_fd = 1;
+	}
+	if (lstat(rootdir, &sb)) {
+		sys_errmsg_die("%s", rootdir);
+	}
+	if (chdir(rootdir))
+		sys_errmsg_die("%s", rootdir);
+
+	if (!(cwd = getcwd(0, GETCWD_SIZE)))
+		sys_errmsg_die("getcwd failed");
+
+	if(in_fd != -1)
+		parse_image();
+
+	root = recursive_add_host_directory(NULL, "/", cwd);
+
+	if (devtable)
+		parse_device_table(root, devtable);
+
+	create_target_filesystem(root);
+
+	cleanup(root);
+
+	if (rootdir != default_rootdir)
+		free(rootdir);
+
+	close(out_fd);
+
+	if (verbose) {
+		char *s = jffs2_stats();
+		fprintf(stderr,"\n\n%s",s);
+		free(s);
+	}
+	if ((verbose)||(jffs2_compression_check_get()&&(jffs2_compression_check_errorcnt_get()))) {
+		fprintf(stderr,"Compression errors: %d\n",jffs2_compression_check_errorcnt_get());
+	}
+
+	jffs2_compressors_exit();
+
+	return 0;
+}
diff --git a/jffsX-utils/rbtree.c b/jffsX-utils/rbtree.c
new file mode 100644
index 0000000..329e098
--- /dev/null
+++ b/jffsX-utils/rbtree.c
@@ -0,0 +1,390 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea at suse.de>
+  (C) 2002  David Woodhouse <dwmw2 at infradead.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; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  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
+
+  linux/lib/rbtree.c
+*/
+
+#include <stdlib.h>
+#include "rbtree.h"
+
+static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *right = node->rb_right;
+	struct rb_node *parent = rb_parent(node);
+
+	if ((node->rb_right = right->rb_left))
+		rb_set_parent(right->rb_left, node);
+	right->rb_left = node;
+
+	rb_set_parent(right, parent);
+
+	if (parent)
+	{
+		if (node == parent->rb_left)
+			parent->rb_left = right;
+		else
+			parent->rb_right = right;
+	}
+	else
+		root->rb_node = right;
+	rb_set_parent(node, right);
+}
+
+static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *left = node->rb_left;
+	struct rb_node *parent = rb_parent(node);
+
+	if ((node->rb_left = left->rb_right))
+		rb_set_parent(left->rb_right, node);
+	left->rb_right = node;
+
+	rb_set_parent(left, parent);
+
+	if (parent)
+	{
+		if (node == parent->rb_right)
+			parent->rb_right = left;
+		else
+			parent->rb_left = left;
+	}
+	else
+		root->rb_node = left;
+	rb_set_parent(node, left);
+}
+
+void rb_insert_color(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *parent, *gparent;
+
+	while ((parent = rb_parent(node)) && rb_is_red(parent))
+	{
+		gparent = rb_parent(parent);
+
+		if (parent == gparent->rb_left)
+		{
+			{
+				register struct rb_node *uncle = gparent->rb_right;
+				if (uncle && rb_is_red(uncle))
+				{
+					rb_set_black(uncle);
+					rb_set_black(parent);
+					rb_set_red(gparent);
+					node = gparent;
+					continue;
+				}
+			}
+
+			if (parent->rb_right == node)
+			{
+				register struct rb_node *tmp;
+				__rb_rotate_left(parent, root);
+				tmp = parent;
+				parent = node;
+				node = tmp;
+			}
+
+			rb_set_black(parent);
+			rb_set_red(gparent);
+			__rb_rotate_right(gparent, root);
+		} else {
+			{
+				register struct rb_node *uncle = gparent->rb_left;
+				if (uncle && rb_is_red(uncle))
+				{
+					rb_set_black(uncle);
+					rb_set_black(parent);
+					rb_set_red(gparent);
+					node = gparent;
+					continue;
+				}
+			}
+
+			if (parent->rb_left == node)
+			{
+				register struct rb_node *tmp;
+				__rb_rotate_right(parent, root);
+				tmp = parent;
+				parent = node;
+				node = tmp;
+			}
+
+			rb_set_black(parent);
+			rb_set_red(gparent);
+			__rb_rotate_left(gparent, root);
+		}
+	}
+
+	rb_set_black(root->rb_node);
+}
+
+static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
+			     struct rb_root *root)
+{
+	struct rb_node *other;
+
+	while ((!node || rb_is_black(node)) && node != root->rb_node)
+	{
+		if (parent->rb_left == node)
+		{
+			other = parent->rb_right;
+			if (rb_is_red(other))
+			{
+				rb_set_black(other);
+				rb_set_red(parent);
+				__rb_rotate_left(parent, root);
+				other = parent->rb_right;
+			}
+			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+			    (!other->rb_right || rb_is_black(other->rb_right)))
+			{
+				rb_set_red(other);
+				node = parent;
+				parent = rb_parent(node);
+			}
+			else
+			{
+				if (!other->rb_right || rb_is_black(other->rb_right))
+				{
+					struct rb_node *o_left;
+					if ((o_left = other->rb_left))
+						rb_set_black(o_left);
+					rb_set_red(other);
+					__rb_rotate_right(other, root);
+					other = parent->rb_right;
+				}
+				rb_set_color(other, rb_color(parent));
+				rb_set_black(parent);
+				if (other->rb_right)
+					rb_set_black(other->rb_right);
+				__rb_rotate_left(parent, root);
+				node = root->rb_node;
+				break;
+			}
+		}
+		else
+		{
+			other = parent->rb_left;
+			if (rb_is_red(other))
+			{
+				rb_set_black(other);
+				rb_set_red(parent);
+				__rb_rotate_right(parent, root);
+				other = parent->rb_left;
+			}
+			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+			    (!other->rb_right || rb_is_black(other->rb_right)))
+			{
+				rb_set_red(other);
+				node = parent;
+				parent = rb_parent(node);
+			}
+			else
+			{
+				if (!other->rb_left || rb_is_black(other->rb_left))
+				{
+					register struct rb_node *o_right;
+					if ((o_right = other->rb_right))
+						rb_set_black(o_right);
+					rb_set_red(other);
+					__rb_rotate_left(other, root);
+					other = parent->rb_left;
+				}
+				rb_set_color(other, rb_color(parent));
+				rb_set_black(parent);
+				if (other->rb_left)
+					rb_set_black(other->rb_left);
+				__rb_rotate_right(parent, root);
+				node = root->rb_node;
+				break;
+			}
+		}
+	}
+	if (node)
+		rb_set_black(node);
+}
+
+void rb_erase(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *child, *parent;
+	int color;
+
+	if (!node->rb_left)
+		child = node->rb_right;
+	else if (!node->rb_right)
+		child = node->rb_left;
+	else
+	{
+		struct rb_node *old = node, *left;
+
+		node = node->rb_right;
+		while ((left = node->rb_left) != NULL)
+			node = left;
+		child = node->rb_right;
+		parent = rb_parent(node);
+		color = rb_color(node);
+
+		if (child)
+			rb_set_parent(child, parent);
+		if (parent == old) {
+			parent->rb_right = child;
+			parent = node;
+		} else
+			parent->rb_left = child;
+
+		node->rb_parent_color = old->rb_parent_color;
+		node->rb_right = old->rb_right;
+		node->rb_left = old->rb_left;
+
+		if (rb_parent(old))
+		{
+			if (rb_parent(old)->rb_left == old)
+				rb_parent(old)->rb_left = node;
+			else
+				rb_parent(old)->rb_right = node;
+		} else
+			root->rb_node = node;
+
+		rb_set_parent(old->rb_left, node);
+		if (old->rb_right)
+			rb_set_parent(old->rb_right, node);
+		goto color;
+	}
+
+	parent = rb_parent(node);
+	color = rb_color(node);
+
+	if (child)
+		rb_set_parent(child, parent);
+	if (parent)
+	{
+		if (parent->rb_left == node)
+			parent->rb_left = child;
+		else
+			parent->rb_right = child;
+	}
+	else
+		root->rb_node = child;
+
+ color:
+	if (color == RB_BLACK)
+		__rb_erase_color(child, parent, root);
+}
+
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(struct rb_root *root)
+{
+	struct rb_node	*n;
+
+	n = root->rb_node;
+	if (!n)
+		return NULL;
+	while (n->rb_left)
+		n = n->rb_left;
+	return n;
+}
+
+struct rb_node *rb_last(struct rb_root *root)
+{
+	struct rb_node	*n;
+
+	n = root->rb_node;
+	if (!n)
+		return NULL;
+	while (n->rb_right)
+		n = n->rb_right;
+	return n;
+}
+
+struct rb_node *rb_next(struct rb_node *node)
+{
+	struct rb_node *parent;
+
+	if (rb_parent(node) == node)
+		return NULL;
+
+	/* If we have a right-hand child, go down and then left as far
+	   as we can. */
+	if (node->rb_right) {
+		node = node->rb_right;
+		while (node->rb_left)
+			node=node->rb_left;
+		return node;
+	}
+
+	/* No right-hand children.  Everything down and left is
+	   smaller than us, so any 'next' node must be in the general
+	   direction of our parent. Go up the tree; any time the
+	   ancestor is a right-hand child of its parent, keep going
+	   up. First time it's a left-hand child of its parent, said
+	   parent is our 'next' node. */
+	while ((parent = rb_parent(node)) && node == parent->rb_right)
+		node = parent;
+
+	return parent;
+}
+
+struct rb_node *rb_prev(struct rb_node *node)
+{
+	struct rb_node *parent;
+
+	if (rb_parent(node) == node)
+		return NULL;
+
+	/* If we have a left-hand child, go down and then right as far
+	   as we can. */
+	if (node->rb_left) {
+		node = node->rb_left;
+		while (node->rb_right)
+			node=node->rb_right;
+		return node;
+	}
+
+	/* No left-hand children. Go up till we find an ancestor which
+	   is a right-hand child of its parent */
+	while ((parent = rb_parent(node)) && node == parent->rb_left)
+		node = parent;
+
+	return parent;
+}
+
+void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+		     struct rb_root *root)
+{
+	struct rb_node *parent = rb_parent(victim);
+
+	/* Set the surrounding nodes to point to the replacement */
+	if (parent) {
+		if (victim == parent->rb_left)
+			parent->rb_left = new;
+		else
+			parent->rb_right = new;
+	} else {
+		root->rb_node = new;
+	}
+	if (victim->rb_left)
+		rb_set_parent(victim->rb_left, new);
+	if (victim->rb_right)
+		rb_set_parent(victim->rb_right, new);
+
+	/* Copy the pointers/colour from the victim to the replacement */
+	*new = *victim;
+}
diff --git a/jffsX-utils/rbtree.h b/jffsX-utils/rbtree.h
new file mode 100644
index 0000000..0d77b65
--- /dev/null
+++ b/jffsX-utils/rbtree.h
@@ -0,0 +1,171 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea at suse.de>
+
+  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; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  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
+
+  linux/include/linux/rbtree.h
+
+  To use rbtrees you'll have to implement your own insert and search cores.
+  This will avoid us to use callbacks and to drop drammatically performances.
+  I know it's not the cleaner way,  but in C (not in C++) to get
+  performances and genericity...
+
+  Some example of insert and search follows here. The search is a plain
+  normal search over an ordered tree. The insert instead must be implemented
+  int two steps: as first thing the code must insert the element in
+  order as a red leaf in the tree, then the support library function
+  rb_insert_color() must be called. Such function will do the
+  not trivial work to rebalance the rbtree if necessary.
+
+-----------------------------------------------------------------------
+static inline struct page * rb_search_page_cache(struct inode * inode,
+						 unsigned long offset)
+{
+	struct rb_node * n = inode->i_rb_page_cache.rb_node;
+	struct page * page;
+
+	while (n)
+	{
+		page = rb_entry(n, struct page, rb_page_cache);
+
+		if (offset < page->offset)
+			n = n->rb_left;
+		else if (offset > page->offset)
+			n = n->rb_right;
+		else
+			return page;
+	}
+	return NULL;
+}
+
+static inline struct page * __rb_insert_page_cache(struct inode * inode,
+						   unsigned long offset,
+						   struct rb_node * node)
+{
+	struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
+	struct rb_node * parent = NULL;
+	struct page * page;
+
+	while (*p)
+	{
+		parent = *p;
+		page = rb_entry(parent, struct page, rb_page_cache);
+
+		if (offset < page->offset)
+			p = &(*p)->rb_left;
+		else if (offset > page->offset)
+			p = &(*p)->rb_right;
+		else
+			return page;
+	}
+
+	rb_link_node(node, parent, p);
+
+	return NULL;
+}
+
+static inline struct page * rb_insert_page_cache(struct inode * inode,
+						 unsigned long offset,
+						 struct rb_node * node)
+{
+	struct page * ret;
+	if ((ret = __rb_insert_page_cache(inode, offset, node)))
+		goto out;
+	rb_insert_color(node, &inode->i_rb_page_cache);
+ out:
+	return ret;
+}
+-----------------------------------------------------------------------
+*/
+
+#ifndef	_LINUX_RBTREE_H
+#define	_LINUX_RBTREE_H
+
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+
+struct rb_node
+{
+	unsigned long  rb_parent_color;
+#define	RB_RED		0
+#define	RB_BLACK	1
+	struct rb_node *rb_right;
+	struct rb_node *rb_left;
+} __attribute__((aligned(sizeof(long))));
+    /* The alignment might seem pointless, but allegedly CRIS needs it */
+
+struct rb_root
+{
+	struct rb_node *rb_node;
+};
+
+
+#define rb_parent(r)   ((struct rb_node *)((r)->rb_parent_color & ~3))
+#define rb_color(r)   ((r)->rb_parent_color & 1)
+#define rb_is_red(r)   (!rb_color(r))
+#define rb_is_black(r) rb_color(r)
+#define rb_set_red(r)  do { (r)->rb_parent_color &= ~1; } while (0)
+#define rb_set_black(r)  do { (r)->rb_parent_color |= 1; } while (0)
+
+static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
+{
+	rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
+}
+static inline void rb_set_color(struct rb_node *rb, int color)
+{
+	rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
+}
+
+#define RB_ROOT	(struct rb_root) { NULL, }
+
+/* Newer gcc versions take care of exporting this */
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define container_of(ptr, type, member) ({                      \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define	rb_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define RB_EMPTY_ROOT(root)	((root)->rb_node == NULL)
+#define RB_EMPTY_NODE(node)	(rb_parent(node) == node)
+#define RB_CLEAR_NODE(node)	(rb_set_parent(node, node))
+
+extern void rb_insert_color(struct rb_node *, struct rb_root *);
+extern void rb_erase(struct rb_node *, struct rb_root *);
+
+/* Find logical next and previous nodes in a tree */
+extern struct rb_node *rb_next(struct rb_node *);
+extern struct rb_node *rb_prev(struct rb_node *);
+extern struct rb_node *rb_first(struct rb_root *);
+extern struct rb_node *rb_last(struct rb_root *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+			    struct rb_root *root);
+
+static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
+				struct rb_node ** rb_link)
+{
+	node->rb_parent_color = (unsigned long )parent;
+	node->rb_left = node->rb_right = NULL;
+
+	*rb_link = node;
+}
+
+#endif	/* _LINUX_RBTREE_H */
diff --git a/jffsX-utils/summary.h b/jffsX-utils/summary.h
new file mode 100644
index 0000000..e9d95a5
--- /dev/null
+++ b/jffsX-utils/summary.h
@@ -0,0 +1,177 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004  Ferenc Havasi <havasi at inf.u-szeged.hu>,
+ *                     Zoltan Sogor <weth at inf.u-szeged.hu>,
+ *                     Patrik Kluba <pajko at halom.u-szeged.hu>,
+ *                     University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ */
+
+#ifndef JFFS2_SUMMARY_H
+#define JFFS2_SUMMARY_H
+
+#include <linux/jffs2.h>
+
+#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
+	c->free_size -= _x; c->dirty_size += _x; \
+	jeb->free_size -= _x ; jeb->dirty_size += _x; \
+}while(0)
+#define USED_SPACE(x) do { typeof(x) _x = (x); \
+	c->free_size -= _x; c->used_size += _x; \
+	jeb->free_size -= _x ; jeb->used_size += _x; \
+}while(0)
+#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
+	c->free_size -= _x; c->wasted_size += _x; \
+	jeb->free_size -= _x ; jeb->wasted_size += _x; \
+}while(0)
+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
+	c->free_size -= _x; c->unchecked_size += _x; \
+	jeb->free_size -= _x ; jeb->unchecked_size += _x; \
+}while(0)
+
+#define BLK_STATE_ALLFF		0
+#define BLK_STATE_CLEAN		1
+#define BLK_STATE_PARTDIRTY	2
+#define BLK_STATE_CLEANMARKER	3
+#define BLK_STATE_ALLDIRTY	4
+#define BLK_STATE_BADBLOCK	5
+
+#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
+#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
+#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
+#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash))
+#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash))
+
+/* Summary structures used on flash */
+
+struct jffs2_sum_unknown_flash
+{
+	jint16_t nodetype;	/* node type */
+} __attribute__((packed));
+
+struct jffs2_sum_inode_flash
+{
+	jint16_t nodetype;	/* node type */
+	jint32_t inode;		/* inode number */
+	jint32_t version;	/* inode version */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen; 	/* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_flash
+{
+	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
+	jint32_t totlen;	/* record length */
+	jint32_t offset;	/* ofset on jeb */
+	jint32_t pino;		/* parent inode */
+	jint32_t version;	/* dirent version */
+	jint32_t ino; 		/* == zero for unlink */
+	uint8_t nsize;		/* dirent name size */
+	uint8_t type;		/* dirent type */
+	uint8_t name[0];	/* dirent name */
+} __attribute__((packed));
+
+struct jffs2_sum_xattr_flash
+{
+	jint16_t nodetype;	/* == JFFS2_NODETYPE_XATR */
+	jint32_t xid;		/* xattr identifier */
+	jint32_t version;	/* version number */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen;	/* node length */
+} __attribute__((packed));
+
+struct jffs2_sum_xref_flash
+{
+	jint16_t nodetype;	/* == JFFS2_NODETYPE_XREF */
+	jint32_t offset;	/* offset on jeb */
+} __attribute__((packed));
+
+union jffs2_sum_flash
+{
+	struct jffs2_sum_unknown_flash u;
+	struct jffs2_sum_inode_flash i;
+	struct jffs2_sum_dirent_flash d;
+	struct jffs2_sum_xattr_flash x;
+	struct jffs2_sum_xref_flash r;
+};
+
+/* Summary structures used in the memory */
+
+struct jffs2_sum_unknown_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* node type */
+} __attribute__((packed));
+
+struct jffs2_sum_inode_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* node type */
+	jint32_t inode;		/* inode number */
+	jint32_t version;	/* inode version */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen; 	/* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
+	jint32_t totlen;	/* record length */
+	jint32_t offset;	/* ofset on jeb */
+	jint32_t pino;		/* parent inode */
+	jint32_t version;	/* dirent version */
+	jint32_t ino; 		/* == zero for unlink */
+	uint8_t nsize;		/* dirent name size */
+	uint8_t type;		/* dirent type */
+	uint8_t name[0];	/* dirent name */
+} __attribute__((packed));
+
+struct jffs2_sum_xattr_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;
+	jint32_t xid;
+	jint32_t version;
+	jint32_t offset;
+	jint32_t totlen;
+} __attribute__((packed));
+
+struct jffs2_sum_xref_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;
+	jint32_t offset;
+} __attribute__((packed));
+
+union jffs2_sum_mem
+{
+	struct jffs2_sum_unknown_mem u;
+	struct jffs2_sum_inode_mem i;
+	struct jffs2_sum_dirent_mem d;
+	struct jffs2_sum_xattr_mem x;
+	struct jffs2_sum_xref_mem r;
+};
+
+struct jffs2_summary
+{
+	uint32_t sum_size;
+	uint32_t sum_num;
+	uint32_t sum_padded;
+	union jffs2_sum_mem *sum_list_head;
+	union jffs2_sum_mem *sum_list_tail;
+};
+
+/* Summary marker is stored at the end of every sumarized erase block */
+
+struct jffs2_sum_marker
+{
+	jint32_t offset;	/* offset of the summary node in the jeb */
+	jint32_t magic; 	/* == JFFS2_SUM_MAGIC */
+};
+
+#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker))
+
+#endif
diff --git a/jffsX-utils/sumtool.c b/jffsX-utils/sumtool.c
new file mode 100644
index 0000000..886b545
--- /dev/null
+++ b/jffsX-utils/sumtool.c
@@ -0,0 +1,872 @@
+/*
+ *  sumtool.c
+ *
+ *  Copyright (C) 2004 Zoltan Sogor <weth at inf.u-szeged.hu>,
+ *                     Ferenc Havasi <havasi at inf.u-szeged.hu>
+ *                     University of Szeged, Hungary
+ *                2006 KaiGai Kohei <kaigai at ak.jp.nec.com>
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *
+ * Overview:
+ *   This is a utility insert summary information into JFFS2 image for
+ *   faster mount time
+ *
+ */
+
+#define PROGRAM_NAME "sumtool"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <asm/types.h>
+#include <dirent.h>
+#include <mtd/jffs2-user.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <getopt.h>
+#include <crc32.h>
+#include "summary.h"
+#include "common.h"
+
+#define PAD(x) (((x)+3)&~3)
+
+static struct jffs2_summary *sum_collected = NULL;
+
+static int verbose = 0;
+static int padto = 0;				/* pad the output with 0xFF to the end of the final eraseblock */
+static int add_cleanmarkers = 1;		/* add cleanmarker to output */
+static int use_input_cleanmarker_size = 1;	/* use input file's cleanmarker size (default) */
+static int found_cleanmarkers = 0;		/* cleanmarker found in input file */
+static struct jffs2_unknown_node cleanmarker;
+static int cleanmarker_size = sizeof(cleanmarker);
+static const char *short_options = "o:i:e:hvVblnc:p";
+static int erase_block_size = 65536;
+static int out_fd = -1;
+static int in_fd = -1;
+
+static uint8_t *data_buffer = NULL; 		/* buffer for inodes */
+static unsigned int data_ofs = 0;	 	/* inode buffer offset */
+
+static uint8_t *file_buffer = NULL;		/* file buffer contains the actual erase block*/
+static unsigned int file_ofs = 0;		/* position in the buffer */
+
+int target_endian = __BYTE_ORDER;
+
+static struct option long_options[] = {
+	{"output", 1, NULL, 'o'},
+	{"input", 1, NULL, 'i'},
+	{"eraseblock", 1, NULL, 'e'},
+	{"help", 0, NULL, 'h'},
+	{"verbose", 0, NULL, 'v'},
+	{"version", 0, NULL, 'V'},
+	{"bigendian", 0, NULL, 'b'},
+	{"littleendian", 0, NULL, 'l'},
+	{"no-cleanmarkers", 0, NULL, 'n'},
+	{"cleanmarker", 1, NULL, 'c'},
+	{"pad", 0, NULL, 'p'},
+	{NULL, 0, NULL, 0}
+};
+
+static const char helptext[] =
+"Usage: sumtool [OPTIONS] -i inputfile -o outputfile\n\n"
+"Convert the input JFFS2 image to a summarized JFFS2 image\n"
+"Summary makes mounting faster - if summary support enabled in your kernel\n\n"
+"Options:\n"
+"  -e, --eraseblock=SIZE     Use erase block size SIZE (default: 64KiB)\n"
+"                            (usually 16KiB on NAND)\n"
+"  -c, --cleanmarker=SIZE    Size of cleanmarker (default 12).\n"
+"                            (usually 16 bytes on NAND, and will be set to\n"
+"                            this value if left at the default 12). Will be\n"
+"                            stored in OOB after each physical page composing\n"
+"                            a physical eraseblock.\n"
+"  -n, --no-cleanmarkers     Don't add a cleanmarker to every eraseblock\n"
+"  -o, --output=FILE         Output to FILE \n"
+"  -i, --input=FILE          Input from FILE \n"
+"  -b, --bigendian           Image is big endian\n"
+"  -l  --littleendian        Image is little endian\n"
+"  -h, --help                Display this help text\n"
+"  -v, --verbose             Verbose operation\n"
+"  -V, --version             Display version information\n"
+"  -p, --pad                 Pad the OUTPUT with 0xFF to the end of the final\n"
+"                            eraseblock\n\n";
+
+
+static const char revtext[] = "$Revision: 1.9 $";
+
+static unsigned char ffbuf[16] = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static void full_write(void *target_buff, const void *buf, int len);
+
+void setup_cleanmarker(void)
+{
+	cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
+	cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
+	cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
+}
+
+void process_options (int argc, char **argv)
+{
+	int opt,c;
+
+	while ((opt = getopt_long(argc, argv, short_options, long_options, &c)) >= 0) {
+		switch (opt) {
+			case 'o':
+				if (out_fd != -1)
+					errmsg_die("output filename specified more than once");
+				out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
+				if (out_fd == -1)
+					sys_errmsg_die("open output file");
+				break;
+
+			case 'i':
+				if (in_fd != -1)
+					errmsg_die("input filename specified more than once");
+				in_fd = open(optarg, O_RDONLY);
+				if (in_fd == -1)
+					sys_errmsg_die("open input file");
+				break;
+			case 'b':
+				target_endian = __BIG_ENDIAN;
+				break;
+			case 'l':
+				target_endian = __LITTLE_ENDIAN;
+				break;
+			case 'h':
+			case '?':
+				errmsg_die("%s", helptext);
+			case 'v':
+				verbose = 1;
+				break;
+
+			case 'V':
+				errmsg_die("revision %.*s\n",
+						(int) strlen(revtext) - 13, revtext + 11);
+
+			case 'e': {
+						  char *next;
+						  unsigned units = 0;
+						  erase_block_size = strtol(optarg, &next, 0);
+						  if (!erase_block_size)
+							  errmsg_die("Unrecognisable erase size\n");
+
+						  if (*next) {
+							  if (!strcmp(next, "KiB")) {
+								  units = 1024;
+							  } else if (!strcmp(next, "MiB")) {
+								  units = 1024 * 1024;
+							  } else {
+								  errmsg_die("Unknown units in erasesize\n");
+							  }
+						  } else {
+							  if (erase_block_size < 0x1000)
+								  units = 1024;
+							  else
+								  units = 1;
+						  }
+						  erase_block_size *= units;
+
+						  /* If it's less than 8KiB, they're not allowed */
+						  if (erase_block_size < 0x2000) {
+							  warnmsg("Erase size 0x%x too small. Increasing to 8KiB minimum\n",
+									erase_block_size);
+							  erase_block_size = 0x2000;
+						  }
+						  break;
+					  }
+
+			case 'n':
+					  add_cleanmarkers = 0;
+					  break;
+			case 'c':
+					  cleanmarker_size = strtol(optarg, NULL, 0);
+
+					  if (cleanmarker_size < sizeof(cleanmarker)) {
+						  errmsg_die("cleanmarker size must be >= 12");
+					  }
+					  if (cleanmarker_size >= erase_block_size) {
+						  errmsg_die("cleanmarker size must be < eraseblock size");
+					  }
+
+					  use_input_cleanmarker_size = 0;
+					  found_cleanmarkers = 1;
+					  setup_cleanmarker();
+
+					  break;
+			case 'p':
+					  padto = 1;
+					  break;
+		}
+	}
+}
+
+
+void init_buffers(void)
+{
+	data_buffer = xmalloc(erase_block_size);
+	file_buffer = xmalloc(erase_block_size);
+}
+
+void init_sumlist(void)
+{
+	sum_collected = xzalloc(sizeof(*sum_collected));
+}
+
+void clean_buffers(void)
+{
+	free(data_buffer);
+	free(file_buffer);
+}
+
+void clean_sumlist(void)
+{
+	union jffs2_sum_mem *temp;
+
+	if (sum_collected) {
+
+		while (sum_collected->sum_list_head) {
+			temp = sum_collected->sum_list_head;
+			sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+			free(temp);
+			sum_collected->sum_num--;
+		}
+
+		if (sum_collected->sum_num != 0)
+			warnmsg("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
+
+		free(sum_collected);
+	}
+}
+
+int load_next_block(void)
+{
+	int ret;
+	ret = read(in_fd, file_buffer, erase_block_size);
+	file_ofs = 0;
+
+	bareverbose(verbose, "Load next block : %d bytes read\n", ret);
+
+	return ret;
+}
+
+void write_buff_to_file(void)
+{
+	int ret;
+	int len = data_ofs;
+
+	uint8_t *buf = NULL;
+
+	buf = data_buffer;
+	while (len > 0) {
+		ret = write(out_fd, buf, len);
+
+		if (ret < 0)
+			sys_errmsg_die("write");
+
+		if (ret == 0)
+			sys_errmsg_die("write returned zero");
+
+		len -= ret;
+		buf += ret;
+	}
+
+	data_ofs = 0;
+}
+
+void dump_sum_records(void)
+{
+
+	struct jffs2_raw_summary isum;
+	struct jffs2_sum_marker *sm;
+	union jffs2_sum_mem *temp;
+	jint32_t offset;
+	jint32_t *tpage;
+	void *wpage;
+	int datasize, infosize, padsize;
+	jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
+
+	if (!sum_collected->sum_num || !sum_collected->sum_list_head)
+		return;
+
+	datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
+	infosize = sizeof(struct jffs2_raw_summary) + datasize;
+	padsize = erase_block_size - data_ofs - infosize;
+	infosize += padsize; datasize += padsize;
+	offset = cpu_to_je32(data_ofs);
+
+	tpage = xmalloc(datasize);
+
+	memset(tpage, 0xff, datasize);
+	memset(&isum, 0, sizeof(isum));
+
+	isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
+	isum.totlen = cpu_to_je32(infosize);
+	isum.hdr_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
+	isum.padded = cpu_to_je32(0);
+
+	if (add_cleanmarkers && found_cleanmarkers) {
+		isum.cln_mkr = cpu_to_je32(cleanmarker_size);
+	} else {
+		isum.cln_mkr = cpu_to_je32(0);
+	}
+
+	isum.sum_num = cpu_to_je32(sum_collected->sum_num);
+	wpage = tpage;
+
+	while (sum_collected->sum_num) {
+		switch(je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) {
+
+			case JFFS2_NODETYPE_INODE : {
+											struct jffs2_sum_inode_flash *sino_ptr = wpage;
+
+											sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype;
+											sino_ptr->inode = sum_collected->sum_list_head->i.inode;
+											sino_ptr->version = sum_collected->sum_list_head->i.version;
+											sino_ptr->offset = sum_collected->sum_list_head->i.offset;
+											sino_ptr->totlen = sum_collected->sum_list_head->i.totlen;
+
+											wpage += JFFS2_SUMMARY_INODE_SIZE;
+											break;
+										}
+
+			case JFFS2_NODETYPE_DIRENT : {
+											 struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
+
+											 sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype;
+											 sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen;
+											 sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset;
+											 sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino;
+											 sdrnt_ptr->version = sum_collected->sum_list_head->d.version;
+											 sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino;
+											 sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize;
+											 sdrnt_ptr->type = sum_collected->sum_list_head->d.type;
+
+											 memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name,
+													 sum_collected->sum_list_head->d.nsize);
+
+											 wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize);
+											 break;
+										 }
+
+			case JFFS2_NODETYPE_XATTR: {
+										   struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
+
+										   sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype;
+										   sxattr_ptr->xid = sum_collected->sum_list_head->x.xid;
+										   sxattr_ptr->version = sum_collected->sum_list_head->x.version;
+										   sxattr_ptr->offset = sum_collected->sum_list_head->x.offset;
+										   sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen;
+
+										   wpage += JFFS2_SUMMARY_XATTR_SIZE;
+										   break;
+									   }
+
+			case JFFS2_NODETYPE_XREF: {
+										  struct jffs2_sum_xref_flash *sxref_ptr = wpage;
+
+										  sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype;
+										  sxref_ptr->offset = sum_collected->sum_list_head->r.offset;
+
+										  wpage += JFFS2_SUMMARY_XREF_SIZE;
+										  break;
+									  }
+
+			default : {
+						  warnmsg("Unknown node type!\n");
+					  }
+		}
+
+		temp = sum_collected->sum_list_head;
+		sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+		free(temp);
+
+		sum_collected->sum_num--;
+	}
+
+	sum_collected->sum_size = 0;
+	sum_collected->sum_num = 0;
+	sum_collected->sum_list_tail = NULL;
+
+	wpage += padsize;
+
+	sm = wpage;
+	sm->offset = offset;
+	sm->magic = magic;
+
+	isum.sum_crc = cpu_to_je32(mtd_crc32(0, tpage, datasize));
+	isum.node_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(isum) - 8));
+
+	full_write(data_buffer + data_ofs, &isum, sizeof(isum));
+	full_write(data_buffer + data_ofs, tpage, datasize);
+
+	free(tpage);
+}
+
+static void full_write(void *target_buff, const void *buf, int len)
+{
+	memcpy(target_buff, buf, len);
+	data_ofs += len;
+}
+
+static void pad(int req)
+{
+	while (req) {
+		if (req > sizeof(ffbuf)) {
+			full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf));
+			req -= sizeof(ffbuf);
+		} else {
+			full_write(data_buffer + data_ofs, ffbuf, req);
+			req = 0;
+		}
+	}
+}
+
+static inline void padword(void)
+{
+	if (data_ofs % 4)
+		full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4));
+}
+
+
+static inline void pad_block_if_less_than(int req,int plus)
+{
+
+	int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+	datasize += (4 - (datasize % 4)) % 4;
+
+	if (data_ofs + req > erase_block_size - datasize) {
+		dump_sum_records();
+		write_buff_to_file();
+	}
+
+	if (add_cleanmarkers && found_cleanmarkers) {
+		if (!data_ofs) {
+			full_write(data_buffer, &cleanmarker, sizeof(cleanmarker));
+			pad(cleanmarker_size - sizeof(cleanmarker));
+			padword();
+		}
+	}
+}
+
+void flush_buffers(void)
+{
+
+	if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */
+		if (data_ofs != cleanmarker_size) {	/* INODE BUFFER */
+
+			int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+			datasize += (4 - (datasize % 4)) % 4;
+
+			/* If we have a full inode buffer, then write out inode and summary data  */
+			if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+				dump_sum_records();
+				write_buff_to_file();
+			} else {	/* else just write out inode data */
+				if (padto)
+					pad(erase_block_size - data_ofs);
+				write_buff_to_file();
+			}
+		}
+	} else { /* NO CLEANMARKER */
+		if (data_ofs != 0) { /* INODE BUFFER */
+
+			int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+			datasize += (4 - (datasize % 4)) % 4;
+
+			/* If we have a full inode buffer, then write out inode and summary data */
+			if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+				dump_sum_records();
+				write_buff_to_file();
+			} else {	/* Else just write out inode data */
+				if(padto)
+					pad(erase_block_size - data_ofs);
+				write_buff_to_file();
+			}
+		}
+	}
+}
+
+int add_sum_mem(union jffs2_sum_mem *item)
+{
+
+	if (!sum_collected->sum_list_head)
+		sum_collected->sum_list_head = (union jffs2_sum_mem *) item;
+	if (sum_collected->sum_list_tail)
+		sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
+	sum_collected->sum_list_tail = (union jffs2_sum_mem *) item;
+
+	switch (je16_to_cpu(item->u.nodetype)) {
+		case JFFS2_NODETYPE_INODE:
+			sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
+			sum_collected->sum_num++;
+			break;
+
+		case JFFS2_NODETYPE_DIRENT:
+			sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
+			sum_collected->sum_num++;
+			break;
+
+		case JFFS2_NODETYPE_XATTR:
+			sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
+			sum_collected->sum_num++;
+			break;
+
+		case JFFS2_NODETYPE_XREF:
+			sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE;
+			sum_collected->sum_num++;
+			break;
+
+		default:
+			errmsg_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
+	}
+	return 0;
+}
+
+void add_sum_inode_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_inode_mem *temp = xmalloc(sizeof(*temp));
+
+	temp->nodetype = node->i.nodetype;
+	temp->inode = node->i.ino;
+	temp->version = node->i.version;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->totlen = node->i.totlen;
+	temp->next = NULL;
+
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_dirent_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_dirent_mem *temp = xmalloc(sizeof(*temp) + node->d.nsize);
+
+	temp->nodetype = node->d.nodetype;
+	temp->totlen = node->d.totlen;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->pino = node->d.pino;
+	temp->version = node->d.version;
+	temp->ino = node->d.ino;
+	temp->nsize = node->d.nsize;
+	temp->type = node->d.type;
+	temp->next = NULL;
+
+	memcpy(temp->name,node->d.name,node->d.nsize);
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_xattr_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_xattr_mem *temp = xmalloc(sizeof(*temp));
+
+	temp->nodetype = node->x.nodetype;
+	temp->xid = node->x.xid;
+	temp->version = node->x.version;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->totlen = node->x.totlen;
+	temp->next = NULL;
+
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_xref_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_xref_mem *temp = xmalloc(sizeof(*temp));
+
+	temp->nodetype = node->r.nodetype;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->next = NULL;
+
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void write_dirent_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize));
+	add_sum_dirent_mem(node);
+	full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen));
+	padword();
+}
+
+
+void write_inode_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE);
+	add_sum_inode_mem(node);	/* Add inode summary mem to summary list */
+	full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen));	/* Write out the inode to inode_buffer */
+	padword();
+}
+
+void write_xattr_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE);
+	add_sum_xattr_mem(node);	/* Add xdatum summary mem to summary list */
+	full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen));
+	padword();
+}
+
+void write_xref_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE);
+	add_sum_xref_mem(node);		/* Add xref summary mem to summary list */
+	full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen));
+	padword();
+}
+
+void create_summed_image(int inp_size)
+{
+	uint8_t *p = file_buffer;
+	union jffs2_node_union *node;
+	uint32_t crc, length;
+	uint16_t type;
+	int bitchbitmask = 0;
+	int obsolete;
+	char name[256];
+
+	while ( p < (file_buffer + inp_size)) {
+
+		node = (union jffs2_node_union *) p;
+
+		/* Skip empty space */
+		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+			p += 4;
+			continue;
+		}
+
+		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
+			if (!bitchbitmask++)
+				warnmsg("Wrong bitmask  at  0x%08zx, 0x%04x\n",
+					p - file_buffer, je16_to_cpu (node->u.magic));
+			p += 4;
+			continue;
+		}
+
+		bitchbitmask = 0;
+
+		type = je16_to_cpu(node->u.nodetype);
+		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+			obsolete = 1;
+			type |= JFFS2_NODE_ACCURATE;
+		} else {
+			obsolete = 0;
+		}
+
+		node->u.nodetype = cpu_to_je16(type);
+
+		crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+		if (crc != je32_to_cpu (node->u.hdr_crc)) {
+			warnmsg("Wrong hdr_crc  at  0x%08zx, 0x%08x instead of 0x%08x\n",
+				p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
+			p += 4;
+			continue;
+		}
+
+		switch(je16_to_cpu(node->u.nodetype)) {
+			case JFFS2_NODETYPE_INODE:
+				bareverbose(verbose,
+					"%8s Inode      node at 0x%08zx, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+					je32_to_cpu (node->i.version), je32_to_cpu (node->i.isize),
+					je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
+				if (crc != je32_to_cpu (node->i.node_crc)) {
+					warnmsg("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
+						p - file_buffer, je32_to_cpu (node->i.node_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					continue;
+				}
+
+				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
+				if (crc != je32_to_cpu(node->i.data_crc)) {
+					warnmsg("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
+						p - file_buffer, je32_to_cpu (node->i.data_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					continue;
+				}
+
+				write_inode_to_buff(node);
+
+				p += PAD(je32_to_cpu (node->i.totlen));
+				break;
+
+			case JFFS2_NODETYPE_DIRENT:
+				memcpy (name, node->d.name, node->d.nsize);
+				name [node->d.nsize] = 0x0;
+
+				bareverbose(verbose,
+					"%8s Dirent     node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+					je32_to_cpu (node->d.version), je32_to_cpu (node->d.ino),
+					node->d.nsize, name);
+
+				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
+				if (crc != je32_to_cpu (node->d.node_crc)) {
+					warnmsg("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
+						p - file_buffer, je32_to_cpu (node->d.node_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					continue;
+				}
+
+				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
+				if (crc != je32_to_cpu(node->d.name_crc)) {
+					warnmsg("Wrong name_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
+						p - file_buffer, je32_to_cpu (node->d.name_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					continue;
+				}
+
+				write_dirent_to_buff(node);
+
+				p += PAD(je32_to_cpu (node->d.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XATTR:
+				if (je32_to_cpu(node->x.node_crc) == 0xffffffff)
+					obsolete = 1;
+				bareverbose(verbose,
+					"%8s Xdatum     node at 0x%08zx, totlen 0x%08x, #xid  %5u, version %5u\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->x.totlen),
+					je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version));
+				crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4);
+				if (crc != je32_to_cpu(node->x.node_crc)) {
+					warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+							p - file_buffer, je32_to_cpu(node->x.node_crc), crc);
+					p += PAD(je32_to_cpu (node->x.totlen));
+					continue;
+				}
+				length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len);
+				crc = mtd_crc32(0, node->x.data, length);
+				if (crc != je32_to_cpu(node->x.data_crc)) {
+					warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+							p - file_buffer, je32_to_cpu(node->x.data_crc), crc);
+					p += PAD(je32_to_cpu (node->x.totlen));
+					continue;
+				}
+
+				write_xattr_to_buff(node);
+				p += PAD(je32_to_cpu (node->x.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XREF:
+				if (je32_to_cpu(node->r.node_crc) == 0xffffffff)
+					obsolete = 1;
+				bareverbose(verbose,
+					"%8s Xref       node at 0x%08zx, totlen 0x%08x, #ino  %5u, xid     %5u\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu(node->r.totlen),
+					je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid));
+				crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xref) - 4);
+				if (crc != je32_to_cpu(node->r.node_crc)) {
+					warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+							p - file_buffer, je32_to_cpu(node->r.node_crc), crc);
+					p += PAD(je32_to_cpu (node->r.totlen));
+					continue;
+				}
+
+				write_xref_to_buff(node);
+				p += PAD(je32_to_cpu (node->r.totlen));
+				break;
+
+			case JFFS2_NODETYPE_CLEANMARKER:
+				bareverbose(verbose,
+					"%8s Cleanmarker     at 0x%08zx, totlen 0x%08x\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->u.totlen));
+
+				if (!found_cleanmarkers) {
+					found_cleanmarkers = 1;
+
+					if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){
+						cleanmarker_size = je32_to_cpu (node->u.totlen);
+						setup_cleanmarker();
+					}
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case JFFS2_NODETYPE_PADDING:
+				bareverbose(verbose,
+					"%8s Padding    node at 0x%08zx, totlen 0x%08x\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->u.totlen));
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case 0xffff:
+				p += 4;
+				break;
+
+			default:
+				bareverbose(verbose,
+					"%8s Unknown    node at 0x%08zx, totlen 0x%08x\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->u.totlen));
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int ret;
+
+	process_options(argc,argv);
+
+	if ((in_fd == -1) || (out_fd == -1)) {
+		if(in_fd != -1)
+			close(in_fd);
+		if(out_fd != -1)
+			close(out_fd);
+		fprintf(stderr, "%s", helptext);
+		errmsg_die("You must specify input and output files!\n");
+	}
+
+	init_buffers();
+	init_sumlist();
+
+	while ((ret = load_next_block())) {
+		create_summed_image(ret);
+	}
+
+	flush_buffers();
+	clean_buffers();
+	clean_sumlist();
+
+	if (in_fd != -1)
+		close(in_fd);
+	if (out_fd != -1)
+		close(out_fd);
+
+	return 0;
+}
diff --git a/load_nandsim.sh b/load_nandsim.sh
deleted file mode 100755
index 4d9f0cb..0000000
--- a/load_nandsim.sh
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/bin/sh -euf
-
-#
-# This script inserts NAND simulator module to emulate NAND flash of specified
-# size.
-#
-# Author: Artem Bityutskiy
-#
-
-fatal()
-{
-        echo "Error: $1" 1>&2
-        exit 1
-}
-
-usage()
-{
-	cat 1>&2 <<EOF
-Load NAND simulator to simulate flash of a specified size.
-
-Usage: ${0##*/} <size in MiB> <eraseblock size in KiB> \\
-       <page size (512 or 2048)>
-
-Only the first parameter is mandatory. Default eraseblock size
-is 16KiB, default NAND page size is 512 bytes.
-
-Only the following combinations are supported:
---------------------------------------------------
-| size (MiB) | EB size (KiB) | Page size (bytes) |
---------------------------------------------------
-| 16         | 16            | 512               |
-| 32         | 16            | 512               |
-| 64         | 16            | 512               |
-| 128        | 16            | 512               |
-| 256        | 16            | 512               |
-| 64         | 64            | 2048              |
-| 64         | 128           | 2048              |
-| 64         | 256           | 2048              |
-| 64         | 512           | 2048              |
-| 128        | 64            | 2048              |
-| 128        | 128           | 2048              |
-| 128        | 256           | 2048              |
-| 128        | 512           | 2048              |
-| 256        | 64            | 2048              |
-| 256        | 128           | 2048              |
-| 256        | 256           | 2048              |
-| 256        | 512           | 2048              |
-| 512        | 64            | 2048              |
-| 512        | 128           | 2048              |
-| 512        | 256           | 2048              |
-| 512        | 512           | 2048              |
-| 1024       | 64            | 2048              |
-| 1024       | 128           | 2048              |
-| 1024       | 256           | 2048              |
-| 1024       | 512           | 2048              |
---------------------------------------------------
-EOF
-}
-
-if grep -q "NAND simulator" /proc/mtd; then
-	fatal "nandsim is already loaded"
-fi
-
-if [ "$#" -lt "1" ]; then
-	usage
-	exit 1
-fi
-
-size="$1"
-eb_size="$2"
-page_size="$3"
-if [ "$#" = "1" ]; then
-	eb_size="16"
-	page_size="512"
-elif [ "$#" = "2" ]; then
-	page_size="512"
-fi
-
-if [ "$page_size" -eq 512 ] && [ "$eb_size" -ne "16" ]; then
-	fatal "only 16KiB eraseblocks are possible in case of 512 bytes page"
-fi
-
-first=
-second=
-third=
-fourth=
-
-if [ "$page_size" -eq "512" ]; then
-	first="0x20"
-	case "$size" in
-	16)  second=0x33 ;;
-	32)  second=0x35 ;;
-	64)  second=0x36 ;;
-	128) second=0x78 ;;
-	256) second=0x71 ;;
-	*) fatal "flash size ${size}MiB is not supported, try 16, 32, 64 or 256"
-	esac
-elif [ "$page_size" -eq "2048" ]; then
-	case "$eb_size" in
-	64)  fourth="0x05" ;;
-	128) fourth="0x15" ;;
-	256) fourth="0x25" ;;
-	512) fourth="0x35" ;;
-	*)   fatal "eraseblock ${eb_size}KiB is not supported"
-	esac
-
-
-	case "$size" in
-	64)   first="0x20"; second="0xa2"; third="0x00 ";;
-	128)  first="0xec"; second="0xa1"; third="0x00 ";;
-	256)  first="0x20"; second="0xaa"; third="0x00 ";;
-	512)  first="0x20"; second="0xac"; third="0x00 ";;
-	1024) first="0xec"; second="0xd3"; third="0x51 ";;
-	*) fatal "unable to emulate ${size}MiB flash with ${eb_size}KiB eraseblock"
-	esac
-else
-	fatal "bad NAND page size ${page_size}KiB, it has to be either 512 or 2048"
-fi
-
-first="first_id_byte=$first"
-second="second_id_byte=$second"
-[ -z "$third" ]  || third="third_id_byte=$third"
-[ -z "$fourth" ] || fourth="fourth_id_byte=$fourth"
-
-modprobe nandsim "$first" "$second" $third $fourth
-
-echo "Loaded NAND simulator (${size}MiB, ${eb_size}KiB eraseblock, $page_size bytes NAND page)"
diff --git a/mcast_image.h b/mcast_image.h
deleted file mode 100644
index 8e94ffa..0000000
--- a/mcast_image.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <stdint.h>
-
-#define PKT_SIZE 2820
-
-struct image_pkt_hdr {
-	uint32_t resend;
-	uint32_t totcrc;
-	uint32_t nr_blocks;
-	uint32_t blocksize;
-	uint32_t block_crc;
-	uint32_t block_nr;
-	uint32_t pkt_sequence;
-	uint16_t pkt_nr;
-	uint16_t nr_pkts;
-	uint32_t thislen;
-	uint32_t thiscrc;
-};
-
-struct image_pkt {
-	struct image_pkt_hdr hdr;
-	unsigned char data[PKT_SIZE];
-};
-
-struct fec_parms;
-
-/* k - number of actual data packets
- * n - total number of packets including data and redundant packets
- *   (actual packet size isn't relevant here) */
-struct fec_parms *fec_new(int k, int n);
-void fec_free(struct fec_parms *p);
-
-/* src   - array of (n) pointers to data packets
- * fec   - buffer for packet to be generated
- * index - index of packet to be generated (0 <= index < n)
- * sz    - data packet size
- *
- * _linear version just takes a pointer to the raw data; no
- * mucking about with packet pointers.
- */
-void fec_encode(struct fec_parms *code, unsigned char *src[],
-		unsigned char *fec, int index, int sz);
-void fec_encode_linear(struct fec_parms *code, unsigned char *src,
-		       unsigned char *fec, int index, int sz);
-
-/* data  - array of (k) pointers to data packets, in arbitrary order (see i)
- * i     - indices of (data) packets
- * sz    - data packet size
- *
- * Will never fail as long as you give it (k) individual data packets.
- * Will re-order the (data) pointers but not the indices -- data packets
- * are ordered on return.
- */
-int fec_decode(struct fec_parms *code, unsigned char *data[],
-	       int i[], int sz);
diff --git a/misc-utils/MAKEDEV b/misc-utils/MAKEDEV
new file mode 100755
index 0000000..b59e90e
--- /dev/null
+++ b/misc-utils/MAKEDEV
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+function mkftl () {
+	mknod /dev/ftl$1 b 44 $2
+	for a in `seq 1 15`; do
+		mknod /dev/ftl$1$a b 44 `expr $2 + $a`
+	done
+}
+function mknftl () {
+	mknod /dev/nftl$1 b 93 $2
+	for a in `seq 1 15`; do
+		mknod /dev/nftl$1$a b 93 `expr $2 + $a`
+	done
+}
+function mkrfd () {
+	mknod /dev/rfd$1 b 256 $2
+	for a in `seq 1 15`; do
+		mknod /dev/rfd$1$a b 256 `expr $2 + $a`
+	done
+}
+function mkinftl () {
+	mknod /dev/inftl$1 b 96 $2
+	for a in `seq 1 15`; do
+		mknod /dev/inftl$1$a b 96 `expr $2 + $a`
+	done
+}
+
+M=0
+for C in a b c d e f g h i j k l m n o p; do
+    mkftl $C $M
+    mknftl $C $M
+    mkrfd $C $M
+    mkinftl $C $M
+    let M=M+16
+done
+
+for a in `seq 0 16` ; do
+	mknod /dev/mtd$a c 90 `expr $a + $a`
+	mknod /dev/mtdr$a c 90 `expr $a + $a + 1`
+	mknod /dev/mtdblock$a b 31 $a
+done
diff --git a/misc-utils/doc_loadbios.c b/misc-utils/doc_loadbios.c
new file mode 100644
index 0000000..b999c73
--- /dev/null
+++ b/misc-utils/doc_loadbios.c
@@ -0,0 +1,150 @@
+#define PROGRAM_NAME "doc_loadbios"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+
+#include <mtd/mtd-user.h>
+
+unsigned char databuf[512];
+
+int main(int argc,char **argv)
+{
+	mtd_info_t meminfo;
+	int ifd,ofd;
+	struct stat statbuf;
+	erase_info_t erase;
+	unsigned long retlen, ofs, iplsize, ipltailsize;
+	unsigned char *iplbuf;
+	iplbuf = NULL;
+
+	if (argc < 3) {
+		fprintf(stderr,"You must specify a device,"
+				" the source firmware file and the offset\n");
+		return 1;
+	}
+
+	// Open and size the device
+	if ((ofd = open(argv[1],O_RDWR)) < 0) {
+		perror("Open flash device");
+		return 1;
+	}
+
+	if ((ifd = open(argv[2], O_RDONLY)) < 0) {
+		perror("Open firmware file\n");
+		close(ofd);
+		return 1;
+	}
+
+	if (fstat(ifd, &statbuf) != 0) {
+		perror("Stat firmware file");
+		goto error;
+	}
+
+#if 0
+	if (statbuf.st_size > 65536) {
+		printf("Firmware too large (%ld bytes)\n",statbuf.st_size);
+		goto error;
+	}
+#endif
+
+	if (ioctl(ofd,MEMGETINFO,&meminfo) != 0) {
+		perror("ioctl(MEMGETINFO)");
+		goto error;
+	}
+
+	iplsize = (ipltailsize = 0);
+	if (argc >= 4) {
+		/* DoC Millennium has IPL in the first 1K of flash memory */
+		/* You may want to specify the offset 1024 to store
+		   the firmware next to IPL. */
+		iplsize = strtoul(argv[3], NULL, 0);
+		ipltailsize = iplsize % meminfo.erasesize;
+	}
+
+	if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) {
+		perror("lseek");
+		goto error;
+	}
+
+	if (ipltailsize) {
+		iplbuf = malloc(ipltailsize);
+		if (iplbuf == NULL) {
+			fprintf(stderr, "Not enough memory for IPL tail buffer of"
+					" %lu bytes\n", (unsigned long) ipltailsize);
+			goto error;
+		}
+		printf("Reading IPL%s area of length %lu at offset %lu\n",
+				(iplsize - ipltailsize) ? " tail" : "",
+				(long unsigned) ipltailsize,
+				(long unsigned) (iplsize - ipltailsize));
+		if (read(ofd, iplbuf, ipltailsize) != ipltailsize) {
+			perror("read");
+			goto error;
+		}
+	}
+
+	erase.length = meminfo.erasesize;
+
+	for (ofs = iplsize - ipltailsize ;
+			ofs < iplsize + statbuf.st_size ;
+			ofs += meminfo.erasesize) {
+		erase.start = ofs;
+		printf("Performing Flash Erase of length %lu at offset %lu\n",
+				(long unsigned) erase.length, (long unsigned) erase.start);
+
+		if (ioctl(ofd,MEMERASE,&erase) != 0) {
+			perror("ioctl(MEMERASE)");
+			goto error;
+		}
+	}
+
+	if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) {
+		perror("lseek");
+		goto error;
+	}
+
+	if (ipltailsize) {
+		printf("Writing IPL%s area of length %lu at offset %lu\n",
+				(iplsize - ipltailsize) ? " tail" : "",
+				(long unsigned) ipltailsize,
+				(long unsigned) (iplsize - ipltailsize));
+		if (write(ofd, iplbuf, ipltailsize) != ipltailsize) {
+			perror("write");
+			goto error;
+		}
+	}
+
+	printf("Writing the firmware of length %lu at %lu... ",
+			(unsigned long) statbuf.st_size,
+			(unsigned long) iplsize);
+	do {
+		retlen = read(ifd, databuf, 512);
+		if (retlen < 512)
+			memset(databuf+retlen, 0xff, 512-retlen);
+		if (write(ofd, databuf, 512) != 512) {
+			perror("write");
+			goto error;
+		}
+	} while (retlen == 512);
+	printf("Done.\n");
+
+	if (iplbuf != NULL)
+		free(iplbuf);
+	close(ifd);
+	close(ofd);
+	return 0;
+
+error:
+	if (iplbuf != NULL)
+		free(iplbuf);
+	close(ifd);
+	close(ofd);
+	return 1;
+}
diff --git a/misc-utils/docfdisk.c b/misc-utils/docfdisk.c
new file mode 100644
index 0000000..9956de5
--- /dev/null
+++ b/misc-utils/docfdisk.c
@@ -0,0 +1,318 @@
+/*
+ * docfdisk.c: Modify INFTL partition tables
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+#define PROGRAM_NAME "docfdisk"
+
+#define _XOPEN_SOURCE 500 /* for pread/pwrite */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <string.h>
+
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+#include <mtd/inftl-user.h>
+#include <mtd_swab.h>
+
+unsigned char *buf;
+
+mtd_info_t meminfo;
+erase_info_t erase;
+int fd;
+struct INFTLMediaHeader *mh;
+
+#define MAXSCAN 10
+
+void show_header(int mhoffs) {
+	int i, unitsize, numunits, bmbits, numpart;
+	int start, end, num, nextunit;
+	unsigned int flags;
+	struct INFTLPartition *ip;
+
+	bmbits = le32_to_cpu(mh->BlockMultiplierBits);
+	printf("  bootRecordID          = %s\n"
+			"  NoOfBootImageBlocks   = %d\n"
+			"  NoOfBinaryPartitions  = %d\n"
+			"  NoOfBDTLPartitions    = %d\n"
+			"  BlockMultiplierBits   = %d\n"
+			"  FormatFlags           = %d\n"
+			"  OsakVersion           = %d.%d.%d.%d\n"
+			"  PercentUsed           = %d\n",
+			mh->bootRecordID, le32_to_cpu(mh->NoOfBootImageBlocks),
+			le32_to_cpu(mh->NoOfBinaryPartitions),
+			le32_to_cpu(mh->NoOfBDTLPartitions),
+			bmbits,
+			le32_to_cpu(mh->FormatFlags),
+			((unsigned char *) &mh->OsakVersion)[0] & 0xf,
+			((unsigned char *) &mh->OsakVersion)[1] & 0xf,
+			((unsigned char *) &mh->OsakVersion)[2] & 0xf,
+			((unsigned char *) &mh->OsakVersion)[3] & 0xf,
+			le32_to_cpu(mh->PercentUsed));
+
+	numpart = le32_to_cpu(mh->NoOfBinaryPartitions) +
+		le32_to_cpu(mh->NoOfBDTLPartitions);
+	unitsize = meminfo.erasesize >> bmbits;
+	numunits = meminfo.size / unitsize;
+	nextunit = mhoffs / unitsize;
+	nextunit++;
+	printf("Unitsize is %d bytes.  Device has %d units.\n",
+			unitsize, numunits);
+	if (numunits > 32768) {
+		printf("WARNING: More than 32768 units! Unexpectedly small BlockMultiplierBits.\n");
+	}
+	if (bmbits && (numunits <= 16384)) {
+		printf("NOTICE: Unexpectedly large BlockMultiplierBits.\n");
+	}
+	for (i = 0; i < 4; i++) {
+		ip = &(mh->Partitions[i]);
+		flags = le32_to_cpu(ip->flags);
+		start = le32_to_cpu(ip->firstUnit);
+		end = le32_to_cpu(ip->lastUnit);
+		num = le32_to_cpu(ip->virtualUnits);
+		if (start < nextunit) {
+			printf("ERROR: Overlapping or misordered partitions!\n");
+		}
+		if (start > nextunit) {
+			printf("  Unpartitioned space: %d bytes\n"
+					"    virtualUnits  = %d\n"
+					"    firstUnit     = %d\n"
+					"    lastUnit      = %d\n",
+					(start - nextunit) * unitsize, start - nextunit,
+					nextunit, start - 1);
+		}
+		if (flags & INFTL_BINARY)
+			printf("  Partition %d   (BDK):", i+1);
+		else
+			printf("  Partition %d  (BDTL):", i+1);
+		printf(" %d bytes\n"
+				"    virtualUnits  = %d\n"
+				"    firstUnit     = %d\n"
+				"    lastUnit      = %d\n"
+				"    flags         = 0x%x\n"
+				"    spareUnits    = %d\n",
+				num * unitsize, num, start, end,
+				le32_to_cpu(ip->flags), le32_to_cpu(ip->spareUnits));
+		if (num > (1 + end - start)) {
+			printf("ERROR: virtualUnits not consistent with first/lastUnit!\n");
+		}
+		end++;
+		if (end > nextunit)
+			nextunit = end;
+		if (flags & INFTL_LAST)
+			break;
+	}
+	if (i >= 4) {
+		printf("Odd.  Last partition was not marked with INFTL_LAST.\n");
+		i--;
+	}
+	if ((i+1) != numpart) {
+		printf("ERROR: Number of partitions != (NoOfBinaryPartitions + NoOfBDTLPartitions)\n");
+	}
+	if (nextunit > numunits) {
+		printf("ERROR: Partitions appear to extend beyond end of device!\n");
+	}
+	if (nextunit < numunits) {
+		printf("  Unpartitioned space: %d bytes\n"
+				"    virtualUnits  = %d\n"
+				"    firstUnit     = %d\n"
+				"    lastUnit      = %d\n",
+				(numunits - nextunit) * unitsize, numunits - nextunit,
+				nextunit, numunits - 1);
+	}
+}
+
+
+int main(int argc, char **argv)
+{
+	int ret, i, mhblock, unitsize, block;
+	unsigned int nblocks[4], npart;
+	unsigned int totblocks;
+	struct INFTLPartition *ip;
+	unsigned char *oobbuf;
+	struct mtd_oob_buf oob;
+	char line[20];
+	int mhoffs;
+	struct INFTLMediaHeader *mh2;
+
+	if (argc < 2) {
+		printf(
+				"Usage: %s <mtddevice> [<size1> [<size2> [<size3> [<size4]]]]\n"
+				"  Sizes are in device units (run with no sizes to show unitsize and current\n"
+				"  partitions).  Last size = 0 means go to end of device.\n",
+				PROGRAM_NAME);
+		return 1;
+	}
+
+	npart = argc - 2;
+	if (npart > 4) {
+		printf("Max 4 partitions allowed.\n");
+		return 1;
+	}
+
+	for (i = 0; i < npart; i++) {
+		nblocks[i] = strtoul(argv[2+i], NULL, 0);
+		if (i && !nblocks[i-1]) {
+			printf("No sizes allowed after 0\n");
+			return 1;
+		}
+	}
+
+	// Open and size the device
+	if ((fd = open(argv[1], O_RDWR)) < 0) {
+		perror("Open flash device");
+		return 1;
+	}
+
+	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+		perror("ioctl(MEMGETINFO)");
+		return 1;
+	}
+
+	printf("Device size is %d bytes.  Erasesize is %d bytes.\n",
+			meminfo.size, meminfo.erasesize);
+
+	buf = malloc(meminfo.erasesize);
+	oobbuf = malloc((meminfo.erasesize / meminfo.writesize) * meminfo.oobsize);
+	if (!buf || !oobbuf) {
+		printf("Can't malloc block buffer\n");
+		return 1;
+	}
+	oob.length = meminfo.oobsize;
+
+	mh = (struct INFTLMediaHeader *) buf;
+
+	for (mhblock = 0; mhblock < MAXSCAN; mhblock++) {
+		if ((ret = pread(fd, buf, meminfo.erasesize, mhblock * meminfo.erasesize)) < 0) {
+			if (errno == EBADMSG) {
+				printf("ECC error at eraseblock %d\n", mhblock);
+				continue;
+			}
+			perror("Read eraseblock");
+			return 1;
+		}
+		if (ret != meminfo.erasesize) {
+			printf("Short read!\n");
+			return 1;
+		}
+		if (!strcmp("BNAND", mh->bootRecordID)) break;
+	}
+	if (mhblock >= MAXSCAN) {
+		printf("Unable to find INFTL Media Header\n");
+		return 1;
+	}
+	printf("Found INFTL Media Header at block %d:\n", mhblock);
+	mhoffs = mhblock * meminfo.erasesize;
+
+	oob.ptr = oobbuf;
+	oob.start = mhoffs;
+	for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
+		if (ioctl(fd, MEMREADOOB, &oob)) {
+			perror("ioctl(MEMREADOOB)");
+			return 1;
+		}
+		oob.start += meminfo.writesize;
+		oob.ptr += meminfo.oobsize;
+	}
+
+	show_header(mhoffs);
+
+	if (!npart)
+		return 0;
+
+	printf("\n-------------------------------------------------------------------------\n");
+
+	unitsize = meminfo.erasesize >> le32_to_cpu(mh->BlockMultiplierBits);
+	totblocks = meminfo.size / unitsize;
+	block = mhoffs / unitsize;
+	block++;
+
+	mh->NoOfBDTLPartitions = 0;
+	mh->NoOfBinaryPartitions = npart;
+
+	for (i = 0; i < npart; i++) {
+		ip = &(mh->Partitions[i]);
+		ip->firstUnit = cpu_to_le32(block);
+		if (!nblocks[i])
+			nblocks[i] = totblocks - block;
+		ip->virtualUnits = cpu_to_le32(nblocks[i]);
+		block += nblocks[i];
+		ip->lastUnit = cpu_to_le32(block-1);
+		ip->spareUnits = 0;
+		ip->flags = cpu_to_le32(INFTL_BINARY);
+	}
+	if (block > totblocks) {
+		printf("Requested partitions extend beyond end of device.\n");
+		return 1;
+	}
+	ip->flags = cpu_to_le32(INFTL_BINARY | INFTL_LAST);
+
+	/* update the spare as well */
+	mh2 = (struct INFTLMediaHeader *) (buf + 4096);
+	memcpy((void *) mh2, (void *) mh, sizeof(struct INFTLMediaHeader));
+
+	printf("\nProposed new Media Header:\n");
+	show_header(mhoffs);
+
+	printf("\nReady to update device.  Type 'yes' to proceed, anything else to abort: ");
+	fgets(line, sizeof(line), stdin);
+	if (strcmp("yes\n", line))
+		return 0;
+	printf("Updating MediaHeader...\n");
+
+	erase.start = mhoffs;
+	erase.length = meminfo.erasesize;
+	if (ioctl(fd, MEMERASE, &erase)) {
+		perror("ioctl(MEMERASE)");
+		printf("Your MediaHeader may be hosed.  UHOH!\n");
+		return 1;
+	}
+
+	oob.ptr = oobbuf;
+	oob.start = mhoffs;
+	for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
+		memset(oob.ptr, 0xff, 6); // clear ECC.
+		if (ioctl(fd, MEMWRITEOOB, &oob)) {
+			perror("ioctl(MEMWRITEOOB)");
+			printf("Your MediaHeader may be hosed.  UHOH!\n");
+			return 1;
+		}
+		if ((ret = pwrite(fd, buf, meminfo.writesize, oob.start)) < 0) {
+			perror("Write page");
+			printf("Your MediaHeader may be hosed.  UHOH!\n");
+			return 1;
+		}
+		if (ret != meminfo.writesize) {
+			printf("Short write!\n");
+			printf("Your MediaHeader may be hosed.  UHOH!\n");
+			return 1;
+		}
+
+		oob.start += meminfo.writesize;
+		oob.ptr += meminfo.oobsize;
+		buf += meminfo.writesize;
+	}
+
+	printf("Success.  REBOOT or unload the diskonchip module to update partitions!\n");
+	return 0;
+}
diff --git a/misc-utils/fectest.c b/misc-utils/fectest.c
new file mode 100644
index 0000000..fd577f3
--- /dev/null
+++ b/misc-utils/fectest.c
@@ -0,0 +1,91 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "mcast_image.h"
+#include <crc32.h>
+
+#define ERASE_SIZE 131072
+#define NR_PKTS ((ERASE_SIZE + PKT_SIZE - 1) / PKT_SIZE)
+#define DROPS 8
+
+int main(void)
+{
+	int i, j;
+	unsigned char buf[NR_PKTS * PKT_SIZE];
+	unsigned char pktbuf[(NR_PKTS + DROPS) * PKT_SIZE];
+	struct fec_parms *fec;
+	unsigned char *srcs[NR_PKTS];
+	unsigned char *pkt[NR_PKTS + DROPS];
+	int pktnr[NR_PKTS + DROPS];
+	struct timeval then, now;
+
+	srand(3453);
+	for (i=0; i < sizeof(buf); i++)
+		if (i < ERASE_SIZE)
+			buf[i] = rand();
+		else
+			buf[i] = 0;
+
+	for (i=0; i < NR_PKTS + DROPS; i++)
+		srcs[i] = buf + (i * PKT_SIZE);
+
+	for (i=0; i < NR_PKTS + DROPS; i++) {
+		pkt[i] = malloc(PKT_SIZE);
+		pktnr[i] = -1;
+	}
+	fec = fec_new(NR_PKTS, NR_PKTS + DROPS);
+	if (!fec) {
+		printf("fec_init() failed\n");
+		exit(1);
+	}
+	j = 0;
+	for (i=0; i < NR_PKTS + DROPS; i++) {
+#if 1
+		if (i == 27  || i == 40  || i == 44 || i == 45 || i == 56 )
+			continue;
+#endif
+		if (i == 69 || i == 93 || i == 103)
+			continue;
+		fec_encode(fec, srcs, pkt[j], i, PKT_SIZE);
+		pktnr[j] = i;
+		j++;
+	}
+	gettimeofday(&then, NULL);
+	if (fec_decode(fec, pkt, pktnr, PKT_SIZE)) {
+		printf("Decode failed\n");
+		exit(1);
+	}
+
+	for (i=0; i < NR_PKTS; i++)
+		memcpy(pktbuf + (i*PKT_SIZE), pkt[i], PKT_SIZE);
+	gettimeofday(&now, NULL);
+	now.tv_sec -= then.tv_sec;
+	now.tv_usec -= then.tv_usec;
+	if (now.tv_usec < 0) {
+		now.tv_usec += 1000000;
+		now.tv_sec--;
+	}
+
+	if (memcmp(pktbuf, buf, ERASE_SIZE)) {
+		int fd;
+		printf("Compare failed\n");
+		fd = open("before", O_WRONLY|O_TRUNC|O_CREAT, 0644);
+		if (fd >= 0)
+			write(fd, buf, ERASE_SIZE);
+		close(fd);
+		fd = open("after", O_WRONLY|O_TRUNC|O_CREAT, 0644);
+		if (fd >= 0)
+			write(fd, pktbuf, ERASE_SIZE);
+
+		exit(1);
+	}
+
+	printf("Decoded in %ld.%06lds\n", now.tv_sec, now.tv_usec);
+	return 0;
+}
diff --git a/misc-utils/ftl_check.c b/misc-utils/ftl_check.c
new file mode 100644
index 0000000..0eada8f
--- /dev/null
+++ b/misc-utils/ftl_check.c
@@ -0,0 +1,217 @@
+/* Ported to MTD system.
+ * Based on:
+ */
+/*======================================================================
+
+  Utility to create an FTL partition in a memory region
+
+  ftl_check.c 1.10 1999/10/25 20:01:35
+
+  The contents of this file are subject to the Mozilla Public
+  License Version 1.1 (the "License"); you may not use this file
+  except in compliance with the License. You may obtain a copy of
+  the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS
+  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  implied. See the License for the specific language governing
+  rights and limitations under the License.
+
+  The initial developer of the original code is David A. Hinds
+  <dhinds at pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+  Alternatively, the contents of this file may be used under the
+  terms of the GNU Public License version 2 (the "GPL"), in which
+  case the provisions of the GPL are applicable instead of the
+  above.  If you wish to allow the use of your version of this file
+  only under the terms of the GPL and not to allow others to use
+  your version of this file under the MPL, indicate your decision
+  by deleting the provisions above and replace them with the notice
+  and other provisions required by the GPL.  If you do not delete
+  the provisions above, a recipient may use your version of this
+  file under either the MPL or the GPL.
+
+  ======================================================================*/
+
+#define PROGRAM_NAME "ftl_check"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <mtd/mtd-user.h>
+#include <mtd/ftl-user.h>
+#include <mtd_swab.h>
+
+#include "common.h"
+
+/*====================================================================*/
+
+static void print_size(u_int s)
+{
+	if ((s > 0x100000) && ((s % 0x100000) == 0))
+		printf("%d mb", s / 0x100000);
+	else if ((s > 0x400) && ((s % 0x400) == 0))
+		printf("%d kb", s / 0x400);
+	else
+		printf("%d bytes", s);
+}
+
+/*====================================================================*/
+
+static void check_partition(int fd)
+{
+	mtd_info_t mtd;
+	erase_unit_header_t hdr, hdr2;
+	off_t i;
+	u_int j, nbam, *bam;
+	int control, data, free, deleted;
+
+	/* Get partition size, block size */
+	if (ioctl(fd, MEMGETINFO, &mtd) != 0) {
+		perror("get info failed");
+		return;
+	}
+
+	printf("Memory region info:\n");
+	printf("  Region size = ");
+	print_size(mtd.size);
+	printf("  Erase block size = ");
+	print_size(mtd.erasesize);
+	printf("\n\n");
+
+	for (i = 0; i < mtd.size/mtd.erasesize; i++) {
+		if (lseek(fd, (i * mtd.erasesize), SEEK_SET) == -1) {
+			perror("seek failed");
+			break;
+		}
+		read(fd, &hdr, sizeof(hdr));
+		if ((le32_to_cpu(hdr.FormattedSize) > 0) &&
+				(le32_to_cpu(hdr.FormattedSize) <= mtd.size) &&
+				(le16_to_cpu(hdr.NumEraseUnits) > 0) &&
+				(le16_to_cpu(hdr.NumEraseUnits) <= mtd.size/mtd.erasesize))
+			break;
+	}
+	if (i == mtd.size/mtd.erasesize) {
+		fprintf(stderr, "No valid erase unit headers!\n");
+		return;
+	}
+
+	printf("Partition header:\n");
+	printf("  Formatted size = ");
+	print_size(le32_to_cpu(hdr.FormattedSize));
+	printf(", erase units = %d, transfer units = %d\n",
+			le16_to_cpu(hdr.NumEraseUnits), hdr.NumTransferUnits);
+	printf("  Erase unit size = ");
+	print_size(1 << hdr.EraseUnitSize);
+	printf(", virtual block size = ");
+	print_size(1 << hdr.BlockSize);
+	printf("\n");
+
+	/* Create basic block allocation table for control blocks */
+	nbam = (mtd.erasesize >> hdr.BlockSize);
+	bam = malloc(nbam * sizeof(u_int));
+
+	for (i = 0; i < le16_to_cpu(hdr.NumEraseUnits); i++) {
+		if (lseek(fd, (i << hdr.EraseUnitSize), SEEK_SET) == -1) {
+			perror("seek failed");
+			break;
+		}
+		if (read(fd, &hdr2, sizeof(hdr2)) == -1) {
+			perror("read failed");
+			break;
+		}
+		printf("\nErase unit %"PRIdoff_t":\n", i);
+		if ((hdr2.FormattedSize != hdr.FormattedSize) ||
+				(hdr2.NumEraseUnits != hdr.NumEraseUnits) ||
+				(hdr2.SerialNumber != hdr.SerialNumber))
+			printf("  Erase unit header is corrupt.\n");
+		else if (le16_to_cpu(hdr2.LogicalEUN) == 0xffff)
+			printf("  Transfer unit, erase count = %d\n", le32_to_cpu(hdr2.EraseCount));
+		else {
+			printf("  Logical unit %d, erase count = %d\n",
+					le16_to_cpu(hdr2.LogicalEUN), le32_to_cpu(hdr2.EraseCount));
+			if (lseek(fd, (i << hdr.EraseUnitSize)+le32_to_cpu(hdr.BAMOffset),
+						SEEK_SET) == -1) {
+				perror("seek failed");
+				break;
+			}
+			if (read(fd, bam, nbam * sizeof(u_int)) == -1) {
+				perror("read failed");
+				break;
+			}
+			free = deleted = control = data = 0;
+			for (j = 0; j < nbam; j++) {
+				if (BLOCK_FREE(le32_to_cpu(bam[j])))
+					free++;
+				else if (BLOCK_DELETED(le32_to_cpu(bam[j])))
+					deleted++;
+				else switch (BLOCK_TYPE(le32_to_cpu(bam[j]))) {
+					case BLOCK_CONTROL: control++; break;
+					case BLOCK_DATA: data++; break;
+					default: break;
+				}
+			}
+			printf("  Block allocation: %d control, %d data, %d free,"
+					" %d deleted\n", control, data, free, deleted);
+		}
+	}
+} /* format_partition */
+
+/* Show usage information */
+void showusage(void)
+{
+	fprintf(stderr, "usage: %s device\n", PROGRAM_NAME);
+}
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+	int optch, errflg, fd;
+	struct stat buf;
+
+	errflg = 0;
+	while ((optch = getopt(argc, argv, "h")) != -1) {
+		switch (optch) {
+			case 'h':
+				errflg = 1; break;
+			default:
+				errflg = -1; break;
+		}
+	}
+	if (errflg || (optind != argc-1)) {
+		showusage();
+		exit(errflg > 0 ? 0 : EXIT_FAILURE);
+	}
+
+	if (stat(argv[optind], &buf) != 0) {
+		perror("status check failed");
+		exit(EXIT_FAILURE);
+	}
+	if (!(buf.st_mode & S_IFCHR)) {
+		fprintf(stderr, "%s is not a character special device\n",
+				argv[optind]);
+		exit(EXIT_FAILURE);
+	}
+	fd = open(argv[optind], O_RDONLY);
+	if (fd == -1) {
+		perror("open failed");
+		exit(EXIT_FAILURE);
+	}
+
+	check_partition(fd);
+	close(fd);
+
+	exit(EXIT_SUCCESS);
+	return 0;
+}
diff --git a/misc-utils/ftl_format.c b/misc-utils/ftl_format.c
new file mode 100644
index 0000000..b58677f
--- /dev/null
+++ b/misc-utils/ftl_format.c
@@ -0,0 +1,324 @@
+/* Ported to MTD system.
+ * Based on:
+ */
+/*======================================================================
+
+  Utility to create an FTL partition in a memory region
+
+  ftl_format.c 1.13 1999/10/25 20:01:35
+
+  The contents of this file are subject to the Mozilla Public
+  License Version 1.1 (the "License"); you may not use this file
+  except in compliance with the License. You may obtain a copy of
+  the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS
+  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  implied. See the License for the specific language governing
+  rights and limitations under the License.
+
+  The initial developer of the original code is David A. Hinds
+  <dhinds at pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+  Alternatively, the contents of this file may be used under the
+  terms of the GNU Public License version 2 (the "GPL"), in which
+  case the provisions of the GPL are applicable instead of the
+  above.  If you wish to allow the use of your version of this file
+  only under the terms of the GPL and not to allow others to use
+  your version of this file under the MPL, indicate your decision
+  by deleting the provisions above and replace them with the notice
+  and other provisions required by the GPL.  If you do not delete
+  the provisions above, a recipient may use your version of this
+  file under either the MPL or the GPL.
+
+  ======================================================================*/
+
+#define PROGRAM_NAME "ftl_format"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <mtd/mtd-user.h>
+#include <mtd/ftl-user.h>
+#include <mtd_swab.h>
+#include "common.h"
+
+/*====================================================================*/
+
+static void print_size(u_int s)
+{
+	if ((s > 0x100000) && ((s % 0x100000) == 0))
+		printf("%d mb", s / 0x100000);
+	else if ((s > 0x400) && ((s % 0x400) == 0))
+		printf("%d kb", s / 0x400);
+	else
+		printf("%d bytes", s);
+}
+
+/*====================================================================*/
+
+static const char LinkTarget[] = {
+	0x13, 0x03, 'C', 'I', 'S'
+};
+static const char DataOrg[] = {
+	0x46, 0x39, 0x00, 'F', 'T', 'L', '1', '0', '0', 0x00
+};
+
+static void build_header(erase_unit_header_t *hdr, u_int RegionSize,
+		u_int BlockSize, u_int Spare, int Reserve,
+		u_int BootSize)
+{
+	u_int i, BootUnits, nbam, __FormattedSize;
+
+	/* Default everything to the erased state */
+	memset(hdr, 0xff, sizeof(*hdr));
+	memcpy(hdr->LinkTargetTuple, LinkTarget, 5);
+	memcpy(hdr->DataOrgTuple, DataOrg, 10);
+	hdr->EndTuple[0] = hdr->EndTuple[1] = 0xff;
+	BootSize = (BootSize + (BlockSize-1)) & ~(BlockSize-1);
+	BootUnits = BootSize / BlockSize;
+
+	/* We only support 512-byte blocks */
+	hdr->BlockSize = 9;
+	hdr->EraseUnitSize = 0;
+	for (i = BlockSize; i > 1; i >>= 1)
+		hdr->EraseUnitSize++;
+	hdr->EraseCount = cpu_to_le32(0);
+	hdr->FirstPhysicalEUN = cpu_to_le16(BootUnits);
+	hdr->NumEraseUnits = cpu_to_le16((RegionSize - BootSize) >> hdr->EraseUnitSize);
+	hdr->NumTransferUnits = Spare;
+	__FormattedSize = RegionSize - ((Spare + BootUnits) << hdr->EraseUnitSize);
+	/* Leave a little bit of space between the CIS and BAM */
+	hdr->BAMOffset = cpu_to_le32(0x80);
+	/* Adjust size to account for BAM space */
+	nbam = ((1 << (hdr->EraseUnitSize - hdr->BlockSize)) * sizeof(u_int)
+			+ le32_to_cpu(hdr->BAMOffset) + (1 << hdr->BlockSize) - 1) >> hdr->BlockSize;
+
+	__FormattedSize -=
+		(le16_to_cpu(hdr->NumEraseUnits) - Spare) * (nbam << hdr->BlockSize);
+	__FormattedSize -= ((__FormattedSize * Reserve / 100) & ~0xfff);
+
+	hdr->FormattedSize = cpu_to_le32(__FormattedSize);
+
+	/* hdr->FirstVMAddress defaults to erased state */
+	hdr->NumVMPages = cpu_to_le16(0);
+	hdr->Flags = 0;
+	/* hdr->Code defaults to erased state */
+	hdr->SerialNumber = cpu_to_le32(time(NULL));
+	/* hdr->AltEUHOffset defaults to erased state */
+
+} /* build_header */
+
+/*====================================================================*/
+
+static int format_partition(int fd, int quiet, int interrogate,
+		u_int spare, int reserve, u_int bootsize)
+{
+	mtd_info_t mtd;
+	erase_info_t erase;
+	erase_unit_header_t hdr;
+	u_int step, lun, i, nbam, *bam;
+
+	/* Get partition size, block size */
+	if (ioctl(fd, MEMGETINFO, &mtd) != 0) {
+		perror("get info failed");
+		return -1;
+	}
+
+#if 0
+	/* Intel Series 100 Flash: skip first block */
+	if ((region.JedecMfr == 0x89) && (region.JedecInfo == 0xaa) &&
+			(bootsize == 0)) {
+		if (!quiet)
+			printf("Skipping first block to protect CIS info...\n");
+		bootsize = 1;
+	}
+#endif
+
+	/* Create header */
+	build_header(&hdr, mtd.size, mtd.erasesize,
+			spare, reserve, bootsize);
+
+	if (!quiet) {
+		printf("Partition size = ");
+		print_size(mtd.size);
+		printf(", erase unit size = ");
+		print_size(mtd.erasesize);
+		printf(", %d transfer units\n", spare);
+		if (bootsize != 0) {
+			print_size(le16_to_cpu(hdr.FirstPhysicalEUN) << hdr.EraseUnitSize);
+			printf(" allocated for boot image\n");
+		}
+		printf("Reserved %d%%, formatted size = ", reserve);
+		print_size(le32_to_cpu(hdr.FormattedSize));
+		printf("\n");
+		fflush(stdout);
+	}
+
+	if (interrogate)
+		if (!prompt("This will destroy all data on the target device. Confirm?", false))
+			return -1;
+
+	/* Create basic block allocation table for control blocks */
+	nbam = ((mtd.erasesize >> hdr.BlockSize) * sizeof(u_int)
+			+ le32_to_cpu(hdr.BAMOffset) + (1 << hdr.BlockSize) - 1) >> hdr.BlockSize;
+	bam = malloc(nbam * sizeof(u_int));
+	for (i = 0; i < nbam; i++)
+		bam[i] = cpu_to_le32(BLOCK_CONTROL);
+
+	/* Erase partition */
+	if (!quiet) {
+		printf("Erasing all blocks...\n");
+		fflush(stdout);
+	}
+	erase.length = mtd.erasesize;
+	erase.start = mtd.erasesize * le16_to_cpu(hdr.FirstPhysicalEUN);
+	for (i = 0; i < le16_to_cpu(hdr.NumEraseUnits); i++) {
+		if (ioctl(fd, MEMERASE, &erase) < 0) {
+			if (!quiet) {
+				putchar('\n');
+				fflush(stdout);
+			}
+			perror("block erase failed");
+			return -1;
+		}
+		erase.start += erase.length;
+		if (!quiet) {
+			if (mtd.size <= 0x800000) {
+				if (erase.start % 0x100000) {
+					if (!(erase.start % 0x20000)) putchar('-');
+				}
+				else putchar('+');
+			}
+			else {
+				if (erase.start % 0x800000) {
+					if (!(erase.start % 0x100000)) putchar('+');
+				}
+				else putchar('*');
+			}
+			fflush(stdout);
+		}
+	}
+	if (!quiet) putchar('\n');
+
+	/* Prepare erase units */
+	if (!quiet) {
+		printf("Writing erase unit headers...\n");
+		fflush(stdout);
+	}
+	lun = 0;
+	/* Distribute transfer units over the entire region */
+	step = spare ? (le16_to_cpu(hdr.NumEraseUnits) / spare) : (le16_to_cpu(hdr.NumEraseUnits) + 1);
+	for (i = 0; i < le16_to_cpu(hdr.NumEraseUnits); i++) {
+		off_t ofs = (off_t) (i + le16_to_cpu(hdr.FirstPhysicalEUN)) << hdr.EraseUnitSize;
+		if (lseek(fd, ofs, SEEK_SET) == -1) {
+			perror("seek failed");
+			break;
+		}
+		/* Is this a transfer unit? */
+		if (((i+1) % step) == 0)
+			hdr.LogicalEUN = cpu_to_le16(0xffff);
+		else {
+			hdr.LogicalEUN = cpu_to_le16(lun);
+			lun++;
+		}
+		if (write(fd, &hdr, sizeof(hdr)) == -1) {
+			perror("write failed");
+			break;
+		}
+		if (lseek(fd, ofs + le32_to_cpu(hdr.BAMOffset), SEEK_SET) == -1) {
+			perror("seek failed");
+			break;
+		}
+		if (write(fd, bam, nbam * sizeof(u_int)) == -1) {
+			perror("write failed");
+			break;
+		}
+	}
+	if (i < le16_to_cpu(hdr.NumEraseUnits))
+		return -1;
+	else
+		return 0;
+} /* format_partition */
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+	int quiet, interrogate, reserve;
+	int optch, errflg, fd, ret;
+	u_int spare, bootsize;
+	char *s;
+	extern char *optarg;
+	struct stat buf;
+
+	quiet = 0;
+	interrogate = 0;
+	spare = 1;
+	reserve = 5;
+	errflg = 0;
+	bootsize = 0;
+
+	while ((optch = getopt(argc, argv, "qir:s:b:")) != -1) {
+		switch (optch) {
+			case 'q':
+				quiet = 1; break;
+			case 'i':
+				interrogate = 1; break;
+			case 's':
+				spare = strtoul(optarg, NULL, 0); break;
+			case 'r':
+				reserve = strtoul(optarg, NULL, 0); break;
+			case 'b':
+				bootsize = strtoul(optarg, &s, 0);
+				if ((*s == 'k') || (*s == 'K'))
+					bootsize *= 1024;
+				break;
+			default:
+				errflg = 1; break;
+		}
+	}
+	if (errflg || (optind != argc-1)) {
+		fprintf(stderr, "usage: %s [-q] [-i] [-s spare-blocks]"
+				" [-r reserve-percent] [-b bootsize] device\n", PROGRAM_NAME);
+		exit(EXIT_FAILURE);
+	}
+
+	if (stat(argv[optind], &buf) != 0) {
+		perror("status check failed");
+		exit(EXIT_FAILURE);
+	}
+	if (!(buf.st_mode & S_IFCHR)) {
+		fprintf(stderr, "%s is not a character special device\n",
+				argv[optind]);
+		exit(EXIT_FAILURE);
+	}
+	fd = open(argv[optind], O_RDWR);
+	if (fd == -1) {
+		perror("open failed");
+		exit(EXIT_FAILURE);
+	}
+
+	ret = format_partition(fd, quiet, interrogate, spare, reserve,
+			bootsize);
+	if (!quiet) {
+		if (ret)
+			printf("format failed.\n");
+		else
+			printf("format successful.\n");
+	}
+	close(fd);
+
+	exit((ret) ? EXIT_FAILURE : EXIT_SUCCESS);
+	return 0;
+}
diff --git a/misc-utils/mcast_image.h b/misc-utils/mcast_image.h
new file mode 100644
index 0000000..8e94ffa
--- /dev/null
+++ b/misc-utils/mcast_image.h
@@ -0,0 +1,54 @@
+#include <stdint.h>
+
+#define PKT_SIZE 2820
+
+struct image_pkt_hdr {
+	uint32_t resend;
+	uint32_t totcrc;
+	uint32_t nr_blocks;
+	uint32_t blocksize;
+	uint32_t block_crc;
+	uint32_t block_nr;
+	uint32_t pkt_sequence;
+	uint16_t pkt_nr;
+	uint16_t nr_pkts;
+	uint32_t thislen;
+	uint32_t thiscrc;
+};
+
+struct image_pkt {
+	struct image_pkt_hdr hdr;
+	unsigned char data[PKT_SIZE];
+};
+
+struct fec_parms;
+
+/* k - number of actual data packets
+ * n - total number of packets including data and redundant packets
+ *   (actual packet size isn't relevant here) */
+struct fec_parms *fec_new(int k, int n);
+void fec_free(struct fec_parms *p);
+
+/* src   - array of (n) pointers to data packets
+ * fec   - buffer for packet to be generated
+ * index - index of packet to be generated (0 <= index < n)
+ * sz    - data packet size
+ *
+ * _linear version just takes a pointer to the raw data; no
+ * mucking about with packet pointers.
+ */
+void fec_encode(struct fec_parms *code, unsigned char *src[],
+		unsigned char *fec, int index, int sz);
+void fec_encode_linear(struct fec_parms *code, unsigned char *src,
+		       unsigned char *fec, int index, int sz);
+
+/* data  - array of (k) pointers to data packets, in arbitrary order (see i)
+ * i     - indices of (data) packets
+ * sz    - data packet size
+ *
+ * Will never fail as long as you give it (k) individual data packets.
+ * Will re-order the (data) pointers but not the indices -- data packets
+ * are ordered on return.
+ */
+int fec_decode(struct fec_parms *code, unsigned char *data[],
+	       int i[], int sz);
diff --git a/misc-utils/mtd_debug.c b/misc-utils/mtd_debug.c
new file mode 100644
index 0000000..d6993ce
--- /dev/null
+++ b/misc-utils/mtd_debug.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2d3D, Inc.
+ * Written by Abraham vd Merwe <abraham at 2d3d.co.za>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	  notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	  notice, this list of conditions and the following disclaimer in the
+ *	  documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ *	  may be used to endorse or promote products derived from this software
+ *	  without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define PROGRAM_NAME "mtd_debug"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <mtd/mtd-user.h>
+#include "common.h"
+
+/*
+ * MEMGETINFO
+ */
+static int getmeminfo(int fd, struct mtd_info_user *mtd)
+{
+	return ioctl(fd, MEMGETINFO, mtd);
+}
+
+/*
+ * MEMERASE
+ */
+static int memerase(int fd, struct erase_info_user *erase)
+{
+	return ioctl(fd, MEMERASE, erase);
+}
+
+/*
+ * MEMGETREGIONCOUNT
+ * MEMGETREGIONINFO
+ */
+static int getregions(int fd, struct region_info_user *regions, int *n)
+{
+	int i, err;
+	err = ioctl(fd, MEMGETREGIONCOUNT, n);
+	if (err)
+		return err;
+	for (i = 0; i < *n; i++) {
+		regions[i].regionindex = i;
+		err = ioctl(fd, MEMGETREGIONINFO, &regions[i]);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+int erase_flash(int fd, u_int32_t offset, u_int32_t bytes)
+{
+	int err;
+	struct erase_info_user erase;
+	erase.start = offset;
+	erase.length = bytes;
+	err = memerase(fd, &erase);
+	if (err < 0) {
+		perror("MEMERASE");
+		return 1;
+	}
+	fprintf(stderr, "Erased %d bytes from address 0x%.8x in flash\n", bytes, offset);
+	return 0;
+}
+
+void printsize(u_int32_t x)
+{
+	int i;
+	static const char *flags = "KMGT";
+	printf("%u ", x);
+	for (i = 0; x >= 1024 && flags[i] != '\0'; i++)
+		x /= 1024;
+	i--;
+	if (i >= 0)
+		printf("(%u%c)", x, flags[i]);
+}
+
+int flash_to_file(int fd, off_t offset, size_t len, const char *filename)
+{
+	u_int8_t *buf = NULL;
+	int outfd, err;
+	int size = len * sizeof(u_int8_t);
+	int n = len;
+
+	if (offset != lseek(fd, offset, SEEK_SET)) {
+		perror("lseek()");
+		goto err0;
+	}
+	outfd = creat(filename, 0666);
+	if (outfd < 0) {
+		perror("creat()");
+		goto err1;
+	}
+
+retry:
+	if ((buf = (u_int8_t *) malloc(size)) == NULL) {
+#define BUF_SIZE	(64 * 1024 * sizeof(u_int8_t))
+		fprintf(stderr, "%s: malloc(%#x)\n", __func__, size);
+		if (size != BUF_SIZE) {
+			size = BUF_SIZE;
+			fprintf(stderr, "%s: trying buffer size %#x\n", __func__, size);
+			goto retry;
+		}
+		perror("malloc()");
+		goto err0;
+	}
+	do {
+		if (n <= size)
+			size = n;
+		err = read(fd, buf, size);
+		if (err < 0) {
+			fprintf(stderr, "%s: read, size %#x, n %#x\n", __func__, size, n);
+			perror("read()");
+			goto err2;
+		}
+		err = write(outfd, buf, size);
+		if (err < 0) {
+			fprintf(stderr, "%s: write, size %#x, n %#x\n", __func__, size, n);
+			perror("write()");
+			goto err2;
+		}
+		if (err != size) {
+			fprintf(stderr, "Couldn't copy entire buffer to %s. (%d/%d bytes copied)\n", filename, err, size);
+			goto err2;
+		}
+		n -= size;
+	} while (n > 0);
+
+	if (buf != NULL)
+		free(buf);
+	close(outfd);
+	printf("Copied %zu bytes from address 0x%.8"PRIxoff_t" in flash to %s\n", len, offset, filename);
+	return 0;
+
+err2:
+	close(outfd);
+err1:
+	if (buf != NULL)
+		free(buf);
+err0:
+	return 1;
+}
+
+int file_to_flash(int fd, off_t offset, u_int32_t len, const char *filename)
+{
+	u_int8_t *buf = NULL;
+	FILE *fp;
+	int err;
+	int size = len * sizeof(u_int8_t);
+	int n = len;
+
+	if (offset != lseek(fd, offset, SEEK_SET)) {
+		perror("lseek()");
+		return 1;
+	}
+	if ((fp = fopen(filename, "r")) == NULL) {
+		perror("fopen()");
+		return 1;
+	}
+retry:
+	if ((buf = (u_int8_t *) malloc(size)) == NULL) {
+		fprintf(stderr, "%s: malloc(%#x) failed\n", __func__, size);
+		if (size != BUF_SIZE) {
+			size = BUF_SIZE;
+			fprintf(stderr, "%s: trying buffer size %#x\n", __func__, size);
+			goto retry;
+		}
+		perror("malloc()");
+		fclose(fp);
+		return 1;
+	}
+	do {
+		if (n <= size)
+			size = n;
+		if (fread(buf, size, 1, fp) != 1 || ferror(fp)) {
+			fprintf(stderr, "%s: fread, size %#x, n %#x\n", __func__, size, n);
+			perror("fread()");
+			free(buf);
+			fclose(fp);
+			return 1;
+		}
+		err = write(fd, buf, size);
+		if (err < 0) {
+			fprintf(stderr, "%s: write, size %#x, n %#x\n", __func__, size, n);
+			perror("write()");
+			free(buf);
+			fclose(fp);
+			return 1;
+		}
+		n -= size;
+	} while (n > 0);
+
+	if (buf != NULL)
+		free(buf);
+	fclose(fp);
+	printf("Copied %d bytes from %s to address 0x%.8"PRIxoff_t" in flash\n", len, filename, offset);
+	return 0;
+}
+
+int showinfo(int fd)
+{
+	int i, err, n;
+	struct mtd_info_user mtd;
+	static struct region_info_user region[1024];
+
+	err = getmeminfo(fd, &mtd);
+	if (err < 0) {
+		perror("MEMGETINFO");
+		return 1;
+	}
+
+	err = getregions(fd, region, &n);
+	if (err < 0) {
+		perror("MEMGETREGIONCOUNT");
+		return 1;
+	}
+
+	printf("mtd.type = ");
+	switch (mtd.type) {
+		case MTD_ABSENT:
+			printf("MTD_ABSENT");
+			break;
+		case MTD_RAM:
+			printf("MTD_RAM");
+			break;
+		case MTD_ROM:
+			printf("MTD_ROM");
+			break;
+		case MTD_NORFLASH:
+			printf("MTD_NORFLASH");
+			break;
+		case MTD_NANDFLASH:
+			printf("MTD_NANDFLASH");
+			break;
+		case MTD_MLCNANDFLASH:
+			printf("MTD_MLCNANDFLASH");
+			break;
+		case MTD_DATAFLASH:
+			printf("MTD_DATAFLASH");
+			break;
+		case MTD_UBIVOLUME:
+			printf("MTD_UBIVOLUME");
+		default:
+			printf("(unknown type - new MTD API maybe?)");
+	}
+
+	printf("\nmtd.flags = ");
+	if (mtd.flags == MTD_CAP_ROM)
+		printf("MTD_CAP_ROM");
+	else if (mtd.flags == MTD_CAP_RAM)
+		printf("MTD_CAP_RAM");
+	else if (mtd.flags == MTD_CAP_NORFLASH)
+		printf("MTD_CAP_NORFLASH");
+	else if (mtd.flags == MTD_CAP_NANDFLASH)
+		printf("MTD_CAP_NANDFLASH");
+	else if (mtd.flags == MTD_WRITEABLE)
+		printf("MTD_WRITEABLE");
+	else {
+		int first = 1;
+		static struct {
+			const char *name;
+			int value;
+		} flags[] =
+		{
+			{ "MTD_WRITEABLE", MTD_WRITEABLE },
+			{ "MTD_BIT_WRITEABLE", MTD_BIT_WRITEABLE },
+			{ "MTD_NO_ERASE", MTD_NO_ERASE },
+			{ "MTD_POWERUP_LOCK", MTD_POWERUP_LOCK },
+			{ NULL, -1 }
+		};
+		for (i = 0; flags[i].name != NULL; i++) {
+			if (mtd.flags & flags[i].value) {
+				if (first) {
+					printf("%s", flags[i].name);
+					first = 0;
+				} else {
+					printf(" | %s", flags[i].name);
+				}
+			}
+		}
+	}
+
+	printf("\nmtd.size = ");
+	printsize(mtd.size);
+
+	printf("\nmtd.erasesize = ");
+	printsize(mtd.erasesize);
+
+	printf("\nmtd.writesize = ");
+	printsize(mtd.writesize);
+
+	printf("\nmtd.oobsize = ");
+	printsize(mtd.oobsize);
+
+	printf("\nregions = %d\n\n", n);
+
+	for (i = 0; i < n; i++) {
+		printf("region[%d].offset = 0x%.8x\n"
+				"region[%d].erasesize = ",
+				i, region[i].offset, i);
+		printsize(region[i].erasesize);
+		printf("\nregion[%d].numblocks = %d\n"
+				"region[%d].regionindex = %d\n",
+				i, region[i].numblocks,
+				i, region[i].regionindex);
+	}
+	return 0;
+}
+
+void showusage(void)
+{
+	fprintf(stderr, "usage: %1$s info <device>\n"
+			"       %1$s read <device> <offset> <len> <dest-filename>\n"
+			"       %1$s write <device> <offset> <len> <source-filename>\n"
+			"       %1$s erase <device> <offset> <len>\n",
+			PROGRAM_NAME);
+	exit(EXIT_FAILURE);
+}
+
+int main(int argc, char *argv[])
+{
+	int err = 0, fd;
+	int open_flag;
+
+	enum {
+		OPT_INFO,
+		OPT_READ,
+		OPT_WRITE,
+		OPT_ERASE
+	} option = OPT_INFO;
+
+	/* parse command-line options */
+	if (argc == 3 && !strcmp(argv[1], "info"))
+		option = OPT_INFO;
+	else if (argc == 6 && !strcmp(argv[1], "read"))
+		option = OPT_READ;
+	else if (argc == 6 && !strcmp(argv[1], "write"))
+		option = OPT_WRITE;
+	else if (argc == 5 && !strcmp(argv[1], "erase"))
+		option = OPT_ERASE;
+	else
+		showusage();
+
+	/* open device */
+	open_flag = (option == OPT_INFO || option == OPT_READ) ? O_RDONLY : O_RDWR;
+	if ((fd = open(argv[2], O_SYNC | open_flag)) < 0)
+		errmsg_die("open()");
+
+	switch (option) {
+		case OPT_INFO:
+			showinfo(fd);
+			break;
+		case OPT_READ:
+			err = flash_to_file(fd, strtoll(argv[3], NULL, 0), strtoul(argv[4], NULL, 0), argv[5]);
+			break;
+		case OPT_WRITE:
+			err = file_to_flash(fd, strtoll(argv[3], NULL, 0), strtoul(argv[4], NULL, 0), argv[5]);
+			break;
+		case OPT_ERASE:
+			err = erase_flash(fd, strtoul(argv[3], NULL, 0), strtoul(argv[4], NULL, 0));
+			break;
+	}
+
+	/* close device */
+	if (close(fd) < 0)
+		errmsg_die("close()");
+
+	return err;
+}
diff --git a/misc-utils/mtdpart.c b/misc-utils/mtdpart.c
new file mode 100644
index 0000000..0016e34
--- /dev/null
+++ b/misc-utils/mtdpart.c
@@ -0,0 +1,194 @@
+/*
+ *  mtdpart.c
+ *
+ *  Copyright 2015 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Overview:
+ *   This utility adds or removes a partition from an MTD device.
+ */
+
+#define PROGRAM_NAME "mtdpart"
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <linux/blkpg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "common.h"
+
+static void display_help(int status)
+{
+	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
+"Usage: %1$s add [OPTION] <MTD_DEVICE> <PART_NAME> <START> <SIZE>\n"
+"       %1$s del [OPTION] <MTD_DEVICE> <PART_NUMBER>\n"
+"Adds a partition to an MTD device, or remove an existing partition from it.\n"
+"\n"
+"  -h, --help    Display this help and exit\n"
+"      --version Output version information and exit\n"
+"\n"
+"START location and SIZE of the partition are in bytes. They should align on\n"
+"eraseblock size.\n",
+	PROGRAM_NAME
+	);
+	exit(status);
+}
+
+static void display_version(void)
+{
+	printf("%1$s " VERSION "\n"
+			"\n"
+			"%1$s comes with NO WARRANTY\n"
+			"to the extent permitted by law.\n"
+			"\n"
+			"You may redistribute copies of %1$s\n"
+			"under the terms of the GNU General Public Licence.\n"
+			"See the file `COPYING' for more information.\n",
+			PROGRAM_NAME);
+	exit(EXIT_SUCCESS);
+}
+
+/* Command arguments */
+
+typedef enum {
+	COMMAND_ADD,
+	COMMAND_DEL
+} command_type;
+
+static command_type		command;		/* add or del */
+static const char		*mtddev;		/* mtd device name */
+static const char		*part_name;		/* partition name */
+static int			part_no;		/* partition number */
+static long long		start_addr;		/* start address */
+static long long		length;			/* partition size */
+
+static void process_options(int argc, char * const argv[])
+{
+	int error = 0;
+
+	for (;;) {
+		int option_index = 0;
+		static const char short_options[] = "h";
+		static const struct option long_options[] = {
+			{"version", no_argument, 0, 0},
+			{"help", no_argument, 0, 'h'},
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF) {
+			break;
+		}
+
+		switch (c) {
+			case 0:
+				display_version();
+				break;
+			case 'h':
+				display_help(EXIT_SUCCESS);
+				break;
+			case '?':
+				error++;
+				break;
+		}
+	}
+
+	if ((argc - optind) < 3 || error)
+		display_help(EXIT_FAILURE);
+
+	const char *s_command = argv[optind++];
+	mtddev = argv[optind++];
+
+	if (strcmp(s_command, "del") == 0 && (argc - optind) == 1) {
+		const char *s_part_no = argv[optind++];
+
+		long tmp = simple_strtol(s_part_no, &error);
+		if (tmp < 0)
+		       errmsg_die("Can't specify negative partition number: %ld",
+				  tmp);
+		if (tmp > INT_MAX)
+		       errmsg_die("Partition number exceeds INT_MAX: %ld",
+				  tmp);
+
+		part_no = tmp;
+		command = COMMAND_DEL;
+	} else if (strcmp(s_command, "add") == 0 && (argc - optind) == 3) {
+		const char *s_start;
+		const char *s_length;
+
+		part_name = argv[optind++];
+		s_start = argv[optind++];
+		s_length = argv[optind++];
+
+		if (strlen(part_name) >= BLKPG_DEVNAMELTH)
+			errmsg_die("Partition name (%s) should be less than %d characters",
+				   part_name, BLKPG_DEVNAMELTH);
+
+		start_addr = simple_strtoll(s_start, &error);
+		if (start_addr < 0)
+		       errmsg_die("Can't specify negative start offset: %lld",
+				  start_addr);
+
+		length = simple_strtoll(s_length, &error);
+		if (length < 0)
+		       errmsg_die("Can't specify negative length: %lld",
+				  length);
+
+		command = COMMAND_ADD;
+	} else
+		display_help(EXIT_FAILURE);
+
+	if (error)
+		display_help(EXIT_FAILURE);
+}
+
+
+int main(int argc, char * const argv[])
+{
+	int fd;
+	struct blkpg_partition part;
+	struct blkpg_ioctl_arg arg;
+
+	process_options(argc, argv);
+
+	fd = open(mtddev, O_RDWR | O_CLOEXEC);
+	if (fd == -1)
+		sys_errmsg_die("Cannot open %s", mtddev);
+
+	memset(&part, 0, sizeof(part));
+
+	memset(&arg, 0, sizeof(arg));
+	arg.datalen = sizeof(part);
+	arg.data = ∂
+
+	switch (command) {
+		case COMMAND_ADD:
+			part.start = start_addr;
+			part.length = length;
+			strncpy(part.devname, part_name, sizeof(part.devname));
+			arg.op = BLKPG_ADD_PARTITION;
+			break;
+		case COMMAND_DEL:
+			part.pno = part_no;
+			arg.op = BLKPG_DEL_PARTITION;
+			break;
+	}
+
+	if (ioctl(fd, BLKPG, &arg))
+		sys_errmsg_die("Failed to issue BLKPG ioctl");
+
+	close(fd);
+
+	/* Exit happy */
+	return EXIT_SUCCESS;
+}
diff --git a/misc-utils/recv_image.c b/misc-utils/recv_image.c
new file mode 100644
index 0000000..0093831
--- /dev/null
+++ b/misc-utils/recv_image.c
@@ -0,0 +1,484 @@
+
+#define PROGRAM_NAME "recv_image"
+#define _XOPEN_SOURCE 500
+#define _BSD_SOURCE	/* struct ip_mreq */
+
+#include <errno.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <crc32.h>
+#include "mtd/mtd-user.h"
+#include "mcast_image.h"
+
+#include "common.h"
+
+#define WBUF_SIZE 4096
+struct eraseblock {
+	uint32_t flash_offset;
+	unsigned char wbuf[WBUF_SIZE];
+	int wbuf_ofs;
+	int nr_pkts;
+	int *pkt_indices;
+	uint32_t crc;
+};
+
+int main(int argc, char **argv)
+{
+	struct addrinfo *ai;
+	struct addrinfo hints;
+	struct addrinfo *runp;
+	int ret;
+	int sock;
+	ssize_t len;
+	int flfd;
+	struct mtd_info_user meminfo;
+	unsigned char *eb_buf, *decode_buf, **src_pkts;
+	int nr_blocks = 0;
+	int pkts_per_block;
+	int block_nr = -1;
+	uint32_t image_crc = 0;
+	int total_pkts = 0;
+	int ignored_pkts = 0;
+	loff_t mtdoffset = 0;
+	int badcrcs = 0;
+	int duplicates = 0;
+	int file_mode = 0;
+	struct fec_parms *fec = NULL;
+	int i;
+	struct eraseblock *eraseblocks = NULL;
+	uint32_t start_seq = 0;
+	struct timeval start, now;
+	unsigned long fec_time = 0, flash_time = 0, crc_time = 0,
+		rflash_time = 0, erase_time = 0, net_time = 0;
+
+	if (argc != 4) {
+		fprintf(stderr, "usage: %s <host> <port> <mtddev>\n",
+			PROGRAM_NAME);
+		exit(1);
+	}
+	/* Open the device */
+	flfd = open(argv[3], O_RDWR);
+
+	if (flfd >= 0) {
+		/* Fill in MTD device capability structure */
+		if (ioctl(flfd, MEMGETINFO, &meminfo) != 0) {
+			perror("MEMGETINFO");
+			close(flfd);
+			flfd = -1;
+		} else {
+			printf("Receive to MTD device %s with erasesize %d\n",
+			       argv[3], meminfo.erasesize);
+		}
+	}
+	if (flfd == -1) {
+		/* Try again, as if it's a file */
+		flfd = open(argv[3], O_CREAT|O_TRUNC|O_RDWR, 0644);
+		if (flfd < 0) {
+			perror("open");
+			exit(1);
+		}
+		meminfo.erasesize = 131072;
+		file_mode = 1;
+		printf("Receive to file %s with (assumed) erasesize %d\n",
+		       argv[3], meminfo.erasesize);
+	}
+
+	pkts_per_block = (meminfo.erasesize + PKT_SIZE - 1) / PKT_SIZE;
+
+	eb_buf = malloc(pkts_per_block * PKT_SIZE);
+	decode_buf = malloc(pkts_per_block * PKT_SIZE);
+	if (!eb_buf && !decode_buf) {
+		fprintf(stderr, "No memory for eraseblock buffer\n");
+		exit(1);
+	}
+	src_pkts = malloc(sizeof(unsigned char *) * pkts_per_block);
+	if (!src_pkts) {
+		fprintf(stderr, "No memory for decode packet pointers\n");
+		exit(1);
+	}
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags = AI_ADDRCONFIG;
+	hints.ai_socktype = SOCK_DGRAM;
+
+	ret = getaddrinfo(argv[1], argv[2], &hints, &ai);
+	if (ret) {
+		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
+		exit(1);
+	}
+	runp = ai;
+	for (runp = ai; runp; runp = runp->ai_next) {
+		sock = socket(runp->ai_family, runp->ai_socktype,
+			      runp->ai_protocol);
+		if (sock == -1) {
+			perror("socket");
+			continue;
+		}
+		if (runp->ai_family == AF_INET &&
+		    IN_MULTICAST( ntohl(((struct sockaddr_in *)runp->ai_addr)->sin_addr.s_addr))) {
+			struct ip_mreq rq;
+			rq.imr_multiaddr = ((struct sockaddr_in *)runp->ai_addr)->sin_addr;
+			rq.imr_interface.s_addr = INADDR_ANY;
+			if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &rq, sizeof(rq))) {
+				perror("IP_ADD_MEMBERSHIP");
+				close(sock);
+				continue;
+			}
+
+		} else if (runp->ai_family == AF_INET6 &&
+			   ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr.s6_addr[0] == 0xff) {
+			struct ipv6_mreq rq;
+			rq.ipv6mr_multiaddr =  ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr;
+			rq.ipv6mr_interface = 0;
+			if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &rq, sizeof(rq))) {
+				perror("IPV6_ADD_MEMBERSHIP");
+				close(sock);
+				continue;
+			}
+		}
+		if (bind(sock, runp->ai_addr, runp->ai_addrlen)) {
+			perror("bind");
+			close(sock);
+			continue;
+		}
+		break;
+	}
+	if (!runp)
+		exit(1);
+
+	while (1) {
+		struct image_pkt thispkt;
+
+		len = read(sock, &thispkt, sizeof(thispkt));
+
+		if (len < 0) {
+			perror("read socket");
+			break;
+		}
+		if (len < sizeof(thispkt)) {
+			fprintf(stderr, "Wrong length %zd bytes (expected %zu)\n",
+				len, sizeof(thispkt));
+			continue;
+		}
+		if (!eraseblocks) {
+			image_crc = thispkt.hdr.totcrc;
+			start_seq = ntohl(thispkt.hdr.pkt_sequence);
+
+			if (meminfo.erasesize != ntohl(thispkt.hdr.blocksize)) {
+				fprintf(stderr, "Erasesize mismatch (0x%x not 0x%x)\n",
+					ntohl(thispkt.hdr.blocksize), meminfo.erasesize);
+				exit(1);
+			}
+			nr_blocks = ntohl(thispkt.hdr.nr_blocks);
+
+			fec = fec_new(pkts_per_block, ntohs(thispkt.hdr.nr_pkts));
+
+			eraseblocks = malloc(nr_blocks * sizeof(*eraseblocks));
+			if (!eraseblocks) {
+				fprintf(stderr, "No memory for block map\n");
+				exit(1);
+			}
+			for (i = 0; i < nr_blocks; i++) {
+				eraseblocks[i].pkt_indices = malloc(sizeof(int) * pkts_per_block);
+				if (!eraseblocks[i].pkt_indices) {
+					fprintf(stderr, "Failed to allocate packet indices\n");
+					exit(1);
+				}
+				eraseblocks[i].nr_pkts = 0;
+				if (!file_mode) {
+					if (mtdoffset >= meminfo.size) {
+						fprintf(stderr, "Run out of space on flash\n");
+						exit(1);
+					}
+#if 1 /* Deliberately use bad blocks... test write failures */
+					while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
+						printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
+						mtdoffset += meminfo.erasesize;
+					}
+#endif
+				}
+				eraseblocks[i].flash_offset = mtdoffset;
+				mtdoffset += meminfo.erasesize;
+				eraseblocks[i].wbuf_ofs = 0;
+			}
+			gettimeofday(&start, NULL);
+		}
+		if (image_crc != thispkt.hdr.totcrc) {
+			fprintf(stderr, "\nImage CRC changed from 0x%x to 0x%x. Aborting\n",
+				ntohl(image_crc), ntohl(thispkt.hdr.totcrc));
+			exit(1);
+		}
+
+		block_nr = ntohl(thispkt.hdr.block_nr);
+		if (block_nr >= nr_blocks) {
+			fprintf(stderr, "\nErroneous block_nr %d (> %d)\n",
+				block_nr, nr_blocks);
+			exit(1);
+		}
+		for (i=0; i<eraseblocks[block_nr].nr_pkts; i++) {
+			if (eraseblocks[block_nr].pkt_indices[i] == ntohs(thispkt.hdr.pkt_nr)) {
+//				printf("Discarding duplicate packet at %08x pkt %d\n",
+//				       block_nr * meminfo.erasesize, eraseblocks[block_nr].pkt_indices[i]);
+				duplicates++;
+				break;
+			}
+		}
+		if (i < eraseblocks[block_nr].nr_pkts) {
+			continue;
+		}
+
+		if (eraseblocks[block_nr].nr_pkts >= pkts_per_block) {
+			/* We have a block which we didn't really need */
+			eraseblocks[block_nr].nr_pkts++;
+			ignored_pkts++;
+			continue;
+		}
+
+		if (mtd_crc32(-1, thispkt.data, PKT_SIZE) != ntohl(thispkt.hdr.thiscrc)) {
+			printf("\nDiscard %08x pkt %d with bad CRC (%08x not %08x)\n",
+			       block_nr * meminfo.erasesize, ntohs(thispkt.hdr.pkt_nr),
+			       mtd_crc32(-1, thispkt.data, PKT_SIZE),
+			       ntohl(thispkt.hdr.thiscrc));
+			badcrcs++;
+			continue;
+		}
+	pkt_again:
+		eraseblocks[block_nr].pkt_indices[eraseblocks[block_nr].nr_pkts++] =
+			ntohs(thispkt.hdr.pkt_nr);
+		total_pkts++;
+		if (!(total_pkts % 50) || total_pkts == pkts_per_block * nr_blocks) {
+			uint32_t pkts_sent = ntohl(thispkt.hdr.pkt_sequence) - start_seq + 1;
+			long time_msec;
+			gettimeofday(&now, NULL);
+
+			time_msec = ((now.tv_usec - start.tv_usec) / 1000) +
+				(now.tv_sec - start.tv_sec) * 1000;
+
+			printf("\rReceived %d/%d (%d%%) in %lds @%ldKiB/s, %d lost (%d%%), %d dup/xs    ",
+			       total_pkts, nr_blocks * pkts_per_block,
+			       total_pkts * 100 / nr_blocks / pkts_per_block,
+			       time_msec / 1000,
+			       total_pkts * PKT_SIZE / 1024 * 1000 / time_msec,
+			       pkts_sent - total_pkts - duplicates - ignored_pkts,
+			       (pkts_sent - total_pkts - duplicates - ignored_pkts) * 100 / pkts_sent,
+			       duplicates + ignored_pkts);
+			fflush(stdout);
+		}
+
+		if (eraseblocks[block_nr].wbuf_ofs + PKT_SIZE < WBUF_SIZE) {
+			/* New packet doesn't full the wbuf */
+			memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
+			       thispkt.data, PKT_SIZE);
+			eraseblocks[block_nr].wbuf_ofs += PKT_SIZE;
+		} else {
+			int fits = WBUF_SIZE - eraseblocks[block_nr].wbuf_ofs;
+			ssize_t wrotelen;
+			static int faked = 1;
+
+			memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
+			       thispkt.data, fits);
+			wrotelen = pwrite(flfd, eraseblocks[block_nr].wbuf, WBUF_SIZE,
+					  eraseblocks[block_nr].flash_offset);
+
+			if (wrotelen < WBUF_SIZE || (block_nr == 5 && eraseblocks[block_nr].nr_pkts == 5 && !faked)) {
+				faked = 1;
+				if (wrotelen < 0)
+					perror("\npacket write");
+				else
+					fprintf(stderr, "\nshort write of packet wbuf\n");
+
+				if (!file_mode) {
+					struct erase_info_user erase;
+					/* FIXME: Perhaps we should store pkt crcs and try
+					   to recover data from the offending eraseblock */
+
+					/* We have increased nr_pkts but not yet flash_offset */
+					erase.start = eraseblocks[block_nr].flash_offset &
+						~(meminfo.erasesize - 1);
+					erase.length = meminfo.erasesize;
+
+					printf("Will erase at %08x len %08x (bad write was at %08x)\n",
+					       erase.start, erase.length, eraseblocks[block_nr].flash_offset);
+					if (ioctl(flfd, MEMERASE, &erase)) {
+						perror("MEMERASE");
+						exit(1);
+					}
+					if (mtdoffset >= meminfo.size) {
+						fprintf(stderr, "Run out of space on flash\n");
+						exit(1);
+					}
+					while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
+						printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
+						mtdoffset += meminfo.erasesize;
+						if (mtdoffset >= meminfo.size) {
+							fprintf(stderr, "Run out of space on flash\n");
+							exit(1);
+						}
+					}
+					eraseblocks[block_nr].flash_offset = mtdoffset;
+					printf("Block #%d will now be at %08lx\n", block_nr, (long)mtdoffset);
+					total_pkts -= eraseblocks[block_nr].nr_pkts;
+					eraseblocks[block_nr].nr_pkts = 0;
+					eraseblocks[block_nr].wbuf_ofs = 0;
+					mtdoffset += meminfo.erasesize;
+					goto pkt_again;
+				}
+				else /* Usually nothing we can do in file mode */
+					exit(1);
+			}
+			eraseblocks[block_nr].flash_offset += WBUF_SIZE;
+			/* Copy the remainder into the wbuf */
+			memcpy(eraseblocks[block_nr].wbuf, &thispkt.data[fits], PKT_SIZE - fits);
+			eraseblocks[block_nr].wbuf_ofs = PKT_SIZE - fits;
+		}
+
+		if (eraseblocks[block_nr].nr_pkts == pkts_per_block) {
+			eraseblocks[block_nr].crc = ntohl(thispkt.hdr.block_crc);
+
+			if (total_pkts == nr_blocks * pkts_per_block)
+				break;
+		}
+	}
+	printf("\n");
+	gettimeofday(&now, NULL);
+	net_time = (now.tv_usec - start.tv_usec) / 1000;
+	net_time += (now.tv_sec - start.tv_sec) * 1000;
+	close(sock);
+	for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
+		ssize_t rwlen;
+		gettimeofday(&start, NULL);
+		eraseblocks[block_nr].flash_offset -= meminfo.erasesize;
+		rwlen = pread(flfd, eb_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
+
+		gettimeofday(&now, NULL);
+		rflash_time += (now.tv_usec - start.tv_usec) / 1000;
+		rflash_time += (now.tv_sec - start.tv_sec) * 1000;
+		if (rwlen < 0) {
+			perror("read");
+			/* Argh. Perhaps we could go back and try again, but if the flash is
+			   going to fail to read back what we write to it, and the whole point
+			   in this program is to write to it, what's the point? */
+			fprintf(stderr, "Packets we wrote to flash seem to be unreadable. Aborting\n");
+			exit(1);
+		}
+
+		memcpy(eb_buf + meminfo.erasesize, eraseblocks[block_nr].wbuf,
+		       eraseblocks[block_nr].wbuf_ofs);
+
+		for (i=0; i < pkts_per_block; i++)
+			src_pkts[i] = &eb_buf[i * PKT_SIZE];
+
+		gettimeofday(&start, NULL);
+		if (fec_decode(fec, src_pkts, eraseblocks[block_nr].pkt_indices, PKT_SIZE)) {
+			/* Eep. This cannot happen */
+			printf("The world is broken. fec_decode() returned error\n");
+			exit(1);
+		}
+		gettimeofday(&now, NULL);
+		fec_time += (now.tv_usec - start.tv_usec) / 1000;
+		fec_time += (now.tv_sec - start.tv_sec) * 1000;
+
+		for (i=0; i < pkts_per_block; i++)
+			memcpy(&decode_buf[i*PKT_SIZE], src_pkts[i], PKT_SIZE);
+
+		/* Paranoia */
+		gettimeofday(&start, NULL);
+		if (mtd_crc32(-1, decode_buf, meminfo.erasesize) != eraseblocks[block_nr].crc) {
+			printf("\nCRC mismatch for block #%d: want %08x got %08x\n",
+			       block_nr, eraseblocks[block_nr].crc,
+			       mtd_crc32(-1, decode_buf, meminfo.erasesize));
+			exit(1);
+		}
+		gettimeofday(&now, NULL);
+		crc_time += (now.tv_usec - start.tv_usec) / 1000;
+		crc_time += (now.tv_sec - start.tv_sec) * 1000;
+		start = now;
+
+		if (!file_mode) {
+			struct erase_info_user erase;
+
+			erase.start = eraseblocks[block_nr].flash_offset;
+			erase.length = meminfo.erasesize;
+
+			printf("\rErasing block at %08x...", erase.start);
+
+			if (ioctl(flfd, MEMERASE, &erase)) {
+				perror("MEMERASE");
+				/* This block has dirty data on it. If the erase failed, we're screwed */
+				fprintf(stderr, "Erase to clean FEC data from flash failed. Aborting\n");
+				exit(1);
+			}
+			gettimeofday(&now, NULL);
+			erase_time += (now.tv_usec - start.tv_usec) / 1000;
+			erase_time += (now.tv_sec - start.tv_sec) * 1000;
+			start = now;
+		}
+		else printf("\r");
+	write_again:
+		rwlen = pwrite(flfd, decode_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
+		if (rwlen < meminfo.erasesize) {
+			if (rwlen < 0) {
+				perror("\ndecoded data write");
+			} else
+				fprintf(stderr, "\nshort write of decoded data\n");
+
+			if (!file_mode) {
+				struct erase_info_user erase;
+				erase.start = eraseblocks[block_nr].flash_offset;
+				erase.length = meminfo.erasesize;
+
+				printf("Erasing failed block at %08x\n",
+				       eraseblocks[block_nr].flash_offset);
+
+				if (ioctl(flfd, MEMERASE, &erase)) {
+					perror("MEMERASE");
+					exit(1);
+				}
+				if (mtdoffset >= meminfo.size) {
+					fprintf(stderr, "Run out of space on flash\n");
+					exit(1);
+				}
+				while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
+					printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
+					mtdoffset += meminfo.erasesize;
+					if (mtdoffset >= meminfo.size) {
+						fprintf(stderr, "Run out of space on flash\n");
+						exit(1);
+					}
+				}
+				printf("Will try again at %08lx...", (long)mtdoffset);
+				eraseblocks[block_nr].flash_offset = mtdoffset;
+
+				goto write_again;
+			}
+			else /* Usually nothing we can do in file mode */
+				exit(1);
+		}
+		gettimeofday(&now, NULL);
+		flash_time += (now.tv_usec - start.tv_usec) / 1000;
+		flash_time += (now.tv_sec - start.tv_sec) * 1000;
+
+		printf("wrote image block %08x (%d pkts)    ",
+		       block_nr * meminfo.erasesize, eraseblocks[block_nr].nr_pkts);
+		fflush(stdout);
+	}
+	close(flfd);
+	printf("Net rx   %ld.%03lds\n", net_time / 1000, net_time % 1000);
+	printf("flash rd %ld.%03lds\n", rflash_time / 1000, rflash_time % 1000);
+	printf("FEC time %ld.%03lds\n", fec_time / 1000, fec_time % 1000);
+	printf("CRC time %ld.%03lds\n", crc_time / 1000, crc_time % 1000);
+	printf("flash wr %ld.%03lds\n", flash_time / 1000, flash_time % 1000);
+	printf("flash er %ld.%03lds\n", erase_time / 1000, erase_time % 1000);
+
+	return 0;
+}
diff --git a/misc-utils/serve_image.c b/misc-utils/serve_image.c
new file mode 100644
index 0000000..d3794ec
--- /dev/null
+++ b/misc-utils/serve_image.c
@@ -0,0 +1,300 @@
+#define PROGRAM_NAME "serve_image"
+#define _POSIX_C_SOURCE 199309
+
+#include <time.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <crc32.h>
+#include <inttypes.h>
+
+#include "mcast_image.h"
+
+int tx_rate = 80000;
+int pkt_delay;
+
+#undef RANDOMDROP
+
+int main(int argc, char **argv)
+{
+	struct addrinfo *ai;
+	struct addrinfo hints;
+	struct addrinfo *runp;
+	int ret;
+	int sock;
+	struct image_pkt pktbuf;
+	int rfd;
+	struct stat st;
+	int writeerrors = 0;
+	uint32_t erasesize;
+	unsigned char *image, *blockptr = NULL;
+	uint32_t block_nr, pkt_nr;
+	int nr_blocks;
+	struct timeval then, now, nextpkt;
+	long time_msecs;
+	int pkts_per_block;
+	int total_pkts_per_block;
+	struct fec_parms *fec;
+	unsigned char *last_block;
+	uint32_t *block_crcs;
+	long tosleep;
+	uint32_t sequence = 0;
+
+	if (argc == 6) {
+		tx_rate = atol(argv[5]) * 1024;
+		if (tx_rate < PKT_SIZE || tx_rate > 20000000) {
+			fprintf(stderr, "Bogus TX rate %d KiB/s\n", tx_rate);
+			exit(1);
+		}
+		argc = 5;
+	}
+	if (argc != 5) {
+		fprintf(stderr, "usage: %s <host> <port> <image> <erasesize> [<tx_rate>]\n",
+			PROGRAM_NAME);
+		exit(1);
+	}
+	pkt_delay = (sizeof(pktbuf) * 1000000) / tx_rate;
+	printf("Inter-packet delay (avg): %dµs\n", pkt_delay);
+	printf("Transmit rate: %d KiB/s\n", tx_rate / 1024);
+
+	erasesize = atol(argv[4]);
+	if (!erasesize) {
+		fprintf(stderr, "erasesize cannot be zero\n");
+		exit(1);
+	}
+
+	pkts_per_block = (erasesize + PKT_SIZE - 1) / PKT_SIZE;
+	total_pkts_per_block = pkts_per_block * 3 / 2;
+
+	/* We have to pad it with zeroes, so can't use it in-place */
+	last_block = malloc(pkts_per_block * PKT_SIZE);
+	if (!last_block) {
+		fprintf(stderr, "Failed to allocate last-block buffer\n");
+		exit(1);
+	}
+
+	fec = fec_new(pkts_per_block, total_pkts_per_block);
+	if (!fec) {
+		fprintf(stderr, "Error initialising FEC\n");
+		exit(1);
+	}
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags = AI_ADDRCONFIG;
+	hints.ai_socktype = SOCK_DGRAM;
+
+	ret = getaddrinfo(argv[1], argv[2], &hints, &ai);
+	if (ret) {
+		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
+		exit(1);
+	}
+	runp = ai;
+	for (runp = ai; runp; runp = runp->ai_next) {
+		sock = socket(runp->ai_family, runp->ai_socktype,
+			      runp->ai_protocol);
+		if (sock == -1) {
+			perror("socket");
+			continue;
+		}
+		if (connect(sock, runp->ai_addr, runp->ai_addrlen) == 0)
+			break;
+		perror("connect");
+		close(sock);
+	}
+	if (!runp)
+		exit(1);
+
+	rfd = open(argv[3], O_RDONLY);
+	if (rfd < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	if (fstat(rfd, &st)) {
+		perror("fstat");
+		exit(1);
+	}
+
+	if (st.st_size % erasesize) {
+		fprintf(stderr, "Image size %" PRIu64 " bytes is not a multiple of erasesize %d bytes\n",
+				st.st_size, erasesize);
+		exit(1);
+	}
+	image = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, rfd, 0);
+	if (image == MAP_FAILED) {
+		perror("mmap");
+		exit(1);
+	}
+
+	nr_blocks = st.st_size / erasesize;
+
+	block_crcs = malloc(nr_blocks * sizeof(uint32_t));
+	if (!block_crcs) {
+		fprintf(stderr, "Failed to allocate memory for CRCs\n");
+		exit(1);
+	}
+
+	memcpy(last_block, image + (nr_blocks - 1) * erasesize, erasesize);
+	memset(last_block + erasesize, 0, (PKT_SIZE * pkts_per_block) - erasesize);
+
+	printf("Checking CRC....");
+	fflush(stdout);
+
+	pktbuf.hdr.resend = 0;
+	pktbuf.hdr.totcrc = htonl(mtd_crc32(-1, image, st.st_size));
+	pktbuf.hdr.nr_blocks = htonl(nr_blocks);
+	pktbuf.hdr.blocksize = htonl(erasesize);
+	pktbuf.hdr.thislen = htonl(PKT_SIZE);
+	pktbuf.hdr.nr_pkts = htons(total_pkts_per_block);
+
+	printf("%08x\n", ntohl(pktbuf.hdr.totcrc));
+	printf("Checking block CRCs....");
+	fflush(stdout);
+	for (block_nr=0; block_nr < nr_blocks; block_nr++) {
+		printf("\rChecking block CRCS.... %d/%d",
+		       block_nr + 1, nr_blocks);
+		fflush(stdout);
+		block_crcs[block_nr] = mtd_crc32(-1, image + (block_nr * erasesize), erasesize);
+	}
+
+	printf("\nImage size %ld KiB (0x%08lx). %d blocks at %d pkts/block\n"
+	       "Estimated transmit time per cycle: %ds\n",
+	       (long)st.st_size / 1024, (long) st.st_size,
+	       nr_blocks, pkts_per_block,
+	       nr_blocks * pkts_per_block * pkt_delay / 1000000);
+	gettimeofday(&then, NULL);
+	nextpkt = then;
+
+#ifdef RANDOMDROP
+	srand((unsigned)then.tv_usec);
+	printf("Random seed %u\n", (unsigned)then.tv_usec);
+#endif
+	while (1) for (pkt_nr=0; pkt_nr < total_pkts_per_block; pkt_nr++) {
+
+		if (blockptr && pkt_nr == 0) {
+			unsigned long amt_sent = total_pkts_per_block * nr_blocks * sizeof(pktbuf);
+			gettimeofday(&now, NULL);
+
+			time_msecs = (now.tv_sec - then.tv_sec) * 1000;
+			time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
+			printf("\n%ld KiB sent in %ldms (%ld KiB/s)\n",
+			       amt_sent / 1024, time_msecs,
+			       amt_sent / 1024 * 1000 / time_msecs);
+			then = now;
+		}
+
+		for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
+
+			int actualpkt;
+
+			/* Calculating the redundant FEC blocks is expensive;
+			   the first $pkts_per_block are cheap enough though
+			   because they're just copies. So alternate between
+			   simple and complex stuff, so that we don't start
+			   to choke and fail to keep up with the expected
+			   bitrate in the second half of the sequence */
+			if (block_nr & 1)
+				actualpkt = pkt_nr;
+			else
+				actualpkt = total_pkts_per_block - 1 - pkt_nr;
+
+			blockptr = image + (erasesize * block_nr);
+			if (block_nr == nr_blocks - 1)
+				blockptr = last_block;
+
+			fec_encode_linear(fec, blockptr, pktbuf.data, actualpkt, PKT_SIZE);
+
+			pktbuf.hdr.thiscrc = htonl(mtd_crc32(-1, pktbuf.data, PKT_SIZE));
+			pktbuf.hdr.block_crc = htonl(block_crcs[block_nr]);
+			pktbuf.hdr.block_nr = htonl(block_nr);
+			pktbuf.hdr.pkt_nr = htons(actualpkt);
+			pktbuf.hdr.pkt_sequence = htonl(sequence++);
+
+			printf("\rSending data block %08x packet %3d/%d",
+			       block_nr * erasesize,
+			       pkt_nr, total_pkts_per_block);
+
+			if (pkt_nr && !block_nr) {
+				unsigned long amt_sent = pkt_nr * nr_blocks * sizeof(pktbuf);
+
+				gettimeofday(&now, NULL);
+
+				time_msecs = (now.tv_sec - then.tv_sec) * 1000;
+				time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
+				printf("    (%ld KiB/s)    ",
+				       amt_sent / 1024 * 1000 / time_msecs);
+			}
+
+			fflush(stdout);
+
+#ifdef RANDOMDROP
+			if ((rand() % 1000) < 20) {
+				printf("\nDropping packet %d of block %08x\n", pkt_nr+1, block_nr * erasesize);
+				continue;
+			}
+#endif
+			gettimeofday(&now, NULL);
+#if 1
+			tosleep = nextpkt.tv_usec - now.tv_usec +
+				(1000000 * (nextpkt.tv_sec - now.tv_sec));
+
+			/* We need hrtimers for this to actually work */
+			if (tosleep > 0) {
+				struct timespec req;
+
+				req.tv_nsec = (tosleep % 1000000) * 1000;
+				req.tv_sec = tosleep / 1000000;
+
+				nanosleep(&req, NULL);
+			}
+#else
+			while (now.tv_sec < nextpkt.tv_sec ||
+				 (now.tv_sec == nextpkt.tv_sec &&
+				  now.tv_usec < nextpkt.tv_usec)) {
+				gettimeofday(&now, NULL);
+			}
+#endif
+			nextpkt.tv_usec += pkt_delay;
+			if (nextpkt.tv_usec >= 1000000) {
+				nextpkt.tv_sec += nextpkt.tv_usec / 1000000;
+				nextpkt.tv_usec %= 1000000;
+			}
+
+			/* If the time for the next packet has already
+			   passed (by some margin), then we've lost time
+			   Adjust our expected timings accordingly. If
+			   we're only a little way behind, don't slip yet */
+			if (now.tv_usec > (now.tv_usec + (5 * pkt_delay) +
+					1000000 * (nextpkt.tv_sec - now.tv_sec))) {
+				nextpkt = now;
+			}
+
+			if (write(sock, &pktbuf, sizeof(pktbuf)) < 0) {
+				perror("write");
+				writeerrors++;
+				if (writeerrors > 10) {
+					fprintf(stderr, "Too many consecutive write errors\n");
+					exit(1);
+				}
+			} else
+				writeerrors = 0;
+
+
+
+		}
+	}
+	munmap(image, st.st_size);
+	close(rfd);
+	close(sock);
+	return 0;
+}
diff --git a/mkfs.jffs2.1 b/mkfs.jffs2.1
deleted file mode 100644
index 7c57ddc..0000000
--- a/mkfs.jffs2.1
+++ /dev/null
@@ -1,268 +0,0 @@
-.TH MKFS.JFFS2 1
-.SH NAME
-mkfs.jffs2 \- Create a JFFS2 file system image from directory
-.SH SYNOPSIS
-.B mkfs.jffs2
-[
-.B -p,--pad[=SIZE]
-]
-[
-.B -r,-d,--root
-.I directory
-]
-[
-.B -s,--pagesize=SIZE
-]
-[
-.B -e,--eraseblock=SIZE
-]
-[
-.B -c,--cleanmarker=SIZE
-]
-[
-.B -n,--no-cleanmarkers
-]
-[
-.B -o,--output
-.I image.jffs2
-]
-[
-.B -l,--little-endian
-]
-[
-.B -b,--big-endian
-]
-[
-.B -D,--devtable=FILE
-]
-[
-.B -f,--faketime
-]
-[
-.B -q,--squash
-]
-[
-.B -U,--squash-uids
-]
-[
-.B -P,--squash-perms
-]
-[
-.B --with-xattr
-]
-[
-.B --with-selinux
-]
-[
-.B --with-posix-acl
-]
-[
-.B -m,--compression-mode=MODE
-]
-[
-.B -x,--disable-compressor=NAME
-]
-[
-.B -X,--enable-compressor=NAME
-]
-[
-.B -y,--compressor-priority=PRIORITY:NAME
-]
-[
-.B -L,--list-compressors
-]
-[
-.B -t,--test-compression
-]
-[
-.B -h,--help
-]
-[
-.B -v,--verbose
-]
-[
-.B -V,--version
-]
-[
-.B -i,--incremental
-.I image.jffs2
-]
-
-.SH DESCRIPTION
-The program
-.B mkfs.jffs2
-creates a JFFS2 (Second Journalling Flash File System) file system
-image and writes the resulting image to the file specified by the
-.B -o
-option or by default to the standard output, unless the standard
-output is a terminal device in which case mkfs.jffs2 will abort.
-
-The file system image is created using the files and directories
-contained in the directory specified by the option
-.B -r
-or the present directory, if the
-.B -r
-option is not specified.
-
-Each block of the files to be placed into the file system image
-are compressed using one of the available compressors depending
-on the selected compression mode.
-
-File systems are created with the same endianness as the host,
-unless the
-.B -b
-or
-.B -l
-options are specified.  JFFS2 driver in the 2.4 Linux kernel only
-supported images having the same endianness as the CPU. As of 2.5.48,
-the kernel can be changed with a #define to accept images of the
-non-native endianness. Full bi-endian support in the kernel is not
-planned.
-
-It is unlikely that JFFS2 images are useful except in conjuction
-with the MTD (Memory Technology Device) drivers in the Linux
-kernel, since the JFFS2 file system driver in the kernel requires
-MTD devices.
-.SH OPTIONS
-Options that take SIZE arguments can be specified as either
-decimal (e.g., 65536), octal (0200000), or hexidecimal (0x1000).
-.TP
-.B -p, --pad[=SIZE]
-Pad output to SIZE bytes with 0xFF.  If SIZE is not specified,
-the output is padded to the end of the final erase block.
-.TP
-.B -r, -d, --root=DIR
-Build file system from directory DIR.  The default is the current
-directory.
-.TP
-.B -s, --pagesize=SIZE
-Use page size SIZE.  The default is 4 KiB.  This size is the
-maximum size of a data node.  Set according to target system's memory
-management page size (NOTE: this is NOT related to NAND page size).
-.TP
-.B -e, --eraseblock=SIZE
-Use erase block size SIZE.  The default is 64 KiB.  If you use a erase
-block size different than the erase block size of the target MTD
-device, JFFS2 may not perform optimally. If the SIZE specified is
-below 4096, the units are assumed to be KiB.
-.TP
-.B -c, --cleanmarker=SIZE
-Write \'CLEANMARKER\' nodes with the size specified. It is not
-normally appropriate to specify a size other than the default 12
-bytes.
-.TP
-.B -n, --no-cleanmarkers
-Do not write \'CLEANMARKER\' nodes to the beginning of each erase
-block. This option can be useful for creating JFFS2 images for
-use on NAND flash, and for creating images which are to be used
-on a variety of hardware with differing eraseblock sizes.
-.TP
-.B -o, --output=FILE
-Write JFFS2 image to file FILE.  Default is the standard output.
-.TP
-.B -l, --little-endian
-Create a little-endian JFFS2 image.  Default is to make an image
-with the same endianness as the host.
-.TP
-.B -b, --big-endian
-Create a big-endian JFFS2 image.  Default is to make an image
-with the same endianness as the host.
-.TP
-.B -D, --devtable=FILE
-Use the named FILE as a device table file, for including devices and
-changing permissions in the created image when the user does not have
-appropriate permissions to create them on the file system used as
-source.
-.TP
-.B -f, --faketime
-Change all file timestamps to \'0\' for regression testing.
-.TP
-.B -q, --squash
-Squash permissions and owners, making all files be owned by root and
-removing write permission for \'group\' and \'other\'.
-.TP
-.B -U, --squash-uids
-Squash owners making all files be owned by root.
-.TP
-.B -P, --squash-perms
-Squash permissions, removing write permission for \'group\' and \'other\'.
-.TP
-.B --with-xattr
-Enables xattr, stuff all xattr entries into jffs2 image file.
-.TP
-.B --with-selinux
-Enables xattr, stuff only SELinux Labels into jffs2 image file.
-.TP
-.B --with-posix-acl
-Enable xattr, stuff only POSIX ACL entries into jffs2 image file.
-.TP
-.B -m, --compression-mode=MODE
-Set the default compression mode. The default mode is
-.B priority
-which tries the compressors in a predefinied order and chooses the first
-successful one. The alternatives are:
-.B none
-(mkfs will not compress) and
-.B size
-(mkfs will try all compressor and chooses the one which have the smallest result).
-.TP
-.B -x, --disable-compressor=NAME
-Disable a compressor. Use
-.B -L
-to see the list of the available compressors and their default states.
-.TP
-.B -X, --enable-compressor=NAME
-Enable a compressor. Use
-.B -L
-to see the list of the available compressors and their default states.
-.TP
-.B -y, --compressor-priority=PRIORITY:NAME
-Set the priority of a compressor. Use
-.B -L
-to see the list of the available compressors and their default priority.
-Priorities are used by priority compression mode.
-.TP
-.B -L, --list-compressors
-Show the list of the available compressors and their states.
-.TP
-.B -t, --test-compression
-Call decompress after every compress - and compare the result with the original data -, and
-some other check.
-.TP
-.B -h, --help
-Display help text.
-.TP
-.B -v, --verbose
-Verbose operation.
-.TP
-.B -V, --version
-Display version information.
-.TP
-.B -i, --incremental=FILE
-Generate an appendage image for FILE. If FILE is written to flash and flash
-is appended with the output, then it seems as if it was one thing.
-
-.SH LIMITATIONS
-The format and grammar of the device table file does not allow it to
-create symbolic links when the symbolic links are not already present
-in the root working directory.
-
-However, symbolic links may be specified in the device table file
-using the \fIl\fR type for the purposes of setting their permissions
-and ownership.
-.SH BUGS
-JFFS2 limits device major and minor numbers to 8 bits each.  Some
-consider this a bug.
-
-.B mkfs.jffs2
-does not properly handle hard links in the input directory structure.
-Currently, hard linked files will be expanded to multiple identical
-files in the output image.
-.SH AUTHORS
-David Woodhouse
-.br
-Manual page written by David Schleef <ds at schleef.org>
-.SH SEE ALSO
-.BR mkfs (8),
-.BR mkfs.jffs (1),
-.BR fakeroot (1)
diff --git a/mkfs.jffs2.c b/mkfs.jffs2.c
deleted file mode 100644
index f09c0b2..0000000
--- a/mkfs.jffs2.c
+++ /dev/null
@@ -1,1805 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Build a JFFS2 image in a file, from a given directory tree.
- *
- * Copyright 2001, 2002 Red Hat, Inc.
- *           2001 David A. Schleef <ds at lineo.com>
- *           2002 Axis Communications AB
- *           2001, 2002 Erik Andersen <andersen at codepoet.org>
- *           2004 University of Szeged, Hungary
- *           2006 KaiGai Kohei <kaigai at ak.jp.nec.com>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * 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
- *
- * Cross-endian support added by David Schleef <ds at schleef.org>.
- *
- * Major architectural rewrite by Erik Andersen <andersen at codepoet.org>
- * to allow support for making hard links (though hard links support is
- * not yet implemented), and for munging file permissions and ownership
- * on the fly using --faketime, --squash, --devtable.   And I plugged a
- * few memory leaks, adjusted the error handling and fixed some little
- * nits here and there.
- *
- * I also added a sample device table file.  See device_table.txt
- *  -Erik, September 2001
- *
- * Cleanmarkers support added by Axis Communications AB
- *
- * Rewritten again.  Cleanly separated host and target filsystem
- * activities (mainly so I can reuse all the host handling stuff as I
- * rewrite other mkfs utils).  Added a verbose option to list types
- * and attributes as files are added to the file system.  Major cleanup
- * and scrubbing of the code so it can be read, understood, and
- * modified by mere mortals.
- *
- *  -Erik, November 2002
- */
-
-#define PROGRAM_NAME "mkfs.jffs2"
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <libgen.h>
-#include <ctype.h>
-#include <time.h>
-#include <getopt.h>
-#ifndef WITHOUT_XATTR
-#include <sys/xattr.h>
-#include <sys/acl.h>
-#endif
-#include <byteswap.h>
-#include <crc32.h>
-#include <inttypes.h>
-
-#include "rbtree.h"
-#include "common.h"
-
-/* Do not use the weird XPG version of basename */
-#undef basename
-
-//#define DMALLOC
-//#define mkfs_debug_msg    errmsg
-#define mkfs_debug_msg(a...)	{ }
-
-#define PAD(x) (((x)+3)&~3)
-
-struct filesystem_entry {
-	char *name;					/* Name of this directory (think basename) */
-	char *path;					/* Path of this directory (think dirname) */
-	char *fullname;				/* Full name of this directory (i.e. path+name) */
-	char *hostname;				/* Full path to this file on the host filesystem */
-	uint32_t ino;				/* Inode number of this file in JFFS2 */
-	struct stat sb;				/* Stores directory permissions and whatnot */
-	char *link;					/* Target a symlink points to. */
-	struct filesystem_entry *parent;	/* Parent directory */
-	struct filesystem_entry *prev;	/* Only relevant to non-directories */
-	struct filesystem_entry *next;	/* Only relevant to non-directories */
-	struct filesystem_entry *files;	/* Only relevant to directories */
-	struct rb_node hardlink_rb;
-};
-
-struct rb_root hardlinks;
-static int out_fd = -1;
-static int in_fd = -1;
-static char default_rootdir[] = ".";
-static char *rootdir = default_rootdir;
-static int verbose = 0;
-static int squash_uids = 0;
-static int squash_perms = 0;
-static int fake_times = 0;
-int target_endian = __BYTE_ORDER;
-
-uint32_t find_hardlink(struct filesystem_entry *e)
-{
-	struct filesystem_entry *f;
-	struct rb_node **n = &hardlinks.rb_node;
-	struct rb_node *parent = NULL;
-
-	while (*n) {
-		parent = *n;
-		f = rb_entry(parent, struct filesystem_entry, hardlink_rb);
-
-		if ((f->sb.st_dev < e->sb.st_dev) ||
-		    (f->sb.st_dev == e->sb.st_dev &&
-		     f->sb.st_ino < e->sb.st_ino))
-			n = &parent->rb_left;
-		else if ((f->sb.st_dev > e->sb.st_dev) ||
-			 (f->sb.st_dev == e->sb.st_dev &&
-			  f->sb.st_ino > e->sb.st_ino)) {
-			n = &parent->rb_right;
-		} else
-			return f->ino;
-	}
-
-	rb_link_node(&e->hardlink_rb, parent, n);
-	rb_insert_color(&e->hardlink_rb, &hardlinks);
-	return 0;
-}
-
-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) {
-			sys_errmsg("%s:%s", PROGRAM_NAME, path);
-			return NULL;
-		}
-	}
-	while (bufsize < readsize + 1);
-
-	buf[readsize] = '\0';
-
-	return buf;
-}
-static FILE *xfopen(const char *path, const char *mode)
-{
-	FILE *fp;
-	if ((fp = fopen(path, mode)) == NULL)
-		sys_errmsg_die("%s", path);
-	return fp;
-}
-
-static struct filesystem_entry *find_filesystem_entry(
-		struct filesystem_entry *dir, char *fullname, uint32_t type)
-{
-	struct filesystem_entry *e = dir;
-
-	if (S_ISDIR(dir->sb.st_mode)) {
-		/* If this is the first call, and we actually want this
-		 * directory, then return it now */
-		if (strcmp(fullname, e->fullname) == 0)
-			return e;
-
-		e = dir->files;
-	}
-	while (e) {
-		if (S_ISDIR(e->sb.st_mode)) {
-			int len = strlen(e->fullname);
-
-			/* Check if we are a parent of the correct path */
-			if (strncmp(e->fullname, fullname, len) == 0) {
-				/* Is this an _exact_ match? */
-				if (strcmp(fullname, e->fullname) == 0) {
-					return (e);
-				}
-				/* Looks like we found a parent of the correct path */
-				if (fullname[len] == '/') {
-					if (e->files) {
-						return (find_filesystem_entry (e, fullname, type));
-					} else {
-						return NULL;
-					}
-				}
-			}
-		} else {
-			if (strcmp(fullname, e->fullname) == 0) {
-				return (e);
-			}
-		}
-		e = e->next;
-	}
-	return (NULL);
-}
-
-static struct filesystem_entry *add_host_filesystem_entry(const char *name,
-		const char *path, unsigned long uid, unsigned long gid,
-		unsigned long mode, dev_t rdev, struct filesystem_entry *parent)
-{
-	int status;
-	char *tmp;
-	struct stat sb;
-	time_t timestamp = time(NULL);
-	struct filesystem_entry *entry;
-
-	memset(&sb, 0, sizeof(struct stat));
-	status = lstat(path, &sb);
-
-	if (status >= 0) {
-		/* It is ok for some types of files to not exit on disk (such as
-		 * device nodes), but if they _do_ exist the specified mode had
-		 * better match the actual file or strange things will happen.... */
-		if ((mode & S_IFMT) != (sb.st_mode & S_IFMT)) {
-			errmsg_die ("%s: file type does not match specified type!", path);
-		}
-		timestamp = sb.st_mtime;
-	} else {
-		/* If this is a regular file, it _must_ exist on disk */
-		if ((mode & S_IFMT) == S_IFREG) {
-			errmsg_die("%s: does not exist!", path);
-		}
-	}
-
-	/* Squash all permissions so files are owned by root, all
-	 * timestamps are _right now_, and file permissions
-	 * have group and other write removed */
-	if (squash_uids) {
-		uid = gid = 0;
-	}
-	if (squash_perms) {
-		if (!S_ISLNK(mode)) {
-			mode &= ~(S_IWGRP | S_IWOTH);
-			mode &= ~(S_ISUID | S_ISGID);
-		}
-	}
-	if (fake_times) {
-		timestamp = 0;
-	}
-
-	entry = xcalloc(1, sizeof(struct filesystem_entry));
-
-	entry->hostname = xstrdup(path);
-	entry->fullname = xstrdup(name);
-	tmp = xstrdup(name);
-	entry->name = xstrdup(basename(tmp));
-	free(tmp);
-	tmp = xstrdup(name);
-	entry->path = xstrdup(dirname(tmp));
-	free(tmp);
-
-	entry->sb.st_ino = sb.st_ino;
-	entry->sb.st_dev = sb.st_dev;
-	entry->sb.st_nlink = sb.st_nlink;
-
-	entry->sb.st_uid = uid;
-	entry->sb.st_gid = gid;
-	entry->sb.st_mode = mode;
-	entry->sb.st_rdev = rdev;
-	entry->sb.st_atime = entry->sb.st_ctime =
-		entry->sb.st_mtime = timestamp;
-	if (S_ISREG(mode)) {
-		entry->sb.st_size = sb.st_size;
-	}
-	if (S_ISLNK(mode)) {
-		entry->link = xreadlink(path);
-		entry->sb.st_size = strlen(entry->link);
-	}
-
-	/* This happens only for root */
-	if (!parent)
-		return (entry);
-
-	/* Hook the file into the parent directory */
-	entry->parent = parent;
-	if (!parent->files) {
-		parent->files = entry;
-	} else {
-		struct filesystem_entry *prev;
-		for (prev = parent->files; prev->next; prev = prev->next);
-		prev->next = entry;
-		entry->prev = prev;
-	}
-
-	return (entry);
-}
-
-static struct filesystem_entry *recursive_add_host_directory(
-		struct filesystem_entry *parent, const char *targetpath,
-		const char *hostpath)
-{
-	int i, n;
-	struct stat sb;
-	char *hpath, *tpath;
-	struct dirent *dp, **namelist;
-	struct filesystem_entry *entry;
-
-
-	if (lstat(hostpath, &sb)) {
-		sys_errmsg_die("%s", hostpath);
-	}
-
-	entry = add_host_filesystem_entry(targetpath, hostpath,
-			sb.st_uid, sb.st_gid, sb.st_mode, 0, parent);
-
-	n = scandir(hostpath, &namelist, 0, alphasort);
-	if (n < 0) {
-		sys_errmsg_die("opening directory %s", hostpath);
-	}
-
-	for (i=0; i<n; i++)
-	{
-		dp = namelist[i];
-		if (dp->d_name[0] == '.' && (dp->d_name[1] == 0 ||
-					(dp->d_name[1] == '.' &&  dp->d_name[2] == 0)))
-		{
-			free(dp);
-			continue;
-		}
-
-		xasprintf(&hpath, "%s/%s", hostpath, dp->d_name);
-		if (lstat(hpath, &sb)) {
-			sys_errmsg_die("%s", hpath);
-		}
-		if (strcmp(targetpath, "/") == 0) {
-			xasprintf(&tpath, "%s%s", targetpath, dp->d_name);
-		} else {
-			xasprintf(&tpath, "%s/%s", targetpath, dp->d_name);
-		}
-
-		switch (sb.st_mode & S_IFMT) {
-			case S_IFDIR:
-				recursive_add_host_directory(entry, tpath, hpath);
-				break;
-
-			case S_IFREG:
-			case S_IFSOCK:
-			case S_IFIFO:
-			case S_IFLNK:
-			case S_IFCHR:
-			case S_IFBLK:
-				add_host_filesystem_entry(tpath, hpath, sb.st_uid,
-						sb.st_gid, sb.st_mode, sb.st_rdev, entry);
-				break;
-
-			default:
-				errmsg("Unknown file type %o for %s", sb.st_mode, hpath);
-				break;
-		}
-		free(dp);
-		free(hpath);
-		free(tpath);
-	}
-	free(namelist);
-	return (entry);
-}
-
-/* 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(struct filesystem_entry *root, char *line)
-{
-	char *hostpath;
-	char type, *name = NULL, *tmp, *dir;
-	unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
-	unsigned long start = 0, increment = 1, count = 0;
-	struct filesystem_entry *parent, *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, "/")) {
-		errmsg_die("Device table entries require absolute paths");
-	}
-
-	xasprintf(&hostpath, "%s%s", rootdir, name);
-
-	/* 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;
-		case 'l':
-			mode |= S_IFLNK;
-			break;
-		default:
-			errmsg_die("Unsupported file type '%c'", type);
-	}
-	entry = find_filesystem_entry(root, name, mode);
-	if (entry && !(count > 0 && (type == 'c' || type == 'b'))) {
-		/* Ok, we just need to fixup the existing entry
-		 * and we will be all done... */
-		entry->sb.st_uid = uid;
-		entry->sb.st_gid = gid;
-		entry->sb.st_mode = mode;
-		if (major && minor) {
-			entry->sb.st_rdev = makedev(major, minor);
-		}
-	} else {
-		/* If parent is NULL (happens with device table entries),
-		 * try and find our parent now) */
-		tmp = xstrdup(name);
-		dir = dirname(tmp);
-		parent = find_filesystem_entry(root, dir, S_IFDIR);
-		free(tmp);
-		if (parent == NULL) {
-			errmsg ("skipping device_table entry '%s': no parent directory!", name);
-			free(name);
-			free(hostpath);
-			return 1;
-		}
-
-		switch (type) {
-			case 'd':
-				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
-				break;
-			case 'f':
-				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
-				break;
-			case 'p':
-				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
-				break;
-			case 'c':
-			case 'b':
-				if (count > 0) {
-					dev_t rdev;
-					unsigned long i;
-					char *dname, *hpath;
-
-					for (i = start; i < (start + count); i++) {
-						xasprintf(&dname, "%s%lu", name, i);
-						xasprintf(&hpath, "%s/%s%lu", rootdir, name, i);
-						rdev = makedev(major, minor + (i - start) * increment);
-						add_host_filesystem_entry(dname, hpath, uid, gid,
-								mode, rdev, parent);
-						free(dname);
-						free(hpath);
-					}
-				} else {
-					dev_t rdev = makedev(major, minor);
-					add_host_filesystem_entry(name, hostpath, uid, gid,
-							mode, rdev, parent);
-				}
-				break;
-			default:
-				errmsg_die("Unsupported file type '%c'", type);
-		}
-	}
-	free(name);
-	free(hostpath);
-	return 0;
-}
-
-static int parse_device_table(struct filesystem_entry *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;
-}
-
-static void cleanup(struct filesystem_entry *dir)
-{
-	struct filesystem_entry *e, *prev;
-
-	e = dir->files;
-	while (e) {
-		if (e->name)
-			free(e->name);
-		if (e->path)
-			free(e->path);
-		if (e->fullname)
-			free(e->fullname);
-		e->next = NULL;
-		e->name = NULL;
-		e->path = NULL;
-		e->fullname = NULL;
-		e->prev = NULL;
-		prev = e;
-		if (S_ISDIR(e->sb.st_mode)) {
-			cleanup(e);
-		}
-		e = e->next;
-		free(prev);
-	}
-}
-
-/* Here is where we do the actual creation of the file system */
-#include "mtd/jffs2-user.h"
-
-#define JFFS2_MAX_FILE_SIZE 0xFFFFFFFF
-#ifndef JFFS2_MAX_SYMLINK_LEN
-#define JFFS2_MAX_SYMLINK_LEN 254
-#endif
-
-static uint32_t ino = 0;
-static uint8_t *file_buffer = NULL;		/* file buffer contains the actual erase block*/
-static int out_ofs = 0;
-static int erase_block_size = 65536;
-static int pad_fs_size = 0;
-static int add_cleanmarkers = 1;
-static struct jffs2_unknown_node cleanmarker;
-static int cleanmarker_size = sizeof(cleanmarker);
-static unsigned char ffbuf[16] =
-{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff
-};
-
-/* We set this at start of main() using sysconf(), -1 means we don't know */
-/* When building an fs for non-native systems, use --pagesize=SIZE option */
-int page_size = -1;
-
-#include "compr.h"
-
-static void full_write(int fd, const void *buf, int len)
-{
-	int ret;
-
-	while (len > 0) {
-		ret = write(fd, buf, len);
-
-		if (ret < 0)
-			sys_errmsg_die("write");
-
-		if (ret == 0)
-			sys_errmsg_die("write returned zero");
-
-		len -= ret;
-		buf += ret;
-		out_ofs += ret;
-	}
-}
-
-static void padblock(void)
-{
-	while (out_ofs % erase_block_size) {
-		full_write(out_fd, ffbuf, min(sizeof(ffbuf),
-					erase_block_size - (out_ofs % erase_block_size)));
-	}
-}
-
-static void pad(int req)
-{
-	while (req) {
-		if (req > sizeof(ffbuf)) {
-			full_write(out_fd, ffbuf, sizeof(ffbuf));
-			req -= sizeof(ffbuf);
-		} else {
-			full_write(out_fd, ffbuf, req);
-			req = 0;
-		}
-	}
-}
-
-static inline void padword(void)
-{
-	if (out_ofs % 4) {
-		full_write(out_fd, ffbuf, 4 - (out_ofs % 4));
-	}
-}
-
-static inline void pad_block_if_less_than(int req)
-{
-	if (add_cleanmarkers) {
-		if ((out_ofs % erase_block_size) == 0) {
-			full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
-			pad(cleanmarker_size - sizeof(cleanmarker));
-			padword();
-		}
-	}
-	if ((out_ofs % erase_block_size) + req > erase_block_size) {
-		padblock();
-	}
-	if (add_cleanmarkers) {
-		if ((out_ofs % erase_block_size) == 0) {
-			full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
-			pad(cleanmarker_size - sizeof(cleanmarker));
-			padword();
-		}
-	}
-}
-
-static void write_dirent(struct filesystem_entry *e)
-{
-	char *name = e->name;
-	struct jffs2_raw_dirent rd;
-	struct stat *statbuf = &(e->sb);
-	static uint32_t version = 0;
-
-	memset(&rd, 0, sizeof(rd));
-
-	rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-	rd.totlen = cpu_to_je32(sizeof(rd) + strlen(name));
-	rd.hdr_crc = cpu_to_je32(mtd_crc32(0, &rd,
-				sizeof(struct jffs2_unknown_node) - 4));
-	rd.pino = cpu_to_je32((e->parent) ? e->parent->ino : 1);
-	rd.version = cpu_to_je32(version++);
-	rd.ino = cpu_to_je32(e->ino);
-	rd.mctime = cpu_to_je32(statbuf->st_mtime);
-	rd.nsize = strlen(name);
-	rd.type = IFTODT(statbuf->st_mode);
-	//rd.unused[0] = 0;
-	//rd.unused[1] = 0;
-	rd.node_crc = cpu_to_je32(mtd_crc32(0, &rd, sizeof(rd) - 8));
-	rd.name_crc = cpu_to_je32(mtd_crc32(0, name, strlen(name)));
-
-	pad_block_if_less_than(sizeof(rd) + rd.nsize);
-	full_write(out_fd, &rd, sizeof(rd));
-	full_write(out_fd, name, rd.nsize);
-	padword();
-}
-
-static unsigned int write_regular_file(struct filesystem_entry *e)
-{
-	int fd, len;
-	uint32_t ver;
-	unsigned int offset;
-	unsigned char *buf, *cbuf, *wbuf;
-	struct jffs2_raw_inode ri;
-	struct stat *statbuf;
-	unsigned int totcomp = 0;
-
-	statbuf = &(e->sb);
-	if (statbuf->st_size >= JFFS2_MAX_FILE_SIZE) {
-		errmsg("Skipping file \"%s\" too large.", e->path);
-		return -1;
-	}
-	fd = open(e->hostname, O_RDONLY);
-	if (fd == -1) {
-		sys_errmsg_die("%s: open file", e->hostname);
-	}
-
-	e->ino = ++ino;
-	mkfs_debug_msg("writing file '%s'  ino=%lu  parent_ino=%lu",
-			e->name, (unsigned long) e->ino,
-			(unsigned long) e->parent->ino);
-	write_dirent(e);
-
-	buf = xmalloc(page_size);
-	cbuf = NULL;
-
-	ver = 0;
-	offset = 0;
-
-	memset(&ri, 0, sizeof(ri));
-	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-
-	ri.ino = cpu_to_je32(e->ino);
-	ri.mode = cpu_to_jemode(statbuf->st_mode);
-	ri.uid = cpu_to_je16(statbuf->st_uid);
-	ri.gid = cpu_to_je16(statbuf->st_gid);
-	ri.atime = cpu_to_je32(statbuf->st_atime);
-	ri.ctime = cpu_to_je32(statbuf->st_ctime);
-	ri.mtime = cpu_to_je32(statbuf->st_mtime);
-	ri.isize = cpu_to_je32(statbuf->st_size);
-
-	while ((len = read(fd, buf, page_size))) {
-		unsigned char *tbuf = buf;
-
-		if (len < 0) {
-			sys_errmsg_die("read");
-		}
-
-		while (len) {
-			uint32_t dsize, space;
-			uint16_t compression;
-
-			pad_block_if_less_than(sizeof(ri) + JFFS2_MIN_DATA_LEN);
-
-			dsize = len;
-			space =
-				erase_block_size - (out_ofs % erase_block_size) -
-				sizeof(ri);
-			if (space > dsize)
-				space = dsize;
-
-			compression = jffs2_compress(tbuf, &cbuf, &dsize, &space);
-
-			ri.compr = compression & 0xff;
-			ri.usercompr = (compression >> 8) & 0xff;
-
-			if (ri.compr) {
-				wbuf = cbuf;
-			} else {
-				wbuf = tbuf;
-				dsize = space;
-			}
-
-			ri.totlen = cpu_to_je32(sizeof(ri) + space);
-			ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
-						&ri, sizeof(struct jffs2_unknown_node) - 4));
-
-			ri.version = cpu_to_je32(++ver);
-			ri.offset = cpu_to_je32(offset);
-			ri.csize = cpu_to_je32(space);
-			ri.dsize = cpu_to_je32(dsize);
-			ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
-			ri.data_crc = cpu_to_je32(mtd_crc32(0, wbuf, space));
-
-			full_write(out_fd, &ri, sizeof(ri));
-			totcomp += sizeof(ri);
-			full_write(out_fd, wbuf, space);
-			totcomp += space;
-			padword();
-
-			if (tbuf != cbuf) {
-				free(cbuf);
-				cbuf = NULL;
-			}
-
-			tbuf += dsize;
-			len -= dsize;
-			offset += dsize;
-
-		}
-	}
-	if (!je32_to_cpu(ri.version)) {
-		/* Was empty file */
-		pad_block_if_less_than(sizeof(ri));
-
-		ri.version = cpu_to_je32(++ver);
-		ri.totlen = cpu_to_je32(sizeof(ri));
-		ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
-					&ri, sizeof(struct jffs2_unknown_node) - 4));
-		ri.csize = cpu_to_je32(0);
-		ri.dsize = cpu_to_je32(0);
-		ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
-
-		full_write(out_fd, &ri, sizeof(ri));
-		padword();
-	}
-	free(buf);
-	close(fd);
-	return totcomp;
-}
-
-static void write_symlink(struct filesystem_entry *e)
-{
-	int len;
-	struct stat *statbuf;
-	struct jffs2_raw_inode ri;
-
-	statbuf = &(e->sb);
-	e->ino = ++ino;
-	mkfs_debug_msg("writing symlink '%s'  ino=%lu  parent_ino=%lu",
-			e->name, (unsigned long) e->ino,
-			(unsigned long) e->parent->ino);
-	write_dirent(e);
-
-	len = strlen(e->link);
-	if (len > JFFS2_MAX_SYMLINK_LEN) {
-		errmsg("symlink too large. Truncated to %d chars.",
-				JFFS2_MAX_SYMLINK_LEN);
-		len = JFFS2_MAX_SYMLINK_LEN;
-	}
-
-	memset(&ri, 0, sizeof(ri));
-
-	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-	ri.totlen = cpu_to_je32(sizeof(ri) + len);
-	ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
-				&ri, sizeof(struct jffs2_unknown_node) - 4));
-
-	ri.ino = cpu_to_je32(e->ino);
-	ri.mode = cpu_to_jemode(statbuf->st_mode);
-	ri.uid = cpu_to_je16(statbuf->st_uid);
-	ri.gid = cpu_to_je16(statbuf->st_gid);
-	ri.atime = cpu_to_je32(statbuf->st_atime);
-	ri.ctime = cpu_to_je32(statbuf->st_ctime);
-	ri.mtime = cpu_to_je32(statbuf->st_mtime);
-	ri.isize = cpu_to_je32(statbuf->st_size);
-	ri.version = cpu_to_je32(1);
-	ri.csize = cpu_to_je32(len);
-	ri.dsize = cpu_to_je32(len);
-	ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
-	ri.data_crc = cpu_to_je32(mtd_crc32(0, e->link, len));
-
-	pad_block_if_less_than(sizeof(ri) + len);
-	full_write(out_fd, &ri, sizeof(ri));
-	full_write(out_fd, e->link, len);
-	padword();
-}
-
-static void write_pipe(struct filesystem_entry *e)
-{
-	struct stat *statbuf;
-	struct jffs2_raw_inode ri;
-
-	statbuf = &(e->sb);
-	e->ino = ++ino;
-	if (S_ISDIR(statbuf->st_mode)) {
-		mkfs_debug_msg("writing dir '%s'  ino=%lu  parent_ino=%lu",
-				e->name, (unsigned long) e->ino,
-				(unsigned long) (e->parent) ? e->parent->ino : 1);
-	}
-	write_dirent(e);
-
-	memset(&ri, 0, sizeof(ri));
-
-	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-	ri.totlen = cpu_to_je32(sizeof(ri));
-	ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
-				&ri, sizeof(struct jffs2_unknown_node) - 4));
-
-	ri.ino = cpu_to_je32(e->ino);
-	ri.mode = cpu_to_jemode(statbuf->st_mode);
-	ri.uid = cpu_to_je16(statbuf->st_uid);
-	ri.gid = cpu_to_je16(statbuf->st_gid);
-	ri.atime = cpu_to_je32(statbuf->st_atime);
-	ri.ctime = cpu_to_je32(statbuf->st_ctime);
-	ri.mtime = cpu_to_je32(statbuf->st_mtime);
-	ri.isize = cpu_to_je32(0);
-	ri.version = cpu_to_je32(1);
-	ri.csize = cpu_to_je32(0);
-	ri.dsize = cpu_to_je32(0);
-	ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
-	ri.data_crc = cpu_to_je32(0);
-
-	pad_block_if_less_than(sizeof(ri));
-	full_write(out_fd, &ri, sizeof(ri));
-	padword();
-}
-
-static void write_special_file(struct filesystem_entry *e)
-{
-	jint16_t kdev;
-	struct stat *statbuf;
-	struct jffs2_raw_inode ri;
-
-	statbuf = &(e->sb);
-	e->ino = ++ino;
-	write_dirent(e);
-
-	kdev = cpu_to_je16((major(statbuf->st_rdev) << 8) +
-			minor(statbuf->st_rdev));
-
-	memset(&ri, 0, sizeof(ri));
-
-	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-	ri.totlen = cpu_to_je32(sizeof(ri) + sizeof(kdev));
-	ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
-				&ri, sizeof(struct jffs2_unknown_node) - 4));
-
-	ri.ino = cpu_to_je32(e->ino);
-	ri.mode = cpu_to_jemode(statbuf->st_mode);
-	ri.uid = cpu_to_je16(statbuf->st_uid);
-	ri.gid = cpu_to_je16(statbuf->st_gid);
-	ri.atime = cpu_to_je32(statbuf->st_atime);
-	ri.ctime = cpu_to_je32(statbuf->st_ctime);
-	ri.mtime = cpu_to_je32(statbuf->st_mtime);
-	ri.isize = cpu_to_je32(statbuf->st_size);
-	ri.version = cpu_to_je32(1);
-	ri.csize = cpu_to_je32(sizeof(kdev));
-	ri.dsize = cpu_to_je32(sizeof(kdev));
-	ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
-	ri.data_crc = cpu_to_je32(mtd_crc32(0, &kdev, sizeof(kdev)));
-
-	pad_block_if_less_than(sizeof(ri) + sizeof(kdev));
-	full_write(out_fd, &ri, sizeof(ri));
-	full_write(out_fd, &kdev, sizeof(kdev));
-	padword();
-}
-
-#ifndef WITHOUT_XATTR
-typedef struct xattr_entry {
-	struct xattr_entry *next;
-	uint32_t xid;
-	int xprefix;
-	char *xname;
-	char *xvalue;
-	int name_len;
-	int value_len;
-} xattr_entry_t;
-
-#define XATTR_BUFFER_SIZE		(64 * 1024)	/* 64KB */
-static uint32_t enable_xattr = 0;
-static uint32_t highest_xid = 0;
-static uint32_t highest_xseqno = 0;
-
-static struct {
-	int xprefix;
-	const char *string;
-	int length;
-} xprefix_tbl[] = {
-	{ JFFS2_XPREFIX_USER, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN },
-	{ JFFS2_XPREFIX_SECURITY, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
-	{ JFFS2_XPREFIX_ACL_ACCESS, POSIX_ACL_XATTR_ACCESS, POSIX_ACL_XATTR_ACCESS_LEN },
-	{ JFFS2_XPREFIX_ACL_DEFAULT, POSIX_ACL_XATTR_DEFAULT, POSIX_ACL_XATTR_DEFAULT_LEN },
-	{ JFFS2_XPREFIX_TRUSTED, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN },
-	{ 0, NULL, 0 }
-};
-
-static void formalize_posix_acl(void *xvalue, int *value_len)
-{
-	struct posix_acl_xattr_header *pacl_header;
-	struct posix_acl_xattr_entry *pent, *plim;
-	struct jffs2_acl_header *jacl_header;
-	struct jffs2_acl_entry *jent;
-	struct jffs2_acl_entry_short *jent_s;
-	char buffer[XATTR_BUFFER_SIZE];
-	int offset = 0;
-
-	pacl_header = xvalue;;
-	pent = pacl_header->a_entries;
-	plim = xvalue + *value_len;
-
-	jacl_header = (struct jffs2_acl_header *)buffer;
-	offset += sizeof(struct jffs2_acl_header);
-	jacl_header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
-
-	while (pent < plim) {
-		switch(le16_to_cpu(pent->e_tag)) {
-			case ACL_USER_OBJ:
-			case ACL_GROUP_OBJ:
-			case ACL_MASK:
-			case ACL_OTHER:
-				jent_s = (struct jffs2_acl_entry_short *)(buffer + offset);
-				offset += sizeof(struct jffs2_acl_entry_short);
-				jent_s->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
-				jent_s->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
-				break;
-			case ACL_USER:
-			case ACL_GROUP:
-				jent = (struct jffs2_acl_entry *)(buffer + offset);
-				offset += sizeof(struct jffs2_acl_entry);
-				jent->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
-				jent->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
-				jent->e_id = cpu_to_je32(le32_to_cpu(pent->e_id));
-				break;
-			default:
-				printf("%04x : Unknown XATTR entry tag.\n", le16_to_cpu(pent->e_tag));
-				exit(1);
-		}
-		pent++;
-	}
-	if (offset > *value_len) {
-		printf("Length of JFFS2 ACL expression(%u) is longer than general one(%u).\n",
-				offset, *value_len);
-		exit(1);
-	}
-	memcpy(xvalue, buffer, offset);
-	*value_len = offset;
-}
-
-static xattr_entry_t *create_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
-{
-	xattr_entry_t *xe;
-	struct jffs2_raw_xattr rx;
-	int name_len;
-
-	/* create xattr entry */
-	name_len = strlen(xname);
-	xe = xcalloc(1, sizeof(xattr_entry_t) + name_len + 1 + value_len);
-	xe->next = NULL;
-	xe->xid = ++highest_xid;
-	xe->xprefix = xprefix;
-	xe->xname = ((char *)xe) + sizeof(xattr_entry_t);
-	xe->xvalue = xe->xname + name_len + 1;
-	xe->name_len = name_len;
-	xe->value_len = value_len;
-	strcpy(xe->xname, xname);
-	memcpy(xe->xvalue, xvalue, value_len);
-
-	/* write xattr node */
-	memset(&rx, 0, sizeof(rx));
-	rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
-	rx.totlen = cpu_to_je32(PAD(sizeof(rx) + xe->name_len + 1 + xe->value_len));
-	rx.hdr_crc = cpu_to_je32(mtd_crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
-
-	rx.xid = cpu_to_je32(xe->xid);
-	rx.version = cpu_to_je32(1);	/* initial version */
-	rx.xprefix = xprefix;
-	rx.name_len = xe->name_len;
-	rx.value_len = cpu_to_je16(xe->value_len);
-	rx.data_crc = cpu_to_je32(mtd_crc32(0, xe->xname, xe->name_len + 1 + xe->value_len));
-	rx.node_crc = cpu_to_je32(mtd_crc32(0, &rx, sizeof(rx) - 4));
-
-	pad_block_if_less_than(sizeof(rx) + xe->name_len + 1 + xe->value_len);
-	full_write(out_fd, &rx, sizeof(rx));
-	full_write(out_fd, xe->xname, xe->name_len + 1 + xe->value_len);
-	padword();
-
-	return xe;
-}
-
-#define XATTRENTRY_HASHSIZE	57
-static xattr_entry_t *find_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
-{
-	static xattr_entry_t **xentry_hash = NULL;
-	xattr_entry_t *xe;
-	int index, name_len;
-
-	/* create hash table */
-	if (!xentry_hash)
-		xentry_hash = xcalloc(1, sizeof(xe) * XATTRENTRY_HASHSIZE);
-
-	if (xprefix == JFFS2_XPREFIX_ACL_ACCESS
-			|| xprefix == JFFS2_XPREFIX_ACL_DEFAULT)
-		formalize_posix_acl(xvalue, &value_len);
-
-	name_len = strlen(xname);
-	index = (mtd_crc32(0, xname, name_len) ^ mtd_crc32(0, xvalue, value_len)) % XATTRENTRY_HASHSIZE;
-	for (xe = xentry_hash[index]; xe; xe = xe->next) {
-		if (xe->xprefix == xprefix
-				&& xe->value_len == value_len
-				&& !strcmp(xe->xname, xname)
-				&& !memcmp(xe->xvalue, xvalue, value_len))
-			break;
-	}
-	if (!xe) {
-		xe = create_xattr_entry(xprefix, xname, xvalue, value_len);
-		xe->next = xentry_hash[index];
-		xentry_hash[index] = xe;
-	}
-	return xe;
-}
-
-static void write_xattr_entry(struct filesystem_entry *e)
-{
-	struct jffs2_raw_xref ref;
-	struct xattr_entry *xe;
-	char xlist[XATTR_BUFFER_SIZE], xvalue[XATTR_BUFFER_SIZE];
-	char *xname;
-	const char *prefix_str;
-	int i, xprefix, prefix_len;
-	int list_sz, offset, name_len, value_len;
-
-	if (!enable_xattr)
-		return;
-
-	list_sz = llistxattr(e->hostname, xlist, XATTR_BUFFER_SIZE);
-	if (list_sz < 0) {
-		if (verbose)
-			printf("llistxattr('%s') = %d : %s\n",
-					e->hostname, errno, strerror(errno));
-		return;
-	}
-
-	for (offset = 0; offset < list_sz; offset += name_len) {
-		xname = xlist + offset;
-		name_len = strlen(xname) + 1;
-
-		for (i = 0; (xprefix = xprefix_tbl[i].xprefix); i++) {
-			prefix_str = xprefix_tbl[i].string;
-			prefix_len = xprefix_tbl[i].length;
-			if (prefix_str[prefix_len - 1] == '.') {
-				if (!strncmp(xname, prefix_str, prefix_len - 1))
-					break;
-			} else {
-				if (!strcmp(xname, prefix_str))
-					break;
-			}
-		}
-		if (!xprefix) {
-			if (verbose)
-				printf("%s: xattr '%s' is not supported.\n",
-						e->hostname, xname);
-			continue;
-		}
-		if ((enable_xattr & (1 << xprefix)) == 0)
-			continue;
-
-		value_len = lgetxattr(e->hostname, xname, xvalue, XATTR_BUFFER_SIZE);
-		if (value_len < 0) {
-			if (verbose)
-				printf("lgetxattr('%s', '%s') = %d : %s\n",
-						e->hostname, xname, errno, strerror(errno));
-			continue;
-		}
-		xe = find_xattr_entry(xprefix, xname + prefix_len, xvalue, value_len);
-		if (!xe) {
-			if (verbose)
-				printf("%s : xattr '%s' was ignored.\n",
-						e->hostname, xname);
-			continue;
-		}
-
-		memset(&ref, 0, sizeof(ref));
-		ref.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-		ref.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF);
-		ref.totlen = cpu_to_je32(sizeof(ref));
-		ref.hdr_crc = cpu_to_je32(mtd_crc32(0, &ref, sizeof(struct jffs2_unknown_node) - 4));
-		ref.ino = cpu_to_je32(e->ino);
-		ref.xid = cpu_to_je32(xe->xid);
-		ref.xseqno = cpu_to_je32(highest_xseqno += 2);
-		ref.node_crc = cpu_to_je32(mtd_crc32(0, &ref, sizeof(ref) - 4));
-
-		pad_block_if_less_than(sizeof(ref));
-		full_write(out_fd, &ref, sizeof(ref));
-		padword();
-	}
-}
-
-#else /* WITHOUT_XATTR */
-#define write_xattr_entry(x)
-#endif
-
-static void recursive_populate_directory(struct filesystem_entry *dir)
-{
-	struct filesystem_entry *e;
-	unsigned int wrote;
-
-	if (verbose) {
-		printf("%s\n", dir->fullname);
-	}
-	write_xattr_entry(dir);		/* for '/' */
-
-	e = dir->files;
-	while (e) {
-		if (e->sb.st_nlink >= 1 &&
-		    (e->ino = find_hardlink(e))) {
-
-			write_dirent(e);
-			if (verbose) {
-				printf("\tL %04o %9lu             %5d:%-3d %s\n",
-				       e->sb.st_mode & ~S_IFMT, (unsigned long) e->ino,
-				       (int) (e->sb.st_uid), (int) (e->sb.st_gid),
-				       e->name);
-			}
-		} else switch (e->sb.st_mode & S_IFMT) {
-			case S_IFDIR:
-				if (verbose) {
-					printf("\td %04o %9" PRIdoff_t "             %5d:%-3d %s\n",
-							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
-							(int) (e->sb.st_uid), (int) (e->sb.st_gid),
-							e->name);
-				}
-				write_pipe(e);
-				write_xattr_entry(e);
-				break;
-			case S_IFSOCK:
-				if (verbose) {
-					printf("\ts %04o %9" PRIdoff_t "             %5d:%-3d %s\n",
-							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
-							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
-				}
-				write_pipe(e);
-				write_xattr_entry(e);
-				break;
-			case S_IFIFO:
-				if (verbose) {
-					printf("\tp %04o %9" PRIdoff_t "             %5d:%-3d %s\n",
-							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
-							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
-				}
-				write_pipe(e);
-				write_xattr_entry(e);
-				break;
-			case S_IFCHR:
-				if (verbose) {
-					printf("\tc %04o %4d,%4d             %5d:%-3d %s\n",
-							e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
-							minor(e->sb.st_rdev), (int) e->sb.st_uid,
-							(int) e->sb.st_gid, e->name);
-				}
-				write_special_file(e);
-				write_xattr_entry(e);
-				break;
-			case S_IFBLK:
-				if (verbose) {
-					printf("\tb %04o %4d,%4d             %5d:%-3d %s\n",
-							e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
-							minor(e->sb.st_rdev), (int) e->sb.st_uid,
-							(int) e->sb.st_gid, e->name);
-				}
-				write_special_file(e);
-				write_xattr_entry(e);
-				break;
-			case S_IFLNK:
-				if (verbose) {
-					printf("\tl %04o %9" PRIdoff_t "             %5d:%-3d %s -> %s\n",
-							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
-							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name,
-							e->link);
-				}
-				write_symlink(e);
-				write_xattr_entry(e);
-				break;
-			case S_IFREG:
-				wrote = write_regular_file(e);
-				write_xattr_entry(e);
-				if (verbose) {
-					printf("\tf %04o %9" PRIdoff_t " (%9u) %5d:%-3d %s\n",
-							e->sb.st_mode & ~S_IFMT, e->sb.st_size, wrote,
-							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
-				}
-				break;
-			default:
-				errmsg("Unknown mode %o for %s", e->sb.st_mode,
-						e->fullname);
-				break;
-		}
-		e = e->next;
-	}
-
-	e = dir->files;
-	while (e) {
-		if (S_ISDIR(e->sb.st_mode)) {
-			if (e->files) {
-				recursive_populate_directory(e);
-			} else if (verbose) {
-				printf("%s\n", e->fullname);
-			}
-		}
-		e = e->next;
-	}
-}
-
-static void create_target_filesystem(struct filesystem_entry *root)
-{
-	cleanmarker.magic    = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
-	cleanmarker.totlen   = cpu_to_je32(cleanmarker_size);
-	cleanmarker.hdr_crc  = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
-
-	if (ino == 0)
-		ino = 1;
-
-	root->ino = 1;
-	recursive_populate_directory(root);
-
-	if (pad_fs_size == -1) {
-		padblock();
-	} else {
-		if (pad_fs_size && add_cleanmarkers){
-			padblock();
-			while (out_ofs < pad_fs_size) {
-				full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
-				pad(cleanmarker_size - sizeof(cleanmarker));
-				padblock();
-			}
-		} else {
-			while (out_ofs < pad_fs_size) {
-				full_write(out_fd, ffbuf, min(sizeof(ffbuf), pad_fs_size - out_ofs));
-			}
-
-		}
-	}
-}
-
-static struct option long_options[] = {
-	{"pad", 2, NULL, 'p'},
-	{"root", 1, NULL, 'r'},
-	{"pagesize", 1, NULL, 's'},
-	{"eraseblock", 1, NULL, 'e'},
-	{"output", 1, NULL, 'o'},
-	{"help", 0, NULL, 'h'},
-	{"verbose", 0, NULL, 'v'},
-	{"version", 0, NULL, 'V'},
-	{"big-endian", 0, NULL, 'b'},
-	{"little-endian", 0, NULL, 'l'},
-	{"no-cleanmarkers", 0, NULL, 'n'},
-	{"cleanmarker", 1, NULL, 'c'},
-	{"squash", 0, NULL, 'q'},
-	{"squash-uids", 0, NULL, 'U'},
-	{"squash-perms", 0, NULL, 'P'},
-	{"faketime", 0, NULL, 'f'},
-	{"devtable", 1, NULL, 'D'},
-	{"compression-mode", 1, NULL, 'm'},
-	{"disable-compressor", 1, NULL, 'x'},
-	{"enable-compressor", 1, NULL, 'X'},
-	{"test-compression", 0, NULL, 't'},
-	{"compressor-priority", 1, NULL, 'y'},
-	{"incremental", 1, NULL, 'i'},
-#ifndef WITHOUT_XATTR
-	{"with-xattr", 0, NULL, 1000 },
-	{"with-selinux", 0, NULL, 1001 },
-	{"with-posix-acl", 0, NULL, 1002 },
-#endif
-	{NULL, 0, NULL, 0}
-};
-
-static const char helptext[] =
-"Usage: mkfs.jffs2 [OPTIONS]\n"
-"Make a JFFS2 file system image from an existing directory tree\n\n"
-"Options:\n"
-"  -p, --pad[=SIZE]        Pad output to SIZE bytes with 0xFF. If SIZE is\n"
-"                          not specified, the output is padded to the end of\n"
-"                          the final erase block\n"
-"  -r, -d, --root=DIR      Build file system from directory DIR (default: cwd)\n"
-"  -s, --pagesize=SIZE     Use page size (max data node size) SIZE.\n"
-"                          Set according to target system's memory management\n"
-"                          page size (default: 4KiB)\n"
-"  -e, --eraseblock=SIZE   Use erase block size SIZE (default: 64KiB)\n"
-"  -c, --cleanmarker=SIZE  Size of cleanmarker (default 12)\n"
-"  -m, --compr-mode=MODE   Select compression mode (default: priority)\n"
-"  -x, --disable-compressor=COMPRESSOR_NAME\n"
-"                          Disable a compressor\n"
-"  -X, --enable-compressor=COMPRESSOR_NAME\n"
-"                          Enable a compressor\n"
-"  -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME\n"
-"                          Set the priority of a compressor\n"
-"  -L, --list-compressors  Show the list of the available compressors\n"
-"  -t, --test-compression  Call decompress and compare with the original (for test)\n"
-"  -n, --no-cleanmarkers   Don't add a cleanmarker to every eraseblock\n"
-"  -o, --output=FILE       Output to FILE (default: stdout)\n"
-"  -l, --little-endian     Create a little-endian filesystem\n"
-"  -b, --big-endian        Create a big-endian filesystem\n"
-"  -D, --devtable=FILE     Use the named FILE as a device table file\n"
-"  -f, --faketime          Change all file times to '0' for regression testing\n"
-"  -q, --squash            Squash permissions and owners making all files be owned by root\n"
-"  -U, --squash-uids       Squash owners making all files be owned by root\n"
-"  -P, --squash-perms      Squash permissions on all files\n"
-#ifndef WITHOUT_XATTR
-"      --with-xattr        stuff all xattr entries into image\n"
-"      --with-selinux      stuff only SELinux Labels into jffs2 image\n"
-"      --with-posix-acl    stuff only POSIX ACL entries into jffs2 image\n"
-#endif
-"  -h, --help              Display this help text\n"
-"  -v, --verbose           Verbose operation\n"
-"  -V, --version           Display version information\n"
-"  -i, --incremental=FILE  Parse FILE and generate appendage output for it\n\n";
-
-static const char revtext[] = "1.60";
-
-int load_next_block() {
-
-	int ret;
-	ret = read(in_fd, file_buffer, erase_block_size);
-
-	if(verbose)
-		printf("Load next block : %d bytes read\n",ret);
-
-	return ret;
-}
-
-void process_buffer(int inp_size) {
-	uint8_t		*p = file_buffer;
-	union jffs2_node_union 	*node;
-	uint16_t	type;
-	int		bitchbitmask = 0;
-	int		obsolete;
-
-	char	name[256];
-
-	while ( p < (file_buffer + inp_size)) {
-
-		node = (union jffs2_node_union *) p;
-
-		/* Skip empty space */
-		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
-			p += 4;
-			continue;
-		}
-
-		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
-			if (!bitchbitmask++)
-				printf ("Wrong bitmask  at  0x%08zx, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic));
-			p += 4;
-			continue;
-		}
-
-		bitchbitmask = 0;
-
-		type = je16_to_cpu(node->u.nodetype);
-		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
-			obsolete = 1;
-			type |= JFFS2_NODE_ACCURATE;
-		} else
-			obsolete = 0;
-
-		node->u.nodetype = cpu_to_je16(type);
-
-		switch(je16_to_cpu(node->u.nodetype)) {
-
-			case JFFS2_NODETYPE_INODE:
-				if(verbose)
-					printf ("%8s Inode      node at 0x%08zx, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
-							obsolete ? "Obsolete" : "",
-							p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
-							je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
-							je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
-
-				if ( je32_to_cpu (node->i.ino) > ino )
-					ino = je32_to_cpu (node->i.ino);
-
-				p += PAD(je32_to_cpu (node->i.totlen));
-				break;
-
-			case JFFS2_NODETYPE_DIRENT:
-				memcpy (name, node->d.name, node->d.nsize);
-				name [node->d.nsize] = 0x0;
-
-				if(verbose)
-					printf ("%8s Dirent     node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
-							obsolete ? "Obsolete" : "",
-							p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
-							je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
-							node->d.nsize, name);
-
-				p += PAD(je32_to_cpu (node->d.totlen));
-				break;
-
-			case JFFS2_NODETYPE_CLEANMARKER:
-				if (verbose) {
-					printf ("%8s Cleanmarker     at 0x%08zx, totlen 0x%08x\n",
-							obsolete ? "Obsolete" : "",
-							p - file_buffer, je32_to_cpu (node->u.totlen));
-				}
-
-				p += PAD(je32_to_cpu (node->u.totlen));
-				break;
-
-			case JFFS2_NODETYPE_PADDING:
-				if (verbose) {
-					printf ("%8s Padding    node at 0x%08zx, totlen 0x%08x\n",
-							obsolete ? "Obsolete" : "",
-							p - file_buffer, je32_to_cpu (node->u.totlen));
-				}
-
-				p += PAD(je32_to_cpu (node->u.totlen));
-				break;
-
-			case 0xffff:
-				p += 4;
-				break;
-
-			default:
-				if (verbose) {
-					printf ("%8s Unknown    node at 0x%08zx, totlen 0x%08x\n",
-							obsolete ? "Obsolete" : "",
-							p - file_buffer, je32_to_cpu (node->u.totlen));
-				}
-
-				p += PAD(je32_to_cpu (node->u.totlen));
-		}
-	}
-}
-
-void parse_image(){
-	int ret;
-
-	file_buffer = xmalloc(erase_block_size);
-
-	while ((ret = load_next_block())) {
-		process_buffer(ret);
-	}
-
-	if (file_buffer)
-		free(file_buffer);
-
-	close(in_fd);
-}
-
-int main(int argc, char **argv)
-{
-	int c, opt;
-	char *cwd;
-	struct stat sb;
-	FILE *devtable = NULL;
-	struct filesystem_entry *root;
-	char *compr_name = NULL;
-	int compr_prior  = -1;
-	int warn_page_size = 0;
-
-	page_size = sysconf(_SC_PAGESIZE);
-	if (page_size < 0) /* System doesn't know so ... */
-		page_size = 4096; /* ... we make an educated guess */
-	if (page_size != 4096)
-		warn_page_size = 1; /* warn user if page size not 4096 */
-
-	jffs2_compressors_init();
-
-	while ((opt = getopt_long(argc, argv,
-					"D:d:r:s:o:qUPfh?vVe:lbp::nc:m:x:X:Lty:i:", long_options, &c)) >= 0)
-	{
-		switch (opt) {
-			case 'D':
-				devtable = xfopen(optarg, "r");
-				if (fstat(fileno(devtable), &sb) < 0)
-					sys_errmsg_die("%s", optarg);
-				if (sb.st_size < 10)
-					errmsg_die("%s: not a proper device table file", optarg);
-				break;
-
-			case 'r':
-			case 'd':	/* for compatibility with mkfs.jffs, genext2fs, etc... */
-				if (rootdir != default_rootdir) {
-					errmsg_die("root directory specified more than once");
-				}
-				rootdir = xstrdup(optarg);
-				break;
-
-			case 's':
-				page_size = strtol(optarg, NULL, 0);
-				warn_page_size = 0; /* set by user, so don't need to warn */
-				break;
-
-			case 'o':
-				if (out_fd != -1) {
-					errmsg_die("output filename specified more than once");
-				}
-				out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
-				if (out_fd == -1) {
-					sys_errmsg_die("open output file");
-				}
-				break;
-
-			case 'q':
-				squash_uids = 1;
-				squash_perms = 1;
-				break;
-
-			case 'U':
-				squash_uids = 1;
-				break;
-
-			case 'P':
-				squash_perms = 1;
-				break;
-
-			case 'f':
-				fake_times = 1;
-				break;
-
-			case 'h':
-			case '?':
-				errmsg_die("%s", helptext);
-
-			case 'v':
-				verbose = 1;
-				break;
-
-			case 'V':
-				errmsg_die("revision %s\n", revtext);
-
-			case 'e': {
-						  char *next;
-						  unsigned units = 0;
-						  erase_block_size = strtol(optarg, &next, 0);
-						  if (!erase_block_size)
-							  errmsg_die("Unrecognisable erase size\n");
-
-						  if (*next) {
-							  if (!strcmp(next, "KiB")) {
-								  units = 1024;
-							  } else if (!strcmp(next, "MiB")) {
-								  units = 1024 * 1024;
-							  } else {
-								  errmsg_die("Unknown units in erasesize\n");
-							  }
-						  } else {
-							  if (erase_block_size < 0x1000)
-								  units = 1024;
-							  else
-								  units = 1;
-						  }
-						  erase_block_size *= units;
-
-						  /* If it's less than 8KiB, they're not allowed */
-						  if (erase_block_size < 0x2000) {
-							  fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n",
-									  erase_block_size);
-							  erase_block_size = 0x2000;
-						  }
-						  break;
-					  }
-
-			case 'l':
-					  target_endian = __LITTLE_ENDIAN;
-					  break;
-
-			case 'b':
-					  target_endian = __BIG_ENDIAN;
-					  break;
-
-			case 'p':
-					  if (optarg)
-						  pad_fs_size = strtol(optarg, NULL, 0);
-					  else
-						  pad_fs_size = -1;
-					  break;
-			case 'n':
-					  add_cleanmarkers = 0;
-					  break;
-			case 'c':
-					  cleanmarker_size = strtol(optarg, NULL, 0);
-					  if (cleanmarker_size < sizeof(cleanmarker)) {
-						  errmsg_die("cleanmarker size must be >= 12");
-					  }
-					  if (cleanmarker_size >= erase_block_size) {
-						  errmsg_die("cleanmarker size must be < eraseblock size");
-					  }
-					  break;
-			case 'm':
-					  if (jffs2_set_compression_mode_name(optarg)) {
-						  errmsg_die("Unknown compression mode %s", optarg);
-					  }
-					  break;
-			case 'x':
-					  if (jffs2_disable_compressor_name(optarg)) {
-						  errmsg_die("Unknown compressor name %s",optarg);
-					  }
-					  break;
-			case 'X':
-					  if (jffs2_enable_compressor_name(optarg)) {
-						  errmsg_die("Unknown compressor name %s",optarg);
-					  }
-					  break;
-			case 'L':
-					  errmsg_die("\n%s",jffs2_list_compressors());
-					  break;
-			case 't':
-					  jffs2_compression_check_set(1);
-					  break;
-			case 'y':
-					  compr_name = xmalloc(strlen(optarg));
-					  sscanf(optarg,"%d:%s",&compr_prior,compr_name);
-					  if ((compr_prior>=0)&&(compr_name)) {
-						  if (jffs2_set_compressor_priority(compr_name, compr_prior))
-							  exit(EXIT_FAILURE);
-					  }
-					  else {
-						  errmsg_die("Cannot parse %s",optarg);
-					  }
-					  free(compr_name);
-					  break;
-			case 'i':
-					  if (in_fd != -1) {
-						  errmsg_die("(incremental) filename specified more than once");
-					  }
-					  in_fd = open(optarg, O_RDONLY);
-					  if (in_fd == -1) {
-						  sys_errmsg_die("cannot open (incremental) file");
-					  }
-					  break;
-#ifndef WITHOUT_XATTR
-			case 1000:	/* --with-xattr  */
-					  enable_xattr |= (1 << JFFS2_XPREFIX_USER)
-						  | (1 << JFFS2_XPREFIX_SECURITY)
-						  | (1 << JFFS2_XPREFIX_ACL_ACCESS)
-						  | (1 << JFFS2_XPREFIX_ACL_DEFAULT)
-						  | (1 << JFFS2_XPREFIX_TRUSTED);
-					  break;
-			case 1001:	/*  --with-selinux  */
-					  enable_xattr |= (1 << JFFS2_XPREFIX_SECURITY);
-					  break;
-			case 1002:	/*  --with-posix-acl  */
-					  enable_xattr |= (1 << JFFS2_XPREFIX_ACL_ACCESS)
-						  | (1 << JFFS2_XPREFIX_ACL_DEFAULT);
-					  break;
-#endif
-		}
-	}
-	if (warn_page_size) {
-		errmsg("Page size for this system is by default %d", page_size);
-		errmsg("Use the --pagesize=SIZE option if this is not what you want");
-	}
-	if (out_fd == -1) {
-		if (isatty(1)) {
-			errmsg_die("%s", helptext);
-		}
-		out_fd = 1;
-	}
-	if (lstat(rootdir, &sb)) {
-		sys_errmsg_die("%s", rootdir);
-	}
-	if (chdir(rootdir))
-		sys_errmsg_die("%s", rootdir);
-
-	if (!(cwd = getcwd(0, GETCWD_SIZE)))
-		sys_errmsg_die("getcwd failed");
-
-	if(in_fd != -1)
-		parse_image();
-
-	root = recursive_add_host_directory(NULL, "/", cwd);
-
-	if (devtable)
-		parse_device_table(root, devtable);
-
-	create_target_filesystem(root);
-
-	cleanup(root);
-
-	if (rootdir != default_rootdir)
-		free(rootdir);
-
-	close(out_fd);
-
-	if (verbose) {
-		char *s = jffs2_stats();
-		fprintf(stderr,"\n\n%s",s);
-		free(s);
-	}
-	if ((verbose)||(jffs2_compression_check_get()&&(jffs2_compression_check_errorcnt_get()))) {
-		fprintf(stderr,"Compression errors: %d\n",jffs2_compression_check_errorcnt_get());
-	}
-
-	jffs2_compressors_exit();
-
-	return 0;
-}
diff --git a/mkfs.ubifs/.gitignore b/mkfs.ubifs/.gitignore
deleted file mode 100644
index 6b0e85c..0000000
--- a/mkfs.ubifs/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/mkfs.ubifs
diff --git a/mkfs.ubifs/COPYING b/mkfs.ubifs/COPYING
deleted file mode 100644
index 60549be..0000000
--- a/mkfs.ubifs/COPYING
+++ /dev/null
@@ -1,340 +0,0 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-

-		    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-

-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-

-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-

-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-			    NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-

-	    How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
-
-    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; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    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
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) 19yy name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/mkfs.ubifs/README b/mkfs.ubifs/README
deleted file mode 100644
index 7e19939..0000000
--- a/mkfs.ubifs/README
+++ /dev/null
@@ -1,9 +0,0 @@
-UBIFS File System - Make File System program
-
-* crc16.h and crc16.c were copied from the linux kernel.
-* crc32.h and crc32.c were copied from mtd-utils and amended.
-* ubifs.h is a selection of definitions from fs/ubifs/ubifs.h from the linux kernel.
-* key.h is copied from fs/ubifs/key.h from the linux kernel.
-* defs.h is a bunch of definitions to smooth things over.
-* lpt.c is a selection of functions copied from fs/ubifs/lpt.c from the linux kernel, and amended.
-* hashtable/* was downloaded from http://www.cl.cam.ac.uk/~cwc22/hashtable/
diff --git a/mkfs.ubifs/compr.c b/mkfs.ubifs/compr.c
deleted file mode 100644
index 34b2f60..0000000
--- a/mkfs.ubifs/compr.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2008 Nokia Corporation.
- * Copyright (C) 2008 University of Szeged, Hungary
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Authors: Artem Bityutskiy
- *          Adrian Hunter
- *          Zoltan Sogor
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <lzo/lzo1x.h>
-#include <linux/types.h>
-
-#define crc32 __zlib_crc32
-#include <zlib.h>
-#undef crc32
-
-#include "compr.h"
-#include "mkfs.ubifs.h"
-
-static void *lzo_mem;
-static unsigned long long errcnt = 0;
-static struct ubifs_info *c = &info_;
-
-#define DEFLATE_DEF_LEVEL     Z_DEFAULT_COMPRESSION
-#define DEFLATE_DEF_WINBITS   11
-#define DEFLATE_DEF_MEMLEVEL  8
-
-static int zlib_deflate(void *in_buf, size_t in_len, void *out_buf,
-			size_t *out_len)
-{
-	z_stream strm;
-
-	strm.zalloc = NULL;
-	strm.zfree = NULL;
-
-	/*
-	 * Match exactly the zlib parameters used by the Linux kernel crypto
-	 * API.
-	 */
-        if (deflateInit2(&strm, DEFLATE_DEF_LEVEL, Z_DEFLATED,
-			 -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL,
-			 Z_DEFAULT_STRATEGY)) {
-		errcnt += 1;
-		return -1;
-	}
-
-	strm.next_in = in_buf;
-	strm.avail_in = in_len;
-	strm.total_in = 0;
-
-	strm.next_out = out_buf;
-	strm.avail_out = *out_len;
-	strm.total_out = 0;
-
-	if (deflate(&strm, Z_FINISH) != Z_STREAM_END) {
-		deflateEnd(&strm);
-		errcnt += 1;
-		return -1;
-	}
-
-	if (deflateEnd(&strm) != Z_OK) {
-		errcnt += 1;
-		return -1;
-	}
-
-	*out_len = strm.total_out;
-
-	return 0;
-}
-
-static int lzo_compress(void *in_buf, size_t in_len, void *out_buf,
-			size_t *out_len)
-{
-	lzo_uint len;
-	int ret;
-
-	len = *out_len;
-	ret = lzo1x_999_compress(in_buf, in_len, out_buf, &len, lzo_mem);
-	*out_len = len;
-
-	if (ret != LZO_E_OK) {
-		errcnt += 1;
-		return -1;
-	}
-
-	return 0;
-}
-
-static int no_compress(void *in_buf, size_t in_len, void *out_buf,
-		       size_t *out_len)
-{
-	memcpy(out_buf, in_buf, in_len);
-	*out_len = in_len;
-	return 0;
-}
-
-static char *zlib_buf;
-
-static int favor_lzo_compress(void *in_buf, size_t in_len, void *out_buf,
-			       size_t *out_len, int *type)
-{
-	int lzo_ret, zlib_ret;
-	size_t lzo_len, zlib_len;
-
-	lzo_len = zlib_len = *out_len;
-	lzo_ret = lzo_compress(in_buf, in_len, out_buf, &lzo_len);
-	zlib_ret = zlib_deflate(in_buf, in_len, zlib_buf, &zlib_len);
-
-	if (lzo_ret && zlib_ret)
-		/* Both compressors failed */
-		return -1;
-
-	if (!lzo_ret && !zlib_ret) {
-		double percent;
-
-		/* Both compressors succeeded */
-		if (lzo_len <= zlib_len )
-			goto select_lzo;
-
-		percent = (double)zlib_len / (double)lzo_len;
-		percent *= 100;
-		if (percent > 100 - c->favor_percent)
-			goto select_lzo;
-		goto select_zlib;
-	}
-
-	if (lzo_ret)
-		/* Only zlib compressor succeeded */
-		goto select_zlib;
-
-	/* Only LZO compressor succeeded */
-
-select_lzo:
-	*out_len = lzo_len;
-	*type = MKFS_UBIFS_COMPR_LZO;
-	return 0;
-
-select_zlib:
-	*out_len = zlib_len;
-	*type = MKFS_UBIFS_COMPR_ZLIB;
-	memcpy(out_buf, zlib_buf, zlib_len);
-	return 0;
-}
-
-int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len,
-		  int type)
-{
-	int ret;
-
-	if (in_len < UBIFS_MIN_COMPR_LEN) {
-		no_compress(in_buf, in_len, out_buf, out_len);
-		return MKFS_UBIFS_COMPR_NONE;
-	}
-
-	if (c->favor_lzo)
-		ret = favor_lzo_compress(in_buf, in_len, out_buf, out_len, &type);
-	else {
-		switch (type) {
-		case MKFS_UBIFS_COMPR_LZO:
-			ret = lzo_compress(in_buf, in_len, out_buf, out_len);
-			break;
-		case MKFS_UBIFS_COMPR_ZLIB:
-			ret = zlib_deflate(in_buf, in_len, out_buf, out_len);
-			break;
-		case MKFS_UBIFS_COMPR_NONE:
-			ret = 1;
-			break;
-		default:
-			errcnt += 1;
-			ret = 1;
-			break;
-		}
-	}
-	if (ret || *out_len >= in_len) {
-		no_compress(in_buf, in_len, out_buf, out_len);
-		return MKFS_UBIFS_COMPR_NONE;
-	}
-	return type;
-}
-
-int init_compression(void)
-{
-	lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
-	if (!lzo_mem)
-		return -1;
-
-	zlib_buf = malloc(UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR);
-	if (!zlib_buf) {
-		free(lzo_mem);
-		return -1;
-	}
-
-	return 0;
-}
-
-void destroy_compression(void)
-{
-	free(zlib_buf);
-	free(lzo_mem);
-	if (errcnt)
-		fprintf(stderr, "%llu compression errors occurred\n", errcnt);
-}
diff --git a/mkfs.ubifs/compr.h b/mkfs.ubifs/compr.h
deleted file mode 100644
index e3dd95c..0000000
--- a/mkfs.ubifs/compr.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2008 Nokia Corporation.
- * Copyright (C) 2008 University of Szeged, Hungary
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Authors: Artem Bityutskiy
- *          Adrian Hunter
- *          Zoltan Sogor
- */
-
-#ifndef __UBIFS_COMPRESS_H__
-#define __UBIFS_COMPRESS_H__
-
-/*
- * Compressors may end-up with more data in the output buffer than in the input
- * buffer. This constant defined the worst case factor, i.e. we assume that the
- * output buffer may be at max. WORST_COMPR_FACTOR times larger than input
- * buffer.
- */
-#define WORST_COMPR_FACTOR 4
-
-enum compression_type
-{
-	MKFS_UBIFS_COMPR_NONE,
-	MKFS_UBIFS_COMPR_LZO,
-	MKFS_UBIFS_COMPR_ZLIB,
-};
-
-int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len,
-		  int type);
-int init_compression(void);
-void destroy_compression(void);
-
-#endif
diff --git a/mkfs.ubifs/crc16.c b/mkfs.ubifs/crc16.c
deleted file mode 100644
index a19512e..0000000
--- a/mkfs.ubifs/crc16.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * This code was taken from the linux kernel. The license is GPL Version 2.
- */
-
-#include "crc16.h"
-
-/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
-uint16_t const crc16_table[256] = {
-	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
-	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
-	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
-	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
-	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
-	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
-	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
-	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
-	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
-	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
-	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
-	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
-	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
-	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
-	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
-	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
-	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
-	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
-	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
-	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
-	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
-	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
-	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
-	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
-	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
-	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
-	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
-	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
-	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
-	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
-	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
-	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
-};
-
-/**
- * crc16 - compute the CRC-16 for the data buffer
- * @crc:	previous CRC value
- * @buffer:	data pointer
- * @len:	number of bytes in the buffer
- *
- * Returns the updated CRC value.
- */
-uint16_t crc16(uint16_t crc, uint8_t const *buffer, size_t len)
-{
-	while (len--)
-		crc = crc16_byte(crc, *buffer++);
-	return crc;
-}
diff --git a/mkfs.ubifs/crc16.h b/mkfs.ubifs/crc16.h
deleted file mode 100644
index 539d21a..0000000
--- a/mkfs.ubifs/crc16.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Implements the standard CRC-16:
- *   Width 16
- *   Poly  0x8005 (x^16 + x^15 + x^2 + 1)
- *   Init  0
- *
- * Copyright (c) 2005 Ben Gardner <bgardner at wabtec.com>
- *
- * This code was taken from the linux kernel. The license is GPL Version 2.
- */
-
-#ifndef __CRC16_H__
-#define __CRC16_H__
-
-#include <stdlib.h>
-#include <stdint.h>
-
-extern uint16_t const crc16_table[256];
-
-extern uint16_t crc16(uint16_t crc, const uint8_t *buffer, size_t len);
-
-static inline uint16_t crc16_byte(uint16_t crc, const uint8_t data)
-{
-	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
-}
-
-#endif /* __CRC16_H__ */
diff --git a/mkfs.ubifs/defs.h b/mkfs.ubifs/defs.h
deleted file mode 100644
index 1fa3316..0000000
--- a/mkfs.ubifs/defs.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Greate deal of the code was taken from the kernel UBIFS implementation, and
- * this file contains some "glue" definitions.
- */
-
-#ifndef __UBIFS_DEFS_H__
-#define __UBIFS_DEFS_H__
-
-#define t16(x) ({ \
-	uint16_t __b = (x); \
-	(__LITTLE_ENDIAN==__BYTE_ORDER) ? __b : bswap_16(__b); \
-})
-
-#define t32(x) ({ \
-	uint32_t __b = (x); \
-	(__LITTLE_ENDIAN==__BYTE_ORDER) ? __b : bswap_32(__b); \
-})
-
-#define t64(x) ({ \
-	uint64_t __b = (x); \
-	(__LITTLE_ENDIAN==__BYTE_ORDER) ? __b : bswap_64(__b); \
-})
-
-#define cpu_to_le16(x) ((__le16){t16(x)})
-#define cpu_to_le32(x) ((__le32){t32(x)})
-#define cpu_to_le64(x) ((__le64){t64(x)})
-
-#define le16_to_cpu(x) (t16((x)))
-#define le32_to_cpu(x) (t32((x)))
-#define le64_to_cpu(x) (t64((x)))
-
-#define unlikely(x) (x)
-
-#define ubifs_assert(x) ({})
-
-struct qstr
-{
-	char *name;
-	size_t len;
-};
-
-/**
- * fls - find last (most-significant) bit set
- * @x: the word to search
- *
- * This is defined the same way as ffs.
- * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
- */
-static inline int fls(int x)
-{
-	int r = 32;
-
-	if (!x)
-		return 0;
-	if (!(x & 0xffff0000u)) {
-		x <<= 16;
-		r -= 16;
-	}
-	if (!(x & 0xff000000u)) {
-		x <<= 8;
-		r -= 8;
-	}
-	if (!(x & 0xf0000000u)) {
-		x <<= 4;
-		r -= 4;
-	}
-	if (!(x & 0xc0000000u)) {
-		x <<= 2;
-		r -= 2;
-	}
-	if (!(x & 0x80000000u)) {
-		x <<= 1;
-		r -= 1;
-	}
-	return r;
-}
-
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
-#if INT_MAX != 0x7fffffff
-#error : sizeof(int) must be 4 for this program
-#endif
-
-#if (~0ULL) != 0xffffffffffffffffULL
-#error : sizeof(long long) must be 8 for this program
-#endif
-
-#endif
diff --git a/mkfs.ubifs/devtable.c b/mkfs.ubifs/devtable.c
deleted file mode 100644
index dee035d..0000000
--- a/mkfs.ubifs/devtable.c
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Copyright (C) 2008 Nokia Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Author: Artem Bityutskiy
- *
- * Part of the device table parsing code was taken from the mkfs.jffs2 utility.
- * The original author of that code is Erik Andersen, hence:
- *	Copyright (C) 2001, 2002 Erik Andersen <andersen at codepoet.org>
- */
-
-/*
- * This file implemented device table support. 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)
- *
- * 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.
- *
- * Please, refer the device_table.txt file which can be found at MTD utilities
- * for more information about what the device table is.
- */
-
-#include "mkfs.ubifs.h"
-#include "hashtable/hashtable.h"
-#include "hashtable/hashtable_itr.h"
-
-/*
- * The hash table which contains paths to files/directories/device nodes
- * referred to in the device table. For example, if the device table refers
- * "/dev/loop0", the @path_htbl will contain "/dev" element.
- */
-static struct hashtable *path_htbl;
-
-/* Hash function used for hash tables */
-static unsigned int r5_hash(void *s)
-{
-	unsigned int a = 0;
-	const signed char *str = s;
-
-	while (*str) {
-		a += *str << 4;
-		a += *str >> 4;
-		a *= 11;
-		str++;
-	}
-
-	return a;
-}
-
-/*
- * Check whether 2 keys of a hash table are equivalent. The keys are path/file
- * names, so we simply use 'strcmp()'.
- */
-static int is_equivalent(void *k1, void *k2)
-{
-	return !strcmp(k1, k2);
-}
-
-/**
- * separate_last - separate out the last path component
- * @buf: the path to split
- * @len: length of the @buf string
- * @path: the beginning of path is returned here
- * @name: the last path component is returned here
- *
- * This helper function separates out the the last component of the full path
- * string. For example, "/dev/loop" would be split on "/dev" and "loop". This
- * function allocates memory for @path and @name and return the result there.
- * Returns zero in case of success and a negative error code in case of
- * failure.
- */
-static int separate_last(const char *buf, int len, char **path, char **name)
-{
-	int path_len = len, name_len;
-	const char *p = buf + len, *n;
-
-	while (*--p != '/')
-		path_len -= 1;
-
-	/* Drop the final '/' unless this is the root directory */
-	name_len = len - path_len;
-	n = buf + path_len;
-	if (path_len > 1)
-		path_len -= 1;
-
-	*path = malloc(path_len + 1);
-	if (!*path)
-		return err_msg("cannot allocate %d bytes of memory",
-			       path_len + 1);
-	memcpy(*path, buf, path_len);
-	(*path)[path_len] = '\0';
-
-	*name = malloc(name_len + 1);
-	if (!*name) {
-		free(*path);
-		return err_msg("cannot allocate %d bytes of memory",
-			       name_len + 1);
-	}
-	memcpy(*name, n, name_len + 1);
-
-	return 0;
-}
-
-static int interpret_table_entry(const char *line)
-{
-	char buf[1024], type, *path = NULL, *name = NULL;
-	int len;
-	struct path_htbl_element *ph_elt = NULL;
-	struct name_htbl_element *nh_elt = NULL;
-	unsigned int mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
-	unsigned int start = 0, increment = 0, count = 0;
-
-	if (sscanf(line, "%1023s %c %o %u %u %u %u %u %u %u",
-		   buf, &type, &mode, &uid, &gid, &major, &minor,
-		   &start, &increment, &count) < 0)
-		return sys_err_msg("sscanf failed");
-
-	dbg_msg(3, "name %s, type %c, mode %o, uid %u, gid %u, major %u, "
-		"minor %u, start %u, inc %u, cnt %u",
-		buf, type, mode, uid, gid, major, minor, start,
-		increment, count);
-
-	len = strnlen(buf, 1024);
-	if (len == 1024)
-		return err_msg("too long path");
-
-	if (!strcmp(buf, "/"))
-		return err_msg("device table entries require absolute paths");
-	if (buf[1] == '\0')
-		return err_msg("root directory cannot be created");
-	if (strstr(buf, "//"))
-		return err_msg("'//' cannot be used in the path");
-	if (buf[len - 1] == '/')
-		return err_msg("do not put '/' at the end");
-
-	if (strstr(buf, "/./") || strstr(buf, "/../") ||
-	    !strcmp(buf + len - 2, "/.") || !strcmp(buf + len - 3, "/.."))
-		return err_msg("'.' and '..' cannot be used in the path");
-
-	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:
-			return err_msg("unsupported file type '%c'", type);
-	}
-
-	if (separate_last(buf, len, &path, &name))
-		return -1;
-
-	/*
-	 * Check if this path already exist in the path hash table and add it
-	 * if it is not.
-	 */
-	ph_elt = hashtable_search(path_htbl, path);
-	if (!ph_elt) {
-		dbg_msg(3, "inserting '%s' into path hash table", path);
-		ph_elt = malloc(sizeof(struct path_htbl_element));
-		if (!ph_elt) {
-			err_msg("cannot allocate %zd bytes of memory",
-				sizeof(struct path_htbl_element));
-			goto out_free;
-		}
-
-		if (!hashtable_insert(path_htbl, path, ph_elt)) {
-			err_msg("cannot insert into path hash table");
-			goto out_free;
-		}
-
-		ph_elt->path = path;
-		path = NULL;
-		ph_elt->name_htbl = create_hashtable(128, &r5_hash,
-						     &is_equivalent);
-		if (!ph_elt->name_htbl) {
-			err_msg("cannot create name hash table");
-			goto out_free;
-		}
-	}
-
-	if (increment != 0 && count == 0)
-		return err_msg("count cannot be zero if increment is non-zero");
-
-	/*
-	 * Add the file/directory/device node (last component of the path) to
-	 * the name hashtable. The name hashtable resides in the corresponding
-	 * path hashtable element.
-	 */
-
-	if (count == 0) {
-		/* This entry does not require any iterating */
-		nh_elt = malloc(sizeof(struct name_htbl_element));
-		if (!nh_elt) {
-			err_msg("cannot allocate %zd bytes of memory",
-				sizeof(struct name_htbl_element));
-			goto out_free;
-		}
-
-		nh_elt->mode = mode;
-		nh_elt->uid = uid;
-		nh_elt->gid = gid;
-		nh_elt->dev = makedev(major, minor);
-
-		dbg_msg(3, "inserting '%s' into name hash table (major %d, minor %d)",
-			name, major(nh_elt->dev), minor(nh_elt->dev));
-
-		if (hashtable_search(ph_elt->name_htbl, name))
-			return err_msg("'%s' is referred twice", buf);
-
-		nh_elt->name = name;
-		if (!hashtable_insert(ph_elt->name_htbl, name, nh_elt)) {
-			err_msg("cannot insert into name hash table");
-			goto out_free;
-		}
-	} else {
-		int i, num = start + count, len = strlen(name) + 20;
-		char *nm;
-
-		for (i = start; i < num; i++) {
-			nh_elt = malloc(sizeof(struct name_htbl_element));
-			if (!nh_elt) {
-				err_msg("cannot allocate %zd bytes of memory",
-					sizeof(struct name_htbl_element));
-				goto out_free;
-			}
-
-			nh_elt->mode = mode;
-			nh_elt->uid = uid;
-			nh_elt->gid = gid;
-			nh_elt->dev = makedev(major, minor + (i - start) * increment);
-
-			nm = malloc(len);
-			if (!nm) {
-				err_msg("cannot allocate %d bytes of memory", len);
-				goto out_free;
-			}
-
-			sprintf(nm, "%s%d", name, i);
-			nh_elt->name = nm;
-
-			dbg_msg(3, "inserting '%s' into name hash table (major %d, minor %d)",
-			        nm, major(nh_elt->dev), minor(nh_elt->dev));
-
-			if (hashtable_search(ph_elt->name_htbl, nm)) {
-				err_msg("'%s' is referred twice", buf);
-				free (nm);
-				goto out_free;
-			}
-
-			if (!hashtable_insert(ph_elt->name_htbl, nm, nh_elt)) {
-				err_msg("cannot insert into name hash table");
-				free (nm);
-				goto out_free;
-			}
-		}
-		free(name);
-		name = NULL;
-	}
-
-	return 0;
-
-out_free:
-	free(ph_elt);
-	free(nh_elt);
-	free(path);
-	free(name);
-	return -1;
-}
-
-/**
- * parse_devtable - parse the device table.
- * @tbl_file: device table file name
- *
- * This function parses the device table and prepare the hash table which will
- * later be used by mkfs.ubifs to create the specified files/device nodes.
- * Returns zero in case of success and a negative error code in case of
- * failure.
- */
-int parse_devtable(const char *tbl_file)
-{
-	FILE *f;
-	char *line = NULL;
-	struct stat st;
-	size_t len;
-
-	dbg_msg(1, "parsing device table file '%s'", tbl_file);
-
-	path_htbl = create_hashtable(128, &r5_hash, &is_equivalent);
-	if (!path_htbl)
-		return err_msg("cannot create path hash table");
-
-	f = fopen(tbl_file, "r");
-	if (!f)
-		return sys_err_msg("cannot open '%s'", tbl_file);
-
-	if (fstat(fileno(f), &st) < 0) {
-		sys_err_msg("cannot stat '%s'", tbl_file);
-		goto out_close;
-	}
-
-	if (st.st_size < 10) {
-		sys_err_msg("'%s' is too short", tbl_file);
-		goto out_close;
-	}
-
-	/*
-	 * 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
-	 */
-	while (getline(&line, &len, f) != -1) {
-		/* First trim off any white-space */
-		len = strlen(line);
-
-		/* Trim trailing white-space */
-		while (len > 0 && isspace(line[len - 1]))
-			line[--len] = '\0';
-		/* Trim leading white-space */
-		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)) {
-				err_msg("cannot parse '%s'", line);
-				goto out_close;
-			}
-		}
-
-		free(line);
-		line = NULL;
-	}
-
-	dbg_msg(1, "finished parsing");
-	fclose(f);
-	return 0;
-
-out_close:
-	fclose(f);
-	free_devtable_info();
-	return -1;
-}
-
-/**
- * devtbl_find_path - find a path in the path hash table.
- * @path: UBIFS path to find.
- *
- * This looks up the path hash table. Returns the path hash table element
- * reference if @path was found and %NULL if not.
- */
-struct path_htbl_element *devtbl_find_path(const char *path)
-{
-	if (!path_htbl)
-		return NULL;
-
-	return hashtable_search(path_htbl, (void *)path);
-}
-
-/**
- * devtbl_find_name - find a name in the name hash table.
- * @ph_etl: path hash table element to find at
- * @name: name to find
- *
- * This looks up the name hash table. Returns the name hash table element
- * reference if @name found and %NULL if not.
- */
-struct name_htbl_element *devtbl_find_name(struct path_htbl_element *ph_elt,
-					   const char *name)
-{
-	if (!path_htbl)
-		return NULL;
-
-	return hashtable_search(ph_elt->name_htbl, (void *)name);
-}
-
-/**
- * override_attributes - override inode attributes.
- * @st: struct stat object to containing the attributes to override
- * @ph_elt: path hash table element object
- * @nh_elt: name hash table element object containing the new values
- *
- * The device table file may override attributes like UID of files. For
- * example, the device table may contain a "/dev" entry, and the UBIFS FS on
- * the host may contain "/dev" directory. In this case the attributes of the
- * "/dev" directory inode has to be as the device table specifies.
- *
- * Note, the hash element is removed by this function as well.
- */
-int override_attributes(struct stat *st, struct path_htbl_element *ph_elt,
-			struct name_htbl_element *nh_elt)
-{
-	if (!path_htbl)
-		return 0;
-
-	if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode) ||
-	    S_ISFIFO(st->st_mode))
-		return err_msg("%s/%s both exists at UBIFS root at host, "
-			       "and is referred from the device table",
-			       strcmp(ph_elt->path, "/") ? ph_elt->path : "",
-			       nh_elt->name);
-
-	if ((st->st_mode & S_IFMT) != (nh_elt->mode & S_IFMT))
-		return err_msg("%s/%s is referred from the device table also exists in "
-			       "the UBIFS root directory at host, but the file type is "
-			       "different", strcmp(ph_elt->path, "/") ? ph_elt->path : "",
-			       nh_elt->name);
-
-	dbg_msg(3, "set UID %d, GID %d, mode %o for %s/%s as device table says",
-		nh_elt->uid, nh_elt->gid, nh_elt->mode, ph_elt->path, nh_elt->name);
-
-	st->st_uid = nh_elt->uid;
-	st->st_gid = nh_elt->gid;
-	st->st_mode = nh_elt->mode;
-
-	hashtable_remove(ph_elt->name_htbl, (void *)nh_elt->name);
-	return 0;
-}
-
-/**
- * first_name_htbl_element - return first element of the name hash table.
- * @ph_elt: the path hash table the name hash table belongs to
- * @itr: double pointer to a 'struct hashtable_itr' object where the
- *       information about further iterations is stored
- *
- * This function implements name hash table iteration together with
- * 'next_name_htbl_element()'. Returns the first name hash table element or
- * %NULL if the hash table is empty.
- */
-struct name_htbl_element *
-first_name_htbl_element(struct path_htbl_element *ph_elt,
-			struct hashtable_itr **itr)
-{
-	if (!path_htbl || !ph_elt || hashtable_count(ph_elt->name_htbl) == 0)
-		return NULL;
-
-	*itr = hashtable_iterator(ph_elt->name_htbl);
-	return hashtable_iterator_value(*itr);
-}
-
-/**
- * first_name_htbl_element - return next element of the name hash table.
- * @ph_elt: the path hash table the name hash table belongs to
- * @itr: double pointer to a 'struct hashtable_itr' object where the
- *       information about further iterations is stored
- *
- * This function implements name hash table iteration together with
- * 'first_name_htbl_element()'. Returns the next name hash table element or
- * %NULL if there are no more elements.
- */
-struct name_htbl_element *
-next_name_htbl_element(struct path_htbl_element *ph_elt,
-		       struct hashtable_itr **itr)
-{
-	if (!path_htbl || !ph_elt || !hashtable_iterator_advance(*itr))
-		return NULL;
-
-	return hashtable_iterator_value(*itr);
-}
-
-/**
- * free_devtable_info - free device table information.
- *
- * This function frees the path hash table and the name hash tables.
- */
-void free_devtable_info(void)
-{
-	struct hashtable_itr *ph_itr;
-	struct path_htbl_element *ph_elt;
-
-	if (!path_htbl)
-		return;
-
-	if (hashtable_count(path_htbl) > 0) {
-		ph_itr = hashtable_iterator(path_htbl);
-		do {
-			ph_elt = hashtable_iterator_value(ph_itr);
-			/*
-			 * Note, since we use the same string for the key and
-			 * @name in the name hash table elements, we do not
-			 * have to iterate name hash table because @name memory
-			 * will be freed when freeing the key.
-			 */
-			hashtable_destroy(ph_elt->name_htbl, 1);
-		} while (hashtable_iterator_advance(ph_itr));
-	}
-	hashtable_destroy(path_htbl, 1);
-}
diff --git a/mkfs.ubifs/hashtable/hashtable.c b/mkfs.ubifs/hashtable/hashtable.c
deleted file mode 100644
index c1f99ed..0000000
--- a/mkfs.ubifs/hashtable/hashtable.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/* Copyright (C) 2004 Christopher Clark <firstname.lastname at cl.cam.ac.uk> */
-
-#define PROGRAM_NAME "hashtable"
-
-#include "common.h"
-#include "hashtable.h"
-#include "hashtable_private.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
-/*
-Credit for primes table: Aaron Krowne
- http://br.endernet.org/~akrowne/
- http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
-*/
-static const unsigned int primes[] = {
-53, 97, 193, 389,
-769, 1543, 3079, 6151,
-12289, 24593, 49157, 98317,
-196613, 393241, 786433, 1572869,
-3145739, 6291469, 12582917, 25165843,
-50331653, 100663319, 201326611, 402653189,
-805306457, 1610612741
-};
-const unsigned int prime_table_length = ARRAY_SIZE(primes);
-const float max_load_factor = 0.65;
-
-/*****************************************************************************/
-struct hashtable *
-create_hashtable(unsigned int minsize,
-                 unsigned int (*hashf) (void*),
-                 int (*eqf) (void*,void*))
-{
-    struct hashtable *h;
-    unsigned int pindex, size = primes[0];
-    /* Check requested hashtable isn't too large */
-    if (minsize > (1u << 30)) return NULL;
-    /* Enforce size as prime */
-    for (pindex=0; pindex < prime_table_length; pindex++) {
-        if (primes[pindex] > minsize) { size = primes[pindex]; break; }
-    }
-    h = (struct hashtable *)malloc(sizeof(struct hashtable));
-    if (NULL == h) return NULL; /*oom*/
-    h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
-    if (NULL == h->table) { free(h); return NULL; } /*oom*/
-    memset(h->table, 0, size * sizeof(struct entry *));
-    h->tablelength  = size;
-    h->primeindex   = pindex;
-    h->entrycount   = 0;
-    h->hashfn       = hashf;
-    h->eqfn         = eqf;
-    h->loadlimit    = (unsigned int) ceil(size * max_load_factor);
-    return h;
-}
-
-/*****************************************************************************/
-unsigned int
-hash(struct hashtable *h, void *k)
-{
-    /* Aim to protect against poor hash functions by adding logic here
-     * - logic taken from java 1.4 hashtable source */
-    unsigned int i = h->hashfn(k);
-    i += ~(i << 9);
-    i ^=  ((i >> 14) | (i << 18)); /* >>> */
-    i +=  (i << 4);
-    i ^=  ((i >> 10) | (i << 22)); /* >>> */
-    return i;
-}
-
-/*****************************************************************************/
-static int
-hashtable_expand(struct hashtable *h)
-{
-    /* Double the size of the table to accomodate more entries */
-    struct entry **newtable;
-    struct entry *e;
-    struct entry **pE;
-    unsigned int newsize, i, index;
-    /* Check we're not hitting max capacity */
-    if (h->primeindex == (prime_table_length - 1)) return 0;
-    newsize = primes[++(h->primeindex)];
-
-    newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
-    if (NULL != newtable)
-    {
-        memset(newtable, 0, newsize * sizeof(struct entry *));
-        /* This algorithm is not 'stable'. ie. it reverses the list
-         * when it transfers entries between the tables */
-        for (i = 0; i < h->tablelength; i++) {
-            while (NULL != (e = h->table[i])) {
-                h->table[i] = e->next;
-                index = indexFor(newsize,e->h);
-                e->next = newtable[index];
-                newtable[index] = e;
-            }
-        }
-        free(h->table);
-        h->table = newtable;
-    }
-    /* Plan B: realloc instead */
-    else
-    {
-        newtable = (struct entry **)
-                   realloc(h->table, newsize * sizeof(struct entry *));
-        if (NULL == newtable) { (h->primeindex)--; return 0; }
-        h->table = newtable;
-        memset(newtable[h->tablelength], 0, newsize - h->tablelength);
-        for (i = 0; i < h->tablelength; i++) {
-            for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
-                index = indexFor(newsize,e->h);
-                if (index == i)
-                {
-                    pE = &(e->next);
-                }
-                else
-                {
-                    *pE = e->next;
-                    e->next = newtable[index];
-                    newtable[index] = e;
-                }
-            }
-        }
-    }
-    h->tablelength = newsize;
-    h->loadlimit   = (unsigned int) ceil(newsize * max_load_factor);
-    return -1;
-}
-
-/*****************************************************************************/
-unsigned int
-hashtable_count(struct hashtable *h)
-{
-    return h->entrycount;
-}
-
-/*****************************************************************************/
-int
-hashtable_insert(struct hashtable *h, void *k, void *v)
-{
-    /* This method allows duplicate keys - but they shouldn't be used */
-    unsigned int index;
-    struct entry *e;
-    if (++(h->entrycount) > h->loadlimit)
-    {
-        /* Ignore the return value. If expand fails, we should
-         * still try cramming just this value into the existing table
-         * -- we may not have memory for a larger table, but one more
-         * element may be ok. Next time we insert, we'll try expanding again.*/
-        hashtable_expand(h);
-    }
-    e = (struct entry *)malloc(sizeof(struct entry));
-    if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
-    e->h = hash(h,k);
-    index = indexFor(h->tablelength,e->h);
-    e->k = k;
-    e->v = v;
-    e->next = h->table[index];
-    h->table[index] = e;
-    return -1;
-}
-
-/*****************************************************************************/
-void * /* returns value associated with key */
-hashtable_search(struct hashtable *h, void *k)
-{
-    struct entry *e;
-    unsigned int hashvalue, index;
-    hashvalue = hash(h,k);
-    index = indexFor(h->tablelength,hashvalue);
-    e = h->table[index];
-    while (NULL != e)
-    {
-        /* Check hash value to short circuit heavier comparison */
-        if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
-        e = e->next;
-    }
-    return NULL;
-}
-
-/*****************************************************************************/
-void * /* returns value associated with key */
-hashtable_remove(struct hashtable *h, void *k)
-{
-    /* TODO: consider compacting the table when the load factor drops enough,
-     *       or provide a 'compact' method. */
-
-    struct entry *e;
-    struct entry **pE;
-    void *v;
-    unsigned int hashvalue, index;
-
-    hashvalue = hash(h,k);
-    index = indexFor(h->tablelength,hash(h,k));
-    pE = &(h->table[index]);
-    e = *pE;
-    while (NULL != e)
-    {
-        /* Check hash value to short circuit heavier comparison */
-        if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
-        {
-            *pE = e->next;
-            h->entrycount--;
-            v = e->v;
-            freekey(e->k);
-            free(e);
-            return v;
-        }
-        pE = &(e->next);
-        e = e->next;
-    }
-    return NULL;
-}
-
-/*****************************************************************************/
-/* destroy */
-void
-hashtable_destroy(struct hashtable *h, int free_values)
-{
-    unsigned int i;
-    struct entry *e, *f;
-    struct entry **table = h->table;
-    if (free_values)
-    {
-        for (i = 0; i < h->tablelength; i++)
-        {
-            e = table[i];
-            while (NULL != e)
-            { f = e; e = e->next; freekey(f->k); free(f->v); free(f); }
-        }
-    }
-    else
-    {
-        for (i = 0; i < h->tablelength; i++)
-        {
-            e = table[i];
-            while (NULL != e)
-            { f = e; e = e->next; freekey(f->k); free(f); }
-        }
-    }
-    free(h->table);
-    free(h);
-}
-
-/*
- * Copyright (c) 2002, Christopher Clark
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of the original author; nor the names of any contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
diff --git a/mkfs.ubifs/hashtable/hashtable.h b/mkfs.ubifs/hashtable/hashtable.h
deleted file mode 100644
index c0b0acd..0000000
--- a/mkfs.ubifs/hashtable/hashtable.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/* Copyright (C) 2002 Christopher Clark <firstname.lastname at cl.cam.ac.uk> */
-
-#ifndef __HASHTABLE_CWC22_H__
-#define __HASHTABLE_CWC22_H__
-
-struct hashtable;
-
-/* Example of use:
- *
- *      struct hashtable  *h;
- *      struct some_key   *k;
- *      struct some_value *v;
- *
- *      static unsigned int         hash_from_key_fn( void *k );
- *      static int                  keys_equal_fn ( void *key1, void *key2 );
- *
- *      h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
- *      k = (struct some_key *)     malloc(sizeof(struct some_key));
- *      v = (struct some_value *)   malloc(sizeof(struct some_value));
- *
- *      (initialise k and v to suitable values)
- *
- *      if (! hashtable_insert(h,k,v) )
- *      {     exit(-1);               }
- *
- *      if (NULL == (found = hashtable_search(h,k) ))
- *      {    printf("not found!");                  }
- *
- *      if (NULL == (found = hashtable_remove(h,k) ))
- *      {    printf("Not found\n");                 }
- *
- */
-
-/* Macros may be used to define type-safe(r) hashtable access functions, with
- * methods specialized to take known key and value types as parameters.
- *
- * Example:
- *
- * Insert this at the start of your file:
- *
- * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
- * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
- * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
- *
- * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
- * These operate just like hashtable_insert etc., with the same parameters,
- * but their function signatures have 'struct some_key *' rather than
- * 'void *', and hence can generate compile time errors if your program is
- * supplying incorrect data as a key (and similarly for value).
- *
- * Note that the hash and key equality functions passed to create_hashtable
- * still take 'void *' parameters instead of 'some key *'. This shouldn't be
- * a difficult issue as they're only defined and passed once, and the other
- * functions will ensure that only valid keys are supplied to them.
- *
- * The cost for this checking is increased code size and runtime overhead
- * - if performance is important, it may be worth switching back to the
- * unsafe methods once your program has been debugged with the safe methods.
- * This just requires switching to some simple alternative defines - eg:
- * #define insert_some hashtable_insert
- *
- */
-
-/*****************************************************************************
- * create_hashtable
-
- * @name                    create_hashtable
- * @param   minsize         minimum initial size of hashtable
- * @param   hashfunction    function for hashing keys
- * @param   key_eq_fn       function for determining key equality
- * @return                  newly created hashtable or NULL on failure
- */
-
-struct hashtable *
-create_hashtable(unsigned int minsize,
-                 unsigned int (*hashfunction) (void*),
-                 int (*key_eq_fn) (void*,void*));
-
-/*****************************************************************************
- * hashtable_insert
-
- * @name        hashtable_insert
- * @param   h   the hashtable to insert into
- * @param   k   the key - hashtable claims ownership and will free on removal
- * @param   v   the value - does not claim ownership
- * @return      non-zero for successful insertion
- *
- * This function will cause the table to expand if the insertion would take
- * the ratio of entries to table size over the maximum load factor.
- *
- * This function does not check for repeated insertions with a duplicate key.
- * The value returned when using a duplicate key is undefined -- when
- * the hashtable changes size, the order of retrieval of duplicate key
- * entries is reversed.
- * If in doubt, remove before insert.
- */
-
-int
-hashtable_insert(struct hashtable *h, void *k, void *v);
-
-#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
-int fnname (struct hashtable *h, keytype *k, valuetype *v) \
-{ \
-    return hashtable_insert(h,k,v); \
-}
-
-/*****************************************************************************
- * hashtable_search
-
- * @name        hashtable_search
- * @param   h   the hashtable to search
- * @param   k   the key to search for  - does not claim ownership
- * @return      the value associated with the key, or NULL if none found
- */
-
-void *
-hashtable_search(struct hashtable *h, void *k);
-
-#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
-valuetype * fnname (struct hashtable *h, keytype *k) \
-{ \
-    return (valuetype *) (hashtable_search(h,k)); \
-}
-
-/*****************************************************************************
- * hashtable_remove
-
- * @name        hashtable_remove
- * @param   h   the hashtable to remove the item from
- * @param   k   the key to search for  - does not claim ownership
- * @return      the value associated with the key, or NULL if none found
- */
-
-void * /* returns value */
-hashtable_remove(struct hashtable *h, void *k);
-
-#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
-valuetype * fnname (struct hashtable *h, keytype *k) \
-{ \
-    return (valuetype *) (hashtable_remove(h,k)); \
-}
-
-
-/*****************************************************************************
- * hashtable_count
-
- * @name        hashtable_count
- * @param   h   the hashtable
- * @return      the number of items stored in the hashtable
- */
-unsigned int
-hashtable_count(struct hashtable *h);
-
-
-/*****************************************************************************
- * hashtable_destroy
-
- * @name        hashtable_destroy
- * @param   h   the hashtable
- * @param       free_values     whether to call 'free' on the remaining values
- */
-
-void
-hashtable_destroy(struct hashtable *h, int free_values);
-
-#endif /* __HASHTABLE_CWC22_H__ */
-
-/*
- * Copyright (c) 2002, Christopher Clark
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of the original author; nor the names of any contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
diff --git a/mkfs.ubifs/hashtable/hashtable_itr.c b/mkfs.ubifs/hashtable/hashtable_itr.c
deleted file mode 100644
index d102453..0000000
--- a/mkfs.ubifs/hashtable/hashtable_itr.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/* Copyright (C) 2002, 2004 Christopher Clark  <firstname.lastname at cl.cam.ac.uk> */
-
-#include "hashtable.h"
-#include "hashtable_private.h"
-#include "hashtable_itr.h"
-#include <stdlib.h> /* defines NULL */
-
-/*****************************************************************************/
-/* hashtable_iterator    - iterator constructor */
-
-struct hashtable_itr *
-hashtable_iterator(struct hashtable *h)
-{
-    unsigned int i, tablelength;
-    struct hashtable_itr *itr = (struct hashtable_itr *)
-        malloc(sizeof(struct hashtable_itr));
-    if (NULL == itr) return NULL;
-    itr->h = h;
-    itr->e = NULL;
-    itr->parent = NULL;
-    tablelength = h->tablelength;
-    itr->index = tablelength;
-    if (0 == h->entrycount) return itr;
-
-    for (i = 0; i < tablelength; i++)
-    {
-        if (NULL != h->table[i])
-        {
-            itr->e = h->table[i];
-            itr->index = i;
-            break;
-        }
-    }
-    return itr;
-}
-
-/*****************************************************************************/
-/* advance - advance the iterator to the next element
- *           returns zero if advanced to end of table */
-
-int
-hashtable_iterator_advance(struct hashtable_itr *itr)
-{
-    unsigned int j,tablelength;
-    struct entry **table;
-    struct entry *next;
-    if (NULL == itr->e) return 0; /* stupidity check */
-
-    next = itr->e->next;
-    if (NULL != next)
-    {
-        itr->parent = itr->e;
-        itr->e = next;
-        return -1;
-    }
-    tablelength = itr->h->tablelength;
-    itr->parent = NULL;
-    if (tablelength <= (j = ++(itr->index)))
-    {
-        itr->e = NULL;
-        return 0;
-    }
-    table = itr->h->table;
-    while (NULL == (next = table[j]))
-    {
-        if (++j >= tablelength)
-        {
-            itr->index = tablelength;
-            itr->e = NULL;
-            return 0;
-        }
-    }
-    itr->index = j;
-    itr->e = next;
-    return -1;
-}
-
-/*****************************************************************************/
-/* remove - remove the entry at the current iterator position
- *          and advance the iterator, if there is a successive
- *          element.
- *          If you want the value, read it before you remove:
- *          beware memory leaks if you don't.
- *          Returns zero if end of iteration. */
-
-int
-hashtable_iterator_remove(struct hashtable_itr *itr)
-{
-    struct entry *remember_e, *remember_parent;
-    int ret;
-
-    /* Do the removal */
-    if (NULL == (itr->parent))
-    {
-        /* element is head of a chain */
-        itr->h->table[itr->index] = itr->e->next;
-    } else {
-        /* element is mid-chain */
-        itr->parent->next = itr->e->next;
-    }
-    /* itr->e is now outside the hashtable */
-    remember_e = itr->e;
-    itr->h->entrycount--;
-    freekey(remember_e->k);
-
-    /* Advance the iterator, correcting the parent */
-    remember_parent = itr->parent;
-    ret = hashtable_iterator_advance(itr);
-    if (itr->parent == remember_e) { itr->parent = remember_parent; }
-    free(remember_e);
-    return ret;
-}
-
-/*****************************************************************************/
-int /* returns zero if not found */
-hashtable_iterator_search(struct hashtable_itr *itr,
-                          struct hashtable *h, void *k)
-{
-    struct entry *e, *parent;
-    unsigned int hashvalue, index;
-
-    hashvalue = hash(h,k);
-    index = indexFor(h->tablelength,hashvalue);
-
-    e = h->table[index];
-    parent = NULL;
-    while (NULL != e)
-    {
-        /* Check hash value to short circuit heavier comparison */
-        if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
-        {
-            itr->index = index;
-            itr->e = e;
-            itr->parent = parent;
-            itr->h = h;
-            return -1;
-        }
-        parent = e;
-        e = e->next;
-    }
-    return 0;
-}
-
-
-/*
- * Copyright (c) 2002, 2004, Christopher Clark
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of the original author; nor the names of any contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
diff --git a/mkfs.ubifs/hashtable/hashtable_itr.h b/mkfs.ubifs/hashtable/hashtable_itr.h
deleted file mode 100644
index 5c94a04..0000000
--- a/mkfs.ubifs/hashtable/hashtable_itr.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname at cl.cam.ac.uk> */
-
-#ifndef __HASHTABLE_ITR_CWC22__
-#define __HASHTABLE_ITR_CWC22__
-#include "hashtable.h"
-#include "hashtable_private.h" /* needed to enable inlining */
-
-/*****************************************************************************/
-/* This struct is only concrete here to allow the inlining of two of the
- * accessor functions. */
-struct hashtable_itr
-{
-    struct hashtable *h;
-    struct entry *e;
-    struct entry *parent;
-    unsigned int index;
-};
-
-
-/*****************************************************************************/
-/* hashtable_iterator
- */
-
-struct hashtable_itr *
-hashtable_iterator(struct hashtable *h);
-
-/*****************************************************************************/
-/* hashtable_iterator_key
- * - return the value of the (key,value) pair at the current position */
-
-static inline void *
-hashtable_iterator_key(struct hashtable_itr *i)
-{
-    return i->e->k;
-}
-
-/*****************************************************************************/
-/* value - return the value of the (key,value) pair at the current position */
-
-static inline void *
-hashtable_iterator_value(struct hashtable_itr *i)
-{
-    return i->e->v;
-}
-
-/*****************************************************************************/
-/* advance - advance the iterator to the next element
- *           returns zero if advanced to end of table */
-
-int
-hashtable_iterator_advance(struct hashtable_itr *itr);
-
-/*****************************************************************************/
-/* remove - remove current element and advance the iterator to the next element
- *          NB: if you need the value to free it, read it before
- *          removing. ie: beware memory leaks!
- *          returns zero if advanced to end of table */
-
-int
-hashtable_iterator_remove(struct hashtable_itr *itr);
-
-/*****************************************************************************/
-/* search - overwrite the supplied iterator, to point to the entry
- *          matching the supplied key.
-            h points to the hashtable to be searched.
- *          returns zero if not found. */
-int
-hashtable_iterator_search(struct hashtable_itr *itr,
-                          struct hashtable *h, void *k);
-
-#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
-int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \
-{ \
-    return (hashtable_iterator_search(i,h,k)); \
-}
-
-
-
-#endif /* __HASHTABLE_ITR_CWC22__*/
-
-/*
- * Copyright (c) 2002, 2004, Christopher Clark
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of the original author; nor the names of any contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
diff --git a/mkfs.ubifs/hashtable/hashtable_private.h b/mkfs.ubifs/hashtable/hashtable_private.h
deleted file mode 100644
index 3a558e6..0000000
--- a/mkfs.ubifs/hashtable/hashtable_private.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname at cl.cam.ac.uk> */
-
-#ifndef __HASHTABLE_PRIVATE_CWC22_H__
-#define __HASHTABLE_PRIVATE_CWC22_H__
-
-#include "hashtable.h"
-
-/*****************************************************************************/
-struct entry
-{
-    void *k, *v;
-    unsigned int h;
-    struct entry *next;
-};
-
-struct hashtable {
-    unsigned int tablelength;
-    struct entry **table;
-    unsigned int entrycount;
-    unsigned int loadlimit;
-    unsigned int primeindex;
-    unsigned int (*hashfn) (void *k);
-    int (*eqfn) (void *k1, void *k2);
-};
-
-/*****************************************************************************/
-unsigned int
-hash(struct hashtable *h, void *k);
-
-/*****************************************************************************/
-/* indexFor */
-static inline unsigned int
-indexFor(unsigned int tablelength, unsigned int hashvalue) {
-    return (hashvalue % tablelength);
-};
-
-/* Only works if tablelength == 2^N */
-/*static inline unsigned int
-indexFor(unsigned int tablelength, unsigned int hashvalue)
-{
-    return (hashvalue & (tablelength - 1u));
-}
-*/
-
-/*****************************************************************************/
-#define freekey(X) free(X)
-/*define freekey(X) ; */
-
-
-/*****************************************************************************/
-
-#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
-
-/*
- * Copyright (c) 2002, Christopher Clark
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of the original author; nor the names of any contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
diff --git a/mkfs.ubifs/key.h b/mkfs.ubifs/key.h
deleted file mode 100644
index d3a02d4..0000000
--- a/mkfs.ubifs/key.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * This file is part of UBIFS.
- *
- * Copyright (C) 2006-2008 Nokia Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Authors: Artem Bityutskiy (Битюцкий Артём)
- *          Adrian Hunter
- */
-
-/*
- * This header contains various key-related definitions and helper function.
- * UBIFS allows several key schemes, so we access key fields only via these
- * helpers. At the moment only one key scheme is supported.
- *
- * Simple key scheme
- * ~~~~~~~~~~~~~~~~~
- *
- * Keys are 64-bits long. First 32-bits are inode number (parent inode number
- * in case of direntry key). Next 3 bits are node type. The last 29 bits are
- * 4KiB offset in case of inode node, and direntry hash in case of a direntry
- * node. We use "r5" hash borrowed from reiserfs.
- */
-
-#ifndef __UBIFS_KEY_H__
-#define __UBIFS_KEY_H__
-
-/**
- * key_mask_hash - mask a valid hash value.
- * @val: value to be masked
- *
- * We use hash values as offset in directories, so values %0 and %1 are
- * reserved for "." and "..". %2 is reserved for "end of readdir" marker. This
- * function makes sure the reserved values are not used.
- */
-static inline uint32_t key_mask_hash(uint32_t hash)
-{
-	hash &= UBIFS_S_KEY_HASH_MASK;
-	if (unlikely(hash <= 2))
-		hash += 3;
-	return hash;
-}
-
-/**
- * key_r5_hash - R5 hash function (borrowed from reiserfs).
- * @s: direntry name
- * @len: name length
- */
-static inline uint32_t key_r5_hash(const char *s, int len)
-{
-	uint32_t a = 0;
-	const signed char *str = (const signed char *)s;
-
-	len = len;
-	while (*str) {
-		a += *str << 4;
-		a += *str >> 4;
-		a *= 11;
-		str++;
-	}
-
-	return key_mask_hash(a);
-}
-
-/**
- * key_test_hash - testing hash function.
- * @str: direntry name
- * @len: name length
- */
-static inline uint32_t key_test_hash(const char *str, int len)
-{
-	uint32_t a = 0;
-
-	len = min_t(uint32_t, len, 4);
-	memcpy(&a, str, len);
-	return key_mask_hash(a);
-}
-
-/**
- * ino_key_init - initialize inode key.
- * @c: UBIFS file-system description object
- * @key: key to initialize
- * @inum: inode number
- */
-static inline void ino_key_init(union ubifs_key *key, ino_t inum)
-{
-	key->u32[0] = inum;
-	key->u32[1] = UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS;
-}
-
-/**
- * dent_key_init - initialize directory entry key.
- * @c: UBIFS file-system description object
- * @key: key to initialize
- * @inum: parent inode number
- * @nm: direntry name and length
- */
-static inline void dent_key_init(const struct ubifs_info *c,
-				 union ubifs_key *key, ino_t inum,
-				 const struct qstr *nm)
-{
-	uint32_t hash = c->key_hash(nm->name, nm->len);
-
-	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
-	key->u32[0] = inum;
-	key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
-}
-
-/**
- * data_key_init - initialize data key.
- * @c: UBIFS file-system description object
- * @key: key to initialize
- * @inum: inode number
- * @block: block number
- */
-static inline void data_key_init(union ubifs_key *key, ino_t inum,
-				 unsigned int block)
-{
-	ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
-	key->u32[0] = inum;
-	key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS);
-}
-
-/**
- * key_write - transform a key from in-memory format.
- * @c: UBIFS file-system description object
- * @from: the key to transform
- * @to: the key to store the result
- */
-static inline void key_write(const union ubifs_key *from, void *to)
-{
-	union ubifs_key *t = to;
-
-	t->j32[0] = cpu_to_le32(from->u32[0]);
-	t->j32[1] = cpu_to_le32(from->u32[1]);
-	memset(to + 8, 0, UBIFS_MAX_KEY_LEN - 8);
-}
-
-/**
- * key_write_idx - transform a key from in-memory format for the index.
- * @c: UBIFS file-system description object
- * @from: the key to transform
- * @to: the key to store the result
- */
-static inline void key_write_idx(const union ubifs_key *from, void *to)
-{
-	union ubifs_key *t = to;
-
-	t->j32[0] = cpu_to_le32(from->u32[0]);
-	t->j32[1] = cpu_to_le32(from->u32[1]);
-}
-
-/**
- * keys_cmp - compare keys.
- * @c: UBIFS file-system description object
- * @key1: the first key to compare
- * @key2: the second key to compare
- *
- * This function compares 2 keys and returns %-1 if @key1 is less than
- * @key2, 0 if the keys are equivalent and %1 if @key1 is greater than @key2.
- */
-static inline int keys_cmp(const union ubifs_key *key1,
-			   const union ubifs_key *key2)
-{
-	if (key1->u32[0] < key2->u32[0])
-		return -1;
-	if (key1->u32[0] > key2->u32[0])
-		return 1;
-	if (key1->u32[1] < key2->u32[1])
-		return -1;
-	if (key1->u32[1] > key2->u32[1])
-		return 1;
-
-	return 0;
-}
-
-#endif /* !__UBIFS_KEY_H__ */
diff --git a/mkfs.ubifs/lpt.c b/mkfs.ubifs/lpt.c
deleted file mode 100644
index 6aa0b88..0000000
--- a/mkfs.ubifs/lpt.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- * This file is part of UBIFS.
- *
- * Copyright (C) 2006, 2007 Nokia Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Authors: Adrian Hunter
- *          Artem Bityutskiy
- */
-
-#include "mkfs.ubifs.h"
-
-/**
- * do_calc_lpt_geom - calculate sizes for the LPT area.
- * @c: the UBIFS file-system description object
- *
- * Calculate the sizes of LPT bit fields, nodes, and tree, based on the
- * properties of the flash and whether LPT is "big" (c->big_lpt).
- */
-static void do_calc_lpt_geom(struct ubifs_info *c)
-{
-	int n, bits, per_leb_wastage;
-	long long sz, tot_wastage;
-
-	c->pnode_cnt = (c->main_lebs + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
-
-	n = (c->pnode_cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
-	c->nnode_cnt = n;
-	while (n > 1) {
-		n = (n + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
-		c->nnode_cnt += n;
-	}
-
-	c->lpt_hght = 1;
-	n = UBIFS_LPT_FANOUT;
-	while (n < c->pnode_cnt) {
-		c->lpt_hght += 1;
-		n <<= UBIFS_LPT_FANOUT_SHIFT;
-	}
-
-	c->space_bits = fls(c->leb_size) - 3;
-	c->lpt_lnum_bits = fls(c->lpt_lebs);
-	c->lpt_offs_bits = fls(c->leb_size - 1);
-	c->lpt_spc_bits = fls(c->leb_size);
-
-	n = (c->max_leb_cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
-	c->pcnt_bits = fls(n - 1);
-
-	c->lnum_bits = fls(c->max_leb_cnt - 1);
-
-	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
-	       (c->big_lpt ? c->pcnt_bits : 0) +
-	       (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT;
-	c->pnode_sz = (bits + 7) / 8;
-
-	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
-	       (c->big_lpt ? c->pcnt_bits : 0) +
-	       (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT;
-	c->nnode_sz = (bits + 7) / 8;
-
-	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
-	       c->lpt_lebs * c->lpt_spc_bits * 2;
-	c->ltab_sz = (bits + 7) / 8;
-
-	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
-	       c->lnum_bits * c->lsave_cnt;
-	c->lsave_sz = (bits + 7) / 8;
-
-	/* Calculate the minimum LPT size */
-	c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
-	c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
-	c->lpt_sz += c->ltab_sz;
-	c->lpt_sz += c->lsave_sz;
-
-	/* Add wastage */
-	sz = c->lpt_sz;
-	per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz);
-	sz += per_leb_wastage;
-	tot_wastage = per_leb_wastage;
-	while (sz > c->leb_size) {
-		sz += per_leb_wastage;
-		sz -= c->leb_size;
-		tot_wastage += per_leb_wastage;
-	}
-	tot_wastage += ALIGN(sz, c->min_io_size) - sz;
-	c->lpt_sz += tot_wastage;
-}
-
-/**
- * calc_dflt_lpt_geom - calculate default LPT geometry.
- * @c: the UBIFS file-system description object
- * @main_lebs: number of main area LEBs is passed and returned here
- * @big_lpt: whether the LPT area is "big" is returned here
- *
- * The size of the LPT area depends on parameters that themselves are dependent
- * on the size of the LPT area. This function, successively recalculates the LPT
- * area geometry until the parameters and resultant geometry are consistent.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt)
-{
-	int i, lebs_needed;
-	long long sz;
-
-	/* Start by assuming the minimum number of LPT LEBs */
-	c->lpt_lebs = UBIFS_MIN_LPT_LEBS;
-	c->main_lebs = *main_lebs - c->lpt_lebs;
-	if (c->main_lebs <= 0)
-		return -EINVAL;
-
-	/* And assume we will use the small LPT model */
-	c->big_lpt = 0;
-
-	/*
-	 * Calculate the geometry based on assumptions above and then see if it
-	 * makes sense
-	 */
-	do_calc_lpt_geom(c);
-
-	/* Small LPT model must have lpt_sz < leb_size */
-	if (c->lpt_sz > c->leb_size) {
-		/* Nope, so try again using big LPT model */
-		c->big_lpt = 1;
-		do_calc_lpt_geom(c);
-	}
-
-	/* Now check there are enough LPT LEBs */
-	for (i = 0; i < 64 ; i++) {
-		sz = c->lpt_sz * 4; /* Allow 4 times the size */
-		sz += c->leb_size - 1;
-		do_div(sz, c->leb_size);
-		lebs_needed = sz;
-		if (lebs_needed > c->lpt_lebs) {
-			/* Not enough LPT LEBs so try again with more */
-			c->lpt_lebs = lebs_needed;
-			c->main_lebs = *main_lebs - c->lpt_lebs;
-			if (c->main_lebs <= 0)
-				return -EINVAL;
-			do_calc_lpt_geom(c);
-			continue;
-		}
-		if (c->ltab_sz > c->leb_size) {
-			err_msg("LPT ltab too big");
-			return -EINVAL;
-		}
-		*main_lebs = c->main_lebs;
-		*big_lpt = c->big_lpt;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-/**
- * pack_bits - pack bit fields end-to-end.
- * @addr: address at which to pack (passed and next address returned)
- * @pos: bit position at which to pack (passed and next position returned)
- * @val: value to pack
- * @nrbits: number of bits of value to pack (1-32)
- */
-static void pack_bits(uint8_t **addr, int *pos, uint32_t val, int nrbits)
-{
-	uint8_t *p = *addr;
-	int b = *pos;
-
-	if (b) {
-		*p |= ((uint8_t)val) << b;
-		nrbits += b;
-		if (nrbits > 8) {
-			*++p = (uint8_t)(val >>= (8 - b));
-			if (nrbits > 16) {
-				*++p = (uint8_t)(val >>= 8);
-				if (nrbits > 24) {
-					*++p = (uint8_t)(val >>= 8);
-					if (nrbits > 32)
-						*++p = (uint8_t)(val >>= 8);
-				}
-			}
-		}
-	} else {
-		*p = (uint8_t)val;
-		if (nrbits > 8) {
-			*++p = (uint8_t)(val >>= 8);
-			if (nrbits > 16) {
-				*++p = (uint8_t)(val >>= 8);
-				if (nrbits > 24)
-					*++p = (uint8_t)(val >>= 8);
-			}
-		}
-	}
-	b = nrbits & 7;
-	if (b == 0)
-		p++;
-	*addr = p;
-	*pos = b;
-}
-
-/**
- * pack_pnode - pack all the bit fields of a pnode.
- * @c: UBIFS file-system description object
- * @buf: buffer into which to pack
- * @pnode: pnode to pack
- */
-static void pack_pnode(struct ubifs_info *c, void *buf,
-		       struct ubifs_pnode *pnode)
-{
-	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
-	int i, pos = 0;
-	uint16_t crc;
-
-	pack_bits(&addr, &pos, UBIFS_LPT_PNODE, UBIFS_LPT_TYPE_BITS);
-	if (c->big_lpt)
-		pack_bits(&addr, &pos, pnode->num, c->pcnt_bits);
-	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
-		pack_bits(&addr, &pos, pnode->lprops[i].free >> 3,
-			  c->space_bits);
-		pack_bits(&addr, &pos, pnode->lprops[i].dirty >> 3,
-			  c->space_bits);
-		if (pnode->lprops[i].flags & LPROPS_INDEX)
-			pack_bits(&addr, &pos, 1, 1);
-		else
-			pack_bits(&addr, &pos, 0, 1);
-	}
-	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
-		    c->pnode_sz - UBIFS_LPT_CRC_BYTES);
-	addr = buf;
-	pos = 0;
-	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
-}
-
-/**
- * pack_nnode - pack all the bit fields of a nnode.
- * @c: UBIFS file-system description object
- * @buf: buffer into which to pack
- * @nnode: nnode to pack
- */
-static void pack_nnode(struct ubifs_info *c, void *buf,
-		       struct ubifs_nnode *nnode)
-{
-	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
-	int i, pos = 0;
-	uint16_t crc;
-
-	pack_bits(&addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS);
-	if (c->big_lpt)
-		pack_bits(&addr, &pos, nnode->num, c->pcnt_bits);
-	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
-		int lnum = nnode->nbranch[i].lnum;
-
-		if (lnum == 0)
-			lnum = c->lpt_last + 1;
-		pack_bits(&addr, &pos, lnum - c->lpt_first, c->lpt_lnum_bits);
-		pack_bits(&addr, &pos, nnode->nbranch[i].offs,
-			  c->lpt_offs_bits);
-	}
-	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
-		    c->nnode_sz - UBIFS_LPT_CRC_BYTES);
-	addr = buf;
-	pos = 0;
-	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
-}
-
-/**
- * pack_ltab - pack the LPT's own lprops table.
- * @c: UBIFS file-system description object
- * @buf: buffer into which to pack
- * @ltab: LPT's own lprops table to pack
- */
-static void pack_ltab(struct ubifs_info *c, void *buf,
-			 struct ubifs_lpt_lprops *ltab)
-{
-	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
-	int i, pos = 0;
-	uint16_t crc;
-
-	pack_bits(&addr, &pos, UBIFS_LPT_LTAB, UBIFS_LPT_TYPE_BITS);
-	for (i = 0; i < c->lpt_lebs; i++) {
-		pack_bits(&addr, &pos, ltab[i].free, c->lpt_spc_bits);
-		pack_bits(&addr, &pos, ltab[i].dirty, c->lpt_spc_bits);
-	}
-	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
-		    c->ltab_sz - UBIFS_LPT_CRC_BYTES);
-	addr = buf;
-	pos = 0;
-	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
-}
-
-/**
- * pack_lsave - pack the LPT's save table.
- * @c: UBIFS file-system description object
- * @buf: buffer into which to pack
- * @lsave: LPT's save table to pack
- */
-static void pack_lsave(struct ubifs_info *c, void *buf, int *lsave)
-{
-	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
-	int i, pos = 0;
-	uint16_t crc;
-
-	pack_bits(&addr, &pos, UBIFS_LPT_LSAVE, UBIFS_LPT_TYPE_BITS);
-	for (i = 0; i < c->lsave_cnt; i++)
-		pack_bits(&addr, &pos, lsave[i], c->lnum_bits);
-	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
-		    c->lsave_sz - UBIFS_LPT_CRC_BYTES);
-	addr = buf;
-	pos = 0;
-	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
-}
-
-/**
- * set_ltab - set LPT LEB properties.
- * @c: UBIFS file-system description object
- * @lnum: LEB number
- * @free: amount of free space
- * @dirty: amount of dirty space
- */
-static void set_ltab(struct ubifs_info *c, int lnum, int free, int dirty)
-{
-	dbg_msg(3, "LEB %d free %d dirty %d to %d %d",
-		lnum, c->ltab[lnum - c->lpt_first].free,
-		c->ltab[lnum - c->lpt_first].dirty, free, dirty);
-	c->ltab[lnum - c->lpt_first].free = free;
-	c->ltab[lnum - c->lpt_first].dirty = dirty;
-}
-
-/**
- * calc_nnode_num - calculate nnode number.
- * @row: the row in the tree (root is zero)
- * @col: the column in the row (leftmost is zero)
- *
- * The nnode number is a number that uniquely identifies a nnode and can be used
- * easily to traverse the tree from the root to that nnode.
- *
- * This function calculates and returns the nnode number for the nnode at @row
- * and @col.
- */
-static int calc_nnode_num(int row, int col)
-{
-	int num, bits;
-
-	num = 1;
-	while (row--) {
-		bits = (col & (UBIFS_LPT_FANOUT - 1));
-		col >>= UBIFS_LPT_FANOUT_SHIFT;
-		num <<= UBIFS_LPT_FANOUT_SHIFT;
-		num |= bits;
-	}
-	return num;
-}
-
-/**
- * create_lpt - create LPT.
- * @c: UBIFS file-system description object
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int create_lpt(struct ubifs_info *c)
-{
-	int lnum, err = 0, i, j, cnt, len, alen, row;
-	int blnum, boffs, bsz, bcnt;
-	struct ubifs_pnode *pnode = NULL;
-	struct ubifs_nnode *nnode = NULL;
-	void *buf = NULL, *p;
-	int *lsave = NULL;
-
-	pnode = malloc(sizeof(struct ubifs_pnode));
-	nnode = malloc(sizeof(struct ubifs_nnode));
-	buf = malloc(c->leb_size);
-	lsave = malloc(sizeof(int) * c->lsave_cnt);
-	if (!pnode || !nnode || !buf || !lsave) {
-		err = -ENOMEM;
-		goto out;
-	}
-	memset(pnode, 0 , sizeof(struct ubifs_pnode));
-	memset(nnode, 0 , sizeof(struct ubifs_nnode));
-
-	c->lscan_lnum = c->main_first;
-
-	lnum = c->lpt_first;
-	p = buf;
-	len = 0;
-	/* Number of leaf nodes (pnodes) */
-	cnt = (c->main_lebs + UBIFS_LPT_FANOUT - 1) >> UBIFS_LPT_FANOUT_SHIFT;
-	//printf("pnode_cnt=%d\n",cnt);
-
-	/*
-	 * To calculate the internal node branches, we keep information about
-	 * the level below.
-	 */
-	blnum = lnum; /* LEB number of level below */
-	boffs = 0; /* Offset of level below */
-	bcnt = cnt; /* Number of nodes in level below */
-	bsz = c->pnode_sz; /* Size of nodes in level below */
-
-	/* Add pnodes */
-	for (i = 0; i < cnt; i++) {
-		if (len + c->pnode_sz > c->leb_size) {
-			alen = ALIGN(len, c->min_io_size);
-			set_ltab(c, lnum, c->leb_size - alen, alen - len);
-			memset(p, 0xff, alen - len);
-			err = write_leb(lnum++, alen, buf);
-			if (err)
-				goto out;
-			p = buf;
-			len = 0;
-		}
-		/* Fill in the pnode */
-		for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
-			int k = (i << UBIFS_LPT_FANOUT_SHIFT) + j;
-
-			if (k < c->main_lebs)
-				pnode->lprops[j] = c->lpt[k];
-			else {
-				pnode->lprops[j].free = c->leb_size;
-				pnode->lprops[j].dirty = 0;
-				pnode->lprops[j].flags = 0;
-			}
-		}
-		pack_pnode(c, p, pnode);
-		p += c->pnode_sz;
-		len += c->pnode_sz;
-		/*
-		 * pnodes are simply numbered left to right starting at zero,
-		 * which means the pnode number can be used easily to traverse
-		 * down the tree to the corresponding pnode.
-		 */
-		pnode->num += 1;
-	}
-
-	row = c->lpt_hght - 1;
-	/* Add all nnodes, one level at a time */
-	while (1) {
-		/* Number of internal nodes (nnodes) at next level */
-		cnt = (cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
-		if (cnt == 0)
-			cnt = 1;
-		for (i = 0; i < cnt; i++) {
-			if (len + c->nnode_sz > c->leb_size) {
-				alen = ALIGN(len, c->min_io_size);
-				set_ltab(c, lnum, c->leb_size - alen,
-					    alen - len);
-				memset(p, 0xff, alen - len);
-				err = write_leb(lnum++, alen, buf);
-				if (err)
-					goto out;
-				p = buf;
-				len = 0;
-			}
-			/* The root is on row zero */
-			if (row == 0) {
-				c->lpt_lnum = lnum;
-				c->lpt_offs = len;
-			}
-			/* Set branches to the level below */
-			for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
-				if (bcnt) {
-					if (boffs + bsz > c->leb_size) {
-						blnum += 1;
-						boffs = 0;
-					}
-					nnode->nbranch[j].lnum = blnum;
-					nnode->nbranch[j].offs = boffs;
-					boffs += bsz;
-					bcnt--;
-				} else {
-					nnode->nbranch[j].lnum = 0;
-					nnode->nbranch[j].offs = 0;
-				}
-			}
-			nnode->num = calc_nnode_num(row, i);
-			pack_nnode(c, p, nnode);
-			p += c->nnode_sz;
-			len += c->nnode_sz;
-		}
-		/* Row zero  is the top row */
-		if (row == 0)
-			break;
-		/* Update the information about the level below */
-		bcnt = cnt;
-		bsz = c->nnode_sz;
-		row -= 1;
-	}
-
-	if (c->big_lpt) {
-		/* Need to add LPT's save table */
-		if (len + c->lsave_sz > c->leb_size) {
-			alen = ALIGN(len, c->min_io_size);
-			set_ltab(c, lnum, c->leb_size - alen, alen - len);
-			memset(p, 0xff, alen - len);
-			err = write_leb(lnum++, alen, buf);
-			if (err)
-				goto out;
-			p = buf;
-			len = 0;
-		}
-
-		c->lsave_lnum = lnum;
-		c->lsave_offs = len;
-
-		for (i = 0; i < c->lsave_cnt; i++)
-			lsave[i] = c->main_first + i;
-
-		pack_lsave(c, p, lsave);
-		p += c->lsave_sz;
-		len += c->lsave_sz;
-	}
-
-	/* Need to add LPT's own LEB properties table */
-	if (len + c->ltab_sz > c->leb_size) {
-		alen = ALIGN(len, c->min_io_size);
-		set_ltab(c, lnum, c->leb_size - alen, alen - len);
-		memset(p, 0xff, alen - len);
-		err = write_leb(lnum++, alen, buf);
-		if (err)
-			goto out;
-		p = buf;
-		len = 0;
-	}
-
-	c->ltab_lnum = lnum;
-	c->ltab_offs = len;
-
-	/* Update ltab before packing it */
-	len += c->ltab_sz;
-	alen = ALIGN(len, c->min_io_size);
-	set_ltab(c, lnum, c->leb_size - alen, alen - len);
-
-	pack_ltab(c, p, c->ltab);
-	p += c->ltab_sz;
-
-	/* Write remaining buffer */
-	memset(p, 0xff, alen - len);
-	err = write_leb(lnum, alen, buf);
-	if (err)
-		goto out;
-
-	c->nhead_lnum = lnum;
-	c->nhead_offs = ALIGN(len, c->min_io_size);
-
-	dbg_msg(1, "lpt_sz:         %lld", c->lpt_sz);
-	dbg_msg(1, "space_bits:     %d", c->space_bits);
-	dbg_msg(1, "lpt_lnum_bits:  %d", c->lpt_lnum_bits);
-	dbg_msg(1, "lpt_offs_bits:  %d", c->lpt_offs_bits);
-	dbg_msg(1, "lpt_spc_bits:   %d", c->lpt_spc_bits);
-	dbg_msg(1, "pcnt_bits:      %d", c->pcnt_bits);
-	dbg_msg(1, "lnum_bits:      %d", c->lnum_bits);
-	dbg_msg(1, "pnode_sz:       %d", c->pnode_sz);
-	dbg_msg(1, "nnode_sz:       %d", c->nnode_sz);
-	dbg_msg(1, "ltab_sz:        %d", c->ltab_sz);
-	dbg_msg(1, "lsave_sz:       %d", c->lsave_sz);
-	dbg_msg(1, "lsave_cnt:      %d", c->lsave_cnt);
-	dbg_msg(1, "lpt_hght:       %d", c->lpt_hght);
-	dbg_msg(1, "big_lpt:        %d", c->big_lpt);
-	dbg_msg(1, "LPT root is at  %d:%d", c->lpt_lnum, c->lpt_offs);
-	dbg_msg(1, "LPT head is at  %d:%d", c->nhead_lnum, c->nhead_offs);
-	dbg_msg(1, "LPT ltab is at  %d:%d", c->ltab_lnum, c->ltab_offs);
-	if (c->big_lpt)
-		dbg_msg(1, "LPT lsave is at %d:%d",
-		        c->lsave_lnum, c->lsave_offs);
-out:
-	free(lsave);
-	free(buf);
-	free(nnode);
-	free(pnode);
-	return err;
-}
diff --git a/mkfs.ubifs/lpt.h b/mkfs.ubifs/lpt.h
deleted file mode 100644
index 4cde59d..0000000
--- a/mkfs.ubifs/lpt.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2008 Nokia Corporation.
- * Copyright (C) 2008 University of Szeged, Hungary
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Authors: Artem Bityutskiy
- *          Adrian Hunter
- */
-
-#ifndef __UBIFS_LPT_H__
-#define __UBIFS_LPT_H__
-
-int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt);
-int create_lpt(struct ubifs_info *c);
-
-#endif
diff --git a/mkfs.ubifs/mkfs.ubifs.c b/mkfs.ubifs/mkfs.ubifs.c
deleted file mode 100644
index ca17e2b..0000000
--- a/mkfs.ubifs/mkfs.ubifs.c
+++ /dev/null
@@ -1,2324 +0,0 @@
-/*
- * Copyright (C) 2008 Nokia Corporation.
- * Copyright (C) 2008 University of Szeged, Hungary
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Authors: Adrian Hunter
- *          Artem Bityutskiy
- *          Zoltan Sogor
- */
-
-#define _XOPEN_SOURCE 500 /* For realpath() */
-
-#include "mkfs.ubifs.h"
-#include <crc32.h>
-#include "common.h"
-
-/* Size (prime number) of hash table for link counting */
-#define HASH_TABLE_SIZE 10099
-
-/* The node buffer must allow for worst case compression */
-#define NODE_BUFFER_SIZE (UBIFS_DATA_NODE_SZ + \
-			  UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
-
-/* Default time granularity in nanoseconds */
-#define DEFAULT_TIME_GRAN 1000000000
-
-/**
- * struct idx_entry - index entry.
- * @next: next index entry (NULL at end of list)
- * @prev: previous index entry (NULL at beginning of list)
- * @key: key
- * @name: directory entry name used for sorting colliding keys by name
- * @lnum: LEB number
- * @offs: offset
- * @len: length
- *
- * The index is recorded as a linked list which is sorted and used to create
- * the bottom level of the on-flash index tree. The remaining levels of the
- * index tree are each built from the level below.
- */
-struct idx_entry {
-	struct idx_entry *next;
-	struct idx_entry *prev;
-	union ubifs_key key;
-	char *name;
-	int lnum;
-	int offs;
-	int len;
-};
-
-/**
- * struct inum_mapping - inode number mapping for link counting.
- * @next: next inum_mapping (NULL at end of list)
- * @prev: previous inum_mapping (NULL at beginning of list)
- * @dev: source device on which the source inode number resides
- * @inum: source inode number of the file
- * @use_inum: target inode number of the file
- * @use_nlink: number of links
- * @path_name: a path name of the file
- * @st: struct stat object containing inode attributes which have to be used
- *      when the inode is being created (actually only UID, GID, access
- *      mode, major and minor device numbers)
- *
- * If a file has more than one hard link, then the number of hard links that
- * exist in the source directory hierarchy must be counted to exclude the
- * possibility that the file is linked from outside the source directory
- * hierarchy.
- *
- * The inum_mappings are stored in a hash_table of linked lists.
- */
-struct inum_mapping {
-	struct inum_mapping *next;
-	struct inum_mapping *prev;
-	dev_t dev;
-	ino_t inum;
-	ino_t use_inum;
-	unsigned int use_nlink;
-	char *path_name;
-	struct stat st;
-};
-
-/*
- * Because we copy functions from the kernel, we use a subset of the UBIFS
- * file-system description object struct ubifs_info.
- */
-struct ubifs_info info_;
-static struct ubifs_info *c = &info_;
-static libubi_t ubi;
-
-/* Debug levels are: 0 (none), 1 (statistics), 2 (files) ,3 (more details) */
-int debug_level;
-int verbose;
-int yes;
-
-static char *root;
-static int root_len;
-static struct stat root_st;
-static char *output;
-static int out_fd;
-static int out_ubi;
-static int squash_owner;
-
-/* The 'head' (position) which nodes are written */
-static int head_lnum;
-static int head_offs;
-static int head_flags;
-
-/* The index list */
-static struct idx_entry *idx_list_first;
-static struct idx_entry *idx_list_last;
-static size_t idx_cnt;
-
-/* Global buffers */
-static void *leb_buf;
-static void *node_buf;
-static void *block_buf;
-
-/* Hash table for inode link counting */
-static struct inum_mapping **hash_table;
-
-/* Inode creation sequence number */
-static unsigned long long creat_sqnum;
-
-static const char *optstring = "d:r:m:o:D:yh?vVe:c:g:f:Fp:k:x:X:j:R:l:j:UQq";
-
-static const struct option longopts[] = {
-	{"root",               1, NULL, 'r'},
-	{"min-io-size",        1, NULL, 'm'},
-	{"leb-size",           1, NULL, 'e'},
-	{"max-leb-cnt",        1, NULL, 'c'},
-	{"output",             1, NULL, 'o'},
-	{"devtable",           1, NULL, 'D'},
-	{"yes",                0, NULL, 'y'},
-	{"help",               0, NULL, 'h'},
-	{"verbose",            0, NULL, 'v'},
-	{"version",            0, NULL, 'V'},
-	{"debug-level",        1, NULL, 'g'},
-	{"jrn-size",           1, NULL, 'j'},
-	{"reserved",           1, NULL, 'R'},
-	{"compr",              1, NULL, 'x'},
-	{"favor-percent",      1, NULL, 'X'},
-	{"fanout",             1, NULL, 'f'},
-	{"space-fixup",        0, NULL, 'F'},
-	{"keyhash",            1, NULL, 'k'},
-	{"log-lebs",           1, NULL, 'l'},
-	{"orph-lebs",          1, NULL, 'p'},
-	{"squash-uids" ,       0, NULL, 'U'},
-	{NULL, 0, NULL, 0}
-};
-
-static const char *helptext =
-"Usage: mkfs.ubifs [OPTIONS] target\n"
-"Make a UBIFS file system image from an existing directory tree\n\n"
-"Examples:\n"
-"Build file system from directory /opt/img, writting the result in the ubifs.img file\n"
-"\tmkfs.ubifs -m 512 -e 128KiB -c 100 -r /opt/img ubifs.img\n"
-"The same, but writting directly to an UBI volume\n"
-"\tmkfs.ubifs -r /opt/img /dev/ubi0_0\n"
-"Creating an empty UBIFS filesystem on an UBI volume\n"
-"\tmkfs.ubifs /dev/ubi0_0\n\n"
-"Options:\n"
-"-r, -d, --root=DIR       build file system from directory DIR\n"
-"-m, --min-io-size=SIZE   minimum I/O unit size\n"
-"-e, --leb-size=SIZE      logical erase block size\n"
-"-c, --max-leb-cnt=COUNT  maximum logical erase block count\n"
-"-o, --output=FILE        output to FILE\n"
-"-j, --jrn-size=SIZE      journal size\n"
-"-R, --reserved=SIZE      how much space should be reserved for the super-user\n"
-"-x, --compr=TYPE         compression type - \"lzo\", \"favor_lzo\", \"zlib\" or\n"
-"                         \"none\" (default: \"lzo\")\n"
-"-X, --favor-percent      may only be used with favor LZO compression and defines\n"
-"                         how many percent better zlib should compress to make\n"
-"                         mkfs.ubifs use zlib instead of LZO (default 20%)\n"
-"-f, --fanout=NUM         fanout NUM (default: 8)\n"
-"-F, --space-fixup        file-system free space has to be fixed up on first mount\n"
-"                         (requires kernel version 3.0 or greater)\n"
-"-k, --keyhash=TYPE       key hash type - \"r5\" or \"test\" (default: \"r5\")\n"
-"-p, --orph-lebs=COUNT    count of erase blocks for orphans (default: 1)\n"
-"-D, --devtable=FILE      use device table FILE\n"
-"-U, --squash-uids        squash owners making all files owned by root\n"
-"-l, --log-lebs=COUNT     count of erase blocks for the log (used only for\n"
-"                         debugging)\n"
-"-y, --yes                assume the answer is \"yes\" for all questions\n"
-"-v, --verbose            verbose operation\n"
-"-V, --version            display version information\n"
-"-g, --debug=LEVEL        display debug information (0 - none, 1 - statistics,\n"
-"                         2 - files, 3 - more details)\n"
-"-h, --help               display this help text\n\n"
-"Note, SIZE is specified in bytes, but it may also be specified in Kilobytes,\n"
-"Megabytes, and Gigabytes if a KiB, MiB, or GiB suffix is used.\n\n"
-"If you specify \"lzo\" or \"zlib\" compressors, mkfs.ubifs will use this compressor\n"
-"for all data. The \"none\" disables any data compression. The \"favor_lzo\" is not\n"
-"really a separate compressor. It is just a method of combining \"lzo\" and \"zlib\"\n"
-"compressors. Namely, mkfs.ubifs tries to compress data with both \"lzo\" and \"zlib\"\n"
-"compressors, then it compares which compressor is better. If \"zlib\" compresses 20\n"
-"or more percent better than \"lzo\", mkfs.ubifs chooses \"lzo\", otherwise it chooses\n"
-"\"zlib\". The \"--favor-percent\" may specify arbitrary threshold instead of the\n"
-"default 20%.\n\n"
-"The -F parameter is used to set the \"fix up free space\" flag in the superblock,\n"
-"which forces UBIFS to \"fixup\" all the free space which it is going to use. This\n"
-"option is useful to work-around the problem of double free space programming: if the\n"
-"flasher program which flashes the UBI image is unable to skip NAND pages containing\n"
-"only 0xFF bytes, the effect is that some NAND pages are written to twice - first time\n"
-"when flashing the image and the second time when UBIFS is mounted and writes useful\n"
-"data there. A proper UBI-aware flasher should skip such NAND pages, though. Note, this\n"
-"flag may make the first mount very slow, because the \"free space fixup\" procedure\n"
-"takes time. This feature is supported by the Linux kernel starting from version 3.0.\n";
-
-/**
- * make_path - make a path name from a directory and a name.
- * @dir: directory path name
- * @name: name
- */
-static char *make_path(const char *dir, const char *name)
-{
-	char *s;
-
-	s = malloc(strlen(dir) + strlen(name) + 2);
-	if (!s)
-		return NULL;
-	strcpy(s, dir);
-	if (dir[strlen(dir) - 1] != '/')
-		strcat(s, "/");
-	strcat(s, name);
-	return s;
-}
-
-/**
- * is_contained - determine if a file is beneath a directory.
- * @file: file path name
- * @dir: directory path name
- *
- * This function returns %1 if @file is accessible from the @dir directory and
- * %0 otherwise. In case of error, returns %-1.
- */
-static int is_contained(const char *file, const char *dir)
-{
-	char *real_file = NULL;
-	char *real_dir = NULL;
-	char *file_base, *copy;
-	int ret = -1;
-
-	/* Make a copy of the file path because 'dirname()' can modify it */
-	copy = strdup(file);
-	if (!copy)
-		return -1;
-	file_base = dirname(copy);
-
-	/* Turn the paths into the canonical form */
-	real_file = malloc(PATH_MAX);
-	if (!real_file)
-		goto out_free;
-
-	real_dir = malloc(PATH_MAX);
-	if (!real_dir)
-		goto out_free;
-
-	if (!realpath(file_base, real_file)) {
-		perror("Could not canonicalize file path");
-		goto out_free;
-	}
-	if (!realpath(dir, real_dir)) {
-		perror("Could not canonicalize directory");
-		goto out_free;
-	}
-
-	ret = !!strstr(real_file, real_dir);
-
-out_free:
-	free(copy);
-	free(real_file);
-	free(real_dir);
-	return ret;
-}
-
-/**
- * calc_min_log_lebs - calculate the minimum number of log LEBs needed.
- * @max_bud_bytes: journal size (buds only)
- */
-static int calc_min_log_lebs(unsigned long long max_bud_bytes)
-{
-	int buds, log_lebs;
-	unsigned long long log_size;
-
-	buds = (max_bud_bytes + c->leb_size - 1) / c->leb_size;
-	log_size = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size);
-	log_size *= buds;
-	log_size += ALIGN(UBIFS_CS_NODE_SZ +
-			  UBIFS_REF_NODE_SZ * (c->jhead_cnt + 2),
-			  c->min_io_size);
-	log_lebs = (log_size + c->leb_size - 1) / c->leb_size;
-	log_lebs += 1;
-	return log_lebs;
-}
-
-/**
- * add_space_overhead - add UBIFS overhead.
- * @size: flash space which should be visible to the user
- *
- * UBIFS has overhead, and if we need to reserve @size bytes for the user data,
- * we have to reserve more flash space, to compensate the overhead. This
- * function calculates and returns the amount of physical flash space which
- * should be reserved to provide @size bytes for the user.
- */
-static long long add_space_overhead(long long size)
-{
-        int divisor, factor, f, max_idx_node_sz;
-
-        /*
-	 * Do the opposite to what the 'ubifs_reported_space()' kernel UBIFS
-	 * function does.
-         */
-	max_idx_node_sz =  ubifs_idx_node_sz(c, c->fanout);
-        f = c->fanout > 3 ? c->fanout >> 1 : 2;
-        divisor = UBIFS_BLOCK_SIZE;
-        factor = UBIFS_MAX_DATA_NODE_SZ;
-        factor += (max_idx_node_sz * 3) / (f - 1);
-        size *= factor;
-        return size / divisor;
-}
-
-static int validate_options(void)
-{
-	int tmp;
-
-	if (!output)
-		return err_msg("no output file or UBI volume specified");
-	if (root) {
-		tmp = is_contained(output, root);
-		if (tmp < 0)
-			return err_msg("failed to perform output file root check");
-		else if (tmp)
-			return err_msg("output file cannot be in the UBIFS root "
-			               "directory");
-	}
-	if (!is_power_of_2(c->min_io_size))
-		return err_msg("min. I/O unit size should be power of 2");
-	if (c->leb_size < c->min_io_size)
-		return err_msg("min. I/O unit cannot be larger than LEB size");
-	if (c->leb_size < UBIFS_MIN_LEB_SZ)
-		return err_msg("too small LEB size %d, minimum is %d",
-			       c->leb_size, UBIFS_MIN_LEB_SZ);
-	if (c->leb_size % c->min_io_size)
-		return err_msg("LEB should be multiple of min. I/O units");
-	if (c->leb_size % 8)
-		return err_msg("LEB size has to be multiple of 8");
-	if (c->leb_size > UBIFS_MAX_LEB_SZ)
-		return err_msg("too large LEB size %d, maximum is %d",
-				c->leb_size, UBIFS_MAX_LEB_SZ);
-	if (c->max_leb_cnt < UBIFS_MIN_LEB_CNT)
-		return err_msg("too low max. count of LEBs, minimum is %d",
-			       UBIFS_MIN_LEB_CNT);
-	if (c->fanout < UBIFS_MIN_FANOUT)
-		return err_msg("too low fanout, minimum is %d",
-			       UBIFS_MIN_FANOUT);
-	tmp = c->leb_size - UBIFS_IDX_NODE_SZ;
-	tmp /= UBIFS_BRANCH_SZ + UBIFS_MAX_KEY_LEN;
-	if (c->fanout > tmp)
-		return err_msg("too high fanout, maximum is %d", tmp);
-	if (c->log_lebs < UBIFS_MIN_LOG_LEBS)
-		return err_msg("too few log LEBs, minimum is %d",
-			       UBIFS_MIN_LOG_LEBS);
-	if (c->log_lebs >= c->max_leb_cnt - UBIFS_MIN_LEB_CNT)
-		return err_msg("too many log LEBs, maximum is %d",
-			       c->max_leb_cnt - UBIFS_MIN_LEB_CNT);
-	if (c->orph_lebs < UBIFS_MIN_ORPH_LEBS)
-		return err_msg("too few orphan LEBs, minimum is %d",
-			       UBIFS_MIN_ORPH_LEBS);
-	if (c->orph_lebs >= c->max_leb_cnt - UBIFS_MIN_LEB_CNT)
-		return err_msg("too many orphan LEBs, maximum is %d",
-			       c->max_leb_cnt - UBIFS_MIN_LEB_CNT);
-	tmp = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs;
-	tmp += c->orph_lebs + 4;
-	if (tmp > c->max_leb_cnt)
-		return err_msg("too low max. count of LEBs, expected at "
-			       "least %d", tmp);
-	tmp = calc_min_log_lebs(c->max_bud_bytes);
-	if (c->log_lebs < calc_min_log_lebs(c->max_bud_bytes))
-		return err_msg("too few log LEBs, expected at least %d", tmp);
-	if (c->rp_size >= ((long long)c->leb_size * c->max_leb_cnt) / 2)
-		return err_msg("too much reserved space %lld", c->rp_size);
-	return 0;
-}
-
-/**
- * get_multiplier - convert size specifier to an integer multiplier.
- * @str: the size specifier string
- *
- * This function parses the @str size specifier, which may be one of
- * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
- * size multiplier in case of success and %-1 in case of failure.
- */
-static int get_multiplier(const char *str)
-{
-	if (!str)
-		return 1;
-
-	/* Remove spaces before the specifier */
-	while (*str == ' ' || *str == '\t')
-		str += 1;
-
-	if (!strcmp(str, "KiB"))
-		return 1024;
-	if (!strcmp(str, "MiB"))
-		return 1024 * 1024;
-	if (!strcmp(str, "GiB"))
-		return 1024 * 1024 * 1024;
-
-	return -1;
-}
-
-/**
- * get_bytes - convert a string containing amount of bytes into an
- *             integer.
- * @str: string to convert
- *
- * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB' size
- * specifiers. Returns positive amount of bytes in case of success and %-1 in
- * case of failure.
- */
-static long long get_bytes(const char *str)
-{
-	char *endp;
-	long long bytes = strtoull(str, &endp, 0);
-
-	if (endp == str || bytes < 0)
-		return err_msg("incorrect amount of bytes: \"%s\"", str);
-
-	if (*endp != '\0') {
-		int mult = get_multiplier(endp);
-
-		if (mult == -1)
-			return err_msg("bad size specifier: \"%s\" - "
-				       "should be 'KiB', 'MiB' or 'GiB'", endp);
-		bytes *= mult;
-	}
-
-	return bytes;
-}
-/**
- * open_ubi - open the UBI volume.
- * @node: name of the UBI volume character device to fetch information about
- *
- * Returns %0 in case of success and %-1 in case of failure
- */
-static int open_ubi(const char *node)
-{
-	struct stat st;
-
-	if (stat(node, &st) || !S_ISCHR(st.st_mode))
-		return -1;
-
-	ubi = libubi_open();
-	if (!ubi)
-		return -1;
-	if (ubi_get_vol_info(ubi, node, &c->vi))
-		return -1;
-	if (ubi_get_dev_info1(ubi, c->vi.dev_num, &c->di))
-		return -1;
-	return 0;
-}
-
-static int get_options(int argc, char**argv)
-{
-	int opt, i;
-	const char *tbl_file = NULL;
-	struct stat st;
-	char *endp;
-
-	c->fanout = 8;
-	c->orph_lebs = 1;
-	c->key_hash = key_r5_hash;
-	c->key_len = UBIFS_SK_LEN;
-	c->default_compr = UBIFS_COMPR_LZO;
-	c->favor_percent = 20;
-	c->lsave_cnt = 256;
-	c->leb_size = -1;
-	c->min_io_size = -1;
-	c->max_leb_cnt = -1;
-	c->max_bud_bytes = -1;
-	c->log_lebs = -1;
-
-	while (1) {
-		opt = getopt_long(argc, argv, optstring, longopts, &i);
-		if (opt == -1)
-			break;
-		switch (opt) {
-		case 'r':
-		case 'd':
-			root_len = strlen(optarg);
-			root = malloc(root_len + 2);
-			if (!root)
-				return err_msg("cannot allocate memory");
-
-			/*
-			 * The further code expects '/' at the end of the root
-			 * UBIFS directory on the host.
-			 */
-			memcpy(root, optarg, root_len);
-			if (root[root_len - 1] != '/')
-				root[root_len++] = '/';
-			root[root_len] = 0;
-
-			/* Make sure the root directory exists */
-			if (stat(root, &st))
-				return sys_err_msg("bad root directory '%s'",
-						   root);
-			break;
-		case 'm':
-			c->min_io_size = get_bytes(optarg);
-			if (c->min_io_size <= 0)
-				return err_msg("bad min. I/O size");
-			break;
-		case 'e':
-			c->leb_size = get_bytes(optarg);
-			if (c->leb_size <= 0)
-				return err_msg("bad LEB size");
-			break;
-		case 'c':
-			c->max_leb_cnt = get_bytes(optarg);
-			if (c->max_leb_cnt <= 0)
-				return err_msg("bad maximum LEB count");
-			break;
-		case 'o':
-			output = xstrdup(optarg);
-			break;
-		case 'D':
-			tbl_file = optarg;
-			if (stat(tbl_file, &st) < 0)
-				return sys_err_msg("bad device table file '%s'",
-						   tbl_file);
-			break;
-		case 'y':
-			yes = 1;
-			break;
-		case 'h':
-		case '?':
-			printf("%s", helptext);
-			exit(0);
-		case 'v':
-			verbose = 1;
-			break;
-		case 'V':
-			common_print_version();
-			exit(0);
-		case 'g':
-			debug_level = strtol(optarg, &endp, 0);
-			if (*endp != '\0' || endp == optarg ||
-			    debug_level < 0 || debug_level > 3)
-				return err_msg("bad debugging level '%s'",
-					       optarg);
-			break;
-		case 'f':
-			c->fanout = strtol(optarg, &endp, 0);
-			if (*endp != '\0' || endp == optarg || c->fanout <= 0)
-				return err_msg("bad fanout %s", optarg);
-			break;
-		case 'F':
-			c->space_fixup = 1;
-			break;
-		case 'l':
-			c->log_lebs = strtol(optarg, &endp, 0);
-			if (*endp != '\0' || endp == optarg || c->log_lebs <= 0)
-				return err_msg("bad count of log LEBs '%s'",
-					       optarg);
-			break;
-		case 'p':
-			c->orph_lebs = strtol(optarg, &endp, 0);
-			if (*endp != '\0' || endp == optarg ||
-			    c->orph_lebs <= 0)
-				return err_msg("bad orphan LEB count '%s'",
-					       optarg);
-			break;
-		case 'k':
-			if (strcmp(optarg, "r5") == 0) {
-				c->key_hash = key_r5_hash;
-				c->key_hash_type = UBIFS_KEY_HASH_R5;
-			} else if (strcmp(optarg, "test") == 0) {
-				c->key_hash = key_test_hash;
-				c->key_hash_type = UBIFS_KEY_HASH_TEST;
-			} else
-				return err_msg("bad key hash");
-			break;
-		case 'x':
-			if (strcmp(optarg, "favor_lzo") == 0)
-				c->favor_lzo = 1;
-			else if (strcmp(optarg, "zlib") == 0)
-				c->default_compr = UBIFS_COMPR_ZLIB;
-			else if (strcmp(optarg, "none") == 0)
-				c->default_compr = UBIFS_COMPR_NONE;
-			else if (strcmp(optarg, "lzo") != 0)
-				return err_msg("bad compressor name");
-			break;
-		case 'X':
-			c->favor_percent = strtol(optarg, &endp, 0);
-			if (*endp != '\0' || endp == optarg ||
-			    c->favor_percent <= 0 || c->favor_percent >= 100)
-				return err_msg("bad favor LZO percent '%s'",
-					       optarg);
-			break;
-		case 'j':
-			c->max_bud_bytes = get_bytes(optarg);
-			if (c->max_bud_bytes <= 0)
-				return err_msg("bad maximum amount of buds");
-			break;
-		case 'R':
-			c->rp_size = get_bytes(optarg);
-			if (c->rp_size < 0)
-				return err_msg("bad reserved bytes count");
-			break;
-		case 'U':
-			squash_owner = 1;
-			break;
-		}
-	}
-
-	if (optind != argc && !output)
-		output = xstrdup(argv[optind]);
-
-	if (!output)
-		return err_msg("not output device or file specified");
-
-	out_ubi = !open_ubi(output);
-
-	if (out_ubi) {
-		c->min_io_size = c->di.min_io_size;
-		c->leb_size = c->vi.leb_size;
-		if (c->max_leb_cnt == -1)
-			c->max_leb_cnt = c->vi.rsvd_lebs;
-	}
-
-	if (c->min_io_size == -1)
-		return err_msg("min. I/O unit was not specified "
-			       "(use -h for help)");
-
-	if (c->leb_size == -1)
-		return err_msg("LEB size was not specified (use -h for help)");
-
-	if (c->max_leb_cnt == -1)
-		return err_msg("Maximum count of LEBs was not specified "
-			       "(use -h for help)");
-
-	if (c->max_bud_bytes == -1) {
-		int lebs;
-
-		lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
-		lebs -= c->orph_lebs;
-		if (c->log_lebs != -1)
-			lebs -= c->log_lebs;
-		else
-			lebs -= UBIFS_MIN_LOG_LEBS;
-		/*
-		 * We do not know lprops geometry so far, so assume minimum
-		 * count of lprops LEBs.
-		 */
-		lebs -= UBIFS_MIN_LPT_LEBS;
-		/* Make the journal about 12.5% of main area lebs */
-		c->max_bud_bytes = (lebs / 8) * (long long)c->leb_size;
-		/* Make the max journal size 8MiB */
-		if (c->max_bud_bytes > 8 * 1024 * 1024)
-			c->max_bud_bytes = 8 * 1024 * 1024;
-		if (c->max_bud_bytes < 4 * c->leb_size)
-			c->max_bud_bytes = 4 * c->leb_size;
-	}
-
-	if (c->log_lebs == -1) {
-		c->log_lebs = calc_min_log_lebs(c->max_bud_bytes);
-		c->log_lebs += 2;
-	}
-
-	if (c->min_io_size < 8)
-		c->min_io_size = 8;
-	c->rp_size = add_space_overhead(c->rp_size);
-
-	if (verbose) {
-		printf("mkfs.ubifs\n");
-		printf("\troot:         %s\n", root);
-		printf("\tmin_io_size:  %d\n", c->min_io_size);
-		printf("\tleb_size:     %d\n", c->leb_size);
-		printf("\tmax_leb_cnt:  %d\n", c->max_leb_cnt);
-		printf("\toutput:       %s\n", output);
-		printf("\tjrn_size:     %llu\n", c->max_bud_bytes);
-		printf("\treserved:     %llu\n", c->rp_size);
-		switch (c->default_compr) {
-		case UBIFS_COMPR_LZO:
-			printf("\tcompr:        lzo\n");
-			break;
-		case UBIFS_COMPR_ZLIB:
-			printf("\tcompr:        zlib\n");
-			break;
-		case UBIFS_COMPR_NONE:
-			printf("\tcompr:        none\n");
-			break;
-		}
-		printf("\tkeyhash:      %s\n", (c->key_hash == key_r5_hash) ?
-						"r5" : "test");
-		printf("\tfanout:       %d\n", c->fanout);
-		printf("\torph_lebs:    %d\n", c->orph_lebs);
-		printf("\tspace_fixup:  %d\n", c->space_fixup);
-	}
-
-	if (validate_options())
-		return -1;
-
-	if (tbl_file && parse_devtable(tbl_file))
-		return err_msg("cannot parse device table file '%s'", tbl_file);
-
-	return 0;
-}
-
-/**
- * prepare_node - fill in the common header.
- * @node: node
- * @len: node length
- */
-static void prepare_node(void *node, int len)
-{
-	uint32_t crc;
-	struct ubifs_ch *ch = node;
-
-	ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
-	ch->len = cpu_to_le32(len);
-	ch->group_type = UBIFS_NO_NODE_GROUP;
-	ch->sqnum = cpu_to_le64(++c->max_sqnum);
-	ch->padding[0] = ch->padding[1] = 0;
-	crc = mtd_crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
-	ch->crc = cpu_to_le32(crc);
-}
-
-/**
- * write_leb - copy the image of a LEB to the output target.
- * @lnum: LEB number
- * @len: length of data in the buffer
- * @buf: buffer (must be at least c->leb_size bytes)
- */
-int write_leb(int lnum, int len, void *buf)
-{
-	off_t pos = (off_t)lnum * c->leb_size;
-
-	dbg_msg(3, "LEB %d len %d", lnum, len);
-	memset(buf + len, 0xff, c->leb_size - len);
-	if (out_ubi)
-		if (ubi_leb_change_start(ubi, out_fd, lnum, c->leb_size))
-			return sys_err_msg("ubi_leb_change_start failed");
-
-	if (lseek(out_fd, pos, SEEK_SET) != pos)
-		return sys_err_msg("lseek failed seeking %"PRIdoff_t, pos);
-
-	if (write(out_fd, buf, c->leb_size) != c->leb_size)
-		return sys_err_msg("write failed writing %d bytes at pos %"PRIdoff_t,
-				   c->leb_size, pos);
-
-	return 0;
-}
-
-/**
- * write_empty_leb - copy the image of an empty LEB to the output target.
- * @lnum: LEB number
- */
-static int write_empty_leb(int lnum)
-{
-	return write_leb(lnum, 0, leb_buf);
-}
-
-/**
- * do_pad - pad a buffer to the minimum I/O size.
- * @buf: buffer
- * @len: buffer length
- */
-static int do_pad(void *buf, int len)
-{
-	int pad_len, alen = ALIGN(len, 8), wlen = ALIGN(alen, c->min_io_size);
-	uint32_t crc;
-
-	memset(buf + len, 0xff, alen - len);
-	pad_len = wlen - alen;
-	dbg_msg(3, "len %d pad_len %d", len, pad_len);
-	buf += alen;
-	if (pad_len >= (int)UBIFS_PAD_NODE_SZ) {
-		struct ubifs_ch *ch = buf;
-		struct ubifs_pad_node *pad_node = buf;
-
-		ch->magic      = cpu_to_le32(UBIFS_NODE_MAGIC);
-		ch->node_type  = UBIFS_PAD_NODE;
-		ch->group_type = UBIFS_NO_NODE_GROUP;
-		ch->padding[0] = ch->padding[1] = 0;
-		ch->sqnum      = cpu_to_le64(0);
-		ch->len        = cpu_to_le32(UBIFS_PAD_NODE_SZ);
-
-		pad_len -= UBIFS_PAD_NODE_SZ;
-		pad_node->pad_len = cpu_to_le32(pad_len);
-
-		crc = mtd_crc32(UBIFS_CRC32_INIT, buf + 8,
-				  UBIFS_PAD_NODE_SZ - 8);
-		ch->crc = cpu_to_le32(crc);
-
-		memset(buf + UBIFS_PAD_NODE_SZ, 0, pad_len);
-	} else if (pad_len > 0)
-		memset(buf, UBIFS_PADDING_BYTE, pad_len);
-
-	return wlen;
-}
-
-/**
- * write_node - write a node to a LEB.
- * @node: node
- * @len: node length
- * @lnum: LEB number
- */
-static int write_node(void *node, int len, int lnum)
-{
-	prepare_node(node, len);
-
-	memcpy(leb_buf, node, len);
-
-	len = do_pad(leb_buf, len);
-
-	return write_leb(lnum, len, leb_buf);
-}
-
-/**
- * calc_dark - calculate LEB dark space size.
- * @c: the UBIFS file-system description object
- * @spc: amount of free and dirty space in the LEB
- *
- * This function calculates amount of dark space in an LEB which has @spc bytes
- * of free and dirty space. Returns the calculations result.
- *
- * Dark space is the space which is not always usable - it depends on which
- * nodes are written in which order. E.g., if an LEB has only 512 free bytes,
- * it is dark space, because it cannot fit a large data node. So UBIFS cannot
- * count on this LEB and treat these 512 bytes as usable because it is not true
- * if, for example, only big chunks of uncompressible data will be written to
- * the FS.
- */
-static int calc_dark(struct ubifs_info *c, int spc)
-{
-	if (spc < c->dark_wm)
-		return spc;
-
-	/*
-	 * If we have slightly more space then the dark space watermark, we can
-	 * anyway safely assume it we'll be able to write a node of the
-	 * smallest size there.
-	 */
-	if (spc - c->dark_wm < (int)MIN_WRITE_SZ)
-		return spc - MIN_WRITE_SZ;
-
-	return c->dark_wm;
-}
-
-/**
- * set_lprops - set the LEB property values for a LEB.
- * @lnum: LEB number
- * @offs: end offset of data in the LEB
- * @flags: LEB property flags
- */
-static void set_lprops(int lnum, int offs, int flags)
-{
-	int i = lnum - c->main_first, free, dirty;
-	int a = max_t(int, c->min_io_size, 8);
-
-	free = c->leb_size - ALIGN(offs, a);
-	dirty = c->leb_size - free - ALIGN(offs, 8);
-	dbg_msg(3, "LEB %d free %d dirty %d flags %d", lnum, free, dirty,
-		flags);
-	if (i < c->main_lebs) {
-		c->lpt[i].free = free;
-		c->lpt[i].dirty = dirty;
-		c->lpt[i].flags = flags;
-	}
-	c->lst.total_free += free;
-	c->lst.total_dirty += dirty;
-	if (flags & LPROPS_INDEX)
-		c->lst.idx_lebs += 1;
-	else {
-		int spc;
-
-		spc = free + dirty;
-		if (spc < c->dead_wm)
-			c->lst.total_dead += spc;
-		else
-			c->lst.total_dark += calc_dark(c, spc);
-		c->lst.total_used += c->leb_size - spc;
-	}
-}
-
-/**
- * add_to_index - add a node key and position to the index.
- * @key: node key
- * @lnum: node LEB number
- * @offs: node offset
- * @len: node length
- */
-static int add_to_index(union ubifs_key *key, char *name, int lnum, int offs,
-			int len)
-{
-	struct idx_entry *e;
-
-	dbg_msg(3, "LEB %d offs %d len %d", lnum, offs, len);
-	e = malloc(sizeof(struct idx_entry));
-	if (!e)
-		return err_msg("out of memory");
-	e->next = NULL;
-	e->prev = idx_list_last;
-	e->key = *key;
-	e->name = name;
-	e->lnum = lnum;
-	e->offs = offs;
-	e->len = len;
-	if (!idx_list_first)
-		idx_list_first = e;
-	if (idx_list_last)
-		idx_list_last->next = e;
-	idx_list_last = e;
-	idx_cnt += 1;
-	return 0;
-}
-
-/**
- * flush_nodes - write the current head and move the head to the next LEB.
- */
-static int flush_nodes(void)
-{
-	int len, err;
-
-	if (!head_offs)
-		return 0;
-	len = do_pad(leb_buf, head_offs);
-	err = write_leb(head_lnum, len, leb_buf);
-	if (err)
-		return err;
-	set_lprops(head_lnum, head_offs, head_flags);
-	head_lnum += 1;
-	head_offs = 0;
-	return 0;
-}
-
-/**
- * reserve_space - reserve space for a node on the head.
- * @len: node length
- * @lnum: LEB number is returned here
- * @offs: offset is returned here
- */
-static int reserve_space(int len, int *lnum, int *offs)
-{
-	int err;
-
-	if (len > c->leb_size - head_offs) {
-		err = flush_nodes();
-		if (err)
-			return err;
-	}
-	*lnum = head_lnum;
-	*offs = head_offs;
-	head_offs += ALIGN(len, 8);
-	return 0;
-}
-
-/**
- * add_node - write a node to the head.
- * @key: node key
- * @node: node
- * @len: node length
- */
-static int add_node(union ubifs_key *key, char *name, void *node, int len)
-{
-	int err, lnum, offs;
-
-	prepare_node(node, len);
-
-	err = reserve_space(len, &lnum, &offs);
-	if (err)
-		return err;
-
-	memcpy(leb_buf + offs, node, len);
-	memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len);
-
-	add_to_index(key, name, lnum, offs, len);
-
-	return 0;
-}
-
-/**
- * add_inode_with_data - write an inode.
- * @st: stat information of source inode
- * @inum: target inode number
- * @data: inode data (for special inodes e.g. symlink path etc)
- * @data_len: inode data length
- * @flags: source inode flags
- */
-static int add_inode_with_data(struct stat *st, ino_t inum, void *data,
-			       unsigned int data_len, int flags)
-{
-	struct ubifs_ino_node *ino = node_buf;
-	union ubifs_key key;
-	int len, use_flags = 0;
-
-	if (c->default_compr != UBIFS_COMPR_NONE)
-		use_flags |= UBIFS_COMPR_FL;
-	if (flags & FS_COMPR_FL)
-		use_flags |= UBIFS_COMPR_FL;
-	if (flags & FS_SYNC_FL)
-		use_flags |= UBIFS_SYNC_FL;
-	if (flags & FS_IMMUTABLE_FL)
-		use_flags |= UBIFS_IMMUTABLE_FL;
-	if (flags & FS_APPEND_FL)
-		use_flags |= UBIFS_APPEND_FL;
-	if (flags & FS_DIRSYNC_FL && S_ISDIR(st->st_mode))
-		use_flags |= UBIFS_DIRSYNC_FL;
-
-	memset(ino, 0, UBIFS_INO_NODE_SZ);
-
-	ino_key_init(&key, inum);
-	ino->ch.node_type = UBIFS_INO_NODE;
-	key_write(&key, &ino->key);
-	ino->creat_sqnum = cpu_to_le64(creat_sqnum);
-	ino->size       = cpu_to_le64(st->st_size);
-	ino->nlink      = cpu_to_le32(st->st_nlink);
-	/*
-	 * The time fields are updated assuming the default time granularity
-	 * of 1 second. To support finer granularities, utime() would be needed.
-	 */
-	ino->atime_sec  = cpu_to_le64(st->st_atime);
-	ino->ctime_sec  = cpu_to_le64(st->st_ctime);
-	ino->mtime_sec  = cpu_to_le64(st->st_mtime);
-	ino->atime_nsec = 0;
-	ino->ctime_nsec = 0;
-	ino->mtime_nsec = 0;
-	ino->uid        = cpu_to_le32(st->st_uid);
-	ino->gid        = cpu_to_le32(st->st_gid);
-	ino->mode       = cpu_to_le32(st->st_mode);
-	ino->flags      = cpu_to_le32(use_flags);
-	ino->data_len   = cpu_to_le32(data_len);
-	ino->compr_type = cpu_to_le16(c->default_compr);
-	if (data_len)
-		memcpy(&ino->data, data, data_len);
-
-	len = UBIFS_INO_NODE_SZ + data_len;
-
-	return add_node(&key, NULL, ino, len);
-}
-
-/**
- * add_inode - write an inode.
- * @st: stat information of source inode
- * @inum: target inode number
- * @flags: source inode flags
- */
-static int add_inode(struct stat *st, ino_t inum, int flags)
-{
-	return add_inode_with_data(st, inum, NULL, 0, flags);
-}
-
-/**
- * add_dir_inode - write an inode for a directory.
- * @dir: source directory
- * @inum: target inode number
- * @size: target directory size
- * @nlink: target directory link count
- * @st: struct stat object describing attributes (except size and nlink) of the
- *      target inode to create
- *
- * Note, this function may be called with %NULL @dir, when the directory which
- * is being created does not exist at the host file system, but is defined by
- * the device table.
- */
-static int add_dir_inode(DIR *dir, ino_t inum, loff_t size, unsigned int nlink,
-			 struct stat *st)
-{
-	int fd, flags = 0;
-
-	st->st_size = size;
-	st->st_nlink = nlink;
-
-	if (dir) {
-		fd = dirfd(dir);
-		if (fd == -1)
-			return sys_err_msg("dirfd failed");
-		if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1)
-			flags = 0;
-	}
-
-	return add_inode(st, inum, flags);
-}
-
-/**
- * add_dev_inode - write an inode for a character or block device.
- * @st: stat information of source inode
- * @inum: target inode number
- * @flags: source inode flags
- */
-static int add_dev_inode(struct stat *st, ino_t inum, int flags)
-{
-	union ubifs_dev_desc dev;
-
-	dev.huge = cpu_to_le64(makedev(major(st->st_rdev), minor(st->st_rdev)));
-	return add_inode_with_data(st, inum, &dev, 8, flags);
-}
-
-/**
- * add_symlink_inode - write an inode for a symbolic link.
- * @path_name: path name of symbolic link inode itself (not the link target)
- * @st: stat information of source inode
- * @inum: target inode number
- * @flags: source inode flags
- */
-static int add_symlink_inode(const char *path_name, struct stat *st, ino_t inum,
-			     int flags)
-{
-	char buf[UBIFS_MAX_INO_DATA + 2];
-	ssize_t len;
-
-	/* Take the symlink as is */
-	len = readlink(path_name, buf, UBIFS_MAX_INO_DATA + 1);
-	if (len <= 0)
-		return sys_err_msg("readlink failed for %s", path_name);
-	if (len > UBIFS_MAX_INO_DATA)
-		return err_msg("symlink too long for %s", path_name);
-
-	return add_inode_with_data(st, inum, buf, len, flags);
-}
-
-/**
- * add_dent_node - write a directory entry node.
- * @dir_inum: target inode number of directory
- * @name: directory entry name
- * @inum: target inode number of the directory entry
- * @type: type of the target inode
- */
-static int add_dent_node(ino_t dir_inum, const char *name, ino_t inum,
-			 unsigned char type)
-{
-	struct ubifs_dent_node *dent = node_buf;
-	union ubifs_key key;
-	struct qstr dname;
-	char *kname;
-	int len;
-
-	dbg_msg(3, "%s ino %lu type %u dir ino %lu", name, (unsigned long)inum,
-		(unsigned int)type, (unsigned long)dir_inum);
-	memset(dent, 0, UBIFS_DENT_NODE_SZ);
-
-	dname.name = (void *)name;
-	dname.len = strlen(name);
-
-	dent->ch.node_type = UBIFS_DENT_NODE;
-
-	dent_key_init(c, &key, dir_inum, &dname);
-	key_write(&key, dent->key);
-	dent->inum = cpu_to_le64(inum);
-	dent->padding1 = 0;
-	dent->type = type;
-	dent->nlen = cpu_to_le16(dname.len);
-	memcpy(dent->name, dname.name, dname.len);
-	dent->name[dname.len] = '\0';
-
-	len = UBIFS_DENT_NODE_SZ + dname.len + 1;
-
-	kname = strdup(name);
-	if (!kname)
-		return err_msg("cannot allocate memory");
-
-	return add_node(&key, kname, dent, len);
-}
-
-/**
- * lookup_inum_mapping - add an inode mapping for link counting.
- * @dev: source device on which source inode number resides
- * @inum: source inode number
- */
-static struct inum_mapping *lookup_inum_mapping(dev_t dev, ino_t inum)
-{
-	struct inum_mapping *im;
-	unsigned int k;
-
-	k = inum % HASH_TABLE_SIZE;
-	im = hash_table[k];
-	while (im) {
-		if (im->dev == dev && im->inum == inum)
-			return im;
-		im = im->next;
-	}
-	im = malloc(sizeof(struct inum_mapping));
-	if (!im)
-		return NULL;
-	im->next = hash_table[k];
-	im->prev = NULL;
-	im->dev = dev;
-	im->inum = inum;
-	im->use_inum = 0;
-	im->use_nlink = 0;
-	if (hash_table[k])
-		hash_table[k]->prev = im;
-	hash_table[k] = im;
-	return im;
-}
-
-/**
- * all_zero - does a buffer contain only zero bytes.
- * @buf: buffer
- * @len: buffer length
- */
-static int all_zero(void *buf, int len)
-{
-	unsigned char *p = buf;
-
-	while (len--)
-		if (*p++ != 0)
-			return 0;
-	return 1;
-}
-
-/**
- * add_file - write the data of a file and its inode to the output file.
- * @path_name: source path name
- * @st: source inode stat information
- * @inum: target inode number
- * @flags: source inode flags
- */
-static int add_file(const char *path_name, struct stat *st, ino_t inum,
-		    int flags)
-{
-	struct ubifs_data_node *dn = node_buf;
-	void *buf = block_buf;
-	loff_t file_size = 0;
-	ssize_t ret, bytes_read;
-	union ubifs_key key;
-	int fd, dn_len, err, compr_type, use_compr;
-	unsigned int block_no = 0;
-	size_t out_len;
-
-	fd = open(path_name, O_RDONLY | O_LARGEFILE);
-	if (fd == -1)
-		return sys_err_msg("failed to open file '%s'", path_name);
-	do {
-		/* Read next block */
-		bytes_read = 0;
-		do {
-			ret = read(fd, buf + bytes_read,
-				   UBIFS_BLOCK_SIZE - bytes_read);
-			if (ret == -1) {
-				sys_err_msg("failed to read file '%s'",
-					    path_name);
-				close(fd);
-				return 1;
-			}
-			bytes_read += ret;
-		} while (ret != 0 && bytes_read != UBIFS_BLOCK_SIZE);
-		if (bytes_read == 0)
-			break;
-		file_size += bytes_read;
-		/* Skip holes */
-		if (all_zero(buf, bytes_read)) {
-			block_no += 1;
-			continue;
-		}
-		/* Make data node */
-		memset(dn, 0, UBIFS_DATA_NODE_SZ);
-		data_key_init(&key, inum, block_no++);
-		dn->ch.node_type = UBIFS_DATA_NODE;
-		key_write(&key, &dn->key);
-		dn->size = cpu_to_le32(bytes_read);
-		out_len = NODE_BUFFER_SIZE - UBIFS_DATA_NODE_SZ;
-		if (c->default_compr == UBIFS_COMPR_NONE &&
-		    (flags & FS_COMPR_FL))
-			use_compr = UBIFS_COMPR_LZO;
-		else
-			use_compr = c->default_compr;
-		compr_type = compress_data(buf, bytes_read, &dn->data,
-					   &out_len, use_compr);
-		dn->compr_type = cpu_to_le16(compr_type);
-		dn_len = UBIFS_DATA_NODE_SZ + out_len;
-		/* Add data node to file system */
-		err = add_node(&key, NULL, dn, dn_len);
-		if (err) {
-			close(fd);
-			return err;
-		}
-	} while (ret != 0);
-	if (close(fd) == -1)
-		return sys_err_msg("failed to close file '%s'", path_name);
-	if (file_size != st->st_size)
-		return err_msg("file size changed during writing file '%s'",
-			       path_name);
-	return add_inode(st, inum, flags);
-}
-
-/**
- * add_non_dir - write a non-directory to the output file.
- * @path_name: source path name
- * @inum: target inode number is passed and returned here (due to link counting)
- * @nlink: number of links if known otherwise zero
- * @type: UBIFS inode type is returned here
- * @st: struct stat object containing inode attributes which should be use when
- *      creating the UBIFS inode
- */
-static int add_non_dir(const char *path_name, ino_t *inum, unsigned int nlink,
-		       unsigned char *type, struct stat *st)
-{
-	int fd, flags = 0;
-
-	dbg_msg(2, "%s", path_name);
-
-	if (S_ISREG(st->st_mode)) {
-		fd = open(path_name, O_RDONLY);
-		if (fd == -1)
-			return sys_err_msg("failed to open file '%s'",
-					   path_name);
-		if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1)
-			flags = 0;
-		if (close(fd) == -1)
-			return sys_err_msg("failed to close file '%s'",
-					   path_name);
-		*type = UBIFS_ITYPE_REG;
-	} else if (S_ISCHR(st->st_mode))
-		*type = UBIFS_ITYPE_CHR;
-	else if (S_ISBLK(st->st_mode))
-		*type = UBIFS_ITYPE_BLK;
-	else if (S_ISLNK(st->st_mode))
-		*type = UBIFS_ITYPE_LNK;
-	else if (S_ISSOCK(st->st_mode))
-		*type = UBIFS_ITYPE_SOCK;
-	else if (S_ISFIFO(st->st_mode))
-		*type = UBIFS_ITYPE_FIFO;
-	else
-		return err_msg("file '%s' has unknown inode type", path_name);
-
-	if (nlink)
-		st->st_nlink = nlink;
-	else if (st->st_nlink > 1) {
-		/*
-		 * If the number of links is greater than 1, then add this file
-		 * later when we know the number of links that we actually have.
-		 * For now, we just put the inode mapping in the hash table.
-		 */
-		struct inum_mapping *im;
-
-		im = lookup_inum_mapping(st->st_dev, st->st_ino);
-		if (!im)
-			return err_msg("out of memory");
-		if (im->use_nlink == 0) {
-			/* New entry */
-			im->use_inum = *inum;
-			im->use_nlink = 1;
-			im->path_name = malloc(strlen(path_name) + 1);
-			if (!im->path_name)
-				return err_msg("out of memory");
-			strcpy(im->path_name, path_name);
-		} else {
-			/* Existing entry */
-			*inum = im->use_inum;
-			im->use_nlink += 1;
-			/* Return unused inode number */
-			c->highest_inum -= 1;
-		}
-
-		memcpy(&im->st, st, sizeof(struct stat));
-		return 0;
-	} else
-		st->st_nlink = 1;
-
-	creat_sqnum = ++c->max_sqnum;
-
-	if (S_ISREG(st->st_mode))
-		return add_file(path_name, st, *inum, flags);
-	if (S_ISCHR(st->st_mode))
-		return add_dev_inode(st, *inum, flags);
-	if (S_ISBLK(st->st_mode))
-		return add_dev_inode(st, *inum, flags);
-	if (S_ISLNK(st->st_mode))
-		return add_symlink_inode(path_name, st, *inum, flags);
-	if (S_ISSOCK(st->st_mode))
-		return add_inode(st, *inum, flags);
-	if (S_ISFIFO(st->st_mode))
-		return add_inode(st, *inum, flags);
-
-	return err_msg("file '%s' has unknown inode type", path_name);
-}
-
-/**
- * add_directory - write a directory tree to the output file.
- * @dir_name: directory path name
- * @dir_inum: UBIFS inode number of directory
- * @st: directory inode statistics
- * @non_existing: non-zero if this function is called for a directory which
- *                does not exist on the host file-system and it is being
- *                created because it is defined in the device table file.
- */
-static int add_directory(const char *dir_name, ino_t dir_inum, struct stat *st,
-			 int non_existing)
-{
-	struct dirent *entry;
-	DIR *dir = NULL;
-	int err = 0;
-	loff_t size = UBIFS_INO_NODE_SZ;
-	char *name = NULL;
-	unsigned int nlink = 2;
-	struct path_htbl_element *ph_elt;
-	struct name_htbl_element *nh_elt = NULL;
-	struct hashtable_itr *itr;
-	ino_t inum;
-	unsigned char type;
-	unsigned long long dir_creat_sqnum = ++c->max_sqnum;
-
-	dbg_msg(2, "%s", dir_name);
-	if (!non_existing) {
-		dir = opendir(dir_name);
-		if (dir == NULL)
-			return sys_err_msg("cannot open directory '%s'",
-					   dir_name);
-	}
-
-	/*
-	 * Check whether this directory contains files which should be
-	 * added/changed because they were specified in the device table.
-	 * @ph_elt will be non-zero if yes.
-	 */
-	ph_elt = devtbl_find_path(dir_name + root_len - 1);
-
-	/*
-	 * Before adding the directory itself, we have to iterate over all the
-	 * entries the device table adds to this directory and create them.
-	 */
-	for (; !non_existing;) {
-		struct stat dent_st;
-
-		errno = 0;
-		entry = readdir(dir);
-		if (!entry) {
-			if (errno == 0)
-				break;
-			sys_err_msg("error reading directory '%s'", dir_name);
-			err = -1;
-			break;
-		}
-
-		if (strcmp(".", entry->d_name) == 0)
-			continue;
-		if (strcmp("..", entry->d_name) == 0)
-			continue;
-
-		if (ph_elt)
-			/*
-			 * This directory was referred to at the device table
-			 * file. Check if this directory entry is referred at
-			 * too.
-			 */
-			nh_elt = devtbl_find_name(ph_elt, entry->d_name);
-
-		/*
-		 * We are going to create the file corresponding to this
-		 * directory entry (@entry->d_name). We use 'struct stat'
-		 * object to pass information about file attributes (actually
-		 * only about UID, GID, mode, major, and minor). Get attributes
-		 * for this file from the UBIFS rootfs on the host.
-		 */
-		free(name);
-		name = make_path(dir_name, entry->d_name);
-		if (lstat(name, &dent_st) == -1) {
-			sys_err_msg("lstat failed for file '%s'", name);
-			goto out_free;
-		}
-
-		if (squash_owner)
-			/*
-			 * Squash UID/GID. But the device table may override
-			 * this.
-			 */
-			dent_st.st_uid = dent_st.st_gid = 0;
-
-		/*
-		 * And if the device table describes the same file, override
-		 * the attributes. However, this is not allowed for device node
-		 * files.
-		 */
-		if (nh_elt && override_attributes(&dent_st, ph_elt, nh_elt))
-			goto out_free;
-
-		inum = ++c->highest_inum;
-
-		if (S_ISDIR(dent_st.st_mode)) {
-			err = add_directory(name, inum, &dent_st, 0);
-			if (err)
-				goto out_free;
-			nlink += 1;
-			type = UBIFS_ITYPE_DIR;
-		} else {
-			err = add_non_dir(name, &inum, 0, &type, &dent_st);
-			if (err)
-				goto out_free;
-		}
-
-		err = add_dent_node(dir_inum, entry->d_name, inum, type);
-		if (err)
-			goto out_free;
-		size += ALIGN(UBIFS_DENT_NODE_SZ + strlen(entry->d_name) + 1,
-			      8);
-	}
-
-	/*
-	 * OK, we have created all files in this directory (recursively), let's
-	 * also create all files described in the device table. All t
-	 */
-	nh_elt = first_name_htbl_element(ph_elt, &itr);
-	while (nh_elt) {
-		struct stat fake_st;
-
-		/*
-		 * We prohibit creating regular files using the device table,
-		 * the device table may only re-define attributes of regular
-		 * files.
-		 */
-		if (S_ISREG(nh_elt->mode)) {
-			err_msg("Bad device table entry %s/%s - it is "
-				"prohibited to create regular files "
-				"via device table",
-				strcmp(ph_elt->path, "/") ? ph_elt->path : "",
-				nh_elt->name);
-			goto out_free;
-		}
-
-		memcpy(&fake_st, &root_st, sizeof(struct stat));
-		fake_st.st_uid  = nh_elt->uid;
-		fake_st.st_uid  = nh_elt->uid;
-		fake_st.st_mode = nh_elt->mode;
-		fake_st.st_rdev = nh_elt->dev;
-		fake_st.st_nlink = 1;
-
-		free(name);
-		name = make_path(dir_name, nh_elt->name);
-		inum = ++c->highest_inum;
-
-		if (S_ISDIR(nh_elt->mode)) {
-			err = add_directory(name, inum, &fake_st, 1);
-			if (err)
-				goto out_free;
-			nlink += 1;
-			type = UBIFS_ITYPE_DIR;
-		} else {
-			err = add_non_dir(name, &inum, 0, &type, &fake_st);
-			if (err)
-				goto out_free;
-		}
-
-		err = add_dent_node(dir_inum, nh_elt->name, inum, type);
-		if (err)
-			goto out_free;
-		size += ALIGN(UBIFS_DENT_NODE_SZ + strlen(nh_elt->name) + 1, 8);
-
-		nh_elt = next_name_htbl_element(ph_elt, &itr);
-	}
-
-	creat_sqnum = dir_creat_sqnum;
-
-	err = add_dir_inode(dir, dir_inum, size, nlink, st);
-	if (err)
-		goto out_free;
-
-	free(name);
-	if (!non_existing && closedir(dir) == -1)
-		return sys_err_msg("error closing directory '%s'", dir_name);
-
-	return 0;
-
-out_free:
-	free(name);
-	if (!non_existing)
-		closedir(dir);
-	return -1;
-}
-
-/**
- * add_multi_linked_files - write all the files for which we counted links.
- */
-static int add_multi_linked_files(void)
-{
-	int i, err;
-
-	for (i = 0; i < HASH_TABLE_SIZE; i++) {
-		struct inum_mapping *im;
-		unsigned char type = 0;
-
-		for (im = hash_table[i]; im; im = im->next) {
-			dbg_msg(2, "%s", im->path_name);
-			err = add_non_dir(im->path_name, &im->use_inum,
-					  im->use_nlink, &type, &im->st);
-			if (err)
-				return err;
-		}
-	}
-	return 0;
-}
-
-/**
- * write_data - write the files and directories.
- */
-static int write_data(void)
-{
-	int err;
-	mode_t mode = S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
-
-	if (root) {
-		err = stat(root, &root_st);
-		if (err)
-			return sys_err_msg("bad root file-system directory '%s'",
-					   root);
-	} else {
-		root_st.st_mtime = time(NULL);
-		root_st.st_atime = root_st.st_ctime = root_st.st_mtime;
-		root_st.st_mode = mode;
-	}
-
-	head_flags = 0;
-	err = add_directory(root, UBIFS_ROOT_INO, &root_st, !root);
-	if (err)
-		return err;
-	err = add_multi_linked_files();
-	if (err)
-		return err;
-	return flush_nodes();
-}
-
-static int namecmp(const char *name1, const char *name2)
-{
-	size_t len1 = strlen(name1), len2 = strlen(name2);
-	size_t clen = (len1 < len2) ? len1 : len2;
-	int cmp;
-
-	cmp = memcmp(name1, name2, clen);
-	if (cmp)
-		return cmp;
-	return (len1 < len2) ? -1 : 1;
-}
-
-static int cmp_idx(const void *a, const void *b)
-{
-	const struct idx_entry *e1 = *(const struct idx_entry **)a;
-	const struct idx_entry *e2 = *(const struct idx_entry **)b;
-	int cmp;
-
-	cmp = keys_cmp(&e1->key, &e2->key);
-	if (cmp)
-		return cmp;
-	return namecmp(e1->name, e2->name);
-}
-
-/**
- * add_idx_node - write an index node to the head.
- * @node: index node
- * @child_cnt: number of children of this index node
- */
-static int add_idx_node(void *node, int child_cnt)
-{
-	int err, lnum, offs, len;
-
-	len = ubifs_idx_node_sz(c, child_cnt);
-
-	prepare_node(node, len);
-
-	err = reserve_space(len, &lnum, &offs);
-	if (err)
-		return err;
-
-	memcpy(leb_buf + offs, node, len);
-	memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len);
-
-	c->old_idx_sz += ALIGN(len, 8);
-
-	dbg_msg(3, "at %d:%d len %d index size %llu", lnum, offs, len,
-		c->old_idx_sz);
-
-	/* The last index node written will be the root */
-	c->zroot.lnum = lnum;
-	c->zroot.offs = offs;
-	c->zroot.len = len;
-
-	return 0;
-}
-
-/**
- * write_index - write out the index.
- */
-static int write_index(void)
-{
-	size_t sz, i, cnt, idx_sz, pstep, bcnt;
-	struct idx_entry **idx_ptr, **p;
-	struct ubifs_idx_node *idx;
-	struct ubifs_branch *br;
-	int child_cnt = 0, j, level, blnum, boffs, blen, blast_len, err;
-
-	dbg_msg(1, "leaf node count: %zd", idx_cnt);
-
-	/* Reset the head for the index */
-	head_flags = LPROPS_INDEX;
-	/* Allocate index node */
-	idx_sz = ubifs_idx_node_sz(c, c->fanout);
-	idx = malloc(idx_sz);
-	if (!idx)
-		return err_msg("out of memory");
-	/* Make an array of pointers to sort the index list */
-	sz = idx_cnt * sizeof(struct idx_entry *);
-	if (sz / sizeof(struct idx_entry *) != idx_cnt) {
-		free(idx);
-		return err_msg("index is too big (%zu entries)", idx_cnt);
-	}
-	idx_ptr = malloc(sz);
-	if (!idx_ptr) {
-		free(idx);
-		return err_msg("out of memory - needed %zu bytes for index",
-			       sz);
-	}
-	idx_ptr[0] = idx_list_first;
-	for (i = 1; i < idx_cnt; i++)
-		idx_ptr[i] = idx_ptr[i - 1]->next;
-	qsort(idx_ptr, idx_cnt, sizeof(struct idx_entry *), cmp_idx);
-	/* Write level 0 index nodes */
-	cnt = idx_cnt / c->fanout;
-	if (idx_cnt % c->fanout)
-		cnt += 1;
-	p = idx_ptr;
-	blnum = head_lnum;
-	boffs = head_offs;
-	for (i = 0; i < cnt; i++) {
-		/*
-		 * Calculate the child count. All index nodes are created full
-		 * except for the last index node on each row.
-		 */
-		if (i == cnt - 1) {
-			child_cnt = idx_cnt % c->fanout;
-			if (child_cnt == 0)
-				child_cnt = c->fanout;
-		} else
-			child_cnt = c->fanout;
-		memset(idx, 0, idx_sz);
-		idx->ch.node_type = UBIFS_IDX_NODE;
-		idx->child_cnt = cpu_to_le16(child_cnt);
-		idx->level = cpu_to_le16(0);
-		for (j = 0; j < child_cnt; j++, p++) {
-			br = ubifs_idx_branch(c, idx, j);
-			key_write_idx(&(*p)->key, &br->key);
-			br->lnum = cpu_to_le32((*p)->lnum);
-			br->offs = cpu_to_le32((*p)->offs);
-			br->len = cpu_to_le32((*p)->len);
-		}
-		add_idx_node(idx, child_cnt);
-	}
-	/* Write level 1 index nodes and above */
-	level = 0;
-	pstep = 1;
-	while (cnt > 1) {
-		/*
-		 * 'blast_len' is the length of the last index node in the level
-		 * below.
-		 */
-		blast_len = ubifs_idx_node_sz(c, child_cnt);
-		/* 'bcnt' is the number of index nodes in the level below */
-		bcnt = cnt;
-		/* 'cnt' is the number of index nodes in this level */
-		cnt = (cnt + c->fanout - 1) / c->fanout;
-		if (cnt == 0)
-			cnt = 1;
-		level += 1;
-		/*
-		 * The key of an index node is the same as the key of its first
-		 * child. Thus we can get the key by stepping along the bottom
-		 * level 'p' with an increasing large step 'pstep'.
-		 */
-		p = idx_ptr;
-		pstep *= c->fanout;
-		for (i = 0; i < cnt; i++) {
-			/*
-			 * Calculate the child count. All index nodes are
-			 * created full except for the last index node on each
-			 * row.
-			 */
-			if (i == cnt - 1) {
-				child_cnt = bcnt % c->fanout;
-				if (child_cnt == 0)
-					child_cnt = c->fanout;
-			} else
-				child_cnt = c->fanout;
-			memset(idx, 0, idx_sz);
-			idx->ch.node_type = UBIFS_IDX_NODE;
-			idx->child_cnt = cpu_to_le16(child_cnt);
-			idx->level = cpu_to_le16(level);
-			for (j = 0; j < child_cnt; j++) {
-				size_t bn = i * c->fanout + j;
-
-				/*
-				 * The length of the index node in the level
-				 * below is 'idx_sz' except when it is the last
-				 * node on the row. i.e. all the others on the
-				 * row are full.
-				 */
-				if (bn == bcnt - 1)
-					blen = blast_len;
-				else
-					blen = idx_sz;
-				/*
-				 * 'blnum' and 'boffs' hold the position of the
-				 * index node on the level below.
-				 */
-				if (boffs + blen > c->leb_size) {
-					blnum += 1;
-					boffs = 0;
-				}
-				/*
-				 * Fill in the branch with the key and position
-				 * of the index node from the level below.
-				 */
-				br = ubifs_idx_branch(c, idx, j);
-				key_write_idx(&(*p)->key, &br->key);
-				br->lnum = cpu_to_le32(blnum);
-				br->offs = cpu_to_le32(boffs);
-				br->len = cpu_to_le32(blen);
-				/*
-				 * Step to the next index node on the level
-				 * below.
-				 */
-				boffs += ALIGN(blen, 8);
-				p += pstep;
-			}
-			add_idx_node(idx, child_cnt);
-		}
-	}
-
-	/* Free stuff */
-	for (i = 0; i < idx_cnt; i++)
-		free(idx_ptr[i]);
-	free(idx_ptr);
-	free(idx);
-
-	dbg_msg(1, "zroot is at %d:%d len %d", c->zroot.lnum, c->zroot.offs,
-		c->zroot.len);
-
-	/* Set the index head */
-	c->ihead_lnum = head_lnum;
-	c->ihead_offs = ALIGN(head_offs, c->min_io_size);
-	dbg_msg(1, "ihead is at %d:%d", c->ihead_lnum, c->ihead_offs);
-
-	/* Flush the last index LEB */
-	err = flush_nodes();
-	if (err)
-		return err;
-
-	return 0;
-}
-
-/**
- * set_gc_lnum - set the LEB number reserved for the garbage collector.
- */
-static int set_gc_lnum(void)
-{
-	int err;
-
-	c->gc_lnum = head_lnum++;
-	err = write_empty_leb(c->gc_lnum);
-	if (err)
-		return err;
-	set_lprops(c->gc_lnum, 0, 0);
-	c->lst.empty_lebs += 1;
-	return 0;
-}
-
-/**
- * finalize_leb_cnt - now that we know how many LEBs we used.
- */
-static int finalize_leb_cnt(void)
-{
-	c->leb_cnt = head_lnum;
-	if (c->leb_cnt > c->max_leb_cnt)
-		return err_msg("max_leb_cnt too low (%d needed)", c->leb_cnt);
-	c->main_lebs = c->leb_cnt - c->main_first;
-	if (verbose) {
-		printf("\tsuper lebs:   %d\n", UBIFS_SB_LEBS);
-		printf("\tmaster lebs:  %d\n", UBIFS_MST_LEBS);
-		printf("\tlog_lebs:     %d\n", c->log_lebs);
-		printf("\tlpt_lebs:     %d\n", c->lpt_lebs);
-		printf("\torph_lebs:    %d\n", c->orph_lebs);
-		printf("\tmain_lebs:    %d\n", c->main_lebs);
-		printf("\tgc lebs:      %d\n", 1);
-		printf("\tindex lebs:   %d\n", c->lst.idx_lebs);
-		printf("\tleb_cnt:      %d\n", c->leb_cnt);
-	}
-	dbg_msg(1, "total_free:  %llu", c->lst.total_free);
-	dbg_msg(1, "total_dirty: %llu", c->lst.total_dirty);
-	dbg_msg(1, "total_used:  %llu", c->lst.total_used);
-	dbg_msg(1, "total_dead:  %llu", c->lst.total_dead);
-	dbg_msg(1, "total_dark:  %llu", c->lst.total_dark);
-	dbg_msg(1, "index size:  %llu", c->old_idx_sz);
-	dbg_msg(1, "empty_lebs:  %d", c->lst.empty_lebs);
-	return 0;
-}
-
-/**
- * write_super - write the super block.
- */
-static int write_super(void)
-{
-	struct ubifs_sb_node sup;
-
-	memset(&sup, 0, UBIFS_SB_NODE_SZ);
-
-	sup.ch.node_type  = UBIFS_SB_NODE;
-	sup.key_hash      = c->key_hash_type;
-	sup.min_io_size   = cpu_to_le32(c->min_io_size);
-	sup.leb_size      = cpu_to_le32(c->leb_size);
-	sup.leb_cnt       = cpu_to_le32(c->leb_cnt);
-	sup.max_leb_cnt   = cpu_to_le32(c->max_leb_cnt);
-	sup.max_bud_bytes = cpu_to_le64(c->max_bud_bytes);
-	sup.log_lebs      = cpu_to_le32(c->log_lebs);
-	sup.lpt_lebs      = cpu_to_le32(c->lpt_lebs);
-	sup.orph_lebs     = cpu_to_le32(c->orph_lebs);
-	sup.jhead_cnt     = cpu_to_le32(c->jhead_cnt);
-	sup.fanout        = cpu_to_le32(c->fanout);
-	sup.lsave_cnt     = cpu_to_le32(c->lsave_cnt);
-	sup.fmt_version   = cpu_to_le32(UBIFS_FORMAT_VERSION);
-	sup.default_compr = cpu_to_le16(c->default_compr);
-	sup.rp_size       = cpu_to_le64(c->rp_size);
-	sup.time_gran     = cpu_to_le32(DEFAULT_TIME_GRAN);
-	uuid_generate_random(sup.uuid);
-	if (verbose) {
-		char s[40];
-
-		uuid_unparse_upper(sup.uuid, s);
-		printf("\tUUID:         %s\n", s);
-	}
-	if (c->big_lpt)
-		sup.flags |= cpu_to_le32(UBIFS_FLG_BIGLPT);
-	if (c->space_fixup)
-		sup.flags |= cpu_to_le32(UBIFS_FLG_SPACE_FIXUP);
-
-	return write_node(&sup, UBIFS_SB_NODE_SZ, UBIFS_SB_LNUM);
-}
-
-/**
- * write_master - write the master node.
- */
-static int write_master(void)
-{
-	struct ubifs_mst_node mst;
-	int err;
-
-	memset(&mst, 0, UBIFS_MST_NODE_SZ);
-
-	mst.ch.node_type = UBIFS_MST_NODE;
-	mst.log_lnum     = cpu_to_le32(UBIFS_LOG_LNUM);
-	mst.highest_inum = cpu_to_le64(c->highest_inum);
-	mst.cmt_no       = cpu_to_le64(0);
-	mst.flags        = cpu_to_le32(UBIFS_MST_NO_ORPHS);
-	mst.root_lnum    = cpu_to_le32(c->zroot.lnum);
-	mst.root_offs    = cpu_to_le32(c->zroot.offs);
-	mst.root_len     = cpu_to_le32(c->zroot.len);
-	mst.gc_lnum      = cpu_to_le32(c->gc_lnum);
-	mst.ihead_lnum   = cpu_to_le32(c->ihead_lnum);
-	mst.ihead_offs   = cpu_to_le32(c->ihead_offs);
-	mst.index_size   = cpu_to_le64(c->old_idx_sz);
-	mst.lpt_lnum     = cpu_to_le32(c->lpt_lnum);
-	mst.lpt_offs     = cpu_to_le32(c->lpt_offs);
-	mst.nhead_lnum   = cpu_to_le32(c->nhead_lnum);
-	mst.nhead_offs   = cpu_to_le32(c->nhead_offs);
-	mst.ltab_lnum    = cpu_to_le32(c->ltab_lnum);
-	mst.ltab_offs    = cpu_to_le32(c->ltab_offs);
-	mst.lsave_lnum   = cpu_to_le32(c->lsave_lnum);
-	mst.lsave_offs   = cpu_to_le32(c->lsave_offs);
-	mst.lscan_lnum   = cpu_to_le32(c->lscan_lnum);
-	mst.empty_lebs   = cpu_to_le32(c->lst.empty_lebs);
-	mst.idx_lebs     = cpu_to_le32(c->lst.idx_lebs);
-	mst.total_free   = cpu_to_le64(c->lst.total_free);
-	mst.total_dirty  = cpu_to_le64(c->lst.total_dirty);
-	mst.total_used   = cpu_to_le64(c->lst.total_used);
-	mst.total_dead   = cpu_to_le64(c->lst.total_dead);
-	mst.total_dark   = cpu_to_le64(c->lst.total_dark);
-	mst.leb_cnt      = cpu_to_le32(c->leb_cnt);
-
-	err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM);
-	if (err)
-		return err;
-
-	err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1);
-	if (err)
-		return err;
-
-	return 0;
-}
-
-/**
- * write_log - write an empty log.
- */
-static int write_log(void)
-{
-	struct ubifs_cs_node cs;
-	int err, i, lnum;
-
-	lnum = UBIFS_LOG_LNUM;
-
-	cs.ch.node_type = UBIFS_CS_NODE;
-	cs.cmt_no = cpu_to_le64(0);
-
-	err = write_node(&cs, UBIFS_CS_NODE_SZ, lnum);
-	if (err)
-		return err;
-
-	lnum += 1;
-
-	for (i = 1; i < c->log_lebs; i++, lnum++) {
-		err = write_empty_leb(lnum);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
-/**
- * write_lpt - write the LEB properties tree.
- */
-static int write_lpt(void)
-{
-	int err, lnum;
-
-	err = create_lpt(c);
-	if (err)
-		return err;
-
-	lnum = c->nhead_lnum + 1;
-	while (lnum <= c->lpt_last) {
-		err = write_empty_leb(lnum++);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
-/**
- * write_orphan_area - write an empty orphan area.
- */
-static int write_orphan_area(void)
-{
-	int err, i, lnum;
-
-	lnum = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs;
-	for (i = 0; i < c->orph_lebs; i++, lnum++) {
-		err = write_empty_leb(lnum);
-		if (err)
-			return err;
-	}
-	return 0;
-}
-
-/**
- * check_volume_empty - check if the UBI volume is empty.
- *
- * This function checks if the UBI volume is empty by looking if its LEBs are
- * mapped or not.
- *
- * Returns %0 in case of success, %1 is the volume is not empty,
- * and a negative error code in case of failure.
- */
-static int check_volume_empty(void)
-{
-	int lnum, err;
-
-	for (lnum = 0; lnum < c->vi.rsvd_lebs; lnum++) {
-		err = ubi_is_mapped(out_fd, lnum);
-		if (err < 0)
-			return err;
-		if (err == 1)
-			return 1;
-	}
-	return 0;
-}
-
-/**
- * open_target - open the output target.
- *
- * Open the output target. The target can be an UBI volume
- * or a file.
- *
- * Returns %0 in case of success and %-1 in case of failure.
- */
-static int open_target(void)
-{
-	if (out_ubi) {
-		out_fd = open(output, O_RDWR | O_EXCL);
-
-		if (out_fd == -1)
-			return sys_err_msg("cannot open the UBI volume '%s'",
-					   output);
-		if (ubi_set_property(out_fd, UBI_VOL_PROP_DIRECT_WRITE, 1))
-			return sys_err_msg("ubi_set_property failed");
-
-		if (!yes && check_volume_empty()) {
-			if (!prompt("UBI volume is not empty.  Format anyways?", false))
-				return err_msg("UBI volume is not empty");
-		}
-	} else {
-		out_fd = open(output, O_CREAT | O_RDWR | O_TRUNC,
-			      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
-		if (out_fd == -1)
-			return sys_err_msg("cannot create output file '%s'",
-					   output);
-	}
-	return 0;
-}
-
-
-/**
- * close_target - close the output target.
- *
- * Close the output target. If the target was an UBI
- * volume, also close libubi.
- *
- * Returns %0 in case of success and %-1 in case of failure.
- */
-static int close_target(void)
-{
-	if (ubi)
-		libubi_close(ubi);
-	if (out_fd >= 0 && close(out_fd) == -1)
-		return sys_err_msg("cannot close the target '%s'", output);
-	if (output)
-		free(output);
-	return 0;
-}
-
-/**
- * init - initialize things.
- */
-static int init(void)
-{
-	int err, i, main_lebs, big_lpt = 0, sz;
-
-	c->highest_inum = UBIFS_FIRST_INO;
-
-	c->jhead_cnt = 1;
-
-	main_lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
-	main_lebs -= c->log_lebs + c->orph_lebs;
-
-	err = calc_dflt_lpt_geom(c, &main_lebs, &big_lpt);
-	if (err)
-		return err;
-
-	c->main_first = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs +
-			c->orph_lebs;
-	head_lnum = c->main_first;
-	head_offs = 0;
-
-	c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs;
-	c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
-
-	c->lpt = malloc(c->main_lebs * sizeof(struct ubifs_lprops));
-	if (!c->lpt)
-		return err_msg("unable to allocate LPT");
-
-	c->ltab = malloc(c->lpt_lebs * sizeof(struct ubifs_lprops));
-	if (!c->ltab)
-		return err_msg("unable to allocate LPT ltab");
-
-	/* Initialize LPT's own lprops */
-	for (i = 0; i < c->lpt_lebs; i++) {
-		c->ltab[i].free = c->leb_size;
-		c->ltab[i].dirty = 0;
-	}
-
-	c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size);
-	c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size);
-	dbg_msg(1, "dead_wm %d  dark_wm %d", c->dead_wm, c->dark_wm);
-
-	leb_buf = malloc(c->leb_size);
-	if (!leb_buf)
-		return err_msg("out of memory");
-
-	node_buf = malloc(NODE_BUFFER_SIZE);
-	if (!node_buf)
-		return err_msg("out of memory");
-
-	block_buf = malloc(UBIFS_BLOCK_SIZE);
-	if (!block_buf)
-		return err_msg("out of memory");
-
-	sz = sizeof(struct inum_mapping *) * HASH_TABLE_SIZE;
-	hash_table = malloc(sz);
-	if (!hash_table)
-		return err_msg("out of memory");
-	memset(hash_table, 0, sz);
-
-	err = init_compression();
-	if (err)
-		return err;
-
-	return 0;
-}
-
-static void destroy_hash_table(void)
-{
-	int i;
-
-	for (i = 0; i < HASH_TABLE_SIZE; i++) {
-		struct inum_mapping *im, *q;
-
-		for (im = hash_table[i]; im; ) {
-			q = im;
-			im = im->next;
-			free(q->path_name);
-			free(q);
-		}
-	}
-}
-
-/**
- * deinit - deinitialize things.
- */
-static void deinit(void)
-{
-	free(c->lpt);
-	free(c->ltab);
-	free(leb_buf);
-	free(node_buf);
-	free(block_buf);
-	destroy_hash_table();
-	free(hash_table);
-	destroy_compression();
-	free_devtable_info();
-}
-
-/**
- * mkfs - make the file system.
- *
- * Each on-flash area has a corresponding function to create it. The order of
- * the functions reflects what information must be known to complete each stage.
- * As a consequence the output file is not written sequentially. No effort has
- * been made to make efficient use of memory or to allow for the possibility of
- * incremental updates to the output file.
- */
-static int mkfs(void)
-{
-	int err = 0;
-
-	err = init();
-	if (err)
-		goto out;
-
-	err = write_data();
-	if (err)
-		goto out;
-
-	err = set_gc_lnum();
-	if (err)
-		goto out;
-
-	err = write_index();
-	if (err)
-		goto out;
-
-	err = finalize_leb_cnt();
-	if (err)
-		goto out;
-
-	err = write_lpt();
-	if (err)
-		goto out;
-
-	err = write_super();
-	if (err)
-		goto out;
-
-	err = write_master();
-	if (err)
-		goto out;
-
-	err = write_log();
-	if (err)
-		goto out;
-
-	err = write_orphan_area();
-
-out:
-	deinit();
-	return err;
-}
-
-int main(int argc, char *argv[])
-{
-	int err;
-
-	err = get_options(argc, argv);
-	if (err)
-		return err;
-
-	err = open_target();
-	if (err)
-		return err;
-
-	err = mkfs();
-	if (err) {
-		close_target();
-		return err;
-	}
-
-	err = close_target();
-	if (err)
-		return err;
-
-	if (verbose)
-		printf("Success!\n");
-
-	return 0;
-}
diff --git a/mkfs.ubifs/mkfs.ubifs.h b/mkfs.ubifs/mkfs.ubifs.h
deleted file mode 100644
index 944a159..0000000
--- a/mkfs.ubifs/mkfs.ubifs.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2008 Nokia Corporation.
- * Copyright (C) 2008 University of Szeged, Hungary
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Authors: Artem Bityutskiy
- *          Adrian Hunter
- *          Zoltan Sogor
- */
-
-#ifndef __MKFS_UBIFS_H__
-#define __MKFS_UBIFS_H__
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <limits.h>
-#include <string.h>
-#include <stdint.h>
-#include <endian.h>
-#include <byteswap.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <errno.h>
-#include <libgen.h>
-#include <ctype.h>
-#include <uuid/uuid.h>
-#include <sys/file.h>
-
-#include <mtd/ubifs-media.h>
-
-/* common.h requires the PROGRAM_NAME macro */
-#define PROGRAM_NAME "mkfs.ubifs"
-#include "common.h"
-
-#include "libubi.h"
-#include "defs.h"
-#include "crc16.h"
-#include "ubifs.h"
-#include "key.h"
-#include "lpt.h"
-#include "compr.h"
-
-/*
- * Compression flags are duplicated so that compr.c can compile without ubifs.h.
- * Here we make sure they are the same.
- */
-#if MKFS_UBIFS_COMPR_NONE != UBIFS_COMPR_NONE
-#error MKFS_UBIFS_COMPR_NONE != UBIFS_COMPR_NONE
-#endif
-#if MKFS_UBIFS_COMPR_LZO != UBIFS_COMPR_LZO
-#error MKFS_UBIFS_COMPR_LZO != UBIFS_COMPR_LZO
-#endif
-#if MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB
-#error MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB
-#endif
-
-extern int verbose;
-extern int debug_level;
-
-#define dbg_msg(lvl, fmt, ...) do {if (debug_level >= lvl)                \
-	printf("mkfs.ubifs: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__); \
-} while(0)
-
-#define err_msg(fmt, ...) ({                                \
-	fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__); \
-	-1;                                                 \
-})
-
-#define sys_err_msg(fmt, ...) ({                                         \
-	int err_ = errno;                                                \
-	fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__);              \
-	fprintf(stderr, "       %s (error %d)\n", strerror(err_), err_); \
-	-1;                                                              \
-})
-
-/**
- * struct path_htbl_element - an element of the path hash table.
- * @path: the UBIFS path the element describes (the key of the element)
- * @name_htbl: one more (nested) hash table containing names of all
- *             files/directories/device nodes which should be created at this
- *             path
- *
- * See device table handling for more information.
- */
-struct path_htbl_element {
-	const char *path;
-	struct hashtable *name_htbl;
-};
-
-/**
- * struct name_htbl_element - an element in the name hash table
- * @name: name of the file/directory/device node (the key of the element)
- * @mode: accsess rights and file type
- * @uid: user ID
- * @gid: group ID
- * @major: device node major number
- * @minor: device node minor number
- *
- * This is an element of the name hash table. Name hash table sits in the path
- * hash table elements and describes file names which should be created/changed
- * at this path.
- */
-struct name_htbl_element {
-	const char *name;
-	unsigned int mode;
-	unsigned int uid;
-	unsigned int gid;
-	dev_t dev;
-};
-
-extern struct ubifs_info info_;
-
-struct hashtable_itr;
-
-int write_leb(int lnum, int len, void *buf);
-int parse_devtable(const char *tbl_file);
-struct path_htbl_element *devtbl_find_path(const char *path);
-struct name_htbl_element *devtbl_find_name(struct path_htbl_element *ph_elt,
-					   const char *name);
-int override_attributes(struct stat *st, struct path_htbl_element *ph_elt,
-			struct name_htbl_element *nh_elt);
-struct name_htbl_element *
-first_name_htbl_element(struct path_htbl_element *ph_elt,
-			struct hashtable_itr **itr);
-struct name_htbl_element *
-next_name_htbl_element(struct path_htbl_element *ph_elt,
-		       struct hashtable_itr **itr);
-void free_devtable_info(void);
-
-#endif
diff --git a/mkfs.ubifs/ubifs.h b/mkfs.ubifs/ubifs.h
deleted file mode 100644
index 434b651..0000000
--- a/mkfs.ubifs/ubifs.h
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * This file is part of UBIFS.
- *
- * Copyright (C) 2008 Nokia Corporation.
- * Copyright (C) 2008 University of Szeged, Hungary
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Authors: Artem Bityutskiy
- *          Adrian Hunter
- *          Zoltan Sogor
- */
-
-#ifndef __UBIFS_H__
-#define __UBIFS_H__
-
-/* Maximum logical eraseblock size in bytes */
-#define UBIFS_MAX_LEB_SZ (2*1024*1024)
-
-/* Minimum amount of data UBIFS writes to the flash */
-#define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8)
-
-/* Largest key size supported in this implementation */
-#define CUR_MAX_KEY_LEN UBIFS_SK_LEN
-
-/*
- * There is no notion of truncation key because truncation nodes do not exist
- * in TNC. However, when replaying, it is handy to introduce fake "truncation"
- * keys for truncation nodes because the code becomes simpler. So we define
- * %UBIFS_TRUN_KEY type.
- */
-#define UBIFS_TRUN_KEY UBIFS_KEY_TYPES_CNT
-
-/* The below union makes it easier to deal with keys */
-union ubifs_key
-{
-	uint8_t u8[CUR_MAX_KEY_LEN];
-	uint32_t u32[CUR_MAX_KEY_LEN/4];
-	uint64_t u64[CUR_MAX_KEY_LEN/8];
-	__le32 j32[CUR_MAX_KEY_LEN/4];
-};
-
-/*
- * LEB properties flags.
- *
- * LPROPS_UNCAT: not categorized
- * LPROPS_DIRTY: dirty > 0, not index
- * LPROPS_DIRTY_IDX: dirty + free > UBIFS_CH_SZ and index
- * LPROPS_FREE: free > 0, not empty, not index
- * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs
- * LPROPS_EMPTY: LEB is empty, not taken
- * LPROPS_FREEABLE: free + dirty == leb_size, not index, not taken
- * LPROPS_FRDI_IDX: free + dirty == leb_size and index, may be taken
- * LPROPS_CAT_MASK: mask for the LEB categories above
- * LPROPS_TAKEN: LEB was taken (this flag is not saved on the media)
- * LPROPS_INDEX: LEB contains indexing nodes (this flag also exists on flash)
- */
-enum {
-	LPROPS_UNCAT     =  0,
-	LPROPS_DIRTY     =  1,
-	LPROPS_DIRTY_IDX =  2,
-	LPROPS_FREE      =  3,
-	LPROPS_HEAP_CNT  =  3,
-	LPROPS_EMPTY     =  4,
-	LPROPS_FREEABLE  =  5,
-	LPROPS_FRDI_IDX  =  6,
-	LPROPS_CAT_MASK  = 15,
-	LPROPS_TAKEN     = 16,
-	LPROPS_INDEX     = 32,
-};
-
-/**
- * struct ubifs_lprops - logical eraseblock properties.
- * @free: amount of free space in bytes
- * @dirty: amount of dirty space in bytes
- * @flags: LEB properties flags (see above)
- */
-struct ubifs_lprops
-{
-	int free;
-	int dirty;
-	int flags;
-};
-
-/**
- * struct ubifs_lpt_lprops - LPT logical eraseblock properties.
- * @free: amount of free space in bytes
- * @dirty: amount of dirty space in bytes
- */
-struct ubifs_lpt_lprops
-{
-	int free;
-	int dirty;
-};
-
-struct ubifs_nnode;
-
-/**
- * struct ubifs_cnode - LEB Properties Tree common node.
- * @parent: parent nnode
- * @cnext: next cnode to commit
- * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
- * @iip: index in parent
- * @level: level in the tree (zero for pnodes, greater than zero for nnodes)
- * @num: node number
- */
-struct ubifs_cnode
-{
-	struct ubifs_nnode *parent;
-	struct ubifs_cnode *cnext;
-	unsigned long flags;
-	int iip;
-	int level;
-	int num;
-};
-
-/**
- * struct ubifs_pnode - LEB Properties Tree leaf node.
- * @parent: parent nnode
- * @cnext: next cnode to commit
- * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
- * @iip: index in parent
- * @level: level in the tree (always zero for pnodes)
- * @num: node number
- * @lprops: LEB properties array
- */
-struct ubifs_pnode
-{
-	struct ubifs_nnode *parent;
-	struct ubifs_cnode *cnext;
-	unsigned long flags;
-	int iip;
-	int level;
-	int num;
-	struct ubifs_lprops lprops[UBIFS_LPT_FANOUT];
-};
-
-/**
- * struct ubifs_nbranch - LEB Properties Tree internal node branch.
- * @lnum: LEB number of child
- * @offs: offset of child
- * @nnode: nnode child
- * @pnode: pnode child
- * @cnode: cnode child
- */
-struct ubifs_nbranch
-{
-	int lnum;
-	int offs;
-	union
-	{
-		struct ubifs_nnode *nnode;
-		struct ubifs_pnode *pnode;
-		struct ubifs_cnode *cnode;
-	};
-};
-
-/**
- * struct ubifs_nnode - LEB Properties Tree internal node.
- * @parent: parent nnode
- * @cnext: next cnode to commit
- * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
- * @iip: index in parent
- * @level: level in the tree (always greater than zero for nnodes)
- * @num: node number
- * @nbranch: branches to child nodes
- */
-struct ubifs_nnode
-{
-	struct ubifs_nnode *parent;
-	struct ubifs_cnode *cnext;
-	unsigned long flags;
-	int iip;
-	int level;
-	int num;
-	struct ubifs_nbranch nbranch[UBIFS_LPT_FANOUT];
-};
-
-/**
- * struct ubifs_lp_stats - statistics of eraseblocks in the main area.
- * @empty_lebs: number of empty LEBs
- * @taken_empty_lebs: number of taken LEBs
- * @idx_lebs: number of indexing LEBs
- * @total_free: total free space in bytes
- * @total_dirty: total dirty space in bytes
- * @total_used: total used space in bytes (includes only data LEBs)
- * @total_dead: total dead space in bytes (includes only data LEBs)
- * @total_dark: total dark space in bytes (includes only data LEBs)
- */
-struct ubifs_lp_stats {
-	int empty_lebs;
-	int taken_empty_lebs;
-	int idx_lebs;
-	long long total_free;
-	long long total_dirty;
-	long long total_used;
-	long long total_dead;
-	long long total_dark;
-};
-
-/**
- * struct ubifs_zbranch - key/coordinate/length branch stored in znodes.
- * @key: key
- * @znode: znode address in memory
- * @lnum: LEB number of the indexing node
- * @offs: offset of the indexing node within @lnum
- * @len: target node length
- */
-struct ubifs_zbranch
-{
-	union ubifs_key key;
-	struct ubifs_znode *znode;
-	int lnum;
-	int offs;
-	int len;
-};
-
-/**
- * struct ubifs_znode - in-memory representation of an indexing node.
- * @parent: parent znode or NULL if it is the root
- * @cnext: next znode to commit
- * @flags: flags
- * @time: last access time (seconds)
- * @level: level of the entry in the TNC tree
- * @child_cnt: count of child znodes
- * @iip: index in parent's zbranch array
- * @alt: lower bound of key range has altered i.e. child inserted at slot 0
- * @zbranch: array of znode branches (@c->fanout elements)
- */
-struct ubifs_znode
-{
-	struct ubifs_znode *parent;
-	struct ubifs_znode *cnext;
-	unsigned long flags;
-	unsigned long time;
-	int level;
-	int child_cnt;
-	int iip;
-	int alt;
-#ifdef CONFIG_UBIFS_FS_DEBUG
-	int lnum, offs, len;
-#endif
-	struct ubifs_zbranch zbranch[];
-};
-
-/**
- * struct ubifs_info - UBIFS file-system description data structure
- * (per-superblock).
- *
- * @highest_inum: highest used inode number
- * @max_sqnum: current global sequence number
- *
- * @jhead_cnt: count of journal heads
- * @max_bud_bytes: maximum number of bytes allowed in buds
- *
- * @zroot: zbranch which points to the root index node and znode
- * @ihead_lnum: LEB number of index head
- * @ihead_offs: offset of index head
- *
- * @log_lebs: number of logical eraseblocks in the log
- * @lpt_lebs: number of LEBs used for lprops table
- * @lpt_first: first LEB of the lprops table area
- * @lpt_last: last LEB of the lprops table area
- * @main_lebs: count of LEBs in the main area
- * @main_first: first LEB of the main area
- * @default_compr: default compression type
- * @favor_lzo: favor LZO compression method
- * @favor_percent: lzo vs. zlib threshold used in case favor LZO
- *
- * @key_hash_type: type of the key hash
- * @key_hash: direntry key hash function
- * @key_fmt: key format
- * @key_len: key length
- * @fanout: fanout of the index tree (number of links per indexing node)
- *
- * @min_io_size: minimal input/output unit size
- * @leb_size: logical eraseblock size in bytes
- * @leb_cnt: count of logical eraseblocks
- * @max_leb_cnt: maximum count of logical eraseblocks
- *
- * @old_idx_sz: size of index on flash
- * @lst: lprops statistics
- *
- * @dead_wm: LEB dead space watermark
- * @dark_wm: LEB dark space watermark
- *
- * @di: UBI device information
- * @vi: UBI volume information
- *
- * @gc_lnum: LEB number used for garbage collection
- * @rp_size: reserved pool size
- *
- * @space_bits: number of bits needed to record free or dirty space
- * @lpt_lnum_bits: number of bits needed to record a LEB number in the LPT
- * @lpt_offs_bits: number of bits needed to record an offset in the LPT
- * @lpt_spc_bits: number of bits needed to space in the LPT
- * @pcnt_bits: number of bits needed to record pnode or nnode number
- * @lnum_bits: number of bits needed to record LEB number
- * @nnode_sz: size of on-flash nnode
- * @pnode_sz: size of on-flash pnode
- * @ltab_sz: size of on-flash LPT lprops table
- * @lsave_sz: size of on-flash LPT save table
- * @pnode_cnt: number of pnodes
- * @nnode_cnt: number of nnodes
- * @lpt_hght: height of the LPT
- *
- * @lpt_lnum: LEB number of the root nnode of the LPT
- * @lpt_offs: offset of the root nnode of the LPT
- * @nhead_lnum: LEB number of LPT head
- * @nhead_offs: offset of LPT head
- * @big_lpt: flag that LPT is too big to write whole during commit
- * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
- * @lpt_sz: LPT size
- *
- * @ltab_lnum: LEB number of LPT's own lprops table
- * @ltab_offs: offset of LPT's own lprops table
- * @lpt: lprops table
- * @ltab: LPT's own lprops table
- * @lsave_cnt: number of LEB numbers in LPT's save table
- * @lsave_lnum: LEB number of LPT's save table
- * @lsave_offs: offset of LPT's save table
- * @lsave: LPT's save table
- * @lscan_lnum: LEB number of last LPT scan
- */
-struct ubifs_info
-{
-	ino_t highest_inum;
-	unsigned long long max_sqnum;
-
-	int jhead_cnt;
-	long long max_bud_bytes;
-
-	struct ubifs_zbranch zroot;
-	int ihead_lnum;
-	int ihead_offs;
-
-	int log_lebs;
-	int lpt_lebs;
-	int lpt_first;
-	int lpt_last;
-	int orph_lebs;
-	int main_lebs;
-	int main_first;
-	int default_compr;
-	int favor_lzo;
-	int favor_percent;
-
-	uint8_t key_hash_type;
-	uint32_t (*key_hash)(const char *str, int len);
-	int key_fmt;
-	int key_len;
-	int fanout;
-
-	int min_io_size;
-	int leb_size;
-	int leb_cnt;
-	int max_leb_cnt;
-
-	unsigned long long old_idx_sz;
-	struct ubifs_lp_stats lst;
-
-	int dead_wm;
-	int dark_wm;
-
-	struct ubi_dev_info di;
-	struct ubi_vol_info vi;
-
-	int gc_lnum;
-	long long rp_size;
-
-	int space_bits;
-	int lpt_lnum_bits;
-	int lpt_offs_bits;
-	int lpt_spc_bits;
-	int pcnt_bits;
-	int lnum_bits;
-	int nnode_sz;
-	int pnode_sz;
-	int ltab_sz;
-	int lsave_sz;
-	int pnode_cnt;
-	int nnode_cnt;
-	int lpt_hght;
-
-	int lpt_lnum;
-	int lpt_offs;
-	int nhead_lnum;
-	int nhead_offs;
-	int big_lpt;
-	int space_fixup;
-	long long lpt_sz;
-
-	int ltab_lnum;
-	int ltab_offs;
-	struct ubifs_lprops *lpt;
-	struct ubifs_lpt_lprops *ltab;
-	int lsave_cnt;
-	int lsave_lnum;
-	int lsave_offs;
-	int *lsave;
-	int lscan_lnum;
-
-};
-
-/**
- * ubifs_idx_node_sz - return index node size.
- * @c: the UBIFS file-system description object
- * @child_cnt: number of children of this index node
- */
-static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt)
-{
-	return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt;
-}
-
-/**
- * ubifs_idx_branch - return pointer to an index branch.
- * @c: the UBIFS file-system description object
- * @idx: index node
- * @bnum: branch number
- */
-static inline
-struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
-				      const struct ubifs_idx_node *idx,
-				      int bnum)
-{
-	return (struct ubifs_branch *)((void *)idx->branches +
-				       (UBIFS_BRANCH_SZ + c->key_len) * bnum);
-}
-
-#endif /* __UBIFS_H__ */
diff --git a/mtd_debug.c b/mtd_debug.c
deleted file mode 100644
index d6993ce..0000000
--- a/mtd_debug.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Copyright (c) 2d3D, Inc.
- * Written by Abraham vd Merwe <abraham at 2d3d.co.za>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *	  notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *	  notice, this list of conditions and the following disclaimer in the
- *	  documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the names of other contributors
- *	  may be used to endorse or promote products derived from this software
- *	  without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define PROGRAM_NAME "mtd_debug"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <mtd/mtd-user.h>
-#include "common.h"
-
-/*
- * MEMGETINFO
- */
-static int getmeminfo(int fd, struct mtd_info_user *mtd)
-{
-	return ioctl(fd, MEMGETINFO, mtd);
-}
-
-/*
- * MEMERASE
- */
-static int memerase(int fd, struct erase_info_user *erase)
-{
-	return ioctl(fd, MEMERASE, erase);
-}
-
-/*
- * MEMGETREGIONCOUNT
- * MEMGETREGIONINFO
- */
-static int getregions(int fd, struct region_info_user *regions, int *n)
-{
-	int i, err;
-	err = ioctl(fd, MEMGETREGIONCOUNT, n);
-	if (err)
-		return err;
-	for (i = 0; i < *n; i++) {
-		regions[i].regionindex = i;
-		err = ioctl(fd, MEMGETREGIONINFO, &regions[i]);
-		if (err)
-			return err;
-	}
-	return 0;
-}
-
-int erase_flash(int fd, u_int32_t offset, u_int32_t bytes)
-{
-	int err;
-	struct erase_info_user erase;
-	erase.start = offset;
-	erase.length = bytes;
-	err = memerase(fd, &erase);
-	if (err < 0) {
-		perror("MEMERASE");
-		return 1;
-	}
-	fprintf(stderr, "Erased %d bytes from address 0x%.8x in flash\n", bytes, offset);
-	return 0;
-}
-
-void printsize(u_int32_t x)
-{
-	int i;
-	static const char *flags = "KMGT";
-	printf("%u ", x);
-	for (i = 0; x >= 1024 && flags[i] != '\0'; i++)
-		x /= 1024;
-	i--;
-	if (i >= 0)
-		printf("(%u%c)", x, flags[i]);
-}
-
-int flash_to_file(int fd, off_t offset, size_t len, const char *filename)
-{
-	u_int8_t *buf = NULL;
-	int outfd, err;
-	int size = len * sizeof(u_int8_t);
-	int n = len;
-
-	if (offset != lseek(fd, offset, SEEK_SET)) {
-		perror("lseek()");
-		goto err0;
-	}
-	outfd = creat(filename, 0666);
-	if (outfd < 0) {
-		perror("creat()");
-		goto err1;
-	}
-
-retry:
-	if ((buf = (u_int8_t *) malloc(size)) == NULL) {
-#define BUF_SIZE	(64 * 1024 * sizeof(u_int8_t))
-		fprintf(stderr, "%s: malloc(%#x)\n", __func__, size);
-		if (size != BUF_SIZE) {
-			size = BUF_SIZE;
-			fprintf(stderr, "%s: trying buffer size %#x\n", __func__, size);
-			goto retry;
-		}
-		perror("malloc()");
-		goto err0;
-	}
-	do {
-		if (n <= size)
-			size = n;
-		err = read(fd, buf, size);
-		if (err < 0) {
-			fprintf(stderr, "%s: read, size %#x, n %#x\n", __func__, size, n);
-			perror("read()");
-			goto err2;
-		}
-		err = write(outfd, buf, size);
-		if (err < 0) {
-			fprintf(stderr, "%s: write, size %#x, n %#x\n", __func__, size, n);
-			perror("write()");
-			goto err2;
-		}
-		if (err != size) {
-			fprintf(stderr, "Couldn't copy entire buffer to %s. (%d/%d bytes copied)\n", filename, err, size);
-			goto err2;
-		}
-		n -= size;
-	} while (n > 0);
-
-	if (buf != NULL)
-		free(buf);
-	close(outfd);
-	printf("Copied %zu bytes from address 0x%.8"PRIxoff_t" in flash to %s\n", len, offset, filename);
-	return 0;
-
-err2:
-	close(outfd);
-err1:
-	if (buf != NULL)
-		free(buf);
-err0:
-	return 1;
-}
-
-int file_to_flash(int fd, off_t offset, u_int32_t len, const char *filename)
-{
-	u_int8_t *buf = NULL;
-	FILE *fp;
-	int err;
-	int size = len * sizeof(u_int8_t);
-	int n = len;
-
-	if (offset != lseek(fd, offset, SEEK_SET)) {
-		perror("lseek()");
-		return 1;
-	}
-	if ((fp = fopen(filename, "r")) == NULL) {
-		perror("fopen()");
-		return 1;
-	}
-retry:
-	if ((buf = (u_int8_t *) malloc(size)) == NULL) {
-		fprintf(stderr, "%s: malloc(%#x) failed\n", __func__, size);
-		if (size != BUF_SIZE) {
-			size = BUF_SIZE;
-			fprintf(stderr, "%s: trying buffer size %#x\n", __func__, size);
-			goto retry;
-		}
-		perror("malloc()");
-		fclose(fp);
-		return 1;
-	}
-	do {
-		if (n <= size)
-			size = n;
-		if (fread(buf, size, 1, fp) != 1 || ferror(fp)) {
-			fprintf(stderr, "%s: fread, size %#x, n %#x\n", __func__, size, n);
-			perror("fread()");
-			free(buf);
-			fclose(fp);
-			return 1;
-		}
-		err = write(fd, buf, size);
-		if (err < 0) {
-			fprintf(stderr, "%s: write, size %#x, n %#x\n", __func__, size, n);
-			perror("write()");
-			free(buf);
-			fclose(fp);
-			return 1;
-		}
-		n -= size;
-	} while (n > 0);
-
-	if (buf != NULL)
-		free(buf);
-	fclose(fp);
-	printf("Copied %d bytes from %s to address 0x%.8"PRIxoff_t" in flash\n", len, filename, offset);
-	return 0;
-}
-
-int showinfo(int fd)
-{
-	int i, err, n;
-	struct mtd_info_user mtd;
-	static struct region_info_user region[1024];
-
-	err = getmeminfo(fd, &mtd);
-	if (err < 0) {
-		perror("MEMGETINFO");
-		return 1;
-	}
-
-	err = getregions(fd, region, &n);
-	if (err < 0) {
-		perror("MEMGETREGIONCOUNT");
-		return 1;
-	}
-
-	printf("mtd.type = ");
-	switch (mtd.type) {
-		case MTD_ABSENT:
-			printf("MTD_ABSENT");
-			break;
-		case MTD_RAM:
-			printf("MTD_RAM");
-			break;
-		case MTD_ROM:
-			printf("MTD_ROM");
-			break;
-		case MTD_NORFLASH:
-			printf("MTD_NORFLASH");
-			break;
-		case MTD_NANDFLASH:
-			printf("MTD_NANDFLASH");
-			break;
-		case MTD_MLCNANDFLASH:
-			printf("MTD_MLCNANDFLASH");
-			break;
-		case MTD_DATAFLASH:
-			printf("MTD_DATAFLASH");
-			break;
-		case MTD_UBIVOLUME:
-			printf("MTD_UBIVOLUME");
-		default:
-			printf("(unknown type - new MTD API maybe?)");
-	}
-
-	printf("\nmtd.flags = ");
-	if (mtd.flags == MTD_CAP_ROM)
-		printf("MTD_CAP_ROM");
-	else if (mtd.flags == MTD_CAP_RAM)
-		printf("MTD_CAP_RAM");
-	else if (mtd.flags == MTD_CAP_NORFLASH)
-		printf("MTD_CAP_NORFLASH");
-	else if (mtd.flags == MTD_CAP_NANDFLASH)
-		printf("MTD_CAP_NANDFLASH");
-	else if (mtd.flags == MTD_WRITEABLE)
-		printf("MTD_WRITEABLE");
-	else {
-		int first = 1;
-		static struct {
-			const char *name;
-			int value;
-		} flags[] =
-		{
-			{ "MTD_WRITEABLE", MTD_WRITEABLE },
-			{ "MTD_BIT_WRITEABLE", MTD_BIT_WRITEABLE },
-			{ "MTD_NO_ERASE", MTD_NO_ERASE },
-			{ "MTD_POWERUP_LOCK", MTD_POWERUP_LOCK },
-			{ NULL, -1 }
-		};
-		for (i = 0; flags[i].name != NULL; i++) {
-			if (mtd.flags & flags[i].value) {
-				if (first) {
-					printf("%s", flags[i].name);
-					first = 0;
-				} else {
-					printf(" | %s", flags[i].name);
-				}
-			}
-		}
-	}
-
-	printf("\nmtd.size = ");
-	printsize(mtd.size);
-
-	printf("\nmtd.erasesize = ");
-	printsize(mtd.erasesize);
-
-	printf("\nmtd.writesize = ");
-	printsize(mtd.writesize);
-
-	printf("\nmtd.oobsize = ");
-	printsize(mtd.oobsize);
-
-	printf("\nregions = %d\n\n", n);
-
-	for (i = 0; i < n; i++) {
-		printf("region[%d].offset = 0x%.8x\n"
-				"region[%d].erasesize = ",
-				i, region[i].offset, i);
-		printsize(region[i].erasesize);
-		printf("\nregion[%d].numblocks = %d\n"
-				"region[%d].regionindex = %d\n",
-				i, region[i].numblocks,
-				i, region[i].regionindex);
-	}
-	return 0;
-}
-
-void showusage(void)
-{
-	fprintf(stderr, "usage: %1$s info <device>\n"
-			"       %1$s read <device> <offset> <len> <dest-filename>\n"
-			"       %1$s write <device> <offset> <len> <source-filename>\n"
-			"       %1$s erase <device> <offset> <len>\n",
-			PROGRAM_NAME);
-	exit(EXIT_FAILURE);
-}
-
-int main(int argc, char *argv[])
-{
-	int err = 0, fd;
-	int open_flag;
-
-	enum {
-		OPT_INFO,
-		OPT_READ,
-		OPT_WRITE,
-		OPT_ERASE
-	} option = OPT_INFO;
-
-	/* parse command-line options */
-	if (argc == 3 && !strcmp(argv[1], "info"))
-		option = OPT_INFO;
-	else if (argc == 6 && !strcmp(argv[1], "read"))
-		option = OPT_READ;
-	else if (argc == 6 && !strcmp(argv[1], "write"))
-		option = OPT_WRITE;
-	else if (argc == 5 && !strcmp(argv[1], "erase"))
-		option = OPT_ERASE;
-	else
-		showusage();
-
-	/* open device */
-	open_flag = (option == OPT_INFO || option == OPT_READ) ? O_RDONLY : O_RDWR;
-	if ((fd = open(argv[2], O_SYNC | open_flag)) < 0)
-		errmsg_die("open()");
-
-	switch (option) {
-		case OPT_INFO:
-			showinfo(fd);
-			break;
-		case OPT_READ:
-			err = flash_to_file(fd, strtoll(argv[3], NULL, 0), strtoul(argv[4], NULL, 0), argv[5]);
-			break;
-		case OPT_WRITE:
-			err = file_to_flash(fd, strtoll(argv[3], NULL, 0), strtoul(argv[4], NULL, 0), argv[5]);
-			break;
-		case OPT_ERASE:
-			err = erase_flash(fd, strtoul(argv[3], NULL, 0), strtoul(argv[4], NULL, 0));
-			break;
-	}
-
-	/* close device */
-	if (close(fd) < 0)
-		errmsg_die("close()");
-
-	return err;
-}
diff --git a/mtdpart.c b/mtdpart.c
deleted file mode 100644
index 0016e34..0000000
--- a/mtdpart.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- *  mtdpart.c
- *
- *  Copyright 2015 The Chromium OS Authors.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Overview:
- *   This utility adds or removes a partition from an MTD device.
- */
-
-#define PROGRAM_NAME "mtdpart"
-
-#include <fcntl.h>
-#include <getopt.h>
-#include <limits.h>
-#include <linux/blkpg.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "common.h"
-
-static void display_help(int status)
-{
-	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
-"Usage: %1$s add [OPTION] <MTD_DEVICE> <PART_NAME> <START> <SIZE>\n"
-"       %1$s del [OPTION] <MTD_DEVICE> <PART_NUMBER>\n"
-"Adds a partition to an MTD device, or remove an existing partition from it.\n"
-"\n"
-"  -h, --help    Display this help and exit\n"
-"      --version Output version information and exit\n"
-"\n"
-"START location and SIZE of the partition are in bytes. They should align on\n"
-"eraseblock size.\n",
-	PROGRAM_NAME
-	);
-	exit(status);
-}
-
-static void display_version(void)
-{
-	printf("%1$s " VERSION "\n"
-			"\n"
-			"%1$s comes with NO WARRANTY\n"
-			"to the extent permitted by law.\n"
-			"\n"
-			"You may redistribute copies of %1$s\n"
-			"under the terms of the GNU General Public Licence.\n"
-			"See the file `COPYING' for more information.\n",
-			PROGRAM_NAME);
-	exit(EXIT_SUCCESS);
-}
-
-/* Command arguments */
-
-typedef enum {
-	COMMAND_ADD,
-	COMMAND_DEL
-} command_type;
-
-static command_type		command;		/* add or del */
-static const char		*mtddev;		/* mtd device name */
-static const char		*part_name;		/* partition name */
-static int			part_no;		/* partition number */
-static long long		start_addr;		/* start address */
-static long long		length;			/* partition size */
-
-static void process_options(int argc, char * const argv[])
-{
-	int error = 0;
-
-	for (;;) {
-		int option_index = 0;
-		static const char short_options[] = "h";
-		static const struct option long_options[] = {
-			{"version", no_argument, 0, 0},
-			{"help", no_argument, 0, 'h'},
-			{0, 0, 0, 0},
-		};
-
-		int c = getopt_long(argc, argv, short_options,
-				long_options, &option_index);
-		if (c == EOF) {
-			break;
-		}
-
-		switch (c) {
-			case 0:
-				display_version();
-				break;
-			case 'h':
-				display_help(EXIT_SUCCESS);
-				break;
-			case '?':
-				error++;
-				break;
-		}
-	}
-
-	if ((argc - optind) < 3 || error)
-		display_help(EXIT_FAILURE);
-
-	const char *s_command = argv[optind++];
-	mtddev = argv[optind++];
-
-	if (strcmp(s_command, "del") == 0 && (argc - optind) == 1) {
-		const char *s_part_no = argv[optind++];
-
-		long tmp = simple_strtol(s_part_no, &error);
-		if (tmp < 0)
-		       errmsg_die("Can't specify negative partition number: %ld",
-				  tmp);
-		if (tmp > INT_MAX)
-		       errmsg_die("Partition number exceeds INT_MAX: %ld",
-				  tmp);
-
-		part_no = tmp;
-		command = COMMAND_DEL;
-	} else if (strcmp(s_command, "add") == 0 && (argc - optind) == 3) {
-		const char *s_start;
-		const char *s_length;
-
-		part_name = argv[optind++];
-		s_start = argv[optind++];
-		s_length = argv[optind++];
-
-		if (strlen(part_name) >= BLKPG_DEVNAMELTH)
-			errmsg_die("Partition name (%s) should be less than %d characters",
-				   part_name, BLKPG_DEVNAMELTH);
-
-		start_addr = simple_strtoll(s_start, &error);
-		if (start_addr < 0)
-		       errmsg_die("Can't specify negative start offset: %lld",
-				  start_addr);
-
-		length = simple_strtoll(s_length, &error);
-		if (length < 0)
-		       errmsg_die("Can't specify negative length: %lld",
-				  length);
-
-		command = COMMAND_ADD;
-	} else
-		display_help(EXIT_FAILURE);
-
-	if (error)
-		display_help(EXIT_FAILURE);
-}
-
-
-int main(int argc, char * const argv[])
-{
-	int fd;
-	struct blkpg_partition part;
-	struct blkpg_ioctl_arg arg;
-
-	process_options(argc, argv);
-
-	fd = open(mtddev, O_RDWR | O_CLOEXEC);
-	if (fd == -1)
-		sys_errmsg_die("Cannot open %s", mtddev);
-
-	memset(&part, 0, sizeof(part));
-
-	memset(&arg, 0, sizeof(arg));
-	arg.datalen = sizeof(part);
-	arg.data = ∂
-
-	switch (command) {
-		case COMMAND_ADD:
-			part.start = start_addr;
-			part.length = length;
-			strncpy(part.devname, part_name, sizeof(part.devname));
-			arg.op = BLKPG_ADD_PARTITION;
-			break;
-		case COMMAND_DEL:
-			part.pno = part_no;
-			arg.op = BLKPG_DEL_PARTITION;
-			break;
-	}
-
-	if (ioctl(fd, BLKPG, &arg))
-		sys_errmsg_die("Failed to issue BLKPG ioctl");
-
-	close(fd);
-
-	/* Exit happy */
-	return EXIT_SUCCESS;
-}
diff --git a/nand-utils/load_nandsim.sh b/nand-utils/load_nandsim.sh
new file mode 100755
index 0000000..4d9f0cb
--- /dev/null
+++ b/nand-utils/load_nandsim.sh
@@ -0,0 +1,127 @@
+#!/bin/sh -euf
+
+#
+# This script inserts NAND simulator module to emulate NAND flash of specified
+# size.
+#
+# Author: Artem Bityutskiy
+#
+
+fatal()
+{
+        echo "Error: $1" 1>&2
+        exit 1
+}
+
+usage()
+{
+	cat 1>&2 <<EOF
+Load NAND simulator to simulate flash of a specified size.
+
+Usage: ${0##*/} <size in MiB> <eraseblock size in KiB> \\
+       <page size (512 or 2048)>
+
+Only the first parameter is mandatory. Default eraseblock size
+is 16KiB, default NAND page size is 512 bytes.
+
+Only the following combinations are supported:
+--------------------------------------------------
+| size (MiB) | EB size (KiB) | Page size (bytes) |
+--------------------------------------------------
+| 16         | 16            | 512               |
+| 32         | 16            | 512               |
+| 64         | 16            | 512               |
+| 128        | 16            | 512               |
+| 256        | 16            | 512               |
+| 64         | 64            | 2048              |
+| 64         | 128           | 2048              |
+| 64         | 256           | 2048              |
+| 64         | 512           | 2048              |
+| 128        | 64            | 2048              |
+| 128        | 128           | 2048              |
+| 128        | 256           | 2048              |
+| 128        | 512           | 2048              |
+| 256        | 64            | 2048              |
+| 256        | 128           | 2048              |
+| 256        | 256           | 2048              |
+| 256        | 512           | 2048              |
+| 512        | 64            | 2048              |
+| 512        | 128           | 2048              |
+| 512        | 256           | 2048              |
+| 512        | 512           | 2048              |
+| 1024       | 64            | 2048              |
+| 1024       | 128           | 2048              |
+| 1024       | 256           | 2048              |
+| 1024       | 512           | 2048              |
+--------------------------------------------------
+EOF
+}
+
+if grep -q "NAND simulator" /proc/mtd; then
+	fatal "nandsim is already loaded"
+fi
+
+if [ "$#" -lt "1" ]; then
+	usage
+	exit 1
+fi
+
+size="$1"
+eb_size="$2"
+page_size="$3"
+if [ "$#" = "1" ]; then
+	eb_size="16"
+	page_size="512"
+elif [ "$#" = "2" ]; then
+	page_size="512"
+fi
+
+if [ "$page_size" -eq 512 ] && [ "$eb_size" -ne "16" ]; then
+	fatal "only 16KiB eraseblocks are possible in case of 512 bytes page"
+fi
+
+first=
+second=
+third=
+fourth=
+
+if [ "$page_size" -eq "512" ]; then
+	first="0x20"
+	case "$size" in
+	16)  second=0x33 ;;
+	32)  second=0x35 ;;
+	64)  second=0x36 ;;
+	128) second=0x78 ;;
+	256) second=0x71 ;;
+	*) fatal "flash size ${size}MiB is not supported, try 16, 32, 64 or 256"
+	esac
+elif [ "$page_size" -eq "2048" ]; then
+	case "$eb_size" in
+	64)  fourth="0x05" ;;
+	128) fourth="0x15" ;;
+	256) fourth="0x25" ;;
+	512) fourth="0x35" ;;
+	*)   fatal "eraseblock ${eb_size}KiB is not supported"
+	esac
+
+
+	case "$size" in
+	64)   first="0x20"; second="0xa2"; third="0x00 ";;
+	128)  first="0xec"; second="0xa1"; third="0x00 ";;
+	256)  first="0x20"; second="0xaa"; third="0x00 ";;
+	512)  first="0x20"; second="0xac"; third="0x00 ";;
+	1024) first="0xec"; second="0xd3"; third="0x51 ";;
+	*) fatal "unable to emulate ${size}MiB flash with ${eb_size}KiB eraseblock"
+	esac
+else
+	fatal "bad NAND page size ${page_size}KiB, it has to be either 512 or 2048"
+fi
+
+first="first_id_byte=$first"
+second="second_id_byte=$second"
+[ -z "$third" ]  || third="third_id_byte=$third"
+[ -z "$fourth" ] || fourth="fourth_id_byte=$fourth"
+
+modprobe nandsim "$first" "$second" $third $fourth
+
+echo "Loaded NAND simulator (${size}MiB, ${eb_size}KiB eraseblock, $page_size bytes NAND page)"
diff --git a/nand-utils/nanddump.c b/nand-utils/nanddump.c
new file mode 100644
index 0000000..4ee7ed4
--- /dev/null
+++ b/nand-utils/nanddump.c
@@ -0,0 +1,490 @@
+/*
+ *  nanddump.c
+ *
+ *  Copyright (C) 2000 David Woodhouse (dwmw2 at infradead.org)
+ *                     Steven J. Hill (sjhill at realitydiluted.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Overview:
+ *   This utility dumps the contents of raw NAND chips or NAND
+ *   chips contained in DoC devices.
+ */
+
+#define PROGRAM_NAME "nanddump"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+#include "common.h"
+#include <libmtd.h>
+
+static void display_help(int status)
+{
+	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
+"Usage: %s [OPTIONS] MTD-device\n"
+"Dumps the contents of a nand mtd partition.\n"
+"\n"
+"-h         --help               Display this help and exit\n"
+"           --version            Output version information and exit\n"
+"           --bb=METHOD          Choose bad block handling method (see below).\n"
+"-a         --forcebinary        Force printing of binary data to tty\n"
+"-c         --canonicalprint     Print canonical Hex+ASCII dump\n"
+"-f file    --file=file          Dump to file\n"
+"-l length  --length=length      Length\n"
+"-n         --noecc              Read without error correction\n"
+"           --omitoob            Omit OOB data (default)\n"
+"-o         --oob                Dump OOB data\n"
+"-p         --prettyprint        Print nice (hexdump)\n"
+"-q         --quiet              Don't display progress and status messages\n"
+"-s addr    --startaddress=addr  Start address\n"
+"\n"
+"--bb=METHOD, where METHOD can be `padbad', `dumpbad', or `skipbad':\n"
+"    padbad:  dump flash data, substituting 0xFF for any bad blocks\n"
+"    dumpbad: dump flash data, including any bad blocks\n"
+"    skipbad: dump good data, completely skipping any bad blocks (default)\n",
+	PROGRAM_NAME);
+	exit(status);
+}
+
+static void display_version(void)
+{
+	printf("%1$s " VERSION "\n"
+			"\n"
+			"%1$s comes with NO WARRANTY\n"
+			"to the extent permitted by law.\n"
+			"\n"
+			"You may redistribute copies of %1$s\n"
+			"under the terms of the GNU General Public Licence.\n"
+			"See the file `COPYING' for more information.\n",
+			PROGRAM_NAME);
+	exit(EXIT_SUCCESS);
+}
+
+// Option variables
+
+static bool			pretty_print = false;	// print nice
+static bool			noecc = false;		// don't error correct
+static bool			omitoob = true;		// omit oob data
+static long long		start_addr;		// start address
+static long long		length;			// dump length
+static const char		*mtddev;		// mtd device name
+static const char		*dumpfile;		// dump file name
+static bool			quiet = false;		// suppress diagnostic output
+static bool			canonical = false;	// print nice + ascii
+static bool			forcebinary = false;	// force printing binary to tty
+
+static enum {
+	padbad,   // dump flash data, substituting 0xFF for any bad blocks
+	dumpbad,  // dump flash data, including any bad blocks
+	skipbad,  // dump good data, completely skipping any bad blocks
+} bb_method = skipbad;
+
+static void process_options(int argc, char * const argv[])
+{
+	int error = 0;
+	bool oob_default = true;
+
+	for (;;) {
+		int option_index = 0;
+		static const char short_options[] = "hs:f:l:opqnca";
+		static const struct option long_options[] = {
+			{"version", no_argument, 0, 0},
+			{"bb", required_argument, 0, 0},
+			{"omitoob", no_argument, 0, 0},
+			{"help", no_argument, 0, 'h'},
+			{"forcebinary", no_argument, 0, 'a'},
+			{"canonicalprint", no_argument, 0, 'c'},
+			{"file", required_argument, 0, 'f'},
+			{"oob", no_argument, 0, 'o'},
+			{"prettyprint", no_argument, 0, 'p'},
+			{"startaddress", required_argument, 0, 's'},
+			{"length", required_argument, 0, 'l'},
+			{"noecc", no_argument, 0, 'n'},
+			{"quiet", no_argument, 0, 'q'},
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF) {
+			break;
+		}
+
+		switch (c) {
+			case 0:
+				switch (option_index) {
+					case 0:
+						display_version();
+						break;
+					case 1:
+						/* Handle --bb=METHOD */
+						if (!strcmp(optarg, "padbad"))
+							bb_method = padbad;
+						else if (!strcmp(optarg, "dumpbad"))
+							bb_method = dumpbad;
+						else if (!strcmp(optarg, "skipbad"))
+							bb_method = skipbad;
+						else
+							error++;
+						break;
+					case 2: /* --omitoob */
+						if (oob_default) {
+							oob_default = false;
+							omitoob = true;
+						} else {
+							errmsg_die("--oob and --oomitoob are mutually exclusive");
+						}
+						break;
+				}
+				break;
+			case 's':
+				start_addr = simple_strtoll(optarg, &error);
+				break;
+			case 'f':
+				dumpfile = xstrdup(optarg);
+				break;
+			case 'l':
+				length = simple_strtoll(optarg, &error);
+				break;
+			case 'o':
+				if (oob_default) {
+					oob_default = false;
+					omitoob = false;
+				} else {
+					errmsg_die("--oob and --oomitoob are mutually exclusive");
+				}
+				break;
+			case 'a':
+				forcebinary = true;
+				break;
+			case 'c':
+				canonical = true;
+			case 'p':
+				pretty_print = true;
+				break;
+			case 'q':
+				quiet = true;
+				break;
+			case 'n':
+				noecc = true;
+				break;
+			case 'h':
+				display_help(EXIT_SUCCESS);
+				break;
+			case '?':
+				error++;
+				break;
+		}
+	}
+
+	if (start_addr < 0)
+		errmsg_die("Can't specify negative offset with option -s: %lld",
+				start_addr);
+
+	if (length < 0)
+		errmsg_die("Can't specify negative length with option -l: %lld", length);
+
+	if (quiet && pretty_print) {
+		fprintf(stderr, "The quiet and pretty print options are mutually-\n"
+				"exclusive. Choose one or the other.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (forcebinary && pretty_print) {
+		fprintf(stderr, "The forcebinary and pretty print options are\n"
+				"mutually-exclusive. Choose one or the "
+				"other.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if ((argc - optind) != 1 || error)
+		display_help(EXIT_FAILURE);
+
+	mtddev = argv[optind];
+}
+
+#define PRETTY_ROW_SIZE 16
+#define PRETTY_BUF_LEN 80
+
+/**
+ * pretty_dump_to_buffer - formats a blob of data to "hex ASCII" in memory
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ * @linebuf: where to put the converted data
+ * @linebuflen: total size of @linebuf, including space for terminating NULL
+ * @pagedump: true - dumping as page format; false - dumping as OOB format
+ * @ascii: dump ascii formatted data next to hexdump
+ * @prefix: address to print before line in a page dump, ignored if !pagedump
+ *
+ * pretty_dump_to_buffer() works on one "line" of output at a time, i.e.,
+ * PRETTY_ROW_SIZE bytes of input data converted to hex + ASCII output.
+ *
+ * Given a buffer of unsigned char data, pretty_dump_to_buffer() converts the
+ * input data to a hex/ASCII dump at the supplied memory location. A prefix
+ * is included based on whether we are dumping page or OOB data. The converted
+ * output is always NULL-terminated.
+ *
+ * e.g.
+ *   pretty_dump_to_buffer(data, data_len, prettybuf, linelen, true,
+ *                         false, 256);
+ * produces:
+ *   0x00000100: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
+ * NOTE: This function was adapted from linux kernel, "lib/hexdump.c"
+ */
+static void pretty_dump_to_buffer(const unsigned char *buf, size_t len,
+		char *linebuf, size_t linebuflen, bool pagedump, bool ascii,
+		unsigned long long prefix)
+{
+	static const char hex_asc[] = "0123456789abcdef";
+	unsigned char ch;
+	unsigned int j, lx = 0, ascii_column;
+
+	if (pagedump)
+		lx += sprintf(linebuf, "0x%.8llx: ", prefix);
+	else
+		lx += sprintf(linebuf, "  OOB Data: ");
+
+	if (!len)
+		goto nil;
+	if (len > PRETTY_ROW_SIZE)	/* limit to one line at a time */
+		len = PRETTY_ROW_SIZE;
+
+	for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) {
+		ch = buf[j];
+		linebuf[lx++] = hex_asc[(ch & 0xf0) >> 4];
+		linebuf[lx++] = hex_asc[ch & 0x0f];
+		linebuf[lx++] = ' ';
+	}
+	if (j)
+		lx--;
+
+	ascii_column = 3 * PRETTY_ROW_SIZE + 14;
+
+	if (!ascii)
+		goto nil;
+
+	/* Spacing between hex and ASCII - ensure at least one space */
+	lx += sprintf(linebuf + lx, "%*s",
+			MAX((int)MIN(linebuflen, ascii_column) - 1 - lx, 1),
+			" ");
+
+	linebuf[lx++] = '|';
+	for (j = 0; (j < len) && (lx + 2) < linebuflen; j++)
+		linebuf[lx++] = (isascii(buf[j]) && isprint(buf[j])) ? buf[j]
+			: '.';
+	linebuf[lx++] = '|';
+nil:
+	linebuf[lx++] = '\n';
+	linebuf[lx++] = '\0';
+}
+
+
+/*
+ * Main program
+ */
+int main(int argc, char * const argv[])
+{
+	long long ofs, end_addr = 0;
+	long long blockstart = 1;
+	int i, fd, ofd = 0, bs, badblock = 0;
+	struct mtd_dev_info mtd;
+	char pretty_buf[PRETTY_BUF_LEN];
+	int firstblock = 1;
+	struct mtd_ecc_stats stat1, stat2;
+	bool eccstats = false;
+	unsigned char *readbuf = NULL, *oobbuf = NULL;
+	libmtd_t mtd_desc;
+
+	process_options(argc, argv);
+
+	/* Initialize libmtd */
+	mtd_desc = libmtd_open();
+	if (!mtd_desc)
+		return errmsg("can't initialize libmtd");
+
+	/* Open MTD device */
+	if ((fd = open(mtddev, O_RDONLY)) == -1) {
+		perror(mtddev);
+		exit(EXIT_FAILURE);
+	}
+
+	/* Fill in MTD device capability structure */
+	if (mtd_get_dev_info(mtd_desc, mtddev, &mtd) < 0)
+		return errmsg("mtd_get_dev_info failed");
+
+	/* Allocate buffers */
+	oobbuf = xmalloc(sizeof(oobbuf) * mtd.oob_size);
+	readbuf = xmalloc(sizeof(readbuf) * mtd.min_io_size);
+
+	if (noecc)  {
+		if (ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW) != 0) {
+				perror("MTDFILEMODE");
+				goto closeall;
+		}
+	} else {
+		/* check if we can read ecc stats */
+		if (!ioctl(fd, ECCGETSTATS, &stat1)) {
+			eccstats = true;
+			if (!quiet) {
+				fprintf(stderr, "ECC failed: %d\n", stat1.failed);
+				fprintf(stderr, "ECC corrected: %d\n", stat1.corrected);
+				fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks);
+				fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks);
+			}
+		} else
+			perror("No ECC status information available");
+	}
+
+	/* Open output file for writing. If file name is "-", write to standard
+	 * output. */
+	if (!dumpfile) {
+		ofd = STDOUT_FILENO;
+	} else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) {
+		perror(dumpfile);
+		goto closeall;
+	}
+
+	if (!pretty_print && !forcebinary && isatty(ofd)) {
+		fprintf(stderr, "Not printing binary garbage to tty. Use '-a'\n"
+				"or '--forcebinary' to override.\n");
+		goto closeall;
+	}
+
+	/* Initialize start/end addresses and block size */
+	if (start_addr & (mtd.min_io_size - 1)) {
+		fprintf(stderr, "the start address (-s parameter) is not page-aligned!\n"
+				"The pagesize of this NAND Flash is 0x%x.\n",
+				mtd.min_io_size);
+		goto closeall;
+	}
+	if (length)
+		end_addr = start_addr + length;
+	if (!length || end_addr > mtd.size)
+		end_addr = mtd.size;
+
+	bs = mtd.min_io_size;
+
+	/* Print informative message */
+	if (!quiet) {
+		fprintf(stderr, "Block size %d, page size %d, OOB size %d\n",
+				mtd.eb_size, mtd.min_io_size, mtd.oob_size);
+		fprintf(stderr,
+				"Dumping data starting at 0x%08llx and ending at 0x%08llx...\n",
+				start_addr, end_addr);
+	}
+
+	/* Dump the flash contents */
+	for (ofs = start_addr; ofs < end_addr; ofs += bs) {
+		/* Check for bad block */
+		if (bb_method == dumpbad) {
+			badblock = 0;
+		} else if (blockstart != (ofs & (~mtd.eb_size + 1)) ||
+				firstblock) {
+			blockstart = ofs & (~mtd.eb_size + 1);
+			firstblock = 0;
+			if ((badblock = mtd_is_bad(&mtd, fd, ofs / mtd.eb_size)) < 0) {
+				errmsg("libmtd: mtd_is_bad");
+				goto closeall;
+			}
+		}
+
+		if (badblock) {
+			/* skip bad block, increase end_addr */
+			if (bb_method == skipbad) {
+				end_addr += mtd.eb_size;
+				ofs += mtd.eb_size - bs;
+				if (end_addr > mtd.size)
+					end_addr = mtd.size;
+				continue;
+			}
+			memset(readbuf, 0xff, bs);
+		} else {
+			/* Read page data and exit on failure */
+			if (mtd_read(&mtd, fd, ofs / mtd.eb_size, ofs % mtd.eb_size, readbuf, bs)) {
+				errmsg("mtd_read");
+				goto closeall;
+			}
+		}
+
+		/* ECC stats available ? */
+		if (eccstats) {
+			if (ioctl(fd, ECCGETSTATS, &stat2)) {
+				perror("ioctl(ECCGETSTATS)");
+				goto closeall;
+			}
+			if (stat1.failed != stat2.failed)
+				fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
+						" at offset 0x%08llx\n",
+						stat2.failed - stat1.failed, ofs);
+			if (stat1.corrected != stat2.corrected)
+				fprintf(stderr, "ECC: %d corrected bitflip(s) at"
+						" offset 0x%08llx\n",
+						stat2.corrected - stat1.corrected, ofs);
+			stat1 = stat2;
+		}
+
+		/* Write out page data */
+		if (pretty_print) {
+			for (i = 0; i < bs; i += PRETTY_ROW_SIZE) {
+				pretty_dump_to_buffer(readbuf + i, PRETTY_ROW_SIZE,
+						pretty_buf, PRETTY_BUF_LEN, true, canonical, ofs + i);
+				write(ofd, pretty_buf, strlen(pretty_buf));
+			}
+		} else
+			write(ofd, readbuf, bs);
+
+		if (omitoob)
+			continue;
+
+		if (badblock) {
+			memset(oobbuf, 0xff, mtd.oob_size);
+		} else {
+			/* Read OOB data and exit on failure */
+			if (mtd_read_oob(mtd_desc, &mtd, fd, ofs, mtd.oob_size, oobbuf)) {
+				errmsg("libmtd: mtd_read_oob");
+				goto closeall;
+			}
+		}
+
+		/* Write out OOB data */
+		if (pretty_print) {
+			for (i = 0; i < mtd.oob_size; i += PRETTY_ROW_SIZE) {
+				pretty_dump_to_buffer(oobbuf + i, mtd.oob_size - i,
+						pretty_buf, PRETTY_BUF_LEN, false, canonical, 0);
+				write(ofd, pretty_buf, strlen(pretty_buf));
+			}
+		} else
+			write(ofd, oobbuf, mtd.oob_size);
+	}
+
+	/* Close the output file and MTD device, free memory */
+	close(fd);
+	close(ofd);
+	free(oobbuf);
+	free(readbuf);
+
+	/* Exit happy */
+	return EXIT_SUCCESS;
+
+closeall:
+	close(fd);
+	close(ofd);
+	free(oobbuf);
+	free(readbuf);
+	exit(EXIT_FAILURE);
+}
diff --git a/nand-utils/nandtest.c b/nand-utils/nandtest.c
new file mode 100644
index 0000000..0805387
--- /dev/null
+++ b/nand-utils/nandtest.c
@@ -0,0 +1,313 @@
+#define PROGRAM_NAME "nandtest"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <getopt.h>
+
+#include <asm/types.h>
+#include "mtd/mtd-user.h"
+
+void usage(int status)
+{
+	fprintf(status ? stderr : stdout,
+		"usage: %s [OPTIONS] <device>\n\n"
+		"  -h, --help           Display this help output\n"
+		"  -m, --markbad        Mark blocks bad if they appear so\n"
+		"  -s, --seed           Supply random seed\n"
+		"  -p, --passes         Number of passes\n"
+		"  -r <n>, --reads=<n>  Read & check <n> times per pass\n"
+		"  -o, --offset         Start offset on flash\n"
+		"  -l, --length         Length of flash to test\n"
+		"  -k, --keep           Restore existing contents after test\n",
+		PROGRAM_NAME);
+	exit(status);
+}
+
+struct mtd_info_user meminfo;
+struct mtd_ecc_stats oldstats, newstats;
+int fd;
+int markbad=0;
+int seed;
+
+int read_and_compare(loff_t ofs, unsigned char *data, unsigned char *rbuf)
+{
+	ssize_t len;
+	int i;
+
+	len = pread(fd, rbuf, meminfo.erasesize, ofs);
+	if (len < meminfo.erasesize) {
+		printf("\n");
+		if (len)
+			fprintf(stderr, "Short read (%zd bytes)\n", len);
+		else
+			perror("read");
+		exit(1);
+	}
+
+	if (ioctl(fd, ECCGETSTATS, &newstats)) {
+		printf("\n");
+		perror("ECCGETSTATS");
+		close(fd);
+		exit(1);
+	}
+
+	if (newstats.corrected > oldstats.corrected) {
+		printf("\n %d bit(s) ECC corrected at %08x\n",
+				newstats.corrected - oldstats.corrected,
+				(unsigned) ofs);
+		oldstats.corrected = newstats.corrected;
+	}
+	if (newstats.failed > oldstats.failed) {
+		printf("\nECC failed at %08x\n", (unsigned) ofs);
+		oldstats.failed = newstats.failed;
+	}
+
+	printf("\r%08x: checking...", (unsigned)ofs);
+	fflush(stdout);
+
+	if (memcmp(data, rbuf, meminfo.erasesize)) {
+		printf("\n");
+		fprintf(stderr, "compare failed. seed %d\n", seed);
+		for (i=0; i<meminfo.erasesize; i++) {
+			if (data[i] != rbuf[i])
+				printf("Byte 0x%x is %02x should be %02x\n",
+				       i, rbuf[i], data[i]);
+		}
+		return 1;
+	}
+	return 0;
+}
+
+int erase_and_write(loff_t ofs, unsigned char *data, unsigned char *rbuf, int nr_reads)
+{
+	struct erase_info_user er;
+	ssize_t len;
+	int i, read_errs = 0;
+
+	printf("\r%08x: erasing... ", (unsigned)ofs);
+	fflush(stdout);
+
+	er.start = ofs;
+	er.length = meminfo.erasesize;
+
+	if (ioctl(fd, MEMERASE, &er)) {
+		perror("MEMERASE");
+		if (markbad) {
+			printf("Mark block bad at %08lx\n", (long)ofs);
+			ioctl(fd, MEMSETBADBLOCK, &ofs);
+		}
+		return 1;
+	}
+
+	printf("\r%08x: writing...", (unsigned)ofs);
+	fflush(stdout);
+
+	len = pwrite(fd, data, meminfo.erasesize, ofs);
+	if (len < 0) {
+		printf("\n");
+		perror("write");
+		if (markbad) {
+			printf("Mark block bad at %08lx\n", (long)ofs);
+			ioctl(fd, MEMSETBADBLOCK, &ofs);
+		}
+		return 1;
+	}
+	if (len < meminfo.erasesize) {
+		printf("\n");
+		fprintf(stderr, "Short write (%zd bytes)\n", len);
+		exit(1);
+	}
+
+	for (i=1; i<=nr_reads; i++) {
+		printf("\r%08x: reading (%d of %d)...", (unsigned)ofs, i, nr_reads);
+		fflush(stdout);
+		if (read_and_compare(ofs, data, rbuf))
+			read_errs++;
+	}
+	if (read_errs) {
+		fprintf(stderr, "read/check %d of %d failed. seed %d\n", read_errs, nr_reads, seed);
+		return 1;
+	}
+	return 0;
+}
+
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+	int i;
+	unsigned char *wbuf, *rbuf, *kbuf;
+	int pass;
+	int nr_passes = 1;
+	int nr_reads = 4;
+	int keep_contents = 0;
+	uint32_t offset = 0;
+	uint32_t length = -1;
+
+	seed = time(NULL);
+
+	for (;;) {
+		static const char short_options[] = "hkl:mo:p:r:s:";
+		static const struct option long_options[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ "markbad", no_argument, 0, 'm' },
+			{ "seed", required_argument, 0, 's' },
+			{ "passes", required_argument, 0, 'p' },
+			{ "offset", required_argument, 0, 'o' },
+			{ "length", required_argument, 0, 'l' },
+			{ "reads", required_argument, 0, 'r' },
+			{ "keep", no_argument, 0, 'k' },
+			{0, 0, 0, 0},
+		};
+		int option_index = 0;
+		int c = getopt_long(argc, argv, short_options, long_options, &option_index);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+		case 'h':
+			usage(0);
+			break;
+
+		case '?':
+			usage(1);
+			break;
+
+		case 'm':
+			markbad = 1;
+			break;
+
+		case 'k':
+			keep_contents = 1;
+			break;
+
+		case 's':
+			seed = atol(optarg);
+			break;
+
+		case 'p':
+			nr_passes = atol(optarg);
+			break;
+
+		case 'r':
+			nr_reads = atol(optarg);
+			break;
+
+		case 'o':
+			offset = atol(optarg);
+			break;
+
+		case 'l':
+			length = strtol(optarg, NULL, 0);
+			break;
+
+		}
+	}
+	if (argc - optind != 1)
+		usage(1);
+
+	fd = open(argv[optind], O_RDWR);
+	if (fd < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	if (ioctl(fd, MEMGETINFO, &meminfo)) {
+		perror("MEMGETINFO");
+		close(fd);
+		exit(1);
+	}
+
+	if (length == -1)
+		length = meminfo.size;
+
+	if (offset % meminfo.erasesize) {
+		fprintf(stderr, "Offset %x not multiple of erase size %x\n",
+			offset, meminfo.erasesize);
+		exit(1);
+	}
+	if (length % meminfo.erasesize) {
+		fprintf(stderr, "Length %x not multiple of erase size %x\n",
+			length, meminfo.erasesize);
+		exit(1);
+	}
+	if (length + offset > meminfo.size) {
+		fprintf(stderr, "Length %x + offset %x exceeds device size %x\n",
+			length, offset, meminfo.size);
+		exit(1);
+	}
+
+	wbuf = malloc(meminfo.erasesize * 3);
+	if (!wbuf) {
+		fprintf(stderr, "Could not allocate %d bytes for buffer\n",
+			meminfo.erasesize * 2);
+		exit(1);
+	}
+	rbuf = wbuf + meminfo.erasesize;
+	kbuf = rbuf + meminfo.erasesize;
+
+	if (ioctl(fd, ECCGETSTATS, &oldstats)) {
+		perror("ECCGETSTATS");
+		close(fd);
+		exit(1);
+	}
+
+	printf("ECC corrections: %d\n", oldstats.corrected);
+	printf("ECC failures   : %d\n", oldstats.failed);
+	printf("Bad blocks     : %d\n", oldstats.badblocks);
+	printf("BBT blocks     : %d\n", oldstats.bbtblocks);
+
+	srand(seed);
+
+	for (pass = 0; pass < nr_passes; pass++) {
+		loff_t test_ofs;
+
+		for (test_ofs = offset; test_ofs < offset+length; test_ofs += meminfo.erasesize) {
+			ssize_t len;
+
+			seed = rand();
+			srand(seed);
+
+			if (ioctl(fd, MEMGETBADBLOCK, &test_ofs)) {
+				printf("\rBad block at 0x%08x\n", (unsigned)test_ofs);
+				continue;
+			}
+
+			for (i=0; i<meminfo.erasesize; i++)
+				wbuf[i] = rand();
+
+			if (keep_contents) {
+				printf("\r%08x: reading... ", (unsigned)test_ofs);
+				fflush(stdout);
+
+				len = pread(fd, kbuf, meminfo.erasesize, test_ofs);
+				if (len < meminfo.erasesize) {
+					printf("\n");
+					if (len)
+						fprintf(stderr, "Short read (%zd bytes)\n", len);
+					else
+						perror("read");
+					exit(1);
+				}
+			}
+			if (erase_and_write(test_ofs, wbuf, rbuf, nr_reads))
+				continue;
+			if (keep_contents)
+				erase_and_write(test_ofs, kbuf, rbuf, 1);
+		}
+		printf("\nFinished pass %d successfully\n", pass+1);
+	}
+	/* Return happy */
+	return 0;
+}
diff --git a/nand-utils/nandwrite.c b/nand-utils/nandwrite.c
new file mode 100644
index 0000000..9c3fe8f
--- /dev/null
+++ b/nand-utils/nandwrite.c
@@ -0,0 +1,578 @@
+/*
+ *  nandwrite.c
+ *
+ *  Copyright (C) 2000 Steven J. Hill (sjhill at realitydiluted.com)
+ *		  2003 Thomas Gleixner (tglx at linutronix.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Overview:
+ *   This utility writes a binary image directly to a NAND flash
+ *   chip or NAND chips contained in DoC devices. This is the
+ *   "inverse operation" of nanddump.
+ *
+ * tglx: Major rewrite to handle bad blocks, write data with or without ECC
+ *	 write oob data only on request
+ *
+ * Bug/ToDo:
+ */
+
+#define PROGRAM_NAME "nandwrite"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <getopt.h>
+
+#include <asm/types.h>
+#include "mtd/mtd-user.h"
+#include "common.h"
+#include <libmtd.h>
+
+static void display_help(int status)
+{
+	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
+"Usage: nandwrite [OPTION] MTD_DEVICE [INPUTFILE|-]\n"
+"Writes to the specified MTD device.\n"
+"\n"
+"  -a, --autoplace         Use auto OOB layout\n"
+"  -m, --markbad           Mark blocks bad if write fails\n"
+"  -n, --noecc             Write without ecc\n"
+"  -N, --noskipbad         Write without bad block skipping\n"
+"  -o, --oob               Input contains oob data\n"
+"  -O, --onlyoob           Input contains oob data and only write the oob part\n"
+"  -s addr, --start=addr   Set output start address (default is 0)\n"
+"  -p, --pad               Pad writes to page size\n"
+"  -b, --blockalign=1|2|4  Set multiple of eraseblocks to align to\n"
+"      --input-skip=length Skip |length| bytes of the input file\n"
+"      --input-size=length Only read |length| bytes of the input file\n"
+"  -q, --quiet             Don't display progress messages\n"
+"  -h, --help              Display this help and exit\n"
+"      --version           Output version information and exit\n"
+	);
+	exit(status);
+}
+
+static void display_version(void)
+{
+	printf("%1$s " VERSION "\n"
+			"\n"
+			"Copyright (C) 2003 Thomas Gleixner \n"
+			"\n"
+			"%1$s comes with NO WARRANTY\n"
+			"to the extent permitted by law.\n"
+			"\n"
+			"You may redistribute copies of %1$s\n"
+			"under the terms of the GNU General Public Licence.\n"
+			"See the file `COPYING' for more information.\n",
+			PROGRAM_NAME);
+	exit(EXIT_SUCCESS);
+}
+
+static const char	*standard_input = "-";
+static const char	*mtd_device, *img;
+static long long	mtdoffset = 0;
+static long long	inputskip = 0;
+static long long	inputsize = 0;
+static bool		quiet = false;
+static bool		writeoob = false;
+static bool		onlyoob = false;
+static bool		markbad = false;
+static bool		noecc = false;
+static bool		autoplace = false;
+static bool		noskipbad = false;
+static bool		pad = false;
+static int		blockalign = 1; /* default to using actual block size */
+
+static void process_options(int argc, char * const argv[])
+{
+	int error = 0;
+
+	for (;;) {
+		int option_index = 0;
+		static const char short_options[] = "hb:mnNoOpqs:a";
+		static const struct option long_options[] = {
+			/* Order of these args with val==0 matters; see option_index. */
+			{"version", no_argument, 0, 0},
+			{"input-skip", required_argument, 0, 0},
+			{"input-size", required_argument, 0, 0},
+			{"help", no_argument, 0, 'h'},
+			{"blockalign", required_argument, 0, 'b'},
+			{"markbad", no_argument, 0, 'm'},
+			{"noecc", no_argument, 0, 'n'},
+			{"noskipbad", no_argument, 0, 'N'},
+			{"oob", no_argument, 0, 'o'},
+			{"onlyoob", no_argument, 0, 'O'},
+			{"pad", no_argument, 0, 'p'},
+			{"quiet", no_argument, 0, 'q'},
+			{"start", required_argument, 0, 's'},
+			{"autoplace", no_argument, 0, 'a'},
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+		case 0:
+			switch (option_index) {
+			case 0: /* --version */
+				display_version();
+				break;
+			case 1: /* --input-skip */
+				inputskip = simple_strtoll(optarg, &error);
+				break;
+			case 2: /* --input-size */
+				inputsize = simple_strtoll(optarg, &error);
+				break;
+			}
+			break;
+		case 'q':
+			quiet = true;
+			break;
+		case 'n':
+			noecc = true;
+			break;
+		case 'N':
+			noskipbad = true;
+			break;
+		case 'm':
+			markbad = true;
+			break;
+		case 'o':
+			writeoob = true;
+			break;
+		case 'O':
+			writeoob = true;
+			onlyoob = true;
+			break;
+		case 'p':
+			pad = true;
+			break;
+		case 's':
+			mtdoffset = simple_strtoll(optarg, &error);
+			break;
+		case 'b':
+			blockalign = atoi(optarg);
+			break;
+		case 'a':
+			autoplace = true;
+			break;
+		case 'h':
+			display_help(EXIT_SUCCESS);
+			break;
+		case '?':
+			error++;
+			break;
+		}
+	}
+
+	if (mtdoffset < 0)
+		errmsg_die("Can't specify negative device offset with option"
+				" -s: %lld", mtdoffset);
+
+	if (blockalign < 0)
+		errmsg_die("Can't specify negative blockalign with option -b:"
+				" %d", blockalign);
+
+	if (autoplace && noecc)
+		errmsg_die("Autoplacement and no-ECC are mutually exclusive");
+
+	if (!onlyoob && (pad && writeoob))
+		errmsg_die("Can't pad when oob data is present");
+
+	argc -= optind;
+	argv += optind;
+
+	/*
+	 * There must be at least the MTD device node positional
+	 * argument remaining and, optionally, the input file.
+	 */
+
+	if (argc < 1 || argc > 2 || error)
+		display_help(EXIT_FAILURE);
+
+	mtd_device = argv[0];
+
+	/*
+	 * Standard input may be specified either explictly as "-" or
+	 * implicity by simply omitting the second of the two
+	 * positional arguments.
+	 */
+
+	img = ((argc == 2) ? argv[1] : standard_input);
+}
+
+static void erase_buffer(void *buffer, size_t size)
+{
+	const uint8_t kEraseByte = 0xff;
+
+	if (buffer != NULL && size > 0)
+		memset(buffer, kEraseByte, size);
+}
+
+/*
+ * Main program
+ */
+int main(int argc, char * const argv[])
+{
+	int fd = -1;
+	int ifd = -1;
+	int pagelen;
+	long long imglen = 0;
+	bool baderaseblock = false;
+	long long blockstart = -1;
+	struct mtd_dev_info mtd;
+	long long offs;
+	int ret;
+	bool failed = true;
+	/* contains all the data read from the file so far for the current eraseblock */
+	unsigned char *filebuf = NULL;
+	size_t filebuf_max = 0;
+	size_t filebuf_len = 0;
+	/* points to the current page inside filebuf */
+	unsigned char *writebuf = NULL;
+	/* points to the OOB for the current page in filebuf */
+	unsigned char *oobbuf = NULL;
+	libmtd_t mtd_desc;
+	int ebsize_aligned;
+	uint8_t write_mode;
+
+	process_options(argc, argv);
+
+	/* Open the device */
+	if ((fd = open(mtd_device, O_RDWR)) == -1)
+		sys_errmsg_die("%s", mtd_device);
+
+	mtd_desc = libmtd_open();
+	if (!mtd_desc)
+		errmsg_die("can't initialize libmtd");
+
+	/* Fill in MTD device capability structure */
+	if (mtd_get_dev_info(mtd_desc, mtd_device, &mtd) < 0)
+		errmsg_die("mtd_get_dev_info failed");
+
+	/*
+	 * Pretend erasesize is specified number of blocks - to match jffs2
+	 *   (virtual) block size
+	 * Use this value throughout unless otherwise necessary
+	 */
+	ebsize_aligned = mtd.eb_size * blockalign;
+
+	if (mtdoffset & (mtd.min_io_size - 1))
+		errmsg_die("The start address is not page-aligned !\n"
+			   "The pagesize of this NAND Flash is 0x%x.\n",
+			   mtd.min_io_size);
+
+	/* Select OOB write mode */
+	if (noecc)
+		write_mode = MTD_OPS_RAW;
+	else if (autoplace)
+		write_mode = MTD_OPS_AUTO_OOB;
+	else
+		write_mode = MTD_OPS_PLACE_OOB;
+
+	if (noecc)  {
+		ret = ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW);
+		if (ret) {
+			switch (errno) {
+			case ENOTTY:
+				errmsg_die("ioctl MTDFILEMODE is missing");
+			default:
+				sys_errmsg_die("MTDFILEMODE");
+			}
+		}
+	}
+
+	/* Determine if we are reading from standard input or from a file. */
+	if (strcmp(img, standard_input) == 0)
+		ifd = STDIN_FILENO;
+	else
+		ifd = open(img, O_RDONLY);
+
+	if (ifd == -1) {
+		perror(img);
+		goto closeall;
+	}
+
+	pagelen = mtd.min_io_size + ((writeoob) ? mtd.oob_size : 0);
+
+	if (ifd == STDIN_FILENO) {
+		imglen = inputsize ? : pagelen;
+		if (inputskip) {
+			errmsg("seeking stdin not supported");
+			goto closeall;
+		}
+	} else {
+		if (!inputsize) {
+			struct stat st;
+			if (fstat(ifd, &st)) {
+				sys_errmsg("unable to stat input image");
+				goto closeall;
+			}
+			imglen = st.st_size - inputskip;
+		} else
+			imglen = inputsize;
+
+		if (inputskip && lseek(ifd, inputskip, SEEK_CUR) == -1) {
+			sys_errmsg("lseek input by %lld failed", inputskip);
+			goto closeall;
+		}
+	}
+
+	/* Check, if file is page-aligned */
+	if (!pad && (imglen % pagelen) != 0) {
+		fprintf(stderr, "Input file is not page-aligned. Use the padding "
+				 "option.\n");
+		goto closeall;
+	}
+
+	/* Check, if length fits into device */
+	if ((imglen / pagelen) * mtd.min_io_size > mtd.size - mtdoffset) {
+		fprintf(stderr, "Image %lld bytes, NAND page %d bytes, OOB area %d"
+				" bytes, device size %lld bytes\n",
+				imglen, pagelen, mtd.oob_size, mtd.size);
+		sys_errmsg("Input file does not fit into device");
+		goto closeall;
+	}
+
+	/*
+	 * Allocate a buffer big enough to contain all the data (OOB included)
+	 * for one eraseblock. The order of operations here matters; if ebsize
+	 * and pagelen are large enough, then "ebsize_aligned * pagelen" could
+	 * overflow a 32-bit data type.
+	 */
+	filebuf_max = ebsize_aligned / mtd.min_io_size * pagelen;
+	filebuf = xmalloc(filebuf_max);
+	erase_buffer(filebuf, filebuf_max);
+
+	/*
+	 * Get data from input and write to the device while there is
+	 * still input to read and we are still within the device
+	 * bounds. Note that in the case of standard input, the input
+	 * length is simply a quasi-boolean flag whose values are page
+	 * length or zero.
+	 */
+	while ((imglen > 0 || writebuf < filebuf + filebuf_len)
+		&& mtdoffset < mtd.size) {
+		/*
+		 * New eraseblock, check for bad block(s)
+		 * Stay in the loop to be sure that, if mtdoffset changes because
+		 * of a bad block, the next block that will be written to
+		 * is also checked. Thus, we avoid errors if the block(s) after the
+		 * skipped block(s) is also bad (number of blocks depending on
+		 * the blockalign).
+		 */
+		while (blockstart != (mtdoffset & (~ebsize_aligned + 1))) {
+			blockstart = mtdoffset & (~ebsize_aligned + 1);
+			offs = blockstart;
+
+			/*
+			 * if writebuf == filebuf, we are rewinding so we must
+			 * not reset the buffer but just replay it
+			 */
+			if (writebuf != filebuf) {
+				erase_buffer(filebuf, filebuf_len);
+				filebuf_len = 0;
+				writebuf = filebuf;
+			}
+
+			baderaseblock = false;
+			if (!quiet)
+				fprintf(stdout, "Writing data to block %lld at offset 0x%llx\n",
+						 blockstart / ebsize_aligned, blockstart);
+
+			/* Check all the blocks in an erase block for bad blocks */
+			if (noskipbad)
+				continue;
+
+			do {
+				ret = mtd_is_bad(&mtd, fd, offs / ebsize_aligned);
+				if (ret < 0) {
+					sys_errmsg("%s: MTD get bad block failed", mtd_device);
+					goto closeall;
+				} else if (ret == 1) {
+					baderaseblock = true;
+					if (!quiet)
+						fprintf(stderr, "Bad block at %llx, %u block(s) "
+								"from %llx will be skipped\n",
+								offs, blockalign, blockstart);
+				}
+
+				if (baderaseblock) {
+					mtdoffset = blockstart + ebsize_aligned;
+
+					if (mtdoffset > mtd.size) {
+						errmsg("too many bad blocks, cannot complete request");
+						goto closeall;
+					}
+				}
+
+				offs +=  ebsize_aligned / blockalign;
+			} while (offs < blockstart + ebsize_aligned);
+
+		}
+
+		/* Read more data from the input if there isn't enough in the buffer */
+		if (writebuf + mtd.min_io_size > filebuf + filebuf_len) {
+			size_t readlen = mtd.min_io_size;
+			size_t alreadyread = (filebuf + filebuf_len) - writebuf;
+			size_t tinycnt = alreadyread;
+			ssize_t cnt = 0;
+
+			while (tinycnt < readlen) {
+				cnt = read(ifd, writebuf + tinycnt, readlen - tinycnt);
+				if (cnt == 0) { /* EOF */
+					break;
+				} else if (cnt < 0) {
+					perror("File I/O error on input");
+					goto closeall;
+				}
+				tinycnt += cnt;
+			}
+
+			/* No padding needed - we are done */
+			if (tinycnt == 0) {
+				/*
+				 * For standard input, set imglen to 0 to signal
+				 * the end of the "file". For nonstandard input,
+				 * leave it as-is to detect an early EOF.
+				 */
+				if (ifd == STDIN_FILENO)
+					imglen = 0;
+
+				break;
+			}
+
+			/* Padding */
+			if (tinycnt < readlen) {
+				if (!pad) {
+					fprintf(stderr, "Unexpected EOF. Expecting at least "
+							"%zu more bytes. Use the padding option.\n",
+							readlen - tinycnt);
+					goto closeall;
+				}
+				erase_buffer(writebuf + tinycnt, readlen - tinycnt);
+			}
+
+			filebuf_len += readlen - alreadyread;
+			if (ifd != STDIN_FILENO) {
+				imglen -= tinycnt - alreadyread;
+			} else if (cnt == 0) {
+				/* No more bytes - we are done after writing the remaining bytes */
+				imglen = 0;
+			}
+		}
+
+		if (writeoob) {
+			oobbuf = writebuf + mtd.min_io_size;
+
+			/* Read more data for the OOB from the input if there isn't enough in the buffer */
+			if (oobbuf + mtd.oob_size > filebuf + filebuf_len) {
+				size_t readlen = mtd.oob_size;
+				size_t alreadyread = (filebuf + filebuf_len) - oobbuf;
+				size_t tinycnt = alreadyread;
+				ssize_t cnt;
+
+				while (tinycnt < readlen) {
+					cnt = read(ifd, oobbuf + tinycnt, readlen - tinycnt);
+					if (cnt == 0) { /* EOF */
+						break;
+					} else if (cnt < 0) {
+						perror("File I/O error on input");
+						goto closeall;
+					}
+					tinycnt += cnt;
+				}
+
+				if (tinycnt < readlen) {
+					fprintf(stderr, "Unexpected EOF. Expecting at least "
+							"%zu more bytes for OOB\n", readlen - tinycnt);
+					goto closeall;
+				}
+
+				filebuf_len += readlen - alreadyread;
+				if (ifd != STDIN_FILENO) {
+					imglen -= tinycnt - alreadyread;
+				} else if (cnt == 0) {
+					/* No more bytes - we are done after writing the remaining bytes */
+					imglen = 0;
+				}
+			}
+		}
+
+		/* Write out data */
+		ret = mtd_write(mtd_desc, &mtd, fd, mtdoffset / mtd.eb_size,
+				mtdoffset % mtd.eb_size,
+				onlyoob ? NULL : writebuf,
+				onlyoob ? 0 : mtd.min_io_size,
+				writeoob ? oobbuf : NULL,
+				writeoob ? mtd.oob_size : 0,
+				write_mode);
+		if (ret) {
+			long long i;
+			if (errno != EIO) {
+				sys_errmsg("%s: MTD write failure", mtd_device);
+				goto closeall;
+			}
+
+			/* Must rewind to blockstart if we can */
+			writebuf = filebuf;
+
+			fprintf(stderr, "Erasing failed write from %#08llx to %#08llx\n",
+				blockstart, blockstart + ebsize_aligned - 1);
+			for (i = blockstart; i < blockstart + ebsize_aligned; i += mtd.eb_size) {
+				if (mtd_erase(mtd_desc, &mtd, fd, i / mtd.eb_size)) {
+					int errno_tmp = errno;
+					sys_errmsg("%s: MTD Erase failure", mtd_device);
+					if (errno_tmp != EIO)
+						goto closeall;
+				}
+			}
+
+			if (markbad) {
+				fprintf(stderr, "Marking block at %08llx bad\n",
+						mtdoffset & (~mtd.eb_size + 1));
+				if (mtd_mark_bad(&mtd, fd, mtdoffset / mtd.eb_size)) {
+					sys_errmsg("%s: MTD Mark bad block failure", mtd_device);
+					goto closeall;
+				}
+			}
+			mtdoffset = blockstart + ebsize_aligned;
+
+			continue;
+		}
+		mtdoffset += mtd.min_io_size;
+		writebuf += pagelen;
+	}
+
+	failed = false;
+
+closeall:
+	close(ifd);
+	libmtd_close(mtd_desc);
+	free(filebuf);
+	close(fd);
+
+	if (failed || (ifd != STDIN_FILENO && imglen > 0)
+		   || (writebuf < filebuf + filebuf_len))
+		sys_errmsg_die("Data was only partially written due to error");
+
+	/* Return happy */
+	return EXIT_SUCCESS;
+}
diff --git a/nand-utils/nftl_format.c b/nand-utils/nftl_format.c
new file mode 100644
index 0000000..1fc3b36
--- /dev/null
+++ b/nand-utils/nftl_format.c
@@ -0,0 +1,422 @@
+/*
+ * nftl_format.c: Creating a NFTL/INFTL partition on an MTD device
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ *
+ * ToDo:
+ *	1. UnitSizeFactor != 0xFF cases
+ *	2. test, test, and test !!!
+ */
+
+#define PROGRAM_NAME "nftl_format"
+
+#define _XOPEN_SOURCE 500 /* for pread/pwrite */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <string.h>
+
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+#include <mtd/nftl-user.h>
+#include <mtd/inftl-user.h>
+#include <mtd_swab.h>
+
+unsigned char BadUnitTable[MAX_ERASE_ZONES];
+unsigned char *readbuf;
+unsigned char *writebuf[4];
+
+mtd_info_t meminfo;
+erase_info_t erase;
+int fd;
+struct NFTLMediaHeader *NFTLhdr;
+struct INFTLMediaHeader *INFTLhdr;
+
+static int do_oobcheck = 1;
+static int do_rwecheck = 1;
+
+static unsigned char check_block_1(unsigned long block)
+{
+	unsigned char oobbuf[16];
+	struct mtd_oob_buf oob = { 0, 16, oobbuf };
+
+	oob.start = block * meminfo.erasesize;
+	if (ioctl(fd, MEMREADOOB, &oob))
+		return ZONE_BAD_ORIGINAL;
+
+	if(oobbuf[5] == 0)
+		return ZONE_BAD_ORIGINAL;
+
+	oob.start = block * meminfo.erasesize + 512 /* FIXME */;
+	if (ioctl(fd, MEMREADOOB, &oob))
+		return ZONE_BAD_ORIGINAL;
+
+	if(oobbuf[5] == 0)
+		return ZONE_BAD_ORIGINAL;
+
+	return ZONE_GOOD;
+}
+
+static unsigned char check_block_2(unsigned long block)
+{
+	unsigned long ofs = block * meminfo.erasesize;
+	unsigned long blockofs;
+
+	/* Erase test */
+	erase.start = ofs;
+
+	for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
+		pread(fd, readbuf, 512, ofs + blockofs);
+		if (memcmp(readbuf, writebuf[0], 512)) {
+			/* Block wasn't 0xff after erase */
+			printf(": Block not 0xff after erase\n");
+			return ZONE_BAD_ORIGINAL;
+		}
+
+		pwrite(fd, writebuf[1], 512, blockofs + ofs);
+		pread(fd, readbuf, 512, blockofs + ofs);
+		if (memcmp(readbuf, writebuf[1], 512)) {
+			printf(": Block not zero after clearing\n");
+			return ZONE_BAD_ORIGINAL;
+		}
+	}
+
+	/* Write test */
+	if (ioctl(fd, MEMERASE, &erase) != 0) {
+		printf(": Second erase failed (%s)\n", strerror(errno));
+		return ZONE_BAD_ORIGINAL;
+	}
+	for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
+		pwrite(fd, writebuf[2], 512, blockofs + ofs);
+		pread(fd, readbuf, 512, blockofs + ofs);
+		if (memcmp(readbuf, writebuf[2], 512)) {
+			printf(": Block not 0x5a after writing\n");
+			return ZONE_BAD_ORIGINAL;
+		}
+	}
+
+	if (ioctl(fd, MEMERASE, &erase) != 0) {
+		printf(": Third erase failed (%s)\n", strerror(errno));
+		return ZONE_BAD_ORIGINAL;
+	}
+	for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
+		pwrite(fd, writebuf[3], 512, blockofs + ofs);
+		pread(fd, readbuf, 512, blockofs + ofs);
+		if (memcmp(readbuf, writebuf[3], 512)) {
+			printf(": Block not 0xa5 after writing\n");
+			return ZONE_BAD_ORIGINAL;
+		}
+	}
+	if (ioctl(fd, MEMERASE, &erase) != 0) {
+		printf(": Fourth erase failed (%s)\n", strerror(errno));
+		return ZONE_BAD_ORIGINAL;
+	}
+	return ZONE_GOOD;
+}
+
+static unsigned char erase_block(unsigned long block)
+{
+	unsigned char status;
+	int ret;
+
+	status = (do_oobcheck) ? check_block_1(block) : ZONE_GOOD;
+	erase.start = block * meminfo.erasesize;
+
+	if (status != ZONE_GOOD) {
+		printf("\rSkipping bad zone (factory marked) #%ld @ 0x%x\n", block, erase.start);
+		fflush(stdout);
+		return status;
+	}
+
+	printf("\r\t Erasing Zone #%ld @ 0x%x", block, erase.start);
+	fflush(stdout);
+
+	if ((ret=ioctl(fd, MEMERASE, &erase)) != 0) {
+		printf(": Erase failed (%s)\n", strerror(errno));
+		return ZONE_BAD_ORIGINAL;
+	}
+
+	if (do_rwecheck) {
+		printf("\r\tChecking Zone #%ld @ 0x%x", block, erase.start);
+		fflush(stdout);
+		status = check_block_2(block);
+		if (status != ZONE_GOOD) {
+			printf("\rSkipping bad zone (RWE test failed) #%ld @ 0x%x\n", block, erase.start);
+			fflush(stdout);
+		}
+	}
+	return status;
+}
+
+static int checkbbt(void)
+{
+	unsigned char bbt[512];
+	unsigned char bits;
+	int i, addr;
+
+	if (pread(fd, bbt, 512, 0x800) < 0) {
+		printf("%s: failed to read BBT, errno=%d\n", PROGRAM_NAME, errno);
+		return (-1);
+	}
+
+
+	for (i = 0; (i < 512); i++) {
+		addr = i / 4;
+		bits = 0x3 << ((i % 4) * 2);
+		if ((bbt[addr] & bits) == 0) {
+			BadUnitTable[i] = ZONE_BAD_ORIGINAL;
+		}
+	}
+
+	return (0);
+}
+
+void usage(int rc)
+{
+	fprintf(stderr, "Usage: %s [-ib] <mtddevice> [<start offset> [<size>]]\n", PROGRAM_NAME);
+	exit(rc);
+}
+
+int main(int argc, char **argv)
+{
+	unsigned long startofs = 0, part_size = 0;
+	unsigned long ezones = 0, ezone = 0, bad_zones = 0;
+	unsigned char unit_factor = 0xFF;
+	long MediaUnit1 = -1, MediaUnit2 = -1;
+	long MediaUnitOff1 = 0, MediaUnitOff2 = 0;
+	unsigned char oobbuf[16];
+	struct mtd_oob_buf oob = {0, 16, oobbuf};
+	char *mtddevice;
+	const char *nftl;
+	int c, do_inftl = 0, do_bbt = 0;
+
+
+	printf("version 1.24 2005/11/07 11:15:13 gleixner\n");
+
+	if (argc < 2)
+		usage(1);
+
+	nftl = "NFTL";
+
+	while ((c = getopt(argc, argv, "?hib")) > 0) {
+		switch (c) {
+			case 'i':
+				nftl = "INFTL";
+				do_inftl = 1;
+				break;
+			case 'b':
+				do_bbt = 1;
+				break;
+			case 'h':
+			case '?':
+				usage(0);
+				break;
+			default:
+				usage(1);
+				break;
+		}
+	}
+
+	mtddevice = argv[optind++];
+	if (argc > optind) {
+		startofs = strtoul(argv[optind++], NULL, 0);
+	}
+	if (argc > optind) {
+		part_size = strtoul(argv[optind++], NULL, 0);
+	}
+
+	// Open and size the device
+	if ((fd = open(mtddevice, O_RDWR)) < 0) {
+		perror("Open flash device");
+		return 1;
+	}
+
+	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+		perror("ioctl(MEMGETINFO)");
+		close(fd);
+		return 1;
+	}
+
+	switch (meminfo.erasesize) {
+		case 0x1000:
+		case 0x2000:
+		case 0x4000:
+		case 0x8000:
+			break;
+		default:
+			printf("Unrecognized Erase size, 0x%x - I'm confused\n",
+					meminfo.erasesize);
+			close(fd);
+			return 1;
+	}
+	writebuf[0] = malloc(meminfo.erasesize * 5);
+	if (!writebuf[0]) {
+		printf("Malloc failed\n");
+		close(fd);
+		return 1;
+	}
+	writebuf[1] = writebuf[0] + meminfo.erasesize;
+	writebuf[2] = writebuf[1] + meminfo.erasesize;
+	writebuf[3] = writebuf[2] + meminfo.erasesize;
+	readbuf = writebuf[3] + meminfo.erasesize;
+	memset(writebuf[0], 0xff, meminfo.erasesize);
+	memset(writebuf[1], 0x00, meminfo.erasesize);
+	memset(writebuf[2], 0x5a, meminfo.erasesize);
+	memset(writebuf[3], 0xa5, meminfo.erasesize);
+	memset(BadUnitTable, ZONE_GOOD, MAX_ERASE_ZONES);
+
+	if (part_size == 0 || (part_size > meminfo.size - startofs))
+		/* the user doest not or incorrectly specify NFTL partition size */
+		part_size = meminfo.size - startofs;
+
+	erase.length = meminfo.erasesize;
+	ezones = part_size / meminfo.erasesize;
+
+	if (ezones > MAX_ERASE_ZONES) {
+		/* Ought to change the UnitSizeFactor. But later. */
+		part_size = meminfo.erasesize * MAX_ERASE_ZONES;
+		ezones = MAX_ERASE_ZONES;
+		unit_factor = 0xFF;
+	}
+
+	/* If using device BBT then parse that now */
+	if (do_bbt) {
+		checkbbt();
+		do_oobcheck = 0;
+		do_rwecheck = 0;
+	}
+
+	/* Phase 1. Erasing and checking each erase zones in the NFTL partition.
+	   N.B. Erase Zones not used by the NFTL partition are untouched and marked ZONE_GOOD */
+	printf("Phase 1. Checking and erasing Erase Zones from 0x%08lx to 0x%08lx\n",
+			startofs, startofs + part_size);
+	for (ezone = startofs / meminfo.erasesize;
+			ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
+		if (BadUnitTable[ezone] != ZONE_GOOD)
+			continue;
+		if ((BadUnitTable[ezone] = erase_block(ezone)) == ZONE_GOOD) {
+			if (MediaUnit1 == -1) {
+				MediaUnit1 = ezone;
+			} else if (MediaUnit2 == -1) {
+				MediaUnit2 = ezone;
+			}
+		} else {
+			bad_zones++;
+		}
+	}
+	printf("\n");
+
+	/* N.B. from dump of M-System original chips, NumEraseUnits counts the 2 Erase Unit used
+	   by MediaHeader and the FirstPhysicalEUN starts from the MediaHeader */
+	if (do_inftl) {
+		unsigned long maxzones, pezstart, pezend, numvunits;
+
+		INFTLhdr = (struct INFTLMediaHeader *) (writebuf[0]);
+		strcpy(INFTLhdr->bootRecordID, "BNAND");
+		INFTLhdr->NoOfBootImageBlocks = cpu_to_le32(0);
+		INFTLhdr->NoOfBinaryPartitions = cpu_to_le32(0);
+		INFTLhdr->NoOfBDTLPartitions = cpu_to_le32(1);
+		INFTLhdr->BlockMultiplierBits = cpu_to_le32(0);
+		INFTLhdr->FormatFlags = cpu_to_le32(0);
+		INFTLhdr->OsakVersion = cpu_to_le32(OSAK_VERSION);
+		INFTLhdr->PercentUsed = cpu_to_le32(PERCENTUSED);
+		/*
+		 * Calculate number of virtual units we will have to work
+		 * with. I am calculating out the known bad units here, not
+		 * sure if that is what M-Systems do...
+		 */
+		MediaUnit2 = MediaUnit1;
+		MediaUnitOff2 = 4096;
+		maxzones = meminfo.size / meminfo.erasesize;
+		pezstart = startofs / meminfo.erasesize + 1;
+		pezend = startofs / meminfo.erasesize + ezones - 1;
+		numvunits = (ezones - 2) * PERCENTUSED / 100;
+		for (ezone = pezstart; ezone < maxzones; ezone++) {
+			if (BadUnitTable[ezone] != ZONE_GOOD) {
+				if (numvunits > 1)
+					numvunits--;
+			}
+		}
+
+		INFTLhdr->Partitions[0].virtualUnits = cpu_to_le32(numvunits);
+		INFTLhdr->Partitions[0].firstUnit = cpu_to_le32(pezstart);
+		INFTLhdr->Partitions[0].lastUnit = cpu_to_le32(pezend);
+		INFTLhdr->Partitions[0].flags = cpu_to_le32(INFTL_BDTL);
+		INFTLhdr->Partitions[0].spareUnits = cpu_to_le32(0);
+		INFTLhdr->Partitions[0].Reserved0 = INFTLhdr->Partitions[0].firstUnit;
+		INFTLhdr->Partitions[0].Reserved1 = cpu_to_le32(0);
+
+	} else {
+
+		NFTLhdr = (struct NFTLMediaHeader *) (writebuf[0]);
+		strcpy(NFTLhdr->DataOrgID, "ANAND");
+		NFTLhdr->NumEraseUnits = cpu_to_le16(part_size / meminfo.erasesize);
+		NFTLhdr->FirstPhysicalEUN = cpu_to_le16(MediaUnit1);
+		/* N.B. we reserve 2 more Erase Units for "folding" of Virtual Unit Chain */
+		NFTLhdr->FormattedSize = cpu_to_le32(part_size - ( (5+bad_zones) * meminfo.erasesize));
+		NFTLhdr->UnitSizeFactor = unit_factor;
+	}
+
+	/* Phase 2. Writing NFTL Media Headers and Bad Unit Table */
+	printf("Phase 2.a Writing %s Media Header and Bad Unit Table\n", nftl);
+	pwrite(fd, writebuf[0], 512, MediaUnit1 * meminfo.erasesize + MediaUnitOff1);
+	for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
+		pwrite(fd, BadUnitTable + ezone, 512,
+				(MediaUnit1 * meminfo.erasesize) + 512 * (1 + ezone / 512));
+	}
+
+#if 0
+	printf("  MediaHeader contents:\n");
+	printf("    NumEraseUnits: %d\n", le16_to_cpu(NFTLhdr->NumEraseUnits));
+	printf("    FirstPhysicalEUN: %d\n", le16_to_cpu(NFTLhdr->FirstPhysicalEUN));
+	printf("    FormattedSize: %d (%d sectors)\n", le32_to_cpu(NFTLhdr->FormattedSize),
+			le32_to_cpu(NFTLhdr->FormattedSize)/512);
+#endif
+	printf("Phase 2.b Writing Spare %s Media Header and Spare Bad Unit Table\n", nftl);
+	pwrite(fd, writebuf[0], 512, MediaUnit2 * meminfo.erasesize + MediaUnitOff2);
+	for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
+		pwrite(fd, BadUnitTable + ezone, 512,
+				(MediaUnit2 * meminfo.erasesize + MediaUnitOff2) + 512 * (1 + ezone / 512));
+	}
+
+	/* UCI #1 for newly erased Erase Unit */
+	memset(oobbuf, 0xff, 16);
+	oobbuf[11] = oobbuf[10] = oobbuf[9] = 0;
+	oobbuf[8]  = (do_inftl) ? 0x00 : 0x03;
+	oobbuf[12] = oobbuf[14] = 0x69;
+	oobbuf[13] = oobbuf[15] = 0x3c;
+
+	/* N.B. The Media Header and Bad Erase Unit Table are considered as Free Erase Unit
+	   by M-System i.e. their Virtual Unit Number == 0xFFFF in the Unit Control Information #0,
+	   but their Block Status is BLOCK_USED (0x5555) in their Block Control Information */
+	/* Phase 3. Writing Unit Control Information for each Erase Unit */
+	printf("Phase 3. Writing Unit Control Information to each Erase Unit\n");
+	for (ezone = MediaUnit1; ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
+		/* write UCI #1 to each Erase Unit */
+		if (BadUnitTable[ezone] != ZONE_GOOD)
+			continue;
+		oob.start = (ezone * meminfo.erasesize) + 512 + (do_inftl * 512);
+		if (ioctl(fd, MEMWRITEOOB, &oob))
+			printf("MEMWRITEOOB at %lx: %s\n", (unsigned long)oob.start, strerror(errno));
+	}
+
+	exit(0);
+}
diff --git a/nand-utils/nftldump.c b/nand-utils/nftldump.c
new file mode 100644
index 0000000..32f4f2f
--- /dev/null
+++ b/nand-utils/nftldump.c
@@ -0,0 +1,278 @@
+/*
+ * nftldump.c: Dumping the content of NFTL partitions on a "Physical Disk"
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ *
+ * ToDo:
+ *	1. UnitSizeFactor != 0xFF cases
+ *	2. test, test, and test !!!
+ */
+
+#define PROGRAM_NAME "nftldump"
+
+#define _XOPEN_SOURCE 500 /* For pread */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+#include <mtd/nftl-user.h>
+#include <mtd_swab.h>
+
+static struct NFTLMediaHeader MedHead[2];
+static mtd_info_t meminfo;
+
+static struct nftl_oob oobbuf;
+static struct mtd_oob_buf oob = {0, 16, (unsigned char *)&oobbuf};
+
+static int fd, ofd = -1;;
+static int NumMedHeads;
+
+static unsigned char BadUnitTable[MAX_ERASE_ZONES];
+
+#define SWAP16(x) do { x = le16_to_cpu(x); } while(0)
+#define SWAP32(x) do { x = le32_to_cpu(x); } while(0)
+
+/* VUCtable, store the Erase Unit Number of the first Erase Unit in the chain */
+static unsigned short *VUCtable;
+
+/* FixMe: make this dynamic allocated */
+#define ERASESIZE 0x2000
+#define NUMVUNITS ((40*1024*1024) / ERASESIZE)
+static union nftl_uci UCItable[NUMVUNITS][3];
+
+static unsigned short nextEUN(unsigned short curEUN)
+{
+	return UCItable[curEUN][0].a.ReplUnitNum;
+}
+
+static unsigned int find_media_headers(void)
+{
+	int i;
+	static unsigned long ofs = 0;
+
+	NumMedHeads = 0;
+	while (ofs < meminfo.size) {
+		pread(fd, &MedHead[NumMedHeads], sizeof(struct NFTLMediaHeader), ofs);
+		if (!strncmp(MedHead[NumMedHeads].DataOrgID, "ANAND", 6)) {
+			SWAP16(MedHead[NumMedHeads].NumEraseUnits);
+			SWAP16(MedHead[NumMedHeads].FirstPhysicalEUN);
+			SWAP32(MedHead[NumMedHeads].FormattedSize);
+
+			if (NumMedHeads == 0) {
+				printf("NFTL Media Header found at offset 0x%08lx:\n", ofs);
+				printf("NumEraseUnits:    %d\n",
+						MedHead[NumMedHeads].NumEraseUnits);
+				printf("FirstPhysicalEUN: %d\n",
+						MedHead[NumMedHeads].FirstPhysicalEUN);
+				printf("Formatted Size:   %d\n",
+						MedHead[NumMedHeads].FormattedSize);
+				printf("UnitSizeFactor:   0x%x\n",
+						MedHead[NumMedHeads].UnitSizeFactor);
+
+				/* read BadUnitTable, I don't know why pread() does not work for
+				   larger (7680 bytes) chunks */
+				for (i = 0; i < MAX_ERASE_ZONES; i += 512)
+					pread(fd, &BadUnitTable[i], 512, ofs + 512 + i);
+			} else
+				printf("Second NFTL Media Header found at offset 0x%08lx\n",ofs);
+			NumMedHeads++;
+		}
+
+		ofs += meminfo.erasesize;
+		if (NumMedHeads == 2) {
+			if (strncmp((char *)&MedHead[0], (char *)&MedHead[1], sizeof(struct NFTLMediaHeader)) != 0) {
+				printf("warning: NFTL Media Header is not consistent with "
+						"Spare NFTL Media Header\n");
+			}
+			break;
+		}
+	}
+
+	/* allocate Virtual Unit Chain table for this NFTL partition */
+	VUCtable = calloc(MedHead[0].NumEraseUnits, sizeof(unsigned short));
+	return NumMedHeads;
+}
+
+static void dump_erase_units(void)
+{
+	int i, j;
+	unsigned long ofs;
+
+	for (i = MedHead[0].FirstPhysicalEUN; i < MedHead[0].FirstPhysicalEUN +
+			MedHead[0].NumEraseUnits; i++) {
+		/* For each Erase Unit */
+		ofs = i * meminfo.erasesize;
+
+		/* read the Unit Control Information */
+		for (j = 0; j < 3; j++) {
+			oob.start = ofs + (j * 512);
+			if (ioctl(fd, MEMREADOOB, &oob))
+				printf("MEMREADOOB at %lx: %s\n",
+						(unsigned long) oob.start, strerror(errno));
+			memcpy(&UCItable[i][j], &oobbuf.u, 8);
+		}
+		if (UCItable[i][1].b.EraseMark != cpu_to_le16(0x3c69)) {
+			printf("EraseMark not present in unit %d: %x\n",
+					i, UCItable[i][1].b.EraseMark);
+		} else {
+			/* a properly formatted unit */
+			SWAP16(UCItable[i][0].a.VirtUnitNum);
+			SWAP16(UCItable[i][0].a.ReplUnitNum);
+			SWAP16(UCItable[i][0].a.SpareVirtUnitNum);
+			SWAP16(UCItable[i][0].a.SpareReplUnitNum);
+			SWAP32(UCItable[i][1].b.WearInfo);
+			SWAP16(UCItable[i][1].b.EraseMark);
+			SWAP16(UCItable[i][1].b.EraseMark1);
+			SWAP16(UCItable[i][2].c.FoldMark);
+			SWAP16(UCItable[i][2].c.FoldMark1);
+
+			if (!(UCItable[i][0].a.VirtUnitNum & 0x8000)) {
+				/* If this is the first in a chain, store the EUN in the VUC table */
+				if (VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]) {
+					printf("Duplicate start of chain for VUC %d: "
+							"Unit %d replaces Unit %d\n",
+							UCItable[i][0].a.VirtUnitNum & 0x7fff,
+							i, VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]);
+				}
+				VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff] = i;
+			}
+		}
+
+		switch (BadUnitTable[i]) {
+			case ZONE_BAD_ORIGINAL:
+				printf("Unit %d is marked as ZONE_BAD_ORIGINAL\n", i);
+				continue;
+			case ZONE_BAD_MARKED:
+				printf("Unit %d is marked as ZONE_BAD_MARKED\n", i);
+				continue;
+		}
+
+		/* ZONE_GOOD */
+		if (UCItable[i][0].a.VirtUnitNum == 0xffff)
+			printf("Unit %d is free\n", i);
+		else
+			printf("Unit %d is in chain %d and %s a replacement\n", i,
+					UCItable[i][0].a.VirtUnitNum & 0x7fff,
+					UCItable[i][0].a.VirtUnitNum & 0x8000 ? "is" : "is not");
+	}
+}
+
+static void dump_virtual_units(void)
+{
+	int i, j;
+	char readbuf[512];
+
+	for (i = 0; i < (MedHead[0].FormattedSize / meminfo.erasesize); i++) {
+		unsigned short curEUN = VUCtable[i];
+
+		printf("Virtual Unit #%d: ", i);
+		if (!curEUN) {
+			printf("Not present\n");
+			continue;
+		}
+		printf("%d", curEUN);
+
+		/* walk through the Virtual Unit Chain */
+		while ((curEUN = nextEUN(curEUN)) != 0xffff) {
+			printf(", %d", curEUN & 0x7fff);
+		}
+		printf("\n");
+
+		if (ofd != -1) {
+			/* Actually write out the data */
+			for (j = 0; j < meminfo.erasesize / 512; j++) {
+				/* For each sector in the block */
+				unsigned short lastgoodEUN = 0xffff, thisEUN = VUCtable[i];
+				unsigned int status;
+
+				if (thisEUN == 0xffff) thisEUN = 0;
+
+				while (thisEUN && (thisEUN & 0x7fff) != 0x7fff) {
+					oob.start = (thisEUN * ERASESIZE) + (j * 512);
+					ioctl(fd, MEMREADOOB, &oob);
+					status = oobbuf.b.Status | oobbuf.b.Status1;
+
+					switch (status) {
+						case SECTOR_FREE:
+							/* This is still free. Don't look any more */
+							thisEUN = 0;
+							break;
+
+						case SECTOR_USED:
+							/* SECTOR_USED. This is a good one. */
+							lastgoodEUN = thisEUN;
+							break;
+					}
+
+					/* Find the next erase unit in this chain, if any */
+					if (thisEUN)
+						thisEUN = nextEUN(thisEUN) & 0x7fff;
+				}
+
+				if (lastgoodEUN == 0xffff)
+					memset(readbuf, 0, 512);
+				else
+					pread(fd, readbuf, 512,
+							(lastgoodEUN * ERASESIZE) + (j * 512));
+
+				write(ofd, readbuf, 512);
+			}
+
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	if (argc < 2) {
+		printf("Usage: %s <device> [<outfile>]\n", PROGRAM_NAME);
+		exit(1);
+	}
+	fd = open(argv[1], O_RDONLY);
+	if (fd == -1) {
+		perror("open flash");
+		exit (1);
+	}
+
+	if (argc > 2) {
+		ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644);
+		if (ofd == -1)
+			perror ("open outfile");
+	}
+
+	/* get size information of the MTD device */
+	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+		perror("ioctl(MEMGETINFO)");
+		close(fd);
+		return 1;
+	}
+
+	while (find_media_headers() != 0) {
+		dump_erase_units();
+		dump_virtual_units();
+		free(VUCtable);
+	}
+
+	exit(0);
+}
diff --git a/nanddump.c b/nanddump.c
deleted file mode 100644
index 4ee7ed4..0000000
--- a/nanddump.c
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- *  nanddump.c
- *
- *  Copyright (C) 2000 David Woodhouse (dwmw2 at infradead.org)
- *                     Steven J. Hill (sjhill at realitydiluted.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Overview:
- *   This utility dumps the contents of raw NAND chips or NAND
- *   chips contained in DoC devices.
- */
-
-#define PROGRAM_NAME "nanddump"
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <asm/types.h>
-#include <mtd/mtd-user.h>
-#include "common.h"
-#include <libmtd.h>
-
-static void display_help(int status)
-{
-	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
-"Usage: %s [OPTIONS] MTD-device\n"
-"Dumps the contents of a nand mtd partition.\n"
-"\n"
-"-h         --help               Display this help and exit\n"
-"           --version            Output version information and exit\n"
-"           --bb=METHOD          Choose bad block handling method (see below).\n"
-"-a         --forcebinary        Force printing of binary data to tty\n"
-"-c         --canonicalprint     Print canonical Hex+ASCII dump\n"
-"-f file    --file=file          Dump to file\n"
-"-l length  --length=length      Length\n"
-"-n         --noecc              Read without error correction\n"
-"           --omitoob            Omit OOB data (default)\n"
-"-o         --oob                Dump OOB data\n"
-"-p         --prettyprint        Print nice (hexdump)\n"
-"-q         --quiet              Don't display progress and status messages\n"
-"-s addr    --startaddress=addr  Start address\n"
-"\n"
-"--bb=METHOD, where METHOD can be `padbad', `dumpbad', or `skipbad':\n"
-"    padbad:  dump flash data, substituting 0xFF for any bad blocks\n"
-"    dumpbad: dump flash data, including any bad blocks\n"
-"    skipbad: dump good data, completely skipping any bad blocks (default)\n",
-	PROGRAM_NAME);
-	exit(status);
-}
-
-static void display_version(void)
-{
-	printf("%1$s " VERSION "\n"
-			"\n"
-			"%1$s comes with NO WARRANTY\n"
-			"to the extent permitted by law.\n"
-			"\n"
-			"You may redistribute copies of %1$s\n"
-			"under the terms of the GNU General Public Licence.\n"
-			"See the file `COPYING' for more information.\n",
-			PROGRAM_NAME);
-	exit(EXIT_SUCCESS);
-}
-
-// Option variables
-
-static bool			pretty_print = false;	// print nice
-static bool			noecc = false;		// don't error correct
-static bool			omitoob = true;		// omit oob data
-static long long		start_addr;		// start address
-static long long		length;			// dump length
-static const char		*mtddev;		// mtd device name
-static const char		*dumpfile;		// dump file name
-static bool			quiet = false;		// suppress diagnostic output
-static bool			canonical = false;	// print nice + ascii
-static bool			forcebinary = false;	// force printing binary to tty
-
-static enum {
-	padbad,   // dump flash data, substituting 0xFF for any bad blocks
-	dumpbad,  // dump flash data, including any bad blocks
-	skipbad,  // dump good data, completely skipping any bad blocks
-} bb_method = skipbad;
-
-static void process_options(int argc, char * const argv[])
-{
-	int error = 0;
-	bool oob_default = true;
-
-	for (;;) {
-		int option_index = 0;
-		static const char short_options[] = "hs:f:l:opqnca";
-		static const struct option long_options[] = {
-			{"version", no_argument, 0, 0},
-			{"bb", required_argument, 0, 0},
-			{"omitoob", no_argument, 0, 0},
-			{"help", no_argument, 0, 'h'},
-			{"forcebinary", no_argument, 0, 'a'},
-			{"canonicalprint", no_argument, 0, 'c'},
-			{"file", required_argument, 0, 'f'},
-			{"oob", no_argument, 0, 'o'},
-			{"prettyprint", no_argument, 0, 'p'},
-			{"startaddress", required_argument, 0, 's'},
-			{"length", required_argument, 0, 'l'},
-			{"noecc", no_argument, 0, 'n'},
-			{"quiet", no_argument, 0, 'q'},
-			{0, 0, 0, 0},
-		};
-
-		int c = getopt_long(argc, argv, short_options,
-				long_options, &option_index);
-		if (c == EOF) {
-			break;
-		}
-
-		switch (c) {
-			case 0:
-				switch (option_index) {
-					case 0:
-						display_version();
-						break;
-					case 1:
-						/* Handle --bb=METHOD */
-						if (!strcmp(optarg, "padbad"))
-							bb_method = padbad;
-						else if (!strcmp(optarg, "dumpbad"))
-							bb_method = dumpbad;
-						else if (!strcmp(optarg, "skipbad"))
-							bb_method = skipbad;
-						else
-							error++;
-						break;
-					case 2: /* --omitoob */
-						if (oob_default) {
-							oob_default = false;
-							omitoob = true;
-						} else {
-							errmsg_die("--oob and --oomitoob are mutually exclusive");
-						}
-						break;
-				}
-				break;
-			case 's':
-				start_addr = simple_strtoll(optarg, &error);
-				break;
-			case 'f':
-				dumpfile = xstrdup(optarg);
-				break;
-			case 'l':
-				length = simple_strtoll(optarg, &error);
-				break;
-			case 'o':
-				if (oob_default) {
-					oob_default = false;
-					omitoob = false;
-				} else {
-					errmsg_die("--oob and --oomitoob are mutually exclusive");
-				}
-				break;
-			case 'a':
-				forcebinary = true;
-				break;
-			case 'c':
-				canonical = true;
-			case 'p':
-				pretty_print = true;
-				break;
-			case 'q':
-				quiet = true;
-				break;
-			case 'n':
-				noecc = true;
-				break;
-			case 'h':
-				display_help(EXIT_SUCCESS);
-				break;
-			case '?':
-				error++;
-				break;
-		}
-	}
-
-	if (start_addr < 0)
-		errmsg_die("Can't specify negative offset with option -s: %lld",
-				start_addr);
-
-	if (length < 0)
-		errmsg_die("Can't specify negative length with option -l: %lld", length);
-
-	if (quiet && pretty_print) {
-		fprintf(stderr, "The quiet and pretty print options are mutually-\n"
-				"exclusive. Choose one or the other.\n");
-		exit(EXIT_FAILURE);
-	}
-
-	if (forcebinary && pretty_print) {
-		fprintf(stderr, "The forcebinary and pretty print options are\n"
-				"mutually-exclusive. Choose one or the "
-				"other.\n");
-		exit(EXIT_FAILURE);
-	}
-
-	if ((argc - optind) != 1 || error)
-		display_help(EXIT_FAILURE);
-
-	mtddev = argv[optind];
-}
-
-#define PRETTY_ROW_SIZE 16
-#define PRETTY_BUF_LEN 80
-
-/**
- * pretty_dump_to_buffer - formats a blob of data to "hex ASCII" in memory
- * @buf: data blob to dump
- * @len: number of bytes in the @buf
- * @linebuf: where to put the converted data
- * @linebuflen: total size of @linebuf, including space for terminating NULL
- * @pagedump: true - dumping as page format; false - dumping as OOB format
- * @ascii: dump ascii formatted data next to hexdump
- * @prefix: address to print before line in a page dump, ignored if !pagedump
- *
- * pretty_dump_to_buffer() works on one "line" of output at a time, i.e.,
- * PRETTY_ROW_SIZE bytes of input data converted to hex + ASCII output.
- *
- * Given a buffer of unsigned char data, pretty_dump_to_buffer() converts the
- * input data to a hex/ASCII dump at the supplied memory location. A prefix
- * is included based on whether we are dumping page or OOB data. The converted
- * output is always NULL-terminated.
- *
- * e.g.
- *   pretty_dump_to_buffer(data, data_len, prettybuf, linelen, true,
- *                         false, 256);
- * produces:
- *   0x00000100: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
- * NOTE: This function was adapted from linux kernel, "lib/hexdump.c"
- */
-static void pretty_dump_to_buffer(const unsigned char *buf, size_t len,
-		char *linebuf, size_t linebuflen, bool pagedump, bool ascii,
-		unsigned long long prefix)
-{
-	static const char hex_asc[] = "0123456789abcdef";
-	unsigned char ch;
-	unsigned int j, lx = 0, ascii_column;
-
-	if (pagedump)
-		lx += sprintf(linebuf, "0x%.8llx: ", prefix);
-	else
-		lx += sprintf(linebuf, "  OOB Data: ");
-
-	if (!len)
-		goto nil;
-	if (len > PRETTY_ROW_SIZE)	/* limit to one line at a time */
-		len = PRETTY_ROW_SIZE;
-
-	for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) {
-		ch = buf[j];
-		linebuf[lx++] = hex_asc[(ch & 0xf0) >> 4];
-		linebuf[lx++] = hex_asc[ch & 0x0f];
-		linebuf[lx++] = ' ';
-	}
-	if (j)
-		lx--;
-
-	ascii_column = 3 * PRETTY_ROW_SIZE + 14;
-
-	if (!ascii)
-		goto nil;
-
-	/* Spacing between hex and ASCII - ensure at least one space */
-	lx += sprintf(linebuf + lx, "%*s",
-			MAX((int)MIN(linebuflen, ascii_column) - 1 - lx, 1),
-			" ");
-
-	linebuf[lx++] = '|';
-	for (j = 0; (j < len) && (lx + 2) < linebuflen; j++)
-		linebuf[lx++] = (isascii(buf[j]) && isprint(buf[j])) ? buf[j]
-			: '.';
-	linebuf[lx++] = '|';
-nil:
-	linebuf[lx++] = '\n';
-	linebuf[lx++] = '\0';
-}
-
-
-/*
- * Main program
- */
-int main(int argc, char * const argv[])
-{
-	long long ofs, end_addr = 0;
-	long long blockstart = 1;
-	int i, fd, ofd = 0, bs, badblock = 0;
-	struct mtd_dev_info mtd;
-	char pretty_buf[PRETTY_BUF_LEN];
-	int firstblock = 1;
-	struct mtd_ecc_stats stat1, stat2;
-	bool eccstats = false;
-	unsigned char *readbuf = NULL, *oobbuf = NULL;
-	libmtd_t mtd_desc;
-
-	process_options(argc, argv);
-
-	/* Initialize libmtd */
-	mtd_desc = libmtd_open();
-	if (!mtd_desc)
-		return errmsg("can't initialize libmtd");
-
-	/* Open MTD device */
-	if ((fd = open(mtddev, O_RDONLY)) == -1) {
-		perror(mtddev);
-		exit(EXIT_FAILURE);
-	}
-
-	/* Fill in MTD device capability structure */
-	if (mtd_get_dev_info(mtd_desc, mtddev, &mtd) < 0)
-		return errmsg("mtd_get_dev_info failed");
-
-	/* Allocate buffers */
-	oobbuf = xmalloc(sizeof(oobbuf) * mtd.oob_size);
-	readbuf = xmalloc(sizeof(readbuf) * mtd.min_io_size);
-
-	if (noecc)  {
-		if (ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW) != 0) {
-				perror("MTDFILEMODE");
-				goto closeall;
-		}
-	} else {
-		/* check if we can read ecc stats */
-		if (!ioctl(fd, ECCGETSTATS, &stat1)) {
-			eccstats = true;
-			if (!quiet) {
-				fprintf(stderr, "ECC failed: %d\n", stat1.failed);
-				fprintf(stderr, "ECC corrected: %d\n", stat1.corrected);
-				fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks);
-				fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks);
-			}
-		} else
-			perror("No ECC status information available");
-	}
-
-	/* Open output file for writing. If file name is "-", write to standard
-	 * output. */
-	if (!dumpfile) {
-		ofd = STDOUT_FILENO;
-	} else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) {
-		perror(dumpfile);
-		goto closeall;
-	}
-
-	if (!pretty_print && !forcebinary && isatty(ofd)) {
-		fprintf(stderr, "Not printing binary garbage to tty. Use '-a'\n"
-				"or '--forcebinary' to override.\n");
-		goto closeall;
-	}
-
-	/* Initialize start/end addresses and block size */
-	if (start_addr & (mtd.min_io_size - 1)) {
-		fprintf(stderr, "the start address (-s parameter) is not page-aligned!\n"
-				"The pagesize of this NAND Flash is 0x%x.\n",
-				mtd.min_io_size);
-		goto closeall;
-	}
-	if (length)
-		end_addr = start_addr + length;
-	if (!length || end_addr > mtd.size)
-		end_addr = mtd.size;
-
-	bs = mtd.min_io_size;
-
-	/* Print informative message */
-	if (!quiet) {
-		fprintf(stderr, "Block size %d, page size %d, OOB size %d\n",
-				mtd.eb_size, mtd.min_io_size, mtd.oob_size);
-		fprintf(stderr,
-				"Dumping data starting at 0x%08llx and ending at 0x%08llx...\n",
-				start_addr, end_addr);
-	}
-
-	/* Dump the flash contents */
-	for (ofs = start_addr; ofs < end_addr; ofs += bs) {
-		/* Check for bad block */
-		if (bb_method == dumpbad) {
-			badblock = 0;
-		} else if (blockstart != (ofs & (~mtd.eb_size + 1)) ||
-				firstblock) {
-			blockstart = ofs & (~mtd.eb_size + 1);
-			firstblock = 0;
-			if ((badblock = mtd_is_bad(&mtd, fd, ofs / mtd.eb_size)) < 0) {
-				errmsg("libmtd: mtd_is_bad");
-				goto closeall;
-			}
-		}
-
-		if (badblock) {
-			/* skip bad block, increase end_addr */
-			if (bb_method == skipbad) {
-				end_addr += mtd.eb_size;
-				ofs += mtd.eb_size - bs;
-				if (end_addr > mtd.size)
-					end_addr = mtd.size;
-				continue;
-			}
-			memset(readbuf, 0xff, bs);
-		} else {
-			/* Read page data and exit on failure */
-			if (mtd_read(&mtd, fd, ofs / mtd.eb_size, ofs % mtd.eb_size, readbuf, bs)) {
-				errmsg("mtd_read");
-				goto closeall;
-			}
-		}
-
-		/* ECC stats available ? */
-		if (eccstats) {
-			if (ioctl(fd, ECCGETSTATS, &stat2)) {
-				perror("ioctl(ECCGETSTATS)");
-				goto closeall;
-			}
-			if (stat1.failed != stat2.failed)
-				fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
-						" at offset 0x%08llx\n",
-						stat2.failed - stat1.failed, ofs);
-			if (stat1.corrected != stat2.corrected)
-				fprintf(stderr, "ECC: %d corrected bitflip(s) at"
-						" offset 0x%08llx\n",
-						stat2.corrected - stat1.corrected, ofs);
-			stat1 = stat2;
-		}
-
-		/* Write out page data */
-		if (pretty_print) {
-			for (i = 0; i < bs; i += PRETTY_ROW_SIZE) {
-				pretty_dump_to_buffer(readbuf + i, PRETTY_ROW_SIZE,
-						pretty_buf, PRETTY_BUF_LEN, true, canonical, ofs + i);
-				write(ofd, pretty_buf, strlen(pretty_buf));
-			}
-		} else
-			write(ofd, readbuf, bs);
-
-		if (omitoob)
-			continue;
-
-		if (badblock) {
-			memset(oobbuf, 0xff, mtd.oob_size);
-		} else {
-			/* Read OOB data and exit on failure */
-			if (mtd_read_oob(mtd_desc, &mtd, fd, ofs, mtd.oob_size, oobbuf)) {
-				errmsg("libmtd: mtd_read_oob");
-				goto closeall;
-			}
-		}
-
-		/* Write out OOB data */
-		if (pretty_print) {
-			for (i = 0; i < mtd.oob_size; i += PRETTY_ROW_SIZE) {
-				pretty_dump_to_buffer(oobbuf + i, mtd.oob_size - i,
-						pretty_buf, PRETTY_BUF_LEN, false, canonical, 0);
-				write(ofd, pretty_buf, strlen(pretty_buf));
-			}
-		} else
-			write(ofd, oobbuf, mtd.oob_size);
-	}
-
-	/* Close the output file and MTD device, free memory */
-	close(fd);
-	close(ofd);
-	free(oobbuf);
-	free(readbuf);
-
-	/* Exit happy */
-	return EXIT_SUCCESS;
-
-closeall:
-	close(fd);
-	close(ofd);
-	free(oobbuf);
-	free(readbuf);
-	exit(EXIT_FAILURE);
-}
diff --git a/nandtest.c b/nandtest.c
deleted file mode 100644
index 0805387..0000000
--- a/nandtest.c
+++ /dev/null
@@ -1,313 +0,0 @@
-#define PROGRAM_NAME "nandtest"
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <getopt.h>
-
-#include <asm/types.h>
-#include "mtd/mtd-user.h"
-
-void usage(int status)
-{
-	fprintf(status ? stderr : stdout,
-		"usage: %s [OPTIONS] <device>\n\n"
-		"  -h, --help           Display this help output\n"
-		"  -m, --markbad        Mark blocks bad if they appear so\n"
-		"  -s, --seed           Supply random seed\n"
-		"  -p, --passes         Number of passes\n"
-		"  -r <n>, --reads=<n>  Read & check <n> times per pass\n"
-		"  -o, --offset         Start offset on flash\n"
-		"  -l, --length         Length of flash to test\n"
-		"  -k, --keep           Restore existing contents after test\n",
-		PROGRAM_NAME);
-	exit(status);
-}
-
-struct mtd_info_user meminfo;
-struct mtd_ecc_stats oldstats, newstats;
-int fd;
-int markbad=0;
-int seed;
-
-int read_and_compare(loff_t ofs, unsigned char *data, unsigned char *rbuf)
-{
-	ssize_t len;
-	int i;
-
-	len = pread(fd, rbuf, meminfo.erasesize, ofs);
-	if (len < meminfo.erasesize) {
-		printf("\n");
-		if (len)
-			fprintf(stderr, "Short read (%zd bytes)\n", len);
-		else
-			perror("read");
-		exit(1);
-	}
-
-	if (ioctl(fd, ECCGETSTATS, &newstats)) {
-		printf("\n");
-		perror("ECCGETSTATS");
-		close(fd);
-		exit(1);
-	}
-
-	if (newstats.corrected > oldstats.corrected) {
-		printf("\n %d bit(s) ECC corrected at %08x\n",
-				newstats.corrected - oldstats.corrected,
-				(unsigned) ofs);
-		oldstats.corrected = newstats.corrected;
-	}
-	if (newstats.failed > oldstats.failed) {
-		printf("\nECC failed at %08x\n", (unsigned) ofs);
-		oldstats.failed = newstats.failed;
-	}
-
-	printf("\r%08x: checking...", (unsigned)ofs);
-	fflush(stdout);
-
-	if (memcmp(data, rbuf, meminfo.erasesize)) {
-		printf("\n");
-		fprintf(stderr, "compare failed. seed %d\n", seed);
-		for (i=0; i<meminfo.erasesize; i++) {
-			if (data[i] != rbuf[i])
-				printf("Byte 0x%x is %02x should be %02x\n",
-				       i, rbuf[i], data[i]);
-		}
-		return 1;
-	}
-	return 0;
-}
-
-int erase_and_write(loff_t ofs, unsigned char *data, unsigned char *rbuf, int nr_reads)
-{
-	struct erase_info_user er;
-	ssize_t len;
-	int i, read_errs = 0;
-
-	printf("\r%08x: erasing... ", (unsigned)ofs);
-	fflush(stdout);
-
-	er.start = ofs;
-	er.length = meminfo.erasesize;
-
-	if (ioctl(fd, MEMERASE, &er)) {
-		perror("MEMERASE");
-		if (markbad) {
-			printf("Mark block bad at %08lx\n", (long)ofs);
-			ioctl(fd, MEMSETBADBLOCK, &ofs);
-		}
-		return 1;
-	}
-
-	printf("\r%08x: writing...", (unsigned)ofs);
-	fflush(stdout);
-
-	len = pwrite(fd, data, meminfo.erasesize, ofs);
-	if (len < 0) {
-		printf("\n");
-		perror("write");
-		if (markbad) {
-			printf("Mark block bad at %08lx\n", (long)ofs);
-			ioctl(fd, MEMSETBADBLOCK, &ofs);
-		}
-		return 1;
-	}
-	if (len < meminfo.erasesize) {
-		printf("\n");
-		fprintf(stderr, "Short write (%zd bytes)\n", len);
-		exit(1);
-	}
-
-	for (i=1; i<=nr_reads; i++) {
-		printf("\r%08x: reading (%d of %d)...", (unsigned)ofs, i, nr_reads);
-		fflush(stdout);
-		if (read_and_compare(ofs, data, rbuf))
-			read_errs++;
-	}
-	if (read_errs) {
-		fprintf(stderr, "read/check %d of %d failed. seed %d\n", read_errs, nr_reads, seed);
-		return 1;
-	}
-	return 0;
-}
-
-
-/*
- * Main program
- */
-int main(int argc, char **argv)
-{
-	int i;
-	unsigned char *wbuf, *rbuf, *kbuf;
-	int pass;
-	int nr_passes = 1;
-	int nr_reads = 4;
-	int keep_contents = 0;
-	uint32_t offset = 0;
-	uint32_t length = -1;
-
-	seed = time(NULL);
-
-	for (;;) {
-		static const char short_options[] = "hkl:mo:p:r:s:";
-		static const struct option long_options[] = {
-			{ "help", no_argument, 0, 'h' },
-			{ "markbad", no_argument, 0, 'm' },
-			{ "seed", required_argument, 0, 's' },
-			{ "passes", required_argument, 0, 'p' },
-			{ "offset", required_argument, 0, 'o' },
-			{ "length", required_argument, 0, 'l' },
-			{ "reads", required_argument, 0, 'r' },
-			{ "keep", no_argument, 0, 'k' },
-			{0, 0, 0, 0},
-		};
-		int option_index = 0;
-		int c = getopt_long(argc, argv, short_options, long_options, &option_index);
-		if (c == EOF)
-			break;
-
-		switch (c) {
-		case 'h':
-			usage(0);
-			break;
-
-		case '?':
-			usage(1);
-			break;
-
-		case 'm':
-			markbad = 1;
-			break;
-
-		case 'k':
-			keep_contents = 1;
-			break;
-
-		case 's':
-			seed = atol(optarg);
-			break;
-
-		case 'p':
-			nr_passes = atol(optarg);
-			break;
-
-		case 'r':
-			nr_reads = atol(optarg);
-			break;
-
-		case 'o':
-			offset = atol(optarg);
-			break;
-
-		case 'l':
-			length = strtol(optarg, NULL, 0);
-			break;
-
-		}
-	}
-	if (argc - optind != 1)
-		usage(1);
-
-	fd = open(argv[optind], O_RDWR);
-	if (fd < 0) {
-		perror("open");
-		exit(1);
-	}
-
-	if (ioctl(fd, MEMGETINFO, &meminfo)) {
-		perror("MEMGETINFO");
-		close(fd);
-		exit(1);
-	}
-
-	if (length == -1)
-		length = meminfo.size;
-
-	if (offset % meminfo.erasesize) {
-		fprintf(stderr, "Offset %x not multiple of erase size %x\n",
-			offset, meminfo.erasesize);
-		exit(1);
-	}
-	if (length % meminfo.erasesize) {
-		fprintf(stderr, "Length %x not multiple of erase size %x\n",
-			length, meminfo.erasesize);
-		exit(1);
-	}
-	if (length + offset > meminfo.size) {
-		fprintf(stderr, "Length %x + offset %x exceeds device size %x\n",
-			length, offset, meminfo.size);
-		exit(1);
-	}
-
-	wbuf = malloc(meminfo.erasesize * 3);
-	if (!wbuf) {
-		fprintf(stderr, "Could not allocate %d bytes for buffer\n",
-			meminfo.erasesize * 2);
-		exit(1);
-	}
-	rbuf = wbuf + meminfo.erasesize;
-	kbuf = rbuf + meminfo.erasesize;
-
-	if (ioctl(fd, ECCGETSTATS, &oldstats)) {
-		perror("ECCGETSTATS");
-		close(fd);
-		exit(1);
-	}
-
-	printf("ECC corrections: %d\n", oldstats.corrected);
-	printf("ECC failures   : %d\n", oldstats.failed);
-	printf("Bad blocks     : %d\n", oldstats.badblocks);
-	printf("BBT blocks     : %d\n", oldstats.bbtblocks);
-
-	srand(seed);
-
-	for (pass = 0; pass < nr_passes; pass++) {
-		loff_t test_ofs;
-
-		for (test_ofs = offset; test_ofs < offset+length; test_ofs += meminfo.erasesize) {
-			ssize_t len;
-
-			seed = rand();
-			srand(seed);
-
-			if (ioctl(fd, MEMGETBADBLOCK, &test_ofs)) {
-				printf("\rBad block at 0x%08x\n", (unsigned)test_ofs);
-				continue;
-			}
-
-			for (i=0; i<meminfo.erasesize; i++)
-				wbuf[i] = rand();
-
-			if (keep_contents) {
-				printf("\r%08x: reading... ", (unsigned)test_ofs);
-				fflush(stdout);
-
-				len = pread(fd, kbuf, meminfo.erasesize, test_ofs);
-				if (len < meminfo.erasesize) {
-					printf("\n");
-					if (len)
-						fprintf(stderr, "Short read (%zd bytes)\n", len);
-					else
-						perror("read");
-					exit(1);
-				}
-			}
-			if (erase_and_write(test_ofs, wbuf, rbuf, nr_reads))
-				continue;
-			if (keep_contents)
-				erase_and_write(test_ofs, kbuf, rbuf, 1);
-		}
-		printf("\nFinished pass %d successfully\n", pass+1);
-	}
-	/* Return happy */
-	return 0;
-}
diff --git a/nandwrite.c b/nandwrite.c
deleted file mode 100644
index 9c3fe8f..0000000
--- a/nandwrite.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- *  nandwrite.c
- *
- *  Copyright (C) 2000 Steven J. Hill (sjhill at realitydiluted.com)
- *		  2003 Thomas Gleixner (tglx at linutronix.de)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Overview:
- *   This utility writes a binary image directly to a NAND flash
- *   chip or NAND chips contained in DoC devices. This is the
- *   "inverse operation" of nanddump.
- *
- * tglx: Major rewrite to handle bad blocks, write data with or without ECC
- *	 write oob data only on request
- *
- * Bug/ToDo:
- */
-
-#define PROGRAM_NAME "nandwrite"
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <getopt.h>
-
-#include <asm/types.h>
-#include "mtd/mtd-user.h"
-#include "common.h"
-#include <libmtd.h>
-
-static void display_help(int status)
-{
-	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
-"Usage: nandwrite [OPTION] MTD_DEVICE [INPUTFILE|-]\n"
-"Writes to the specified MTD device.\n"
-"\n"
-"  -a, --autoplace         Use auto OOB layout\n"
-"  -m, --markbad           Mark blocks bad if write fails\n"
-"  -n, --noecc             Write without ecc\n"
-"  -N, --noskipbad         Write without bad block skipping\n"
-"  -o, --oob               Input contains oob data\n"
-"  -O, --onlyoob           Input contains oob data and only write the oob part\n"
-"  -s addr, --start=addr   Set output start address (default is 0)\n"
-"  -p, --pad               Pad writes to page size\n"
-"  -b, --blockalign=1|2|4  Set multiple of eraseblocks to align to\n"
-"      --input-skip=length Skip |length| bytes of the input file\n"
-"      --input-size=length Only read |length| bytes of the input file\n"
-"  -q, --quiet             Don't display progress messages\n"
-"  -h, --help              Display this help and exit\n"
-"      --version           Output version information and exit\n"
-	);
-	exit(status);
-}
-
-static void display_version(void)
-{
-	printf("%1$s " VERSION "\n"
-			"\n"
-			"Copyright (C) 2003 Thomas Gleixner \n"
-			"\n"
-			"%1$s comes with NO WARRANTY\n"
-			"to the extent permitted by law.\n"
-			"\n"
-			"You may redistribute copies of %1$s\n"
-			"under the terms of the GNU General Public Licence.\n"
-			"See the file `COPYING' for more information.\n",
-			PROGRAM_NAME);
-	exit(EXIT_SUCCESS);
-}
-
-static const char	*standard_input = "-";
-static const char	*mtd_device, *img;
-static long long	mtdoffset = 0;
-static long long	inputskip = 0;
-static long long	inputsize = 0;
-static bool		quiet = false;
-static bool		writeoob = false;
-static bool		onlyoob = false;
-static bool		markbad = false;
-static bool		noecc = false;
-static bool		autoplace = false;
-static bool		noskipbad = false;
-static bool		pad = false;
-static int		blockalign = 1; /* default to using actual block size */
-
-static void process_options(int argc, char * const argv[])
-{
-	int error = 0;
-
-	for (;;) {
-		int option_index = 0;
-		static const char short_options[] = "hb:mnNoOpqs:a";
-		static const struct option long_options[] = {
-			/* Order of these args with val==0 matters; see option_index. */
-			{"version", no_argument, 0, 0},
-			{"input-skip", required_argument, 0, 0},
-			{"input-size", required_argument, 0, 0},
-			{"help", no_argument, 0, 'h'},
-			{"blockalign", required_argument, 0, 'b'},
-			{"markbad", no_argument, 0, 'm'},
-			{"noecc", no_argument, 0, 'n'},
-			{"noskipbad", no_argument, 0, 'N'},
-			{"oob", no_argument, 0, 'o'},
-			{"onlyoob", no_argument, 0, 'O'},
-			{"pad", no_argument, 0, 'p'},
-			{"quiet", no_argument, 0, 'q'},
-			{"start", required_argument, 0, 's'},
-			{"autoplace", no_argument, 0, 'a'},
-			{0, 0, 0, 0},
-		};
-
-		int c = getopt_long(argc, argv, short_options,
-				long_options, &option_index);
-		if (c == EOF)
-			break;
-
-		switch (c) {
-		case 0:
-			switch (option_index) {
-			case 0: /* --version */
-				display_version();
-				break;
-			case 1: /* --input-skip */
-				inputskip = simple_strtoll(optarg, &error);
-				break;
-			case 2: /* --input-size */
-				inputsize = simple_strtoll(optarg, &error);
-				break;
-			}
-			break;
-		case 'q':
-			quiet = true;
-			break;
-		case 'n':
-			noecc = true;
-			break;
-		case 'N':
-			noskipbad = true;
-			break;
-		case 'm':
-			markbad = true;
-			break;
-		case 'o':
-			writeoob = true;
-			break;
-		case 'O':
-			writeoob = true;
-			onlyoob = true;
-			break;
-		case 'p':
-			pad = true;
-			break;
-		case 's':
-			mtdoffset = simple_strtoll(optarg, &error);
-			break;
-		case 'b':
-			blockalign = atoi(optarg);
-			break;
-		case 'a':
-			autoplace = true;
-			break;
-		case 'h':
-			display_help(EXIT_SUCCESS);
-			break;
-		case '?':
-			error++;
-			break;
-		}
-	}
-
-	if (mtdoffset < 0)
-		errmsg_die("Can't specify negative device offset with option"
-				" -s: %lld", mtdoffset);
-
-	if (blockalign < 0)
-		errmsg_die("Can't specify negative blockalign with option -b:"
-				" %d", blockalign);
-
-	if (autoplace && noecc)
-		errmsg_die("Autoplacement and no-ECC are mutually exclusive");
-
-	if (!onlyoob && (pad && writeoob))
-		errmsg_die("Can't pad when oob data is present");
-
-	argc -= optind;
-	argv += optind;
-
-	/*
-	 * There must be at least the MTD device node positional
-	 * argument remaining and, optionally, the input file.
-	 */
-
-	if (argc < 1 || argc > 2 || error)
-		display_help(EXIT_FAILURE);
-
-	mtd_device = argv[0];
-
-	/*
-	 * Standard input may be specified either explictly as "-" or
-	 * implicity by simply omitting the second of the two
-	 * positional arguments.
-	 */
-
-	img = ((argc == 2) ? argv[1] : standard_input);
-}
-
-static void erase_buffer(void *buffer, size_t size)
-{
-	const uint8_t kEraseByte = 0xff;
-
-	if (buffer != NULL && size > 0)
-		memset(buffer, kEraseByte, size);
-}
-
-/*
- * Main program
- */
-int main(int argc, char * const argv[])
-{
-	int fd = -1;
-	int ifd = -1;
-	int pagelen;
-	long long imglen = 0;
-	bool baderaseblock = false;
-	long long blockstart = -1;
-	struct mtd_dev_info mtd;
-	long long offs;
-	int ret;
-	bool failed = true;
-	/* contains all the data read from the file so far for the current eraseblock */
-	unsigned char *filebuf = NULL;
-	size_t filebuf_max = 0;
-	size_t filebuf_len = 0;
-	/* points to the current page inside filebuf */
-	unsigned char *writebuf = NULL;
-	/* points to the OOB for the current page in filebuf */
-	unsigned char *oobbuf = NULL;
-	libmtd_t mtd_desc;
-	int ebsize_aligned;
-	uint8_t write_mode;
-
-	process_options(argc, argv);
-
-	/* Open the device */
-	if ((fd = open(mtd_device, O_RDWR)) == -1)
-		sys_errmsg_die("%s", mtd_device);
-
-	mtd_desc = libmtd_open();
-	if (!mtd_desc)
-		errmsg_die("can't initialize libmtd");
-
-	/* Fill in MTD device capability structure */
-	if (mtd_get_dev_info(mtd_desc, mtd_device, &mtd) < 0)
-		errmsg_die("mtd_get_dev_info failed");
-
-	/*
-	 * Pretend erasesize is specified number of blocks - to match jffs2
-	 *   (virtual) block size
-	 * Use this value throughout unless otherwise necessary
-	 */
-	ebsize_aligned = mtd.eb_size * blockalign;
-
-	if (mtdoffset & (mtd.min_io_size - 1))
-		errmsg_die("The start address is not page-aligned !\n"
-			   "The pagesize of this NAND Flash is 0x%x.\n",
-			   mtd.min_io_size);
-
-	/* Select OOB write mode */
-	if (noecc)
-		write_mode = MTD_OPS_RAW;
-	else if (autoplace)
-		write_mode = MTD_OPS_AUTO_OOB;
-	else
-		write_mode = MTD_OPS_PLACE_OOB;
-
-	if (noecc)  {
-		ret = ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW);
-		if (ret) {
-			switch (errno) {
-			case ENOTTY:
-				errmsg_die("ioctl MTDFILEMODE is missing");
-			default:
-				sys_errmsg_die("MTDFILEMODE");
-			}
-		}
-	}
-
-	/* Determine if we are reading from standard input or from a file. */
-	if (strcmp(img, standard_input) == 0)
-		ifd = STDIN_FILENO;
-	else
-		ifd = open(img, O_RDONLY);
-
-	if (ifd == -1) {
-		perror(img);
-		goto closeall;
-	}
-
-	pagelen = mtd.min_io_size + ((writeoob) ? mtd.oob_size : 0);
-
-	if (ifd == STDIN_FILENO) {
-		imglen = inputsize ? : pagelen;
-		if (inputskip) {
-			errmsg("seeking stdin not supported");
-			goto closeall;
-		}
-	} else {
-		if (!inputsize) {
-			struct stat st;
-			if (fstat(ifd, &st)) {
-				sys_errmsg("unable to stat input image");
-				goto closeall;
-			}
-			imglen = st.st_size - inputskip;
-		} else
-			imglen = inputsize;
-
-		if (inputskip && lseek(ifd, inputskip, SEEK_CUR) == -1) {
-			sys_errmsg("lseek input by %lld failed", inputskip);
-			goto closeall;
-		}
-	}
-
-	/* Check, if file is page-aligned */
-	if (!pad && (imglen % pagelen) != 0) {
-		fprintf(stderr, "Input file is not page-aligned. Use the padding "
-				 "option.\n");
-		goto closeall;
-	}
-
-	/* Check, if length fits into device */
-	if ((imglen / pagelen) * mtd.min_io_size > mtd.size - mtdoffset) {
-		fprintf(stderr, "Image %lld bytes, NAND page %d bytes, OOB area %d"
-				" bytes, device size %lld bytes\n",
-				imglen, pagelen, mtd.oob_size, mtd.size);
-		sys_errmsg("Input file does not fit into device");
-		goto closeall;
-	}
-
-	/*
-	 * Allocate a buffer big enough to contain all the data (OOB included)
-	 * for one eraseblock. The order of operations here matters; if ebsize
-	 * and pagelen are large enough, then "ebsize_aligned * pagelen" could
-	 * overflow a 32-bit data type.
-	 */
-	filebuf_max = ebsize_aligned / mtd.min_io_size * pagelen;
-	filebuf = xmalloc(filebuf_max);
-	erase_buffer(filebuf, filebuf_max);
-
-	/*
-	 * Get data from input and write to the device while there is
-	 * still input to read and we are still within the device
-	 * bounds. Note that in the case of standard input, the input
-	 * length is simply a quasi-boolean flag whose values are page
-	 * length or zero.
-	 */
-	while ((imglen > 0 || writebuf < filebuf + filebuf_len)
-		&& mtdoffset < mtd.size) {
-		/*
-		 * New eraseblock, check for bad block(s)
-		 * Stay in the loop to be sure that, if mtdoffset changes because
-		 * of a bad block, the next block that will be written to
-		 * is also checked. Thus, we avoid errors if the block(s) after the
-		 * skipped block(s) is also bad (number of blocks depending on
-		 * the blockalign).
-		 */
-		while (blockstart != (mtdoffset & (~ebsize_aligned + 1))) {
-			blockstart = mtdoffset & (~ebsize_aligned + 1);
-			offs = blockstart;
-
-			/*
-			 * if writebuf == filebuf, we are rewinding so we must
-			 * not reset the buffer but just replay it
-			 */
-			if (writebuf != filebuf) {
-				erase_buffer(filebuf, filebuf_len);
-				filebuf_len = 0;
-				writebuf = filebuf;
-			}
-
-			baderaseblock = false;
-			if (!quiet)
-				fprintf(stdout, "Writing data to block %lld at offset 0x%llx\n",
-						 blockstart / ebsize_aligned, blockstart);
-
-			/* Check all the blocks in an erase block for bad blocks */
-			if (noskipbad)
-				continue;
-
-			do {
-				ret = mtd_is_bad(&mtd, fd, offs / ebsize_aligned);
-				if (ret < 0) {
-					sys_errmsg("%s: MTD get bad block failed", mtd_device);
-					goto closeall;
-				} else if (ret == 1) {
-					baderaseblock = true;
-					if (!quiet)
-						fprintf(stderr, "Bad block at %llx, %u block(s) "
-								"from %llx will be skipped\n",
-								offs, blockalign, blockstart);
-				}
-
-				if (baderaseblock) {
-					mtdoffset = blockstart + ebsize_aligned;
-
-					if (mtdoffset > mtd.size) {
-						errmsg("too many bad blocks, cannot complete request");
-						goto closeall;
-					}
-				}
-
-				offs +=  ebsize_aligned / blockalign;
-			} while (offs < blockstart + ebsize_aligned);
-
-		}
-
-		/* Read more data from the input if there isn't enough in the buffer */
-		if (writebuf + mtd.min_io_size > filebuf + filebuf_len) {
-			size_t readlen = mtd.min_io_size;
-			size_t alreadyread = (filebuf + filebuf_len) - writebuf;
-			size_t tinycnt = alreadyread;
-			ssize_t cnt = 0;
-
-			while (tinycnt < readlen) {
-				cnt = read(ifd, writebuf + tinycnt, readlen - tinycnt);
-				if (cnt == 0) { /* EOF */
-					break;
-				} else if (cnt < 0) {
-					perror("File I/O error on input");
-					goto closeall;
-				}
-				tinycnt += cnt;
-			}
-
-			/* No padding needed - we are done */
-			if (tinycnt == 0) {
-				/*
-				 * For standard input, set imglen to 0 to signal
-				 * the end of the "file". For nonstandard input,
-				 * leave it as-is to detect an early EOF.
-				 */
-				if (ifd == STDIN_FILENO)
-					imglen = 0;
-
-				break;
-			}
-
-			/* Padding */
-			if (tinycnt < readlen) {
-				if (!pad) {
-					fprintf(stderr, "Unexpected EOF. Expecting at least "
-							"%zu more bytes. Use the padding option.\n",
-							readlen - tinycnt);
-					goto closeall;
-				}
-				erase_buffer(writebuf + tinycnt, readlen - tinycnt);
-			}
-
-			filebuf_len += readlen - alreadyread;
-			if (ifd != STDIN_FILENO) {
-				imglen -= tinycnt - alreadyread;
-			} else if (cnt == 0) {
-				/* No more bytes - we are done after writing the remaining bytes */
-				imglen = 0;
-			}
-		}
-
-		if (writeoob) {
-			oobbuf = writebuf + mtd.min_io_size;
-
-			/* Read more data for the OOB from the input if there isn't enough in the buffer */
-			if (oobbuf + mtd.oob_size > filebuf + filebuf_len) {
-				size_t readlen = mtd.oob_size;
-				size_t alreadyread = (filebuf + filebuf_len) - oobbuf;
-				size_t tinycnt = alreadyread;
-				ssize_t cnt;
-
-				while (tinycnt < readlen) {
-					cnt = read(ifd, oobbuf + tinycnt, readlen - tinycnt);
-					if (cnt == 0) { /* EOF */
-						break;
-					} else if (cnt < 0) {
-						perror("File I/O error on input");
-						goto closeall;
-					}
-					tinycnt += cnt;
-				}
-
-				if (tinycnt < readlen) {
-					fprintf(stderr, "Unexpected EOF. Expecting at least "
-							"%zu more bytes for OOB\n", readlen - tinycnt);
-					goto closeall;
-				}
-
-				filebuf_len += readlen - alreadyread;
-				if (ifd != STDIN_FILENO) {
-					imglen -= tinycnt - alreadyread;
-				} else if (cnt == 0) {
-					/* No more bytes - we are done after writing the remaining bytes */
-					imglen = 0;
-				}
-			}
-		}
-
-		/* Write out data */
-		ret = mtd_write(mtd_desc, &mtd, fd, mtdoffset / mtd.eb_size,
-				mtdoffset % mtd.eb_size,
-				onlyoob ? NULL : writebuf,
-				onlyoob ? 0 : mtd.min_io_size,
-				writeoob ? oobbuf : NULL,
-				writeoob ? mtd.oob_size : 0,
-				write_mode);
-		if (ret) {
-			long long i;
-			if (errno != EIO) {
-				sys_errmsg("%s: MTD write failure", mtd_device);
-				goto closeall;
-			}
-
-			/* Must rewind to blockstart if we can */
-			writebuf = filebuf;
-
-			fprintf(stderr, "Erasing failed write from %#08llx to %#08llx\n",
-				blockstart, blockstart + ebsize_aligned - 1);
-			for (i = blockstart; i < blockstart + ebsize_aligned; i += mtd.eb_size) {
-				if (mtd_erase(mtd_desc, &mtd, fd, i / mtd.eb_size)) {
-					int errno_tmp = errno;
-					sys_errmsg("%s: MTD Erase failure", mtd_device);
-					if (errno_tmp != EIO)
-						goto closeall;
-				}
-			}
-
-			if (markbad) {
-				fprintf(stderr, "Marking block at %08llx bad\n",
-						mtdoffset & (~mtd.eb_size + 1));
-				if (mtd_mark_bad(&mtd, fd, mtdoffset / mtd.eb_size)) {
-					sys_errmsg("%s: MTD Mark bad block failure", mtd_device);
-					goto closeall;
-				}
-			}
-			mtdoffset = blockstart + ebsize_aligned;
-
-			continue;
-		}
-		mtdoffset += mtd.min_io_size;
-		writebuf += pagelen;
-	}
-
-	failed = false;
-
-closeall:
-	close(ifd);
-	libmtd_close(mtd_desc);
-	free(filebuf);
-	close(fd);
-
-	if (failed || (ifd != STDIN_FILENO && imglen > 0)
-		   || (writebuf < filebuf + filebuf_len))
-		sys_errmsg_die("Data was only partially written due to error");
-
-	/* Return happy */
-	return EXIT_SUCCESS;
-}
diff --git a/nftl_format.c b/nftl_format.c
deleted file mode 100644
index 1fc3b36..0000000
--- a/nftl_format.c
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * nftl_format.c: Creating a NFTL/INFTL partition on an MTD device
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * 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
- *
- * ToDo:
- *	1. UnitSizeFactor != 0xFF cases
- *	2. test, test, and test !!!
- */
-
-#define PROGRAM_NAME "nftl_format"
-
-#define _XOPEN_SOURCE 500 /* for pread/pwrite */
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/mount.h>
-#include <errno.h>
-#include <string.h>
-
-#include <asm/types.h>
-#include <mtd/mtd-user.h>
-#include <mtd/nftl-user.h>
-#include <mtd/inftl-user.h>
-#include <mtd_swab.h>
-
-unsigned char BadUnitTable[MAX_ERASE_ZONES];
-unsigned char *readbuf;
-unsigned char *writebuf[4];
-
-mtd_info_t meminfo;
-erase_info_t erase;
-int fd;
-struct NFTLMediaHeader *NFTLhdr;
-struct INFTLMediaHeader *INFTLhdr;
-
-static int do_oobcheck = 1;
-static int do_rwecheck = 1;
-
-static unsigned char check_block_1(unsigned long block)
-{
-	unsigned char oobbuf[16];
-	struct mtd_oob_buf oob = { 0, 16, oobbuf };
-
-	oob.start = block * meminfo.erasesize;
-	if (ioctl(fd, MEMREADOOB, &oob))
-		return ZONE_BAD_ORIGINAL;
-
-	if(oobbuf[5] == 0)
-		return ZONE_BAD_ORIGINAL;
-
-	oob.start = block * meminfo.erasesize + 512 /* FIXME */;
-	if (ioctl(fd, MEMREADOOB, &oob))
-		return ZONE_BAD_ORIGINAL;
-
-	if(oobbuf[5] == 0)
-		return ZONE_BAD_ORIGINAL;
-
-	return ZONE_GOOD;
-}
-
-static unsigned char check_block_2(unsigned long block)
-{
-	unsigned long ofs = block * meminfo.erasesize;
-	unsigned long blockofs;
-
-	/* Erase test */
-	erase.start = ofs;
-
-	for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
-		pread(fd, readbuf, 512, ofs + blockofs);
-		if (memcmp(readbuf, writebuf[0], 512)) {
-			/* Block wasn't 0xff after erase */
-			printf(": Block not 0xff after erase\n");
-			return ZONE_BAD_ORIGINAL;
-		}
-
-		pwrite(fd, writebuf[1], 512, blockofs + ofs);
-		pread(fd, readbuf, 512, blockofs + ofs);
-		if (memcmp(readbuf, writebuf[1], 512)) {
-			printf(": Block not zero after clearing\n");
-			return ZONE_BAD_ORIGINAL;
-		}
-	}
-
-	/* Write test */
-	if (ioctl(fd, MEMERASE, &erase) != 0) {
-		printf(": Second erase failed (%s)\n", strerror(errno));
-		return ZONE_BAD_ORIGINAL;
-	}
-	for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
-		pwrite(fd, writebuf[2], 512, blockofs + ofs);
-		pread(fd, readbuf, 512, blockofs + ofs);
-		if (memcmp(readbuf, writebuf[2], 512)) {
-			printf(": Block not 0x5a after writing\n");
-			return ZONE_BAD_ORIGINAL;
-		}
-	}
-
-	if (ioctl(fd, MEMERASE, &erase) != 0) {
-		printf(": Third erase failed (%s)\n", strerror(errno));
-		return ZONE_BAD_ORIGINAL;
-	}
-	for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
-		pwrite(fd, writebuf[3], 512, blockofs + ofs);
-		pread(fd, readbuf, 512, blockofs + ofs);
-		if (memcmp(readbuf, writebuf[3], 512)) {
-			printf(": Block not 0xa5 after writing\n");
-			return ZONE_BAD_ORIGINAL;
-		}
-	}
-	if (ioctl(fd, MEMERASE, &erase) != 0) {
-		printf(": Fourth erase failed (%s)\n", strerror(errno));
-		return ZONE_BAD_ORIGINAL;
-	}
-	return ZONE_GOOD;
-}
-
-static unsigned char erase_block(unsigned long block)
-{
-	unsigned char status;
-	int ret;
-
-	status = (do_oobcheck) ? check_block_1(block) : ZONE_GOOD;
-	erase.start = block * meminfo.erasesize;
-
-	if (status != ZONE_GOOD) {
-		printf("\rSkipping bad zone (factory marked) #%ld @ 0x%x\n", block, erase.start);
-		fflush(stdout);
-		return status;
-	}
-
-	printf("\r\t Erasing Zone #%ld @ 0x%x", block, erase.start);
-	fflush(stdout);
-
-	if ((ret=ioctl(fd, MEMERASE, &erase)) != 0) {
-		printf(": Erase failed (%s)\n", strerror(errno));
-		return ZONE_BAD_ORIGINAL;
-	}
-
-	if (do_rwecheck) {
-		printf("\r\tChecking Zone #%ld @ 0x%x", block, erase.start);
-		fflush(stdout);
-		status = check_block_2(block);
-		if (status != ZONE_GOOD) {
-			printf("\rSkipping bad zone (RWE test failed) #%ld @ 0x%x\n", block, erase.start);
-			fflush(stdout);
-		}
-	}
-	return status;
-}
-
-static int checkbbt(void)
-{
-	unsigned char bbt[512];
-	unsigned char bits;
-	int i, addr;
-
-	if (pread(fd, bbt, 512, 0x800) < 0) {
-		printf("%s: failed to read BBT, errno=%d\n", PROGRAM_NAME, errno);
-		return (-1);
-	}
-
-
-	for (i = 0; (i < 512); i++) {
-		addr = i / 4;
-		bits = 0x3 << ((i % 4) * 2);
-		if ((bbt[addr] & bits) == 0) {
-			BadUnitTable[i] = ZONE_BAD_ORIGINAL;
-		}
-	}
-
-	return (0);
-}
-
-void usage(int rc)
-{
-	fprintf(stderr, "Usage: %s [-ib] <mtddevice> [<start offset> [<size>]]\n", PROGRAM_NAME);
-	exit(rc);
-}
-
-int main(int argc, char **argv)
-{
-	unsigned long startofs = 0, part_size = 0;
-	unsigned long ezones = 0, ezone = 0, bad_zones = 0;
-	unsigned char unit_factor = 0xFF;
-	long MediaUnit1 = -1, MediaUnit2 = -1;
-	long MediaUnitOff1 = 0, MediaUnitOff2 = 0;
-	unsigned char oobbuf[16];
-	struct mtd_oob_buf oob = {0, 16, oobbuf};
-	char *mtddevice;
-	const char *nftl;
-	int c, do_inftl = 0, do_bbt = 0;
-
-
-	printf("version 1.24 2005/11/07 11:15:13 gleixner\n");
-
-	if (argc < 2)
-		usage(1);
-
-	nftl = "NFTL";
-
-	while ((c = getopt(argc, argv, "?hib")) > 0) {
-		switch (c) {
-			case 'i':
-				nftl = "INFTL";
-				do_inftl = 1;
-				break;
-			case 'b':
-				do_bbt = 1;
-				break;
-			case 'h':
-			case '?':
-				usage(0);
-				break;
-			default:
-				usage(1);
-				break;
-		}
-	}
-
-	mtddevice = argv[optind++];
-	if (argc > optind) {
-		startofs = strtoul(argv[optind++], NULL, 0);
-	}
-	if (argc > optind) {
-		part_size = strtoul(argv[optind++], NULL, 0);
-	}
-
-	// Open and size the device
-	if ((fd = open(mtddevice, O_RDWR)) < 0) {
-		perror("Open flash device");
-		return 1;
-	}
-
-	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
-		perror("ioctl(MEMGETINFO)");
-		close(fd);
-		return 1;
-	}
-
-	switch (meminfo.erasesize) {
-		case 0x1000:
-		case 0x2000:
-		case 0x4000:
-		case 0x8000:
-			break;
-		default:
-			printf("Unrecognized Erase size, 0x%x - I'm confused\n",
-					meminfo.erasesize);
-			close(fd);
-			return 1;
-	}
-	writebuf[0] = malloc(meminfo.erasesize * 5);
-	if (!writebuf[0]) {
-		printf("Malloc failed\n");
-		close(fd);
-		return 1;
-	}
-	writebuf[1] = writebuf[0] + meminfo.erasesize;
-	writebuf[2] = writebuf[1] + meminfo.erasesize;
-	writebuf[3] = writebuf[2] + meminfo.erasesize;
-	readbuf = writebuf[3] + meminfo.erasesize;
-	memset(writebuf[0], 0xff, meminfo.erasesize);
-	memset(writebuf[1], 0x00, meminfo.erasesize);
-	memset(writebuf[2], 0x5a, meminfo.erasesize);
-	memset(writebuf[3], 0xa5, meminfo.erasesize);
-	memset(BadUnitTable, ZONE_GOOD, MAX_ERASE_ZONES);
-
-	if (part_size == 0 || (part_size > meminfo.size - startofs))
-		/* the user doest not or incorrectly specify NFTL partition size */
-		part_size = meminfo.size - startofs;
-
-	erase.length = meminfo.erasesize;
-	ezones = part_size / meminfo.erasesize;
-
-	if (ezones > MAX_ERASE_ZONES) {
-		/* Ought to change the UnitSizeFactor. But later. */
-		part_size = meminfo.erasesize * MAX_ERASE_ZONES;
-		ezones = MAX_ERASE_ZONES;
-		unit_factor = 0xFF;
-	}
-
-	/* If using device BBT then parse that now */
-	if (do_bbt) {
-		checkbbt();
-		do_oobcheck = 0;
-		do_rwecheck = 0;
-	}
-
-	/* Phase 1. Erasing and checking each erase zones in the NFTL partition.
-	   N.B. Erase Zones not used by the NFTL partition are untouched and marked ZONE_GOOD */
-	printf("Phase 1. Checking and erasing Erase Zones from 0x%08lx to 0x%08lx\n",
-			startofs, startofs + part_size);
-	for (ezone = startofs / meminfo.erasesize;
-			ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
-		if (BadUnitTable[ezone] != ZONE_GOOD)
-			continue;
-		if ((BadUnitTable[ezone] = erase_block(ezone)) == ZONE_GOOD) {
-			if (MediaUnit1 == -1) {
-				MediaUnit1 = ezone;
-			} else if (MediaUnit2 == -1) {
-				MediaUnit2 = ezone;
-			}
-		} else {
-			bad_zones++;
-		}
-	}
-	printf("\n");
-
-	/* N.B. from dump of M-System original chips, NumEraseUnits counts the 2 Erase Unit used
-	   by MediaHeader and the FirstPhysicalEUN starts from the MediaHeader */
-	if (do_inftl) {
-		unsigned long maxzones, pezstart, pezend, numvunits;
-
-		INFTLhdr = (struct INFTLMediaHeader *) (writebuf[0]);
-		strcpy(INFTLhdr->bootRecordID, "BNAND");
-		INFTLhdr->NoOfBootImageBlocks = cpu_to_le32(0);
-		INFTLhdr->NoOfBinaryPartitions = cpu_to_le32(0);
-		INFTLhdr->NoOfBDTLPartitions = cpu_to_le32(1);
-		INFTLhdr->BlockMultiplierBits = cpu_to_le32(0);
-		INFTLhdr->FormatFlags = cpu_to_le32(0);
-		INFTLhdr->OsakVersion = cpu_to_le32(OSAK_VERSION);
-		INFTLhdr->PercentUsed = cpu_to_le32(PERCENTUSED);
-		/*
-		 * Calculate number of virtual units we will have to work
-		 * with. I am calculating out the known bad units here, not
-		 * sure if that is what M-Systems do...
-		 */
-		MediaUnit2 = MediaUnit1;
-		MediaUnitOff2 = 4096;
-		maxzones = meminfo.size / meminfo.erasesize;
-		pezstart = startofs / meminfo.erasesize + 1;
-		pezend = startofs / meminfo.erasesize + ezones - 1;
-		numvunits = (ezones - 2) * PERCENTUSED / 100;
-		for (ezone = pezstart; ezone < maxzones; ezone++) {
-			if (BadUnitTable[ezone] != ZONE_GOOD) {
-				if (numvunits > 1)
-					numvunits--;
-			}
-		}
-
-		INFTLhdr->Partitions[0].virtualUnits = cpu_to_le32(numvunits);
-		INFTLhdr->Partitions[0].firstUnit = cpu_to_le32(pezstart);
-		INFTLhdr->Partitions[0].lastUnit = cpu_to_le32(pezend);
-		INFTLhdr->Partitions[0].flags = cpu_to_le32(INFTL_BDTL);
-		INFTLhdr->Partitions[0].spareUnits = cpu_to_le32(0);
-		INFTLhdr->Partitions[0].Reserved0 = INFTLhdr->Partitions[0].firstUnit;
-		INFTLhdr->Partitions[0].Reserved1 = cpu_to_le32(0);
-
-	} else {
-
-		NFTLhdr = (struct NFTLMediaHeader *) (writebuf[0]);
-		strcpy(NFTLhdr->DataOrgID, "ANAND");
-		NFTLhdr->NumEraseUnits = cpu_to_le16(part_size / meminfo.erasesize);
-		NFTLhdr->FirstPhysicalEUN = cpu_to_le16(MediaUnit1);
-		/* N.B. we reserve 2 more Erase Units for "folding" of Virtual Unit Chain */
-		NFTLhdr->FormattedSize = cpu_to_le32(part_size - ( (5+bad_zones) * meminfo.erasesize));
-		NFTLhdr->UnitSizeFactor = unit_factor;
-	}
-
-	/* Phase 2. Writing NFTL Media Headers and Bad Unit Table */
-	printf("Phase 2.a Writing %s Media Header and Bad Unit Table\n", nftl);
-	pwrite(fd, writebuf[0], 512, MediaUnit1 * meminfo.erasesize + MediaUnitOff1);
-	for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
-		pwrite(fd, BadUnitTable + ezone, 512,
-				(MediaUnit1 * meminfo.erasesize) + 512 * (1 + ezone / 512));
-	}
-
-#if 0
-	printf("  MediaHeader contents:\n");
-	printf("    NumEraseUnits: %d\n", le16_to_cpu(NFTLhdr->NumEraseUnits));
-	printf("    FirstPhysicalEUN: %d\n", le16_to_cpu(NFTLhdr->FirstPhysicalEUN));
-	printf("    FormattedSize: %d (%d sectors)\n", le32_to_cpu(NFTLhdr->FormattedSize),
-			le32_to_cpu(NFTLhdr->FormattedSize)/512);
-#endif
-	printf("Phase 2.b Writing Spare %s Media Header and Spare Bad Unit Table\n", nftl);
-	pwrite(fd, writebuf[0], 512, MediaUnit2 * meminfo.erasesize + MediaUnitOff2);
-	for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
-		pwrite(fd, BadUnitTable + ezone, 512,
-				(MediaUnit2 * meminfo.erasesize + MediaUnitOff2) + 512 * (1 + ezone / 512));
-	}
-
-	/* UCI #1 for newly erased Erase Unit */
-	memset(oobbuf, 0xff, 16);
-	oobbuf[11] = oobbuf[10] = oobbuf[9] = 0;
-	oobbuf[8]  = (do_inftl) ? 0x00 : 0x03;
-	oobbuf[12] = oobbuf[14] = 0x69;
-	oobbuf[13] = oobbuf[15] = 0x3c;
-
-	/* N.B. The Media Header and Bad Erase Unit Table are considered as Free Erase Unit
-	   by M-System i.e. their Virtual Unit Number == 0xFFFF in the Unit Control Information #0,
-	   but their Block Status is BLOCK_USED (0x5555) in their Block Control Information */
-	/* Phase 3. Writing Unit Control Information for each Erase Unit */
-	printf("Phase 3. Writing Unit Control Information to each Erase Unit\n");
-	for (ezone = MediaUnit1; ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
-		/* write UCI #1 to each Erase Unit */
-		if (BadUnitTable[ezone] != ZONE_GOOD)
-			continue;
-		oob.start = (ezone * meminfo.erasesize) + 512 + (do_inftl * 512);
-		if (ioctl(fd, MEMWRITEOOB, &oob))
-			printf("MEMWRITEOOB at %lx: %s\n", (unsigned long)oob.start, strerror(errno));
-	}
-
-	exit(0);
-}
diff --git a/nftldump.c b/nftldump.c
deleted file mode 100644
index 32f4f2f..0000000
--- a/nftldump.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * nftldump.c: Dumping the content of NFTL partitions on a "Physical Disk"
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * 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
- *
- * ToDo:
- *	1. UnitSizeFactor != 0xFF cases
- *	2. test, test, and test !!!
- */
-
-#define PROGRAM_NAME "nftldump"
-
-#define _XOPEN_SOURCE 500 /* For pread */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#include <sys/ioctl.h>
-#include <asm/types.h>
-#include <mtd/mtd-user.h>
-#include <mtd/nftl-user.h>
-#include <mtd_swab.h>
-
-static struct NFTLMediaHeader MedHead[2];
-static mtd_info_t meminfo;
-
-static struct nftl_oob oobbuf;
-static struct mtd_oob_buf oob = {0, 16, (unsigned char *)&oobbuf};
-
-static int fd, ofd = -1;;
-static int NumMedHeads;
-
-static unsigned char BadUnitTable[MAX_ERASE_ZONES];
-
-#define SWAP16(x) do { x = le16_to_cpu(x); } while(0)
-#define SWAP32(x) do { x = le32_to_cpu(x); } while(0)
-
-/* VUCtable, store the Erase Unit Number of the first Erase Unit in the chain */
-static unsigned short *VUCtable;
-
-/* FixMe: make this dynamic allocated */
-#define ERASESIZE 0x2000
-#define NUMVUNITS ((40*1024*1024) / ERASESIZE)
-static union nftl_uci UCItable[NUMVUNITS][3];
-
-static unsigned short nextEUN(unsigned short curEUN)
-{
-	return UCItable[curEUN][0].a.ReplUnitNum;
-}
-
-static unsigned int find_media_headers(void)
-{
-	int i;
-	static unsigned long ofs = 0;
-
-	NumMedHeads = 0;
-	while (ofs < meminfo.size) {
-		pread(fd, &MedHead[NumMedHeads], sizeof(struct NFTLMediaHeader), ofs);
-		if (!strncmp(MedHead[NumMedHeads].DataOrgID, "ANAND", 6)) {
-			SWAP16(MedHead[NumMedHeads].NumEraseUnits);
-			SWAP16(MedHead[NumMedHeads].FirstPhysicalEUN);
-			SWAP32(MedHead[NumMedHeads].FormattedSize);
-
-			if (NumMedHeads == 0) {
-				printf("NFTL Media Header found at offset 0x%08lx:\n", ofs);
-				printf("NumEraseUnits:    %d\n",
-						MedHead[NumMedHeads].NumEraseUnits);
-				printf("FirstPhysicalEUN: %d\n",
-						MedHead[NumMedHeads].FirstPhysicalEUN);
-				printf("Formatted Size:   %d\n",
-						MedHead[NumMedHeads].FormattedSize);
-				printf("UnitSizeFactor:   0x%x\n",
-						MedHead[NumMedHeads].UnitSizeFactor);
-
-				/* read BadUnitTable, I don't know why pread() does not work for
-				   larger (7680 bytes) chunks */
-				for (i = 0; i < MAX_ERASE_ZONES; i += 512)
-					pread(fd, &BadUnitTable[i], 512, ofs + 512 + i);
-			} else
-				printf("Second NFTL Media Header found at offset 0x%08lx\n",ofs);
-			NumMedHeads++;
-		}
-
-		ofs += meminfo.erasesize;
-		if (NumMedHeads == 2) {
-			if (strncmp((char *)&MedHead[0], (char *)&MedHead[1], sizeof(struct NFTLMediaHeader)) != 0) {
-				printf("warning: NFTL Media Header is not consistent with "
-						"Spare NFTL Media Header\n");
-			}
-			break;
-		}
-	}
-
-	/* allocate Virtual Unit Chain table for this NFTL partition */
-	VUCtable = calloc(MedHead[0].NumEraseUnits, sizeof(unsigned short));
-	return NumMedHeads;
-}
-
-static void dump_erase_units(void)
-{
-	int i, j;
-	unsigned long ofs;
-
-	for (i = MedHead[0].FirstPhysicalEUN; i < MedHead[0].FirstPhysicalEUN +
-			MedHead[0].NumEraseUnits; i++) {
-		/* For each Erase Unit */
-		ofs = i * meminfo.erasesize;
-
-		/* read the Unit Control Information */
-		for (j = 0; j < 3; j++) {
-			oob.start = ofs + (j * 512);
-			if (ioctl(fd, MEMREADOOB, &oob))
-				printf("MEMREADOOB at %lx: %s\n",
-						(unsigned long) oob.start, strerror(errno));
-			memcpy(&UCItable[i][j], &oobbuf.u, 8);
-		}
-		if (UCItable[i][1].b.EraseMark != cpu_to_le16(0x3c69)) {
-			printf("EraseMark not present in unit %d: %x\n",
-					i, UCItable[i][1].b.EraseMark);
-		} else {
-			/* a properly formatted unit */
-			SWAP16(UCItable[i][0].a.VirtUnitNum);
-			SWAP16(UCItable[i][0].a.ReplUnitNum);
-			SWAP16(UCItable[i][0].a.SpareVirtUnitNum);
-			SWAP16(UCItable[i][0].a.SpareReplUnitNum);
-			SWAP32(UCItable[i][1].b.WearInfo);
-			SWAP16(UCItable[i][1].b.EraseMark);
-			SWAP16(UCItable[i][1].b.EraseMark1);
-			SWAP16(UCItable[i][2].c.FoldMark);
-			SWAP16(UCItable[i][2].c.FoldMark1);
-
-			if (!(UCItable[i][0].a.VirtUnitNum & 0x8000)) {
-				/* If this is the first in a chain, store the EUN in the VUC table */
-				if (VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]) {
-					printf("Duplicate start of chain for VUC %d: "
-							"Unit %d replaces Unit %d\n",
-							UCItable[i][0].a.VirtUnitNum & 0x7fff,
-							i, VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]);
-				}
-				VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff] = i;
-			}
-		}
-
-		switch (BadUnitTable[i]) {
-			case ZONE_BAD_ORIGINAL:
-				printf("Unit %d is marked as ZONE_BAD_ORIGINAL\n", i);
-				continue;
-			case ZONE_BAD_MARKED:
-				printf("Unit %d is marked as ZONE_BAD_MARKED\n", i);
-				continue;
-		}
-
-		/* ZONE_GOOD */
-		if (UCItable[i][0].a.VirtUnitNum == 0xffff)
-			printf("Unit %d is free\n", i);
-		else
-			printf("Unit %d is in chain %d and %s a replacement\n", i,
-					UCItable[i][0].a.VirtUnitNum & 0x7fff,
-					UCItable[i][0].a.VirtUnitNum & 0x8000 ? "is" : "is not");
-	}
-}
-
-static void dump_virtual_units(void)
-{
-	int i, j;
-	char readbuf[512];
-
-	for (i = 0; i < (MedHead[0].FormattedSize / meminfo.erasesize); i++) {
-		unsigned short curEUN = VUCtable[i];
-
-		printf("Virtual Unit #%d: ", i);
-		if (!curEUN) {
-			printf("Not present\n");
-			continue;
-		}
-		printf("%d", curEUN);
-
-		/* walk through the Virtual Unit Chain */
-		while ((curEUN = nextEUN(curEUN)) != 0xffff) {
-			printf(", %d", curEUN & 0x7fff);
-		}
-		printf("\n");
-
-		if (ofd != -1) {
-			/* Actually write out the data */
-			for (j = 0; j < meminfo.erasesize / 512; j++) {
-				/* For each sector in the block */
-				unsigned short lastgoodEUN = 0xffff, thisEUN = VUCtable[i];
-				unsigned int status;
-
-				if (thisEUN == 0xffff) thisEUN = 0;
-
-				while (thisEUN && (thisEUN & 0x7fff) != 0x7fff) {
-					oob.start = (thisEUN * ERASESIZE) + (j * 512);
-					ioctl(fd, MEMREADOOB, &oob);
-					status = oobbuf.b.Status | oobbuf.b.Status1;
-
-					switch (status) {
-						case SECTOR_FREE:
-							/* This is still free. Don't look any more */
-							thisEUN = 0;
-							break;
-
-						case SECTOR_USED:
-							/* SECTOR_USED. This is a good one. */
-							lastgoodEUN = thisEUN;
-							break;
-					}
-
-					/* Find the next erase unit in this chain, if any */
-					if (thisEUN)
-						thisEUN = nextEUN(thisEUN) & 0x7fff;
-				}
-
-				if (lastgoodEUN == 0xffff)
-					memset(readbuf, 0, 512);
-				else
-					pread(fd, readbuf, 512,
-							(lastgoodEUN * ERASESIZE) + (j * 512));
-
-				write(ofd, readbuf, 512);
-			}
-
-		}
-	}
-}
-
-int main(int argc, char **argv)
-{
-	if (argc < 2) {
-		printf("Usage: %s <device> [<outfile>]\n", PROGRAM_NAME);
-		exit(1);
-	}
-	fd = open(argv[1], O_RDONLY);
-	if (fd == -1) {
-		perror("open flash");
-		exit (1);
-	}
-
-	if (argc > 2) {
-		ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644);
-		if (ofd == -1)
-			perror ("open outfile");
-	}
-
-	/* get size information of the MTD device */
-	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
-		perror("ioctl(MEMGETINFO)");
-		close(fd);
-		return 1;
-	}
-
-	while (find_media_headers() != 0) {
-		dump_erase_units();
-		dump_virtual_units();
-		free(VUCtable);
-	}
-
-	exit(0);
-}
diff --git a/nor-utils/rfddump.c b/nor-utils/rfddump.c
new file mode 100644
index 0000000..0375bac
--- /dev/null
+++ b/nor-utils/rfddump.c
@@ -0,0 +1,337 @@
+/*
+ * rfddump.c
+ *
+ * Copyright (C) 2005 Sean Young <sean at mess.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; either version 2 of the License, or
+ *  (at your option) any later version.
+ */
+
+#define PROGRAM_NAME "rfddump"
+#define VERSION "$Revision 1.0 $"
+
+#define _XOPEN_SOURCE 500 /* For pread */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include <mtd/mtd-user.h>
+#include <linux/types.h>
+#include <mtd_swab.h>
+
+/* next is an array of mapping for each corresponding sector */
+#define RFD_MAGIC		0x9193
+#define HEADER_MAP_OFFSET       3
+#define SECTOR_DELETED          0x0000
+#define SECTOR_ZERO             0xfffe
+#define SECTOR_FREE             0xffff
+
+#define SECTOR_SIZE             512
+
+#define SECTORS_PER_TRACK	63
+
+
+struct rfd {
+	int block_size;
+	int block_count;
+	int header_sectors;
+	int data_sectors;
+	int header_size;
+	uint16_t *header;
+	int sector_count;
+	int *sector_map;
+	const char *mtd_filename;
+	const char *out_filename;
+	int verbose;
+};
+
+void display_help(void)
+{
+	printf("Usage: %s [OPTIONS] MTD-device filename\n"
+			"Dumps the contents of a resident flash disk\n"
+			"\n"
+			"-h         --help               display this help and exit\n"
+			"-V         --version            output version information and exit\n"
+			"-v         --verbose		Be verbose\n"
+			"-b size    --blocksize          Block size (defaults to erase unit)\n",
+			PROGRAM_NAME);
+	exit(0);
+}
+
+void display_version(void)
+{
+	printf("%s " VERSION "\n"
+			"\n"
+			"This is free software; see the source for copying conditions.  There is NO\n"
+			"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
+			PROGRAM_NAME);
+
+	exit(0);
+}
+
+void process_options(int argc, char *argv[], struct rfd *rfd)
+{
+	int error = 0;
+
+	rfd->block_size = 0;
+	rfd->verbose = 0;
+
+	for (;;) {
+		int option_index = 0;
+		static const char *short_options = "hvVb:";
+		static const struct option long_options[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ "version", no_argument, 0, 'V', },
+			{ "blocksize", required_argument, 0, 'b' },
+			{ "verbose", no_argument, 0, 'v' },
+			{ NULL, 0, 0, 0 }
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+			case 'h':
+				display_help();
+				break;
+			case 'V':
+				display_version();
+				break;
+			case 'v':
+				rfd->verbose = 1;
+				break;
+			case 'b':
+				rfd->block_size = atoi(optarg);
+				break;
+			case '?':
+				error = 1;
+				break;
+		}
+	}
+
+	if ((argc - optind) != 2 || error)
+		display_help();
+
+	rfd->mtd_filename = argv[optind];
+	rfd->out_filename = argv[optind + 1];
+}
+
+int build_block_map(struct rfd *rfd, int fd, int block)
+{
+	int  i;
+	int sectors;
+
+	if (pread(fd, rfd->header, rfd->header_size, block * rfd->block_size)
+			!= rfd->header_size) {
+		return -1;
+	}
+
+	if (le16_to_cpu(rfd->header[0]) != RFD_MAGIC) {
+		if (rfd->verbose)
+			printf("Block #%02d: Magic missing\n", block);
+
+		return 0;
+	}
+
+	sectors =  0;
+	for (i=0; i<rfd->data_sectors; i++) {
+		uint16_t entry = le16_to_cpu(rfd->header[i + HEADER_MAP_OFFSET]);
+
+		if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
+			continue;
+
+		if (entry == SECTOR_ZERO)
+			entry = 0;
+
+		if (entry >= rfd->sector_count) {
+			fprintf(stderr, "%s: warning: sector %d out of range\n",
+					rfd->mtd_filename, entry);
+			continue;
+		}
+
+		if (rfd->sector_map[entry] != -1) {
+			fprintf(stderr, "%s: warning: more than one entry "
+					"for sector %d\n", rfd->mtd_filename, entry);
+			continue;
+		}
+
+		rfd->sector_map[entry] = rfd->block_size * block +
+			(i + rfd->header_sectors) * SECTOR_SIZE;
+		sectors++;
+	}
+
+	if (rfd->verbose)
+		printf("Block #%02d: %d sectors\n", block, sectors);
+
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	int fd, sectors_per_block;
+	mtd_info_t mtd_info;
+	struct rfd rfd;
+	int i, blocks_found;
+	int out_fd = 0;
+	uint8_t sector[512];
+	int blank, rc, cylinders;
+
+	process_options(argc, argv, &rfd);
+
+	fd = open(rfd.mtd_filename, O_RDONLY);
+	if (fd == -1) {
+		perror(rfd.mtd_filename);
+		return 1;
+	}
+
+	if (rfd.block_size == 0) {
+		if (ioctl(fd, MEMGETINFO, &mtd_info)) {
+			perror(rfd.mtd_filename);
+			close(fd);
+			return 1;
+		}
+
+		if (mtd_info.type != MTD_NORFLASH) {
+			fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename);
+			close(fd);
+			return 2;
+		}
+
+		sectors_per_block = mtd_info.erasesize / SECTOR_SIZE;
+
+		rfd.block_size = mtd_info.erasesize;
+		rfd.block_count = mtd_info.size / mtd_info.erasesize;
+	} else {
+		struct stat st;
+
+		if (fstat(fd, &st) == -1) {
+			perror(rfd.mtd_filename);
+			close(fd);
+			return 1;
+		}
+
+		if (st.st_size % SECTOR_SIZE)
+			fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename);
+
+		sectors_per_block = rfd.block_size / SECTOR_SIZE;
+
+		if (st.st_size % rfd.block_size)
+			fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename);
+
+		rfd.block_count = st.st_size / rfd.block_size;
+
+		if (!rfd.block_count) {
+			fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename);
+			close(fd);
+			return 2;
+		}
+	}
+
+	rfd.header_sectors =
+		((HEADER_MAP_OFFSET + sectors_per_block) *
+		 sizeof(uint16_t) + SECTOR_SIZE - 1) / SECTOR_SIZE;
+	rfd.data_sectors = sectors_per_block - rfd.header_sectors;
+	cylinders = ((rfd.block_count - 1) * rfd.data_sectors - 1)
+		/ SECTORS_PER_TRACK;
+	rfd.sector_count = cylinders * SECTORS_PER_TRACK;
+	rfd.header_size =
+		(HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t);
+
+	rfd.header = malloc(rfd.header_size);
+	if (!rfd.header) {
+		perror(PROGRAM_NAME);
+		close(fd);
+		return 2;
+	}
+	rfd.sector_map = malloc(rfd.sector_count * sizeof(int));
+	if (!rfd.sector_map) {
+		perror(PROGRAM_NAME);
+		close(fd);
+		free(rfd.sector_map);
+		return 2;
+	}
+
+	rfd.mtd_filename = rfd.mtd_filename;
+
+	for (i=0; i<rfd.sector_count; i++)
+		rfd.sector_map[i] = -1;
+
+	for (blocks_found=i=0; i<rfd.block_count; i++) {
+		rc = build_block_map(&rfd, fd, i);
+		if (rc > 0)
+			blocks_found++;
+		if (rc < 0)
+			goto err;
+	}
+
+	if (!blocks_found) {
+		fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename);
+		goto err;
+	}
+
+	for (i=0; i<rfd.sector_count; i++) {
+		if (rfd.sector_map[i] != -1)
+			break;
+	}
+
+	if (i == rfd.sector_count) {
+		fprintf(stderr, "%s: no sectors found\n", rfd.mtd_filename);
+		goto err;
+	}
+
+	out_fd = open(rfd.out_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+	if (out_fd == -1) {
+		perror(rfd.out_filename);
+		goto err;
+	}
+
+	blank = 0;
+	for (i=0; i<rfd.sector_count; i++) {
+		if (rfd.sector_map[i] == -1) {
+			memset(sector, 0, SECTOR_SIZE);
+			blank++;
+		} else {
+			if (pread(fd, sector, SECTOR_SIZE, rfd.sector_map[i])
+					!= SECTOR_SIZE) {
+				perror(rfd.mtd_filename);
+				goto err;
+			}
+		}
+
+		if (write(out_fd, sector, SECTOR_SIZE) != SECTOR_SIZE) {
+			perror(rfd.out_filename);
+			goto err;
+		}
+	}
+
+	if (rfd.verbose)
+		printf("Copied %d sectors (%d blank)\n", rfd.sector_count, blank);
+
+	close(out_fd);
+	close(fd);
+	free(rfd.header);
+	free(rfd.sector_map);
+
+	return 0;
+
+err:
+	if (out_fd)
+		close(out_fd);
+
+	close(fd);
+	free(rfd.header);
+	free(rfd.sector_map);
+
+	return 2;
+}
diff --git a/nor-utils/rfdformat.c b/nor-utils/rfdformat.c
new file mode 100644
index 0000000..17d9d2d
--- /dev/null
+++ b/nor-utils/rfdformat.c
@@ -0,0 +1,160 @@
+/*
+ * rfdformat.c
+ *
+ * Copyright (C) 2005 Sean Young <sean at mess.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is very easy: just erase all the blocks and put the magic at
+ * the beginning of each block.
+ */
+
+#define PROGRAM_NAME "rfdformat"
+#define VERSION "$Revision 1.0 $"
+
+#define _XOPEN_SOURCE 500 /* For pread/pwrite */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include <mtd/mtd-user.h>
+#include <linux/types.h>
+
+void display_help(void)
+{
+	printf("Usage: %s [OPTIONS] MTD-device\n"
+			"Formats NOR flash for resident flash disk\n"
+			"\n"
+			"-h         --help               display this help and exit\n"
+			"-V         --version            output version information and exit\n",
+			PROGRAM_NAME);
+	exit(0);
+}
+
+void display_version(void)
+{
+	printf("%s " VERSION "\n"
+			"\n"
+			"This is free software; see the source for copying conditions.  There is NO\n"
+			"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
+			PROGRAM_NAME);
+
+	exit(0);
+}
+
+void process_options(int argc, char *argv[], const char **mtd_filename)
+{
+	int error = 0;
+
+	for (;;) {
+		int option_index = 0;
+		static const char *short_options = "hV";
+		static const struct option long_options[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ "version", no_argument, 0, 'V', },
+			{ NULL, 0, 0, 0 }
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+			case 'h':
+				display_help();
+				break;
+			case 'V':
+				display_version();
+				break;
+			case '?':
+				error = 1;
+				break;
+		}
+	}
+
+	if ((argc - optind) != 1 || error)
+		display_help();
+
+	*mtd_filename = argv[optind];
+}
+
+int main(int argc, char *argv[])
+{
+	static const uint8_t magic[] = { 0x93, 0x91 };
+	int fd, block_count, i;
+	struct mtd_info_user mtd_info;
+	char buf[512];
+	const char *mtd_filename;
+
+	process_options(argc, argv, &mtd_filename);
+
+	fd = open(mtd_filename, O_RDWR);
+	if (fd == -1) {
+		perror(mtd_filename);
+		return 1;
+	}
+
+	if (ioctl(fd, MEMGETINFO, &mtd_info)) {
+		perror(mtd_filename);
+		close(fd);
+		return 1;
+	}
+
+	if (mtd_info.type != MTD_NORFLASH) {
+		fprintf(stderr, "%s: not NOR flash\n", mtd_filename);
+		close(fd);
+		return 2;
+	}
+
+	if (mtd_info.size > 32*1024*1024) {
+		fprintf(stderr, "%s: flash larger than 32MiB not supported\n",
+				mtd_filename);
+		close(fd);
+		return 2;
+	}
+
+	block_count = mtd_info.size / mtd_info.erasesize;
+
+	if (block_count < 2) {
+		fprintf(stderr, "%s: at least two erase units required\n",
+				mtd_filename);
+		close(fd);
+		return 2;
+	}
+
+	for (i=0; i<block_count; i++) {
+		struct erase_info_user erase_info;
+
+		erase_info.start = i * mtd_info.erasesize;
+		erase_info.length = mtd_info.erasesize;
+
+		if (ioctl(fd, MEMERASE, &erase_info) != 0) {
+			snprintf(buf, sizeof(buf), "%s: erase", mtd_filename);
+			perror(buf);
+			close(fd);
+			return 2;
+		}
+
+		if (pwrite(fd, magic, sizeof(magic), i * mtd_info.erasesize)
+				!= sizeof(magic)) {
+			snprintf(buf, sizeof(buf), "%s: write", mtd_filename);
+			perror(buf);
+			close(fd);
+			return 2;
+		}
+	}
+
+	close(fd);
+
+	return 0;
+}
diff --git a/rbtree.c b/rbtree.c
deleted file mode 100644
index 329e098..0000000
--- a/rbtree.c
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
-  Red Black Trees
-  (C) 1999  Andrea Arcangeli <andrea at suse.de>
-  (C) 2002  David Woodhouse <dwmw2 at infradead.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; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  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
-
-  linux/lib/rbtree.c
-*/
-
-#include <stdlib.h>
-#include "rbtree.h"
-
-static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
-{
-	struct rb_node *right = node->rb_right;
-	struct rb_node *parent = rb_parent(node);
-
-	if ((node->rb_right = right->rb_left))
-		rb_set_parent(right->rb_left, node);
-	right->rb_left = node;
-
-	rb_set_parent(right, parent);
-
-	if (parent)
-	{
-		if (node == parent->rb_left)
-			parent->rb_left = right;
-		else
-			parent->rb_right = right;
-	}
-	else
-		root->rb_node = right;
-	rb_set_parent(node, right);
-}
-
-static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
-{
-	struct rb_node *left = node->rb_left;
-	struct rb_node *parent = rb_parent(node);
-
-	if ((node->rb_left = left->rb_right))
-		rb_set_parent(left->rb_right, node);
-	left->rb_right = node;
-
-	rb_set_parent(left, parent);
-
-	if (parent)
-	{
-		if (node == parent->rb_right)
-			parent->rb_right = left;
-		else
-			parent->rb_left = left;
-	}
-	else
-		root->rb_node = left;
-	rb_set_parent(node, left);
-}
-
-void rb_insert_color(struct rb_node *node, struct rb_root *root)
-{
-	struct rb_node *parent, *gparent;
-
-	while ((parent = rb_parent(node)) && rb_is_red(parent))
-	{
-		gparent = rb_parent(parent);
-
-		if (parent == gparent->rb_left)
-		{
-			{
-				register struct rb_node *uncle = gparent->rb_right;
-				if (uncle && rb_is_red(uncle))
-				{
-					rb_set_black(uncle);
-					rb_set_black(parent);
-					rb_set_red(gparent);
-					node = gparent;
-					continue;
-				}
-			}
-
-			if (parent->rb_right == node)
-			{
-				register struct rb_node *tmp;
-				__rb_rotate_left(parent, root);
-				tmp = parent;
-				parent = node;
-				node = tmp;
-			}
-
-			rb_set_black(parent);
-			rb_set_red(gparent);
-			__rb_rotate_right(gparent, root);
-		} else {
-			{
-				register struct rb_node *uncle = gparent->rb_left;
-				if (uncle && rb_is_red(uncle))
-				{
-					rb_set_black(uncle);
-					rb_set_black(parent);
-					rb_set_red(gparent);
-					node = gparent;
-					continue;
-				}
-			}
-
-			if (parent->rb_left == node)
-			{
-				register struct rb_node *tmp;
-				__rb_rotate_right(parent, root);
-				tmp = parent;
-				parent = node;
-				node = tmp;
-			}
-
-			rb_set_black(parent);
-			rb_set_red(gparent);
-			__rb_rotate_left(gparent, root);
-		}
-	}
-
-	rb_set_black(root->rb_node);
-}
-
-static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
-			     struct rb_root *root)
-{
-	struct rb_node *other;
-
-	while ((!node || rb_is_black(node)) && node != root->rb_node)
-	{
-		if (parent->rb_left == node)
-		{
-			other = parent->rb_right;
-			if (rb_is_red(other))
-			{
-				rb_set_black(other);
-				rb_set_red(parent);
-				__rb_rotate_left(parent, root);
-				other = parent->rb_right;
-			}
-			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
-			    (!other->rb_right || rb_is_black(other->rb_right)))
-			{
-				rb_set_red(other);
-				node = parent;
-				parent = rb_parent(node);
-			}
-			else
-			{
-				if (!other->rb_right || rb_is_black(other->rb_right))
-				{
-					struct rb_node *o_left;
-					if ((o_left = other->rb_left))
-						rb_set_black(o_left);
-					rb_set_red(other);
-					__rb_rotate_right(other, root);
-					other = parent->rb_right;
-				}
-				rb_set_color(other, rb_color(parent));
-				rb_set_black(parent);
-				if (other->rb_right)
-					rb_set_black(other->rb_right);
-				__rb_rotate_left(parent, root);
-				node = root->rb_node;
-				break;
-			}
-		}
-		else
-		{
-			other = parent->rb_left;
-			if (rb_is_red(other))
-			{
-				rb_set_black(other);
-				rb_set_red(parent);
-				__rb_rotate_right(parent, root);
-				other = parent->rb_left;
-			}
-			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
-			    (!other->rb_right || rb_is_black(other->rb_right)))
-			{
-				rb_set_red(other);
-				node = parent;
-				parent = rb_parent(node);
-			}
-			else
-			{
-				if (!other->rb_left || rb_is_black(other->rb_left))
-				{
-					register struct rb_node *o_right;
-					if ((o_right = other->rb_right))
-						rb_set_black(o_right);
-					rb_set_red(other);
-					__rb_rotate_left(other, root);
-					other = parent->rb_left;
-				}
-				rb_set_color(other, rb_color(parent));
-				rb_set_black(parent);
-				if (other->rb_left)
-					rb_set_black(other->rb_left);
-				__rb_rotate_right(parent, root);
-				node = root->rb_node;
-				break;
-			}
-		}
-	}
-	if (node)
-		rb_set_black(node);
-}
-
-void rb_erase(struct rb_node *node, struct rb_root *root)
-{
-	struct rb_node *child, *parent;
-	int color;
-
-	if (!node->rb_left)
-		child = node->rb_right;
-	else if (!node->rb_right)
-		child = node->rb_left;
-	else
-	{
-		struct rb_node *old = node, *left;
-
-		node = node->rb_right;
-		while ((left = node->rb_left) != NULL)
-			node = left;
-		child = node->rb_right;
-		parent = rb_parent(node);
-		color = rb_color(node);
-
-		if (child)
-			rb_set_parent(child, parent);
-		if (parent == old) {
-			parent->rb_right = child;
-			parent = node;
-		} else
-			parent->rb_left = child;
-
-		node->rb_parent_color = old->rb_parent_color;
-		node->rb_right = old->rb_right;
-		node->rb_left = old->rb_left;
-
-		if (rb_parent(old))
-		{
-			if (rb_parent(old)->rb_left == old)
-				rb_parent(old)->rb_left = node;
-			else
-				rb_parent(old)->rb_right = node;
-		} else
-			root->rb_node = node;
-
-		rb_set_parent(old->rb_left, node);
-		if (old->rb_right)
-			rb_set_parent(old->rb_right, node);
-		goto color;
-	}
-
-	parent = rb_parent(node);
-	color = rb_color(node);
-
-	if (child)
-		rb_set_parent(child, parent);
-	if (parent)
-	{
-		if (parent->rb_left == node)
-			parent->rb_left = child;
-		else
-			parent->rb_right = child;
-	}
-	else
-		root->rb_node = child;
-
- color:
-	if (color == RB_BLACK)
-		__rb_erase_color(child, parent, root);
-}
-
-/*
- * This function returns the first node (in sort order) of the tree.
- */
-struct rb_node *rb_first(struct rb_root *root)
-{
-	struct rb_node	*n;
-
-	n = root->rb_node;
-	if (!n)
-		return NULL;
-	while (n->rb_left)
-		n = n->rb_left;
-	return n;
-}
-
-struct rb_node *rb_last(struct rb_root *root)
-{
-	struct rb_node	*n;
-
-	n = root->rb_node;
-	if (!n)
-		return NULL;
-	while (n->rb_right)
-		n = n->rb_right;
-	return n;
-}
-
-struct rb_node *rb_next(struct rb_node *node)
-{
-	struct rb_node *parent;
-
-	if (rb_parent(node) == node)
-		return NULL;
-
-	/* If we have a right-hand child, go down and then left as far
-	   as we can. */
-	if (node->rb_right) {
-		node = node->rb_right;
-		while (node->rb_left)
-			node=node->rb_left;
-		return node;
-	}
-
-	/* No right-hand children.  Everything down and left is
-	   smaller than us, so any 'next' node must be in the general
-	   direction of our parent. Go up the tree; any time the
-	   ancestor is a right-hand child of its parent, keep going
-	   up. First time it's a left-hand child of its parent, said
-	   parent is our 'next' node. */
-	while ((parent = rb_parent(node)) && node == parent->rb_right)
-		node = parent;
-
-	return parent;
-}
-
-struct rb_node *rb_prev(struct rb_node *node)
-{
-	struct rb_node *parent;
-
-	if (rb_parent(node) == node)
-		return NULL;
-
-	/* If we have a left-hand child, go down and then right as far
-	   as we can. */
-	if (node->rb_left) {
-		node = node->rb_left;
-		while (node->rb_right)
-			node=node->rb_right;
-		return node;
-	}
-
-	/* No left-hand children. Go up till we find an ancestor which
-	   is a right-hand child of its parent */
-	while ((parent = rb_parent(node)) && node == parent->rb_left)
-		node = parent;
-
-	return parent;
-}
-
-void rb_replace_node(struct rb_node *victim, struct rb_node *new,
-		     struct rb_root *root)
-{
-	struct rb_node *parent = rb_parent(victim);
-
-	/* Set the surrounding nodes to point to the replacement */
-	if (parent) {
-		if (victim == parent->rb_left)
-			parent->rb_left = new;
-		else
-			parent->rb_right = new;
-	} else {
-		root->rb_node = new;
-	}
-	if (victim->rb_left)
-		rb_set_parent(victim->rb_left, new);
-	if (victim->rb_right)
-		rb_set_parent(victim->rb_right, new);
-
-	/* Copy the pointers/colour from the victim to the replacement */
-	*new = *victim;
-}
diff --git a/rbtree.h b/rbtree.h
deleted file mode 100644
index 0d77b65..0000000
--- a/rbtree.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
-  Red Black Trees
-  (C) 1999  Andrea Arcangeli <andrea at suse.de>
-
-  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; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  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
-
-  linux/include/linux/rbtree.h
-
-  To use rbtrees you'll have to implement your own insert and search cores.
-  This will avoid us to use callbacks and to drop drammatically performances.
-  I know it's not the cleaner way,  but in C (not in C++) to get
-  performances and genericity...
-
-  Some example of insert and search follows here. The search is a plain
-  normal search over an ordered tree. The insert instead must be implemented
-  int two steps: as first thing the code must insert the element in
-  order as a red leaf in the tree, then the support library function
-  rb_insert_color() must be called. Such function will do the
-  not trivial work to rebalance the rbtree if necessary.
-
------------------------------------------------------------------------
-static inline struct page * rb_search_page_cache(struct inode * inode,
-						 unsigned long offset)
-{
-	struct rb_node * n = inode->i_rb_page_cache.rb_node;
-	struct page * page;
-
-	while (n)
-	{
-		page = rb_entry(n, struct page, rb_page_cache);
-
-		if (offset < page->offset)
-			n = n->rb_left;
-		else if (offset > page->offset)
-			n = n->rb_right;
-		else
-			return page;
-	}
-	return NULL;
-}
-
-static inline struct page * __rb_insert_page_cache(struct inode * inode,
-						   unsigned long offset,
-						   struct rb_node * node)
-{
-	struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
-	struct rb_node * parent = NULL;
-	struct page * page;
-
-	while (*p)
-	{
-		parent = *p;
-		page = rb_entry(parent, struct page, rb_page_cache);
-
-		if (offset < page->offset)
-			p = &(*p)->rb_left;
-		else if (offset > page->offset)
-			p = &(*p)->rb_right;
-		else
-			return page;
-	}
-
-	rb_link_node(node, parent, p);
-
-	return NULL;
-}
-
-static inline struct page * rb_insert_page_cache(struct inode * inode,
-						 unsigned long offset,
-						 struct rb_node * node)
-{
-	struct page * ret;
-	if ((ret = __rb_insert_page_cache(inode, offset, node)))
-		goto out;
-	rb_insert_color(node, &inode->i_rb_page_cache);
- out:
-	return ret;
-}
------------------------------------------------------------------------
-*/
-
-#ifndef	_LINUX_RBTREE_H
-#define	_LINUX_RBTREE_H
-
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-
-struct rb_node
-{
-	unsigned long  rb_parent_color;
-#define	RB_RED		0
-#define	RB_BLACK	1
-	struct rb_node *rb_right;
-	struct rb_node *rb_left;
-} __attribute__((aligned(sizeof(long))));
-    /* The alignment might seem pointless, but allegedly CRIS needs it */
-
-struct rb_root
-{
-	struct rb_node *rb_node;
-};
-
-
-#define rb_parent(r)   ((struct rb_node *)((r)->rb_parent_color & ~3))
-#define rb_color(r)   ((r)->rb_parent_color & 1)
-#define rb_is_red(r)   (!rb_color(r))
-#define rb_is_black(r) rb_color(r)
-#define rb_set_red(r)  do { (r)->rb_parent_color &= ~1; } while (0)
-#define rb_set_black(r)  do { (r)->rb_parent_color |= 1; } while (0)
-
-static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
-{
-	rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
-}
-static inline void rb_set_color(struct rb_node *rb, int color)
-{
-	rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
-}
-
-#define RB_ROOT	(struct rb_root) { NULL, }
-
-/* Newer gcc versions take care of exporting this */
-#ifndef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-#endif
-
-#define container_of(ptr, type, member) ({                      \
-        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
-        (type *)( (char *)__mptr - offsetof(type,member) );})
-
-#define	rb_entry(ptr, type, member) container_of(ptr, type, member)
-
-#define RB_EMPTY_ROOT(root)	((root)->rb_node == NULL)
-#define RB_EMPTY_NODE(node)	(rb_parent(node) == node)
-#define RB_CLEAR_NODE(node)	(rb_set_parent(node, node))
-
-extern void rb_insert_color(struct rb_node *, struct rb_root *);
-extern void rb_erase(struct rb_node *, struct rb_root *);
-
-/* Find logical next and previous nodes in a tree */
-extern struct rb_node *rb_next(struct rb_node *);
-extern struct rb_node *rb_prev(struct rb_node *);
-extern struct rb_node *rb_first(struct rb_root *);
-extern struct rb_node *rb_last(struct rb_root *);
-
-/* Fast replacement of a single node without remove/rebalance/add/rebalance */
-extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
-			    struct rb_root *root);
-
-static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
-				struct rb_node ** rb_link)
-{
-	node->rb_parent_color = (unsigned long )parent;
-	node->rb_left = node->rb_right = NULL;
-
-	*rb_link = node;
-}
-
-#endif	/* _LINUX_RBTREE_H */
diff --git a/recv_image.c b/recv_image.c
deleted file mode 100644
index 0093831..0000000
--- a/recv_image.c
+++ /dev/null
@@ -1,484 +0,0 @@
-
-#define PROGRAM_NAME "recv_image"
-#define _XOPEN_SOURCE 500
-#define _BSD_SOURCE	/* struct ip_mreq */
-
-#include <errno.h>
-#include <stdio.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <crc32.h>
-#include "mtd/mtd-user.h"
-#include "mcast_image.h"
-
-#include "common.h"
-
-#define WBUF_SIZE 4096
-struct eraseblock {
-	uint32_t flash_offset;
-	unsigned char wbuf[WBUF_SIZE];
-	int wbuf_ofs;
-	int nr_pkts;
-	int *pkt_indices;
-	uint32_t crc;
-};
-
-int main(int argc, char **argv)
-{
-	struct addrinfo *ai;
-	struct addrinfo hints;
-	struct addrinfo *runp;
-	int ret;
-	int sock;
-	ssize_t len;
-	int flfd;
-	struct mtd_info_user meminfo;
-	unsigned char *eb_buf, *decode_buf, **src_pkts;
-	int nr_blocks = 0;
-	int pkts_per_block;
-	int block_nr = -1;
-	uint32_t image_crc = 0;
-	int total_pkts = 0;
-	int ignored_pkts = 0;
-	loff_t mtdoffset = 0;
-	int badcrcs = 0;
-	int duplicates = 0;
-	int file_mode = 0;
-	struct fec_parms *fec = NULL;
-	int i;
-	struct eraseblock *eraseblocks = NULL;
-	uint32_t start_seq = 0;
-	struct timeval start, now;
-	unsigned long fec_time = 0, flash_time = 0, crc_time = 0,
-		rflash_time = 0, erase_time = 0, net_time = 0;
-
-	if (argc != 4) {
-		fprintf(stderr, "usage: %s <host> <port> <mtddev>\n",
-			PROGRAM_NAME);
-		exit(1);
-	}
-	/* Open the device */
-	flfd = open(argv[3], O_RDWR);
-
-	if (flfd >= 0) {
-		/* Fill in MTD device capability structure */
-		if (ioctl(flfd, MEMGETINFO, &meminfo) != 0) {
-			perror("MEMGETINFO");
-			close(flfd);
-			flfd = -1;
-		} else {
-			printf("Receive to MTD device %s with erasesize %d\n",
-			       argv[3], meminfo.erasesize);
-		}
-	}
-	if (flfd == -1) {
-		/* Try again, as if it's a file */
-		flfd = open(argv[3], O_CREAT|O_TRUNC|O_RDWR, 0644);
-		if (flfd < 0) {
-			perror("open");
-			exit(1);
-		}
-		meminfo.erasesize = 131072;
-		file_mode = 1;
-		printf("Receive to file %s with (assumed) erasesize %d\n",
-		       argv[3], meminfo.erasesize);
-	}
-
-	pkts_per_block = (meminfo.erasesize + PKT_SIZE - 1) / PKT_SIZE;
-
-	eb_buf = malloc(pkts_per_block * PKT_SIZE);
-	decode_buf = malloc(pkts_per_block * PKT_SIZE);
-	if (!eb_buf && !decode_buf) {
-		fprintf(stderr, "No memory for eraseblock buffer\n");
-		exit(1);
-	}
-	src_pkts = malloc(sizeof(unsigned char *) * pkts_per_block);
-	if (!src_pkts) {
-		fprintf(stderr, "No memory for decode packet pointers\n");
-		exit(1);
-	}
-
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_flags = AI_ADDRCONFIG;
-	hints.ai_socktype = SOCK_DGRAM;
-
-	ret = getaddrinfo(argv[1], argv[2], &hints, &ai);
-	if (ret) {
-		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
-		exit(1);
-	}
-	runp = ai;
-	for (runp = ai; runp; runp = runp->ai_next) {
-		sock = socket(runp->ai_family, runp->ai_socktype,
-			      runp->ai_protocol);
-		if (sock == -1) {
-			perror("socket");
-			continue;
-		}
-		if (runp->ai_family == AF_INET &&
-		    IN_MULTICAST( ntohl(((struct sockaddr_in *)runp->ai_addr)->sin_addr.s_addr))) {
-			struct ip_mreq rq;
-			rq.imr_multiaddr = ((struct sockaddr_in *)runp->ai_addr)->sin_addr;
-			rq.imr_interface.s_addr = INADDR_ANY;
-			if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &rq, sizeof(rq))) {
-				perror("IP_ADD_MEMBERSHIP");
-				close(sock);
-				continue;
-			}
-
-		} else if (runp->ai_family == AF_INET6 &&
-			   ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr.s6_addr[0] == 0xff) {
-			struct ipv6_mreq rq;
-			rq.ipv6mr_multiaddr =  ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr;
-			rq.ipv6mr_interface = 0;
-			if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &rq, sizeof(rq))) {
-				perror("IPV6_ADD_MEMBERSHIP");
-				close(sock);
-				continue;
-			}
-		}
-		if (bind(sock, runp->ai_addr, runp->ai_addrlen)) {
-			perror("bind");
-			close(sock);
-			continue;
-		}
-		break;
-	}
-	if (!runp)
-		exit(1);
-
-	while (1) {
-		struct image_pkt thispkt;
-
-		len = read(sock, &thispkt, sizeof(thispkt));
-
-		if (len < 0) {
-			perror("read socket");
-			break;
-		}
-		if (len < sizeof(thispkt)) {
-			fprintf(stderr, "Wrong length %zd bytes (expected %zu)\n",
-				len, sizeof(thispkt));
-			continue;
-		}
-		if (!eraseblocks) {
-			image_crc = thispkt.hdr.totcrc;
-			start_seq = ntohl(thispkt.hdr.pkt_sequence);
-
-			if (meminfo.erasesize != ntohl(thispkt.hdr.blocksize)) {
-				fprintf(stderr, "Erasesize mismatch (0x%x not 0x%x)\n",
-					ntohl(thispkt.hdr.blocksize), meminfo.erasesize);
-				exit(1);
-			}
-			nr_blocks = ntohl(thispkt.hdr.nr_blocks);
-
-			fec = fec_new(pkts_per_block, ntohs(thispkt.hdr.nr_pkts));
-
-			eraseblocks = malloc(nr_blocks * sizeof(*eraseblocks));
-			if (!eraseblocks) {
-				fprintf(stderr, "No memory for block map\n");
-				exit(1);
-			}
-			for (i = 0; i < nr_blocks; i++) {
-				eraseblocks[i].pkt_indices = malloc(sizeof(int) * pkts_per_block);
-				if (!eraseblocks[i].pkt_indices) {
-					fprintf(stderr, "Failed to allocate packet indices\n");
-					exit(1);
-				}
-				eraseblocks[i].nr_pkts = 0;
-				if (!file_mode) {
-					if (mtdoffset >= meminfo.size) {
-						fprintf(stderr, "Run out of space on flash\n");
-						exit(1);
-					}
-#if 1 /* Deliberately use bad blocks... test write failures */
-					while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
-						printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
-						mtdoffset += meminfo.erasesize;
-					}
-#endif
-				}
-				eraseblocks[i].flash_offset = mtdoffset;
-				mtdoffset += meminfo.erasesize;
-				eraseblocks[i].wbuf_ofs = 0;
-			}
-			gettimeofday(&start, NULL);
-		}
-		if (image_crc != thispkt.hdr.totcrc) {
-			fprintf(stderr, "\nImage CRC changed from 0x%x to 0x%x. Aborting\n",
-				ntohl(image_crc), ntohl(thispkt.hdr.totcrc));
-			exit(1);
-		}
-
-		block_nr = ntohl(thispkt.hdr.block_nr);
-		if (block_nr >= nr_blocks) {
-			fprintf(stderr, "\nErroneous block_nr %d (> %d)\n",
-				block_nr, nr_blocks);
-			exit(1);
-		}
-		for (i=0; i<eraseblocks[block_nr].nr_pkts; i++) {
-			if (eraseblocks[block_nr].pkt_indices[i] == ntohs(thispkt.hdr.pkt_nr)) {
-//				printf("Discarding duplicate packet at %08x pkt %d\n",
-//				       block_nr * meminfo.erasesize, eraseblocks[block_nr].pkt_indices[i]);
-				duplicates++;
-				break;
-			}
-		}
-		if (i < eraseblocks[block_nr].nr_pkts) {
-			continue;
-		}
-
-		if (eraseblocks[block_nr].nr_pkts >= pkts_per_block) {
-			/* We have a block which we didn't really need */
-			eraseblocks[block_nr].nr_pkts++;
-			ignored_pkts++;
-			continue;
-		}
-
-		if (mtd_crc32(-1, thispkt.data, PKT_SIZE) != ntohl(thispkt.hdr.thiscrc)) {
-			printf("\nDiscard %08x pkt %d with bad CRC (%08x not %08x)\n",
-			       block_nr * meminfo.erasesize, ntohs(thispkt.hdr.pkt_nr),
-			       mtd_crc32(-1, thispkt.data, PKT_SIZE),
-			       ntohl(thispkt.hdr.thiscrc));
-			badcrcs++;
-			continue;
-		}
-	pkt_again:
-		eraseblocks[block_nr].pkt_indices[eraseblocks[block_nr].nr_pkts++] =
-			ntohs(thispkt.hdr.pkt_nr);
-		total_pkts++;
-		if (!(total_pkts % 50) || total_pkts == pkts_per_block * nr_blocks) {
-			uint32_t pkts_sent = ntohl(thispkt.hdr.pkt_sequence) - start_seq + 1;
-			long time_msec;
-			gettimeofday(&now, NULL);
-
-			time_msec = ((now.tv_usec - start.tv_usec) / 1000) +
-				(now.tv_sec - start.tv_sec) * 1000;
-
-			printf("\rReceived %d/%d (%d%%) in %lds @%ldKiB/s, %d lost (%d%%), %d dup/xs    ",
-			       total_pkts, nr_blocks * pkts_per_block,
-			       total_pkts * 100 / nr_blocks / pkts_per_block,
-			       time_msec / 1000,
-			       total_pkts * PKT_SIZE / 1024 * 1000 / time_msec,
-			       pkts_sent - total_pkts - duplicates - ignored_pkts,
-			       (pkts_sent - total_pkts - duplicates - ignored_pkts) * 100 / pkts_sent,
-			       duplicates + ignored_pkts);
-			fflush(stdout);
-		}
-
-		if (eraseblocks[block_nr].wbuf_ofs + PKT_SIZE < WBUF_SIZE) {
-			/* New packet doesn't full the wbuf */
-			memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
-			       thispkt.data, PKT_SIZE);
-			eraseblocks[block_nr].wbuf_ofs += PKT_SIZE;
-		} else {
-			int fits = WBUF_SIZE - eraseblocks[block_nr].wbuf_ofs;
-			ssize_t wrotelen;
-			static int faked = 1;
-
-			memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
-			       thispkt.data, fits);
-			wrotelen = pwrite(flfd, eraseblocks[block_nr].wbuf, WBUF_SIZE,
-					  eraseblocks[block_nr].flash_offset);
-
-			if (wrotelen < WBUF_SIZE || (block_nr == 5 && eraseblocks[block_nr].nr_pkts == 5 && !faked)) {
-				faked = 1;
-				if (wrotelen < 0)
-					perror("\npacket write");
-				else
-					fprintf(stderr, "\nshort write of packet wbuf\n");
-
-				if (!file_mode) {
-					struct erase_info_user erase;
-					/* FIXME: Perhaps we should store pkt crcs and try
-					   to recover data from the offending eraseblock */
-
-					/* We have increased nr_pkts but not yet flash_offset */
-					erase.start = eraseblocks[block_nr].flash_offset &
-						~(meminfo.erasesize - 1);
-					erase.length = meminfo.erasesize;
-
-					printf("Will erase at %08x len %08x (bad write was at %08x)\n",
-					       erase.start, erase.length, eraseblocks[block_nr].flash_offset);
-					if (ioctl(flfd, MEMERASE, &erase)) {
-						perror("MEMERASE");
-						exit(1);
-					}
-					if (mtdoffset >= meminfo.size) {
-						fprintf(stderr, "Run out of space on flash\n");
-						exit(1);
-					}
-					while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
-						printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
-						mtdoffset += meminfo.erasesize;
-						if (mtdoffset >= meminfo.size) {
-							fprintf(stderr, "Run out of space on flash\n");
-							exit(1);
-						}
-					}
-					eraseblocks[block_nr].flash_offset = mtdoffset;
-					printf("Block #%d will now be at %08lx\n", block_nr, (long)mtdoffset);
-					total_pkts -= eraseblocks[block_nr].nr_pkts;
-					eraseblocks[block_nr].nr_pkts = 0;
-					eraseblocks[block_nr].wbuf_ofs = 0;
-					mtdoffset += meminfo.erasesize;
-					goto pkt_again;
-				}
-				else /* Usually nothing we can do in file mode */
-					exit(1);
-			}
-			eraseblocks[block_nr].flash_offset += WBUF_SIZE;
-			/* Copy the remainder into the wbuf */
-			memcpy(eraseblocks[block_nr].wbuf, &thispkt.data[fits], PKT_SIZE - fits);
-			eraseblocks[block_nr].wbuf_ofs = PKT_SIZE - fits;
-		}
-
-		if (eraseblocks[block_nr].nr_pkts == pkts_per_block) {
-			eraseblocks[block_nr].crc = ntohl(thispkt.hdr.block_crc);
-
-			if (total_pkts == nr_blocks * pkts_per_block)
-				break;
-		}
-	}
-	printf("\n");
-	gettimeofday(&now, NULL);
-	net_time = (now.tv_usec - start.tv_usec) / 1000;
-	net_time += (now.tv_sec - start.tv_sec) * 1000;
-	close(sock);
-	for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
-		ssize_t rwlen;
-		gettimeofday(&start, NULL);
-		eraseblocks[block_nr].flash_offset -= meminfo.erasesize;
-		rwlen = pread(flfd, eb_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
-
-		gettimeofday(&now, NULL);
-		rflash_time += (now.tv_usec - start.tv_usec) / 1000;
-		rflash_time += (now.tv_sec - start.tv_sec) * 1000;
-		if (rwlen < 0) {
-			perror("read");
-			/* Argh. Perhaps we could go back and try again, but if the flash is
-			   going to fail to read back what we write to it, and the whole point
-			   in this program is to write to it, what's the point? */
-			fprintf(stderr, "Packets we wrote to flash seem to be unreadable. Aborting\n");
-			exit(1);
-		}
-
-		memcpy(eb_buf + meminfo.erasesize, eraseblocks[block_nr].wbuf,
-		       eraseblocks[block_nr].wbuf_ofs);
-
-		for (i=0; i < pkts_per_block; i++)
-			src_pkts[i] = &eb_buf[i * PKT_SIZE];
-
-		gettimeofday(&start, NULL);
-		if (fec_decode(fec, src_pkts, eraseblocks[block_nr].pkt_indices, PKT_SIZE)) {
-			/* Eep. This cannot happen */
-			printf("The world is broken. fec_decode() returned error\n");
-			exit(1);
-		}
-		gettimeofday(&now, NULL);
-		fec_time += (now.tv_usec - start.tv_usec) / 1000;
-		fec_time += (now.tv_sec - start.tv_sec) * 1000;
-
-		for (i=0; i < pkts_per_block; i++)
-			memcpy(&decode_buf[i*PKT_SIZE], src_pkts[i], PKT_SIZE);
-
-		/* Paranoia */
-		gettimeofday(&start, NULL);
-		if (mtd_crc32(-1, decode_buf, meminfo.erasesize) != eraseblocks[block_nr].crc) {
-			printf("\nCRC mismatch for block #%d: want %08x got %08x\n",
-			       block_nr, eraseblocks[block_nr].crc,
-			       mtd_crc32(-1, decode_buf, meminfo.erasesize));
-			exit(1);
-		}
-		gettimeofday(&now, NULL);
-		crc_time += (now.tv_usec - start.tv_usec) / 1000;
-		crc_time += (now.tv_sec - start.tv_sec) * 1000;
-		start = now;
-
-		if (!file_mode) {
-			struct erase_info_user erase;
-
-			erase.start = eraseblocks[block_nr].flash_offset;
-			erase.length = meminfo.erasesize;
-
-			printf("\rErasing block at %08x...", erase.start);
-
-			if (ioctl(flfd, MEMERASE, &erase)) {
-				perror("MEMERASE");
-				/* This block has dirty data on it. If the erase failed, we're screwed */
-				fprintf(stderr, "Erase to clean FEC data from flash failed. Aborting\n");
-				exit(1);
-			}
-			gettimeofday(&now, NULL);
-			erase_time += (now.tv_usec - start.tv_usec) / 1000;
-			erase_time += (now.tv_sec - start.tv_sec) * 1000;
-			start = now;
-		}
-		else printf("\r");
-	write_again:
-		rwlen = pwrite(flfd, decode_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
-		if (rwlen < meminfo.erasesize) {
-			if (rwlen < 0) {
-				perror("\ndecoded data write");
-			} else
-				fprintf(stderr, "\nshort write of decoded data\n");
-
-			if (!file_mode) {
-				struct erase_info_user erase;
-				erase.start = eraseblocks[block_nr].flash_offset;
-				erase.length = meminfo.erasesize;
-
-				printf("Erasing failed block at %08x\n",
-				       eraseblocks[block_nr].flash_offset);
-
-				if (ioctl(flfd, MEMERASE, &erase)) {
-					perror("MEMERASE");
-					exit(1);
-				}
-				if (mtdoffset >= meminfo.size) {
-					fprintf(stderr, "Run out of space on flash\n");
-					exit(1);
-				}
-				while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
-					printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
-					mtdoffset += meminfo.erasesize;
-					if (mtdoffset >= meminfo.size) {
-						fprintf(stderr, "Run out of space on flash\n");
-						exit(1);
-					}
-				}
-				printf("Will try again at %08lx...", (long)mtdoffset);
-				eraseblocks[block_nr].flash_offset = mtdoffset;
-
-				goto write_again;
-			}
-			else /* Usually nothing we can do in file mode */
-				exit(1);
-		}
-		gettimeofday(&now, NULL);
-		flash_time += (now.tv_usec - start.tv_usec) / 1000;
-		flash_time += (now.tv_sec - start.tv_sec) * 1000;
-
-		printf("wrote image block %08x (%d pkts)    ",
-		       block_nr * meminfo.erasesize, eraseblocks[block_nr].nr_pkts);
-		fflush(stdout);
-	}
-	close(flfd);
-	printf("Net rx   %ld.%03lds\n", net_time / 1000, net_time % 1000);
-	printf("flash rd %ld.%03lds\n", rflash_time / 1000, rflash_time % 1000);
-	printf("FEC time %ld.%03lds\n", fec_time / 1000, fec_time % 1000);
-	printf("CRC time %ld.%03lds\n", crc_time / 1000, crc_time % 1000);
-	printf("flash wr %ld.%03lds\n", flash_time / 1000, flash_time % 1000);
-	printf("flash er %ld.%03lds\n", erase_time / 1000, erase_time % 1000);
-
-	return 0;
-}
diff --git a/rfddump.c b/rfddump.c
deleted file mode 100644
index 0375bac..0000000
--- a/rfddump.c
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * rfddump.c
- *
- * Copyright (C) 2005 Sean Young <sean at mess.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; either version 2 of the License, or
- *  (at your option) any later version.
- */
-
-#define PROGRAM_NAME "rfddump"
-#define VERSION "$Revision 1.0 $"
-
-#define _XOPEN_SOURCE 500 /* For pread */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <getopt.h>
-
-#include <mtd/mtd-user.h>
-#include <linux/types.h>
-#include <mtd_swab.h>
-
-/* next is an array of mapping for each corresponding sector */
-#define RFD_MAGIC		0x9193
-#define HEADER_MAP_OFFSET       3
-#define SECTOR_DELETED          0x0000
-#define SECTOR_ZERO             0xfffe
-#define SECTOR_FREE             0xffff
-
-#define SECTOR_SIZE             512
-
-#define SECTORS_PER_TRACK	63
-
-
-struct rfd {
-	int block_size;
-	int block_count;
-	int header_sectors;
-	int data_sectors;
-	int header_size;
-	uint16_t *header;
-	int sector_count;
-	int *sector_map;
-	const char *mtd_filename;
-	const char *out_filename;
-	int verbose;
-};
-
-void display_help(void)
-{
-	printf("Usage: %s [OPTIONS] MTD-device filename\n"
-			"Dumps the contents of a resident flash disk\n"
-			"\n"
-			"-h         --help               display this help and exit\n"
-			"-V         --version            output version information and exit\n"
-			"-v         --verbose		Be verbose\n"
-			"-b size    --blocksize          Block size (defaults to erase unit)\n",
-			PROGRAM_NAME);
-	exit(0);
-}
-
-void display_version(void)
-{
-	printf("%s " VERSION "\n"
-			"\n"
-			"This is free software; see the source for copying conditions.  There is NO\n"
-			"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
-			PROGRAM_NAME);
-
-	exit(0);
-}
-
-void process_options(int argc, char *argv[], struct rfd *rfd)
-{
-	int error = 0;
-
-	rfd->block_size = 0;
-	rfd->verbose = 0;
-
-	for (;;) {
-		int option_index = 0;
-		static const char *short_options = "hvVb:";
-		static const struct option long_options[] = {
-			{ "help", no_argument, 0, 'h' },
-			{ "version", no_argument, 0, 'V', },
-			{ "blocksize", required_argument, 0, 'b' },
-			{ "verbose", no_argument, 0, 'v' },
-			{ NULL, 0, 0, 0 }
-		};
-
-		int c = getopt_long(argc, argv, short_options,
-				long_options, &option_index);
-		if (c == EOF)
-			break;
-
-		switch (c) {
-			case 'h':
-				display_help();
-				break;
-			case 'V':
-				display_version();
-				break;
-			case 'v':
-				rfd->verbose = 1;
-				break;
-			case 'b':
-				rfd->block_size = atoi(optarg);
-				break;
-			case '?':
-				error = 1;
-				break;
-		}
-	}
-
-	if ((argc - optind) != 2 || error)
-		display_help();
-
-	rfd->mtd_filename = argv[optind];
-	rfd->out_filename = argv[optind + 1];
-}
-
-int build_block_map(struct rfd *rfd, int fd, int block)
-{
-	int  i;
-	int sectors;
-
-	if (pread(fd, rfd->header, rfd->header_size, block * rfd->block_size)
-			!= rfd->header_size) {
-		return -1;
-	}
-
-	if (le16_to_cpu(rfd->header[0]) != RFD_MAGIC) {
-		if (rfd->verbose)
-			printf("Block #%02d: Magic missing\n", block);
-
-		return 0;
-	}
-
-	sectors =  0;
-	for (i=0; i<rfd->data_sectors; i++) {
-		uint16_t entry = le16_to_cpu(rfd->header[i + HEADER_MAP_OFFSET]);
-
-		if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
-			continue;
-
-		if (entry == SECTOR_ZERO)
-			entry = 0;
-
-		if (entry >= rfd->sector_count) {
-			fprintf(stderr, "%s: warning: sector %d out of range\n",
-					rfd->mtd_filename, entry);
-			continue;
-		}
-
-		if (rfd->sector_map[entry] != -1) {
-			fprintf(stderr, "%s: warning: more than one entry "
-					"for sector %d\n", rfd->mtd_filename, entry);
-			continue;
-		}
-
-		rfd->sector_map[entry] = rfd->block_size * block +
-			(i + rfd->header_sectors) * SECTOR_SIZE;
-		sectors++;
-	}
-
-	if (rfd->verbose)
-		printf("Block #%02d: %d sectors\n", block, sectors);
-
-	return 1;
-}
-
-int main(int argc, char *argv[])
-{
-	int fd, sectors_per_block;
-	mtd_info_t mtd_info;
-	struct rfd rfd;
-	int i, blocks_found;
-	int out_fd = 0;
-	uint8_t sector[512];
-	int blank, rc, cylinders;
-
-	process_options(argc, argv, &rfd);
-
-	fd = open(rfd.mtd_filename, O_RDONLY);
-	if (fd == -1) {
-		perror(rfd.mtd_filename);
-		return 1;
-	}
-
-	if (rfd.block_size == 0) {
-		if (ioctl(fd, MEMGETINFO, &mtd_info)) {
-			perror(rfd.mtd_filename);
-			close(fd);
-			return 1;
-		}
-
-		if (mtd_info.type != MTD_NORFLASH) {
-			fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename);
-			close(fd);
-			return 2;
-		}
-
-		sectors_per_block = mtd_info.erasesize / SECTOR_SIZE;
-
-		rfd.block_size = mtd_info.erasesize;
-		rfd.block_count = mtd_info.size / mtd_info.erasesize;
-	} else {
-		struct stat st;
-
-		if (fstat(fd, &st) == -1) {
-			perror(rfd.mtd_filename);
-			close(fd);
-			return 1;
-		}
-
-		if (st.st_size % SECTOR_SIZE)
-			fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename);
-
-		sectors_per_block = rfd.block_size / SECTOR_SIZE;
-
-		if (st.st_size % rfd.block_size)
-			fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename);
-
-		rfd.block_count = st.st_size / rfd.block_size;
-
-		if (!rfd.block_count) {
-			fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename);
-			close(fd);
-			return 2;
-		}
-	}
-
-	rfd.header_sectors =
-		((HEADER_MAP_OFFSET + sectors_per_block) *
-		 sizeof(uint16_t) + SECTOR_SIZE - 1) / SECTOR_SIZE;
-	rfd.data_sectors = sectors_per_block - rfd.header_sectors;
-	cylinders = ((rfd.block_count - 1) * rfd.data_sectors - 1)
-		/ SECTORS_PER_TRACK;
-	rfd.sector_count = cylinders * SECTORS_PER_TRACK;
-	rfd.header_size =
-		(HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t);
-
-	rfd.header = malloc(rfd.header_size);
-	if (!rfd.header) {
-		perror(PROGRAM_NAME);
-		close(fd);
-		return 2;
-	}
-	rfd.sector_map = malloc(rfd.sector_count * sizeof(int));
-	if (!rfd.sector_map) {
-		perror(PROGRAM_NAME);
-		close(fd);
-		free(rfd.sector_map);
-		return 2;
-	}
-
-	rfd.mtd_filename = rfd.mtd_filename;
-
-	for (i=0; i<rfd.sector_count; i++)
-		rfd.sector_map[i] = -1;
-
-	for (blocks_found=i=0; i<rfd.block_count; i++) {
-		rc = build_block_map(&rfd, fd, i);
-		if (rc > 0)
-			blocks_found++;
-		if (rc < 0)
-			goto err;
-	}
-
-	if (!blocks_found) {
-		fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename);
-		goto err;
-	}
-
-	for (i=0; i<rfd.sector_count; i++) {
-		if (rfd.sector_map[i] != -1)
-			break;
-	}
-
-	if (i == rfd.sector_count) {
-		fprintf(stderr, "%s: no sectors found\n", rfd.mtd_filename);
-		goto err;
-	}
-
-	out_fd = open(rfd.out_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
-	if (out_fd == -1) {
-		perror(rfd.out_filename);
-		goto err;
-	}
-
-	blank = 0;
-	for (i=0; i<rfd.sector_count; i++) {
-		if (rfd.sector_map[i] == -1) {
-			memset(sector, 0, SECTOR_SIZE);
-			blank++;
-		} else {
-			if (pread(fd, sector, SECTOR_SIZE, rfd.sector_map[i])
-					!= SECTOR_SIZE) {
-				perror(rfd.mtd_filename);
-				goto err;
-			}
-		}
-
-		if (write(out_fd, sector, SECTOR_SIZE) != SECTOR_SIZE) {
-			perror(rfd.out_filename);
-			goto err;
-		}
-	}
-
-	if (rfd.verbose)
-		printf("Copied %d sectors (%d blank)\n", rfd.sector_count, blank);
-
-	close(out_fd);
-	close(fd);
-	free(rfd.header);
-	free(rfd.sector_map);
-
-	return 0;
-
-err:
-	if (out_fd)
-		close(out_fd);
-
-	close(fd);
-	free(rfd.header);
-	free(rfd.sector_map);
-
-	return 2;
-}
diff --git a/rfdformat.c b/rfdformat.c
deleted file mode 100644
index 17d9d2d..0000000
--- a/rfdformat.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * rfdformat.c
- *
- * Copyright (C) 2005 Sean Young <sean at mess.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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This is very easy: just erase all the blocks and put the magic at
- * the beginning of each block.
- */
-
-#define PROGRAM_NAME "rfdformat"
-#define VERSION "$Revision 1.0 $"
-
-#define _XOPEN_SOURCE 500 /* For pread/pwrite */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <getopt.h>
-
-#include <mtd/mtd-user.h>
-#include <linux/types.h>
-
-void display_help(void)
-{
-	printf("Usage: %s [OPTIONS] MTD-device\n"
-			"Formats NOR flash for resident flash disk\n"
-			"\n"
-			"-h         --help               display this help and exit\n"
-			"-V         --version            output version information and exit\n",
-			PROGRAM_NAME);
-	exit(0);
-}
-
-void display_version(void)
-{
-	printf("%s " VERSION "\n"
-			"\n"
-			"This is free software; see the source for copying conditions.  There is NO\n"
-			"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
-			PROGRAM_NAME);
-
-	exit(0);
-}
-
-void process_options(int argc, char *argv[], const char **mtd_filename)
-{
-	int error = 0;
-
-	for (;;) {
-		int option_index = 0;
-		static const char *short_options = "hV";
-		static const struct option long_options[] = {
-			{ "help", no_argument, 0, 'h' },
-			{ "version", no_argument, 0, 'V', },
-			{ NULL, 0, 0, 0 }
-		};
-
-		int c = getopt_long(argc, argv, short_options,
-				long_options, &option_index);
-		if (c == EOF)
-			break;
-
-		switch (c) {
-			case 'h':
-				display_help();
-				break;
-			case 'V':
-				display_version();
-				break;
-			case '?':
-				error = 1;
-				break;
-		}
-	}
-
-	if ((argc - optind) != 1 || error)
-		display_help();
-
-	*mtd_filename = argv[optind];
-}
-
-int main(int argc, char *argv[])
-{
-	static const uint8_t magic[] = { 0x93, 0x91 };
-	int fd, block_count, i;
-	struct mtd_info_user mtd_info;
-	char buf[512];
-	const char *mtd_filename;
-
-	process_options(argc, argv, &mtd_filename);
-
-	fd = open(mtd_filename, O_RDWR);
-	if (fd == -1) {
-		perror(mtd_filename);
-		return 1;
-	}
-
-	if (ioctl(fd, MEMGETINFO, &mtd_info)) {
-		perror(mtd_filename);
-		close(fd);
-		return 1;
-	}
-
-	if (mtd_info.type != MTD_NORFLASH) {
-		fprintf(stderr, "%s: not NOR flash\n", mtd_filename);
-		close(fd);
-		return 2;
-	}
-
-	if (mtd_info.size > 32*1024*1024) {
-		fprintf(stderr, "%s: flash larger than 32MiB not supported\n",
-				mtd_filename);
-		close(fd);
-		return 2;
-	}
-
-	block_count = mtd_info.size / mtd_info.erasesize;
-
-	if (block_count < 2) {
-		fprintf(stderr, "%s: at least two erase units required\n",
-				mtd_filename);
-		close(fd);
-		return 2;
-	}
-
-	for (i=0; i<block_count; i++) {
-		struct erase_info_user erase_info;
-
-		erase_info.start = i * mtd_info.erasesize;
-		erase_info.length = mtd_info.erasesize;
-
-		if (ioctl(fd, MEMERASE, &erase_info) != 0) {
-			snprintf(buf, sizeof(buf), "%s: erase", mtd_filename);
-			perror(buf);
-			close(fd);
-			return 2;
-		}
-
-		if (pwrite(fd, magic, sizeof(magic), i * mtd_info.erasesize)
-				!= sizeof(magic)) {
-			snprintf(buf, sizeof(buf), "%s: write", mtd_filename);
-			perror(buf);
-			close(fd);
-			return 2;
-		}
-	}
-
-	close(fd);
-
-	return 0;
-}
diff --git a/serve_image.c b/serve_image.c
deleted file mode 100644
index d3794ec..0000000
--- a/serve_image.c
+++ /dev/null
@@ -1,300 +0,0 @@
-#define PROGRAM_NAME "serve_image"
-#define _POSIX_C_SOURCE 199309
-
-#include <time.h>
-#include <errno.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/mman.h>
-#include <netinet/in.h>
-#include <sys/time.h>
-#include <crc32.h>
-#include <inttypes.h>
-
-#include "mcast_image.h"
-
-int tx_rate = 80000;
-int pkt_delay;
-
-#undef RANDOMDROP
-
-int main(int argc, char **argv)
-{
-	struct addrinfo *ai;
-	struct addrinfo hints;
-	struct addrinfo *runp;
-	int ret;
-	int sock;
-	struct image_pkt pktbuf;
-	int rfd;
-	struct stat st;
-	int writeerrors = 0;
-	uint32_t erasesize;
-	unsigned char *image, *blockptr = NULL;
-	uint32_t block_nr, pkt_nr;
-	int nr_blocks;
-	struct timeval then, now, nextpkt;
-	long time_msecs;
-	int pkts_per_block;
-	int total_pkts_per_block;
-	struct fec_parms *fec;
-	unsigned char *last_block;
-	uint32_t *block_crcs;
-	long tosleep;
-	uint32_t sequence = 0;
-
-	if (argc == 6) {
-		tx_rate = atol(argv[5]) * 1024;
-		if (tx_rate < PKT_SIZE || tx_rate > 20000000) {
-			fprintf(stderr, "Bogus TX rate %d KiB/s\n", tx_rate);
-			exit(1);
-		}
-		argc = 5;
-	}
-	if (argc != 5) {
-		fprintf(stderr, "usage: %s <host> <port> <image> <erasesize> [<tx_rate>]\n",
-			PROGRAM_NAME);
-		exit(1);
-	}
-	pkt_delay = (sizeof(pktbuf) * 1000000) / tx_rate;
-	printf("Inter-packet delay (avg): %dµs\n", pkt_delay);
-	printf("Transmit rate: %d KiB/s\n", tx_rate / 1024);
-
-	erasesize = atol(argv[4]);
-	if (!erasesize) {
-		fprintf(stderr, "erasesize cannot be zero\n");
-		exit(1);
-	}
-
-	pkts_per_block = (erasesize + PKT_SIZE - 1) / PKT_SIZE;
-	total_pkts_per_block = pkts_per_block * 3 / 2;
-
-	/* We have to pad it with zeroes, so can't use it in-place */
-	last_block = malloc(pkts_per_block * PKT_SIZE);
-	if (!last_block) {
-		fprintf(stderr, "Failed to allocate last-block buffer\n");
-		exit(1);
-	}
-
-	fec = fec_new(pkts_per_block, total_pkts_per_block);
-	if (!fec) {
-		fprintf(stderr, "Error initialising FEC\n");
-		exit(1);
-	}
-
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_flags = AI_ADDRCONFIG;
-	hints.ai_socktype = SOCK_DGRAM;
-
-	ret = getaddrinfo(argv[1], argv[2], &hints, &ai);
-	if (ret) {
-		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
-		exit(1);
-	}
-	runp = ai;
-	for (runp = ai; runp; runp = runp->ai_next) {
-		sock = socket(runp->ai_family, runp->ai_socktype,
-			      runp->ai_protocol);
-		if (sock == -1) {
-			perror("socket");
-			continue;
-		}
-		if (connect(sock, runp->ai_addr, runp->ai_addrlen) == 0)
-			break;
-		perror("connect");
-		close(sock);
-	}
-	if (!runp)
-		exit(1);
-
-	rfd = open(argv[3], O_RDONLY);
-	if (rfd < 0) {
-		perror("open");
-		exit(1);
-	}
-
-	if (fstat(rfd, &st)) {
-		perror("fstat");
-		exit(1);
-	}
-
-	if (st.st_size % erasesize) {
-		fprintf(stderr, "Image size %" PRIu64 " bytes is not a multiple of erasesize %d bytes\n",
-				st.st_size, erasesize);
-		exit(1);
-	}
-	image = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, rfd, 0);
-	if (image == MAP_FAILED) {
-		perror("mmap");
-		exit(1);
-	}
-
-	nr_blocks = st.st_size / erasesize;
-
-	block_crcs = malloc(nr_blocks * sizeof(uint32_t));
-	if (!block_crcs) {
-		fprintf(stderr, "Failed to allocate memory for CRCs\n");
-		exit(1);
-	}
-
-	memcpy(last_block, image + (nr_blocks - 1) * erasesize, erasesize);
-	memset(last_block + erasesize, 0, (PKT_SIZE * pkts_per_block) - erasesize);
-
-	printf("Checking CRC....");
-	fflush(stdout);
-
-	pktbuf.hdr.resend = 0;
-	pktbuf.hdr.totcrc = htonl(mtd_crc32(-1, image, st.st_size));
-	pktbuf.hdr.nr_blocks = htonl(nr_blocks);
-	pktbuf.hdr.blocksize = htonl(erasesize);
-	pktbuf.hdr.thislen = htonl(PKT_SIZE);
-	pktbuf.hdr.nr_pkts = htons(total_pkts_per_block);
-
-	printf("%08x\n", ntohl(pktbuf.hdr.totcrc));
-	printf("Checking block CRCs....");
-	fflush(stdout);
-	for (block_nr=0; block_nr < nr_blocks; block_nr++) {
-		printf("\rChecking block CRCS.... %d/%d",
-		       block_nr + 1, nr_blocks);
-		fflush(stdout);
-		block_crcs[block_nr] = mtd_crc32(-1, image + (block_nr * erasesize), erasesize);
-	}
-
-	printf("\nImage size %ld KiB (0x%08lx). %d blocks at %d pkts/block\n"
-	       "Estimated transmit time per cycle: %ds\n",
-	       (long)st.st_size / 1024, (long) st.st_size,
-	       nr_blocks, pkts_per_block,
-	       nr_blocks * pkts_per_block * pkt_delay / 1000000);
-	gettimeofday(&then, NULL);
-	nextpkt = then;
-
-#ifdef RANDOMDROP
-	srand((unsigned)then.tv_usec);
-	printf("Random seed %u\n", (unsigned)then.tv_usec);
-#endif
-	while (1) for (pkt_nr=0; pkt_nr < total_pkts_per_block; pkt_nr++) {
-
-		if (blockptr && pkt_nr == 0) {
-			unsigned long amt_sent = total_pkts_per_block * nr_blocks * sizeof(pktbuf);
-			gettimeofday(&now, NULL);
-
-			time_msecs = (now.tv_sec - then.tv_sec) * 1000;
-			time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
-			printf("\n%ld KiB sent in %ldms (%ld KiB/s)\n",
-			       amt_sent / 1024, time_msecs,
-			       amt_sent / 1024 * 1000 / time_msecs);
-			then = now;
-		}
-
-		for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
-
-			int actualpkt;
-
-			/* Calculating the redundant FEC blocks is expensive;
-			   the first $pkts_per_block are cheap enough though
-			   because they're just copies. So alternate between
-			   simple and complex stuff, so that we don't start
-			   to choke and fail to keep up with the expected
-			   bitrate in the second half of the sequence */
-			if (block_nr & 1)
-				actualpkt = pkt_nr;
-			else
-				actualpkt = total_pkts_per_block - 1 - pkt_nr;
-
-			blockptr = image + (erasesize * block_nr);
-			if (block_nr == nr_blocks - 1)
-				blockptr = last_block;
-
-			fec_encode_linear(fec, blockptr, pktbuf.data, actualpkt, PKT_SIZE);
-
-			pktbuf.hdr.thiscrc = htonl(mtd_crc32(-1, pktbuf.data, PKT_SIZE));
-			pktbuf.hdr.block_crc = htonl(block_crcs[block_nr]);
-			pktbuf.hdr.block_nr = htonl(block_nr);
-			pktbuf.hdr.pkt_nr = htons(actualpkt);
-			pktbuf.hdr.pkt_sequence = htonl(sequence++);
-
-			printf("\rSending data block %08x packet %3d/%d",
-			       block_nr * erasesize,
-			       pkt_nr, total_pkts_per_block);
-
-			if (pkt_nr && !block_nr) {
-				unsigned long amt_sent = pkt_nr * nr_blocks * sizeof(pktbuf);
-
-				gettimeofday(&now, NULL);
-
-				time_msecs = (now.tv_sec - then.tv_sec) * 1000;
-				time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
-				printf("    (%ld KiB/s)    ",
-				       amt_sent / 1024 * 1000 / time_msecs);
-			}
-
-			fflush(stdout);
-
-#ifdef RANDOMDROP
-			if ((rand() % 1000) < 20) {
-				printf("\nDropping packet %d of block %08x\n", pkt_nr+1, block_nr * erasesize);
-				continue;
-			}
-#endif
-			gettimeofday(&now, NULL);
-#if 1
-			tosleep = nextpkt.tv_usec - now.tv_usec +
-				(1000000 * (nextpkt.tv_sec - now.tv_sec));
-
-			/* We need hrtimers for this to actually work */
-			if (tosleep > 0) {
-				struct timespec req;
-
-				req.tv_nsec = (tosleep % 1000000) * 1000;
-				req.tv_sec = tosleep / 1000000;
-
-				nanosleep(&req, NULL);
-			}
-#else
-			while (now.tv_sec < nextpkt.tv_sec ||
-				 (now.tv_sec == nextpkt.tv_sec &&
-				  now.tv_usec < nextpkt.tv_usec)) {
-				gettimeofday(&now, NULL);
-			}
-#endif
-			nextpkt.tv_usec += pkt_delay;
-			if (nextpkt.tv_usec >= 1000000) {
-				nextpkt.tv_sec += nextpkt.tv_usec / 1000000;
-				nextpkt.tv_usec %= 1000000;
-			}
-
-			/* If the time for the next packet has already
-			   passed (by some margin), then we've lost time
-			   Adjust our expected timings accordingly. If
-			   we're only a little way behind, don't slip yet */
-			if (now.tv_usec > (now.tv_usec + (5 * pkt_delay) +
-					1000000 * (nextpkt.tv_sec - now.tv_sec))) {
-				nextpkt = now;
-			}
-
-			if (write(sock, &pktbuf, sizeof(pktbuf)) < 0) {
-				perror("write");
-				writeerrors++;
-				if (writeerrors > 10) {
-					fprintf(stderr, "Too many consecutive write errors\n");
-					exit(1);
-				}
-			} else
-				writeerrors = 0;
-
-
-
-		}
-	}
-	munmap(image, st.st_size);
-	close(rfd);
-	close(sock);
-	return 0;
-}
diff --git a/summary.h b/summary.h
deleted file mode 100644
index e9d95a5..0000000
--- a/summary.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2004  Ferenc Havasi <havasi at inf.u-szeged.hu>,
- *                     Zoltan Sogor <weth at inf.u-szeged.hu>,
- *                     Patrik Kluba <pajko at halom.u-szeged.hu>,
- *                     University of Szeged, Hungary
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- */
-
-#ifndef JFFS2_SUMMARY_H
-#define JFFS2_SUMMARY_H
-
-#include <linux/jffs2.h>
-
-#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
-	c->free_size -= _x; c->dirty_size += _x; \
-	jeb->free_size -= _x ; jeb->dirty_size += _x; \
-}while(0)
-#define USED_SPACE(x) do { typeof(x) _x = (x); \
-	c->free_size -= _x; c->used_size += _x; \
-	jeb->free_size -= _x ; jeb->used_size += _x; \
-}while(0)
-#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
-	c->free_size -= _x; c->wasted_size += _x; \
-	jeb->free_size -= _x ; jeb->wasted_size += _x; \
-}while(0)
-#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
-	c->free_size -= _x; c->unchecked_size += _x; \
-	jeb->free_size -= _x ; jeb->unchecked_size += _x; \
-}while(0)
-
-#define BLK_STATE_ALLFF		0
-#define BLK_STATE_CLEAN		1
-#define BLK_STATE_PARTDIRTY	2
-#define BLK_STATE_CLEANMARKER	3
-#define BLK_STATE_ALLDIRTY	4
-#define BLK_STATE_BADBLOCK	5
-
-#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
-#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
-#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
-#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash))
-#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash))
-
-/* Summary structures used on flash */
-
-struct jffs2_sum_unknown_flash
-{
-	jint16_t nodetype;	/* node type */
-} __attribute__((packed));
-
-struct jffs2_sum_inode_flash
-{
-	jint16_t nodetype;	/* node type */
-	jint32_t inode;		/* inode number */
-	jint32_t version;	/* inode version */
-	jint32_t offset;	/* offset on jeb */
-	jint32_t totlen; 	/* record length */
-} __attribute__((packed));
-
-struct jffs2_sum_dirent_flash
-{
-	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
-	jint32_t totlen;	/* record length */
-	jint32_t offset;	/* ofset on jeb */
-	jint32_t pino;		/* parent inode */
-	jint32_t version;	/* dirent version */
-	jint32_t ino; 		/* == zero for unlink */
-	uint8_t nsize;		/* dirent name size */
-	uint8_t type;		/* dirent type */
-	uint8_t name[0];	/* dirent name */
-} __attribute__((packed));
-
-struct jffs2_sum_xattr_flash
-{
-	jint16_t nodetype;	/* == JFFS2_NODETYPE_XATR */
-	jint32_t xid;		/* xattr identifier */
-	jint32_t version;	/* version number */
-	jint32_t offset;	/* offset on jeb */
-	jint32_t totlen;	/* node length */
-} __attribute__((packed));
-
-struct jffs2_sum_xref_flash
-{
-	jint16_t nodetype;	/* == JFFS2_NODETYPE_XREF */
-	jint32_t offset;	/* offset on jeb */
-} __attribute__((packed));
-
-union jffs2_sum_flash
-{
-	struct jffs2_sum_unknown_flash u;
-	struct jffs2_sum_inode_flash i;
-	struct jffs2_sum_dirent_flash d;
-	struct jffs2_sum_xattr_flash x;
-	struct jffs2_sum_xref_flash r;
-};
-
-/* Summary structures used in the memory */
-
-struct jffs2_sum_unknown_mem
-{
-	union jffs2_sum_mem *next;
-	jint16_t nodetype;	/* node type */
-} __attribute__((packed));
-
-struct jffs2_sum_inode_mem
-{
-	union jffs2_sum_mem *next;
-	jint16_t nodetype;	/* node type */
-	jint32_t inode;		/* inode number */
-	jint32_t version;	/* inode version */
-	jint32_t offset;	/* offset on jeb */
-	jint32_t totlen; 	/* record length */
-} __attribute__((packed));
-
-struct jffs2_sum_dirent_mem
-{
-	union jffs2_sum_mem *next;
-	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
-	jint32_t totlen;	/* record length */
-	jint32_t offset;	/* ofset on jeb */
-	jint32_t pino;		/* parent inode */
-	jint32_t version;	/* dirent version */
-	jint32_t ino; 		/* == zero for unlink */
-	uint8_t nsize;		/* dirent name size */
-	uint8_t type;		/* dirent type */
-	uint8_t name[0];	/* dirent name */
-} __attribute__((packed));
-
-struct jffs2_sum_xattr_mem
-{
-	union jffs2_sum_mem *next;
-	jint16_t nodetype;
-	jint32_t xid;
-	jint32_t version;
-	jint32_t offset;
-	jint32_t totlen;
-} __attribute__((packed));
-
-struct jffs2_sum_xref_mem
-{
-	union jffs2_sum_mem *next;
-	jint16_t nodetype;
-	jint32_t offset;
-} __attribute__((packed));
-
-union jffs2_sum_mem
-{
-	struct jffs2_sum_unknown_mem u;
-	struct jffs2_sum_inode_mem i;
-	struct jffs2_sum_dirent_mem d;
-	struct jffs2_sum_xattr_mem x;
-	struct jffs2_sum_xref_mem r;
-};
-
-struct jffs2_summary
-{
-	uint32_t sum_size;
-	uint32_t sum_num;
-	uint32_t sum_padded;
-	union jffs2_sum_mem *sum_list_head;
-	union jffs2_sum_mem *sum_list_tail;
-};
-
-/* Summary marker is stored at the end of every sumarized erase block */
-
-struct jffs2_sum_marker
-{
-	jint32_t offset;	/* offset of the summary node in the jeb */
-	jint32_t magic; 	/* == JFFS2_SUM_MAGIC */
-};
-
-#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker))
-
-#endif
diff --git a/sumtool.c b/sumtool.c
deleted file mode 100644
index 886b545..0000000
--- a/sumtool.c
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- *  sumtool.c
- *
- *  Copyright (C) 2004 Zoltan Sogor <weth at inf.u-szeged.hu>,
- *                     Ferenc Havasi <havasi at inf.u-szeged.hu>
- *                     University of Szeged, Hungary
- *                2006 KaiGai Kohei <kaigai at ak.jp.nec.com>
- *
- * 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; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * 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.
- *
- * Overview:
- *   This is a utility insert summary information into JFFS2 image for
- *   faster mount time
- *
- */
-
-#define PROGRAM_NAME "sumtool"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <asm/types.h>
-#include <dirent.h>
-#include <mtd/jffs2-user.h>
-#include <endian.h>
-#include <byteswap.h>
-#include <getopt.h>
-#include <crc32.h>
-#include "summary.h"
-#include "common.h"
-
-#define PAD(x) (((x)+3)&~3)
-
-static struct jffs2_summary *sum_collected = NULL;
-
-static int verbose = 0;
-static int padto = 0;				/* pad the output with 0xFF to the end of the final eraseblock */
-static int add_cleanmarkers = 1;		/* add cleanmarker to output */
-static int use_input_cleanmarker_size = 1;	/* use input file's cleanmarker size (default) */
-static int found_cleanmarkers = 0;		/* cleanmarker found in input file */
-static struct jffs2_unknown_node cleanmarker;
-static int cleanmarker_size = sizeof(cleanmarker);
-static const char *short_options = "o:i:e:hvVblnc:p";
-static int erase_block_size = 65536;
-static int out_fd = -1;
-static int in_fd = -1;
-
-static uint8_t *data_buffer = NULL; 		/* buffer for inodes */
-static unsigned int data_ofs = 0;	 	/* inode buffer offset */
-
-static uint8_t *file_buffer = NULL;		/* file buffer contains the actual erase block*/
-static unsigned int file_ofs = 0;		/* position in the buffer */
-
-int target_endian = __BYTE_ORDER;
-
-static struct option long_options[] = {
-	{"output", 1, NULL, 'o'},
-	{"input", 1, NULL, 'i'},
-	{"eraseblock", 1, NULL, 'e'},
-	{"help", 0, NULL, 'h'},
-	{"verbose", 0, NULL, 'v'},
-	{"version", 0, NULL, 'V'},
-	{"bigendian", 0, NULL, 'b'},
-	{"littleendian", 0, NULL, 'l'},
-	{"no-cleanmarkers", 0, NULL, 'n'},
-	{"cleanmarker", 1, NULL, 'c'},
-	{"pad", 0, NULL, 'p'},
-	{NULL, 0, NULL, 0}
-};
-
-static const char helptext[] =
-"Usage: sumtool [OPTIONS] -i inputfile -o outputfile\n\n"
-"Convert the input JFFS2 image to a summarized JFFS2 image\n"
-"Summary makes mounting faster - if summary support enabled in your kernel\n\n"
-"Options:\n"
-"  -e, --eraseblock=SIZE     Use erase block size SIZE (default: 64KiB)\n"
-"                            (usually 16KiB on NAND)\n"
-"  -c, --cleanmarker=SIZE    Size of cleanmarker (default 12).\n"
-"                            (usually 16 bytes on NAND, and will be set to\n"
-"                            this value if left at the default 12). Will be\n"
-"                            stored in OOB after each physical page composing\n"
-"                            a physical eraseblock.\n"
-"  -n, --no-cleanmarkers     Don't add a cleanmarker to every eraseblock\n"
-"  -o, --output=FILE         Output to FILE \n"
-"  -i, --input=FILE          Input from FILE \n"
-"  -b, --bigendian           Image is big endian\n"
-"  -l  --littleendian        Image is little endian\n"
-"  -h, --help                Display this help text\n"
-"  -v, --verbose             Verbose operation\n"
-"  -V, --version             Display version information\n"
-"  -p, --pad                 Pad the OUTPUT with 0xFF to the end of the final\n"
-"                            eraseblock\n\n";
-
-
-static const char revtext[] = "$Revision: 1.9 $";
-
-static unsigned char ffbuf[16] = {
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-};
-
-static void full_write(void *target_buff, const void *buf, int len);
-
-void setup_cleanmarker(void)
-{
-	cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
-	cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
-	cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
-}
-
-void process_options (int argc, char **argv)
-{
-	int opt,c;
-
-	while ((opt = getopt_long(argc, argv, short_options, long_options, &c)) >= 0) {
-		switch (opt) {
-			case 'o':
-				if (out_fd != -1)
-					errmsg_die("output filename specified more than once");
-				out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
-				if (out_fd == -1)
-					sys_errmsg_die("open output file");
-				break;
-
-			case 'i':
-				if (in_fd != -1)
-					errmsg_die("input filename specified more than once");
-				in_fd = open(optarg, O_RDONLY);
-				if (in_fd == -1)
-					sys_errmsg_die("open input file");
-				break;
-			case 'b':
-				target_endian = __BIG_ENDIAN;
-				break;
-			case 'l':
-				target_endian = __LITTLE_ENDIAN;
-				break;
-			case 'h':
-			case '?':
-				errmsg_die("%s", helptext);
-			case 'v':
-				verbose = 1;
-				break;
-
-			case 'V':
-				errmsg_die("revision %.*s\n",
-						(int) strlen(revtext) - 13, revtext + 11);
-
-			case 'e': {
-						  char *next;
-						  unsigned units = 0;
-						  erase_block_size = strtol(optarg, &next, 0);
-						  if (!erase_block_size)
-							  errmsg_die("Unrecognisable erase size\n");
-
-						  if (*next) {
-							  if (!strcmp(next, "KiB")) {
-								  units = 1024;
-							  } else if (!strcmp(next, "MiB")) {
-								  units = 1024 * 1024;
-							  } else {
-								  errmsg_die("Unknown units in erasesize\n");
-							  }
-						  } else {
-							  if (erase_block_size < 0x1000)
-								  units = 1024;
-							  else
-								  units = 1;
-						  }
-						  erase_block_size *= units;
-
-						  /* If it's less than 8KiB, they're not allowed */
-						  if (erase_block_size < 0x2000) {
-							  warnmsg("Erase size 0x%x too small. Increasing to 8KiB minimum\n",
-									erase_block_size);
-							  erase_block_size = 0x2000;
-						  }
-						  break;
-					  }
-
-			case 'n':
-					  add_cleanmarkers = 0;
-					  break;
-			case 'c':
-					  cleanmarker_size = strtol(optarg, NULL, 0);
-
-					  if (cleanmarker_size < sizeof(cleanmarker)) {
-						  errmsg_die("cleanmarker size must be >= 12");
-					  }
-					  if (cleanmarker_size >= erase_block_size) {
-						  errmsg_die("cleanmarker size must be < eraseblock size");
-					  }
-
-					  use_input_cleanmarker_size = 0;
-					  found_cleanmarkers = 1;
-					  setup_cleanmarker();
-
-					  break;
-			case 'p':
-					  padto = 1;
-					  break;
-		}
-	}
-}
-
-
-void init_buffers(void)
-{
-	data_buffer = xmalloc(erase_block_size);
-	file_buffer = xmalloc(erase_block_size);
-}
-
-void init_sumlist(void)
-{
-	sum_collected = xzalloc(sizeof(*sum_collected));
-}
-
-void clean_buffers(void)
-{
-	free(data_buffer);
-	free(file_buffer);
-}
-
-void clean_sumlist(void)
-{
-	union jffs2_sum_mem *temp;
-
-	if (sum_collected) {
-
-		while (sum_collected->sum_list_head) {
-			temp = sum_collected->sum_list_head;
-			sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
-			free(temp);
-			sum_collected->sum_num--;
-		}
-
-		if (sum_collected->sum_num != 0)
-			warnmsg("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
-
-		free(sum_collected);
-	}
-}
-
-int load_next_block(void)
-{
-	int ret;
-	ret = read(in_fd, file_buffer, erase_block_size);
-	file_ofs = 0;
-
-	bareverbose(verbose, "Load next block : %d bytes read\n", ret);
-
-	return ret;
-}
-
-void write_buff_to_file(void)
-{
-	int ret;
-	int len = data_ofs;
-
-	uint8_t *buf = NULL;
-
-	buf = data_buffer;
-	while (len > 0) {
-		ret = write(out_fd, buf, len);
-
-		if (ret < 0)
-			sys_errmsg_die("write");
-
-		if (ret == 0)
-			sys_errmsg_die("write returned zero");
-
-		len -= ret;
-		buf += ret;
-	}
-
-	data_ofs = 0;
-}
-
-void dump_sum_records(void)
-{
-
-	struct jffs2_raw_summary isum;
-	struct jffs2_sum_marker *sm;
-	union jffs2_sum_mem *temp;
-	jint32_t offset;
-	jint32_t *tpage;
-	void *wpage;
-	int datasize, infosize, padsize;
-	jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
-
-	if (!sum_collected->sum_num || !sum_collected->sum_list_head)
-		return;
-
-	datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
-	infosize = sizeof(struct jffs2_raw_summary) + datasize;
-	padsize = erase_block_size - data_ofs - infosize;
-	infosize += padsize; datasize += padsize;
-	offset = cpu_to_je32(data_ofs);
-
-	tpage = xmalloc(datasize);
-
-	memset(tpage, 0xff, datasize);
-	memset(&isum, 0, sizeof(isum));
-
-	isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
-	isum.totlen = cpu_to_je32(infosize);
-	isum.hdr_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
-	isum.padded = cpu_to_je32(0);
-
-	if (add_cleanmarkers && found_cleanmarkers) {
-		isum.cln_mkr = cpu_to_je32(cleanmarker_size);
-	} else {
-		isum.cln_mkr = cpu_to_je32(0);
-	}
-
-	isum.sum_num = cpu_to_je32(sum_collected->sum_num);
-	wpage = tpage;
-
-	while (sum_collected->sum_num) {
-		switch(je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) {
-
-			case JFFS2_NODETYPE_INODE : {
-											struct jffs2_sum_inode_flash *sino_ptr = wpage;
-
-											sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype;
-											sino_ptr->inode = sum_collected->sum_list_head->i.inode;
-											sino_ptr->version = sum_collected->sum_list_head->i.version;
-											sino_ptr->offset = sum_collected->sum_list_head->i.offset;
-											sino_ptr->totlen = sum_collected->sum_list_head->i.totlen;
-
-											wpage += JFFS2_SUMMARY_INODE_SIZE;
-											break;
-										}
-
-			case JFFS2_NODETYPE_DIRENT : {
-											 struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
-
-											 sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype;
-											 sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen;
-											 sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset;
-											 sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino;
-											 sdrnt_ptr->version = sum_collected->sum_list_head->d.version;
-											 sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino;
-											 sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize;
-											 sdrnt_ptr->type = sum_collected->sum_list_head->d.type;
-
-											 memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name,
-													 sum_collected->sum_list_head->d.nsize);
-
-											 wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize);
-											 break;
-										 }
-
-			case JFFS2_NODETYPE_XATTR: {
-										   struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
-
-										   sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype;
-										   sxattr_ptr->xid = sum_collected->sum_list_head->x.xid;
-										   sxattr_ptr->version = sum_collected->sum_list_head->x.version;
-										   sxattr_ptr->offset = sum_collected->sum_list_head->x.offset;
-										   sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen;
-
-										   wpage += JFFS2_SUMMARY_XATTR_SIZE;
-										   break;
-									   }
-
-			case JFFS2_NODETYPE_XREF: {
-										  struct jffs2_sum_xref_flash *sxref_ptr = wpage;
-
-										  sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype;
-										  sxref_ptr->offset = sum_collected->sum_list_head->r.offset;
-
-										  wpage += JFFS2_SUMMARY_XREF_SIZE;
-										  break;
-									  }
-
-			default : {
-						  warnmsg("Unknown node type!\n");
-					  }
-		}
-
-		temp = sum_collected->sum_list_head;
-		sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
-		free(temp);
-
-		sum_collected->sum_num--;
-	}
-
-	sum_collected->sum_size = 0;
-	sum_collected->sum_num = 0;
-	sum_collected->sum_list_tail = NULL;
-
-	wpage += padsize;
-
-	sm = wpage;
-	sm->offset = offset;
-	sm->magic = magic;
-
-	isum.sum_crc = cpu_to_je32(mtd_crc32(0, tpage, datasize));
-	isum.node_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(isum) - 8));
-
-	full_write(data_buffer + data_ofs, &isum, sizeof(isum));
-	full_write(data_buffer + data_ofs, tpage, datasize);
-
-	free(tpage);
-}
-
-static void full_write(void *target_buff, const void *buf, int len)
-{
-	memcpy(target_buff, buf, len);
-	data_ofs += len;
-}
-
-static void pad(int req)
-{
-	while (req) {
-		if (req > sizeof(ffbuf)) {
-			full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf));
-			req -= sizeof(ffbuf);
-		} else {
-			full_write(data_buffer + data_ofs, ffbuf, req);
-			req = 0;
-		}
-	}
-}
-
-static inline void padword(void)
-{
-	if (data_ofs % 4)
-		full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4));
-}
-
-
-static inline void pad_block_if_less_than(int req,int plus)
-{
-
-	int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
-	datasize += (4 - (datasize % 4)) % 4;
-
-	if (data_ofs + req > erase_block_size - datasize) {
-		dump_sum_records();
-		write_buff_to_file();
-	}
-
-	if (add_cleanmarkers && found_cleanmarkers) {
-		if (!data_ofs) {
-			full_write(data_buffer, &cleanmarker, sizeof(cleanmarker));
-			pad(cleanmarker_size - sizeof(cleanmarker));
-			padword();
-		}
-	}
-}
-
-void flush_buffers(void)
-{
-
-	if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */
-		if (data_ofs != cleanmarker_size) {	/* INODE BUFFER */
-
-			int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
-			datasize += (4 - (datasize % 4)) % 4;
-
-			/* If we have a full inode buffer, then write out inode and summary data  */
-			if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
-				dump_sum_records();
-				write_buff_to_file();
-			} else {	/* else just write out inode data */
-				if (padto)
-					pad(erase_block_size - data_ofs);
-				write_buff_to_file();
-			}
-		}
-	} else { /* NO CLEANMARKER */
-		if (data_ofs != 0) { /* INODE BUFFER */
-
-			int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
-			datasize += (4 - (datasize % 4)) % 4;
-
-			/* If we have a full inode buffer, then write out inode and summary data */
-			if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
-				dump_sum_records();
-				write_buff_to_file();
-			} else {	/* Else just write out inode data */
-				if(padto)
-					pad(erase_block_size - data_ofs);
-				write_buff_to_file();
-			}
-		}
-	}
-}
-
-int add_sum_mem(union jffs2_sum_mem *item)
-{
-
-	if (!sum_collected->sum_list_head)
-		sum_collected->sum_list_head = (union jffs2_sum_mem *) item;
-	if (sum_collected->sum_list_tail)
-		sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
-	sum_collected->sum_list_tail = (union jffs2_sum_mem *) item;
-
-	switch (je16_to_cpu(item->u.nodetype)) {
-		case JFFS2_NODETYPE_INODE:
-			sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
-			sum_collected->sum_num++;
-			break;
-
-		case JFFS2_NODETYPE_DIRENT:
-			sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
-			sum_collected->sum_num++;
-			break;
-
-		case JFFS2_NODETYPE_XATTR:
-			sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
-			sum_collected->sum_num++;
-			break;
-
-		case JFFS2_NODETYPE_XREF:
-			sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE;
-			sum_collected->sum_num++;
-			break;
-
-		default:
-			errmsg_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
-	}
-	return 0;
-}
-
-void add_sum_inode_mem(union jffs2_node_union *node)
-{
-	struct jffs2_sum_inode_mem *temp = xmalloc(sizeof(*temp));
-
-	temp->nodetype = node->i.nodetype;
-	temp->inode = node->i.ino;
-	temp->version = node->i.version;
-	temp->offset = cpu_to_je32(data_ofs);
-	temp->totlen = node->i.totlen;
-	temp->next = NULL;
-
-	add_sum_mem((union jffs2_sum_mem *) temp);
-}
-
-void add_sum_dirent_mem(union jffs2_node_union *node)
-{
-	struct jffs2_sum_dirent_mem *temp = xmalloc(sizeof(*temp) + node->d.nsize);
-
-	temp->nodetype = node->d.nodetype;
-	temp->totlen = node->d.totlen;
-	temp->offset = cpu_to_je32(data_ofs);
-	temp->pino = node->d.pino;
-	temp->version = node->d.version;
-	temp->ino = node->d.ino;
-	temp->nsize = node->d.nsize;
-	temp->type = node->d.type;
-	temp->next = NULL;
-
-	memcpy(temp->name,node->d.name,node->d.nsize);
-	add_sum_mem((union jffs2_sum_mem *) temp);
-}
-
-void add_sum_xattr_mem(union jffs2_node_union *node)
-{
-	struct jffs2_sum_xattr_mem *temp = xmalloc(sizeof(*temp));
-
-	temp->nodetype = node->x.nodetype;
-	temp->xid = node->x.xid;
-	temp->version = node->x.version;
-	temp->offset = cpu_to_je32(data_ofs);
-	temp->totlen = node->x.totlen;
-	temp->next = NULL;
-
-	add_sum_mem((union jffs2_sum_mem *) temp);
-}
-
-void add_sum_xref_mem(union jffs2_node_union *node)
-{
-	struct jffs2_sum_xref_mem *temp = xmalloc(sizeof(*temp));
-
-	temp->nodetype = node->r.nodetype;
-	temp->offset = cpu_to_je32(data_ofs);
-	temp->next = NULL;
-
-	add_sum_mem((union jffs2_sum_mem *) temp);
-}
-
-void write_dirent_to_buff(union jffs2_node_union *node)
-{
-	pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize));
-	add_sum_dirent_mem(node);
-	full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen));
-	padword();
-}
-
-
-void write_inode_to_buff(union jffs2_node_union *node)
-{
-	pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE);
-	add_sum_inode_mem(node);	/* Add inode summary mem to summary list */
-	full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen));	/* Write out the inode to inode_buffer */
-	padword();
-}
-
-void write_xattr_to_buff(union jffs2_node_union *node)
-{
-	pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE);
-	add_sum_xattr_mem(node);	/* Add xdatum summary mem to summary list */
-	full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen));
-	padword();
-}
-
-void write_xref_to_buff(union jffs2_node_union *node)
-{
-	pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE);
-	add_sum_xref_mem(node);		/* Add xref summary mem to summary list */
-	full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen));
-	padword();
-}
-
-void create_summed_image(int inp_size)
-{
-	uint8_t *p = file_buffer;
-	union jffs2_node_union *node;
-	uint32_t crc, length;
-	uint16_t type;
-	int bitchbitmask = 0;
-	int obsolete;
-	char name[256];
-
-	while ( p < (file_buffer + inp_size)) {
-
-		node = (union jffs2_node_union *) p;
-
-		/* Skip empty space */
-		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
-			p += 4;
-			continue;
-		}
-
-		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
-			if (!bitchbitmask++)
-				warnmsg("Wrong bitmask  at  0x%08zx, 0x%04x\n",
-					p - file_buffer, je16_to_cpu (node->u.magic));
-			p += 4;
-			continue;
-		}
-
-		bitchbitmask = 0;
-
-		type = je16_to_cpu(node->u.nodetype);
-		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
-			obsolete = 1;
-			type |= JFFS2_NODE_ACCURATE;
-		} else {
-			obsolete = 0;
-		}
-
-		node->u.nodetype = cpu_to_je16(type);
-
-		crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
-		if (crc != je32_to_cpu (node->u.hdr_crc)) {
-			warnmsg("Wrong hdr_crc  at  0x%08zx, 0x%08x instead of 0x%08x\n",
-				p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
-			p += 4;
-			continue;
-		}
-
-		switch(je16_to_cpu(node->u.nodetype)) {
-			case JFFS2_NODETYPE_INODE:
-				bareverbose(verbose,
-					"%8s Inode      node at 0x%08zx, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
-					obsolete ? "Obsolete" : "",
-					p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
-					je32_to_cpu (node->i.version), je32_to_cpu (node->i.isize),
-					je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
-
-				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
-				if (crc != je32_to_cpu (node->i.node_crc)) {
-					warnmsg("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
-						p - file_buffer, je32_to_cpu (node->i.node_crc), crc);
-					p += PAD(je32_to_cpu (node->i.totlen));
-					continue;
-				}
-
-				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
-				if (crc != je32_to_cpu(node->i.data_crc)) {
-					warnmsg("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
-						p - file_buffer, je32_to_cpu (node->i.data_crc), crc);
-					p += PAD(je32_to_cpu (node->i.totlen));
-					continue;
-				}
-
-				write_inode_to_buff(node);
-
-				p += PAD(je32_to_cpu (node->i.totlen));
-				break;
-
-			case JFFS2_NODETYPE_DIRENT:
-				memcpy (name, node->d.name, node->d.nsize);
-				name [node->d.nsize] = 0x0;
-
-				bareverbose(verbose,
-					"%8s Dirent     node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
-					obsolete ? "Obsolete" : "",
-					p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
-					je32_to_cpu (node->d.version), je32_to_cpu (node->d.ino),
-					node->d.nsize, name);
-
-				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
-				if (crc != je32_to_cpu (node->d.node_crc)) {
-					warnmsg("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
-						p - file_buffer, je32_to_cpu (node->d.node_crc), crc);
-					p += PAD(je32_to_cpu (node->d.totlen));
-					continue;
-				}
-
-				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
-				if (crc != je32_to_cpu(node->d.name_crc)) {
-					warnmsg("Wrong name_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
-						p - file_buffer, je32_to_cpu (node->d.name_crc), crc);
-					p += PAD(je32_to_cpu (node->d.totlen));
-					continue;
-				}
-
-				write_dirent_to_buff(node);
-
-				p += PAD(je32_to_cpu (node->d.totlen));
-				break;
-
-			case JFFS2_NODETYPE_XATTR:
-				if (je32_to_cpu(node->x.node_crc) == 0xffffffff)
-					obsolete = 1;
-				bareverbose(verbose,
-					"%8s Xdatum     node at 0x%08zx, totlen 0x%08x, #xid  %5u, version %5u\n",
-					obsolete ? "Obsolete" : "",
-					p - file_buffer, je32_to_cpu (node->x.totlen),
-					je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version));
-				crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4);
-				if (crc != je32_to_cpu(node->x.node_crc)) {
-					warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
-							p - file_buffer, je32_to_cpu(node->x.node_crc), crc);
-					p += PAD(je32_to_cpu (node->x.totlen));
-					continue;
-				}
-				length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len);
-				crc = mtd_crc32(0, node->x.data, length);
-				if (crc != je32_to_cpu(node->x.data_crc)) {
-					warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
-							p - file_buffer, je32_to_cpu(node->x.data_crc), crc);
-					p += PAD(je32_to_cpu (node->x.totlen));
-					continue;
-				}
-
-				write_xattr_to_buff(node);
-				p += PAD(je32_to_cpu (node->x.totlen));
-				break;
-
-			case JFFS2_NODETYPE_XREF:
-				if (je32_to_cpu(node->r.node_crc) == 0xffffffff)
-					obsolete = 1;
-				bareverbose(verbose,
-					"%8s Xref       node at 0x%08zx, totlen 0x%08x, #ino  %5u, xid     %5u\n",
-					obsolete ? "Obsolete" : "",
-					p - file_buffer, je32_to_cpu(node->r.totlen),
-					je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid));
-				crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xref) - 4);
-				if (crc != je32_to_cpu(node->r.node_crc)) {
-					warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
-							p - file_buffer, je32_to_cpu(node->r.node_crc), crc);
-					p += PAD(je32_to_cpu (node->r.totlen));
-					continue;
-				}
-
-				write_xref_to_buff(node);
-				p += PAD(je32_to_cpu (node->r.totlen));
-				break;
-
-			case JFFS2_NODETYPE_CLEANMARKER:
-				bareverbose(verbose,
-					"%8s Cleanmarker     at 0x%08zx, totlen 0x%08x\n",
-					obsolete ? "Obsolete" : "",
-					p - file_buffer, je32_to_cpu (node->u.totlen));
-
-				if (!found_cleanmarkers) {
-					found_cleanmarkers = 1;
-
-					if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){
-						cleanmarker_size = je32_to_cpu (node->u.totlen);
-						setup_cleanmarker();
-					}
-				}
-
-				p += PAD(je32_to_cpu (node->u.totlen));
-				break;
-
-			case JFFS2_NODETYPE_PADDING:
-				bareverbose(verbose,
-					"%8s Padding    node at 0x%08zx, totlen 0x%08x\n",
-					obsolete ? "Obsolete" : "",
-					p - file_buffer, je32_to_cpu (node->u.totlen));
-				p += PAD(je32_to_cpu (node->u.totlen));
-				break;
-
-			case 0xffff:
-				p += 4;
-				break;
-
-			default:
-				bareverbose(verbose,
-					"%8s Unknown    node at 0x%08zx, totlen 0x%08x\n",
-					obsolete ? "Obsolete" : "",
-					p - file_buffer, je32_to_cpu (node->u.totlen));
-
-				p += PAD(je32_to_cpu (node->u.totlen));
-		}
-	}
-}
-
-int main(int argc, char **argv)
-{
-	int ret;
-
-	process_options(argc,argv);
-
-	if ((in_fd == -1) || (out_fd == -1)) {
-		if(in_fd != -1)
-			close(in_fd);
-		if(out_fd != -1)
-			close(out_fd);
-		fprintf(stderr, "%s", helptext);
-		errmsg_die("You must specify input and output files!\n");
-	}
-
-	init_buffers();
-	init_sumlist();
-
-	while ((ret = load_next_block())) {
-		create_summed_image(ret);
-	}
-
-	flush_buffers();
-	clean_buffers();
-	clean_sumlist();
-
-	if (in_fd != -1)
-		close(in_fd);
-	if (out_fd != -1)
-		close(out_fd);
-
-	return 0;
-}
diff --git a/ubifs-utils/mkfs.ubifs/.gitignore b/ubifs-utils/mkfs.ubifs/.gitignore
new file mode 100644
index 0000000..6b0e85c
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/.gitignore
@@ -0,0 +1 @@
+/mkfs.ubifs
diff --git a/ubifs-utils/mkfs.ubifs/COPYING b/ubifs-utils/mkfs.ubifs/COPYING
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ubifs-utils/mkfs.ubifs/README b/ubifs-utils/mkfs.ubifs/README
new file mode 100644
index 0000000..7e19939
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/README
@@ -0,0 +1,9 @@
+UBIFS File System - Make File System program
+
+* crc16.h and crc16.c were copied from the linux kernel.
+* crc32.h and crc32.c were copied from mtd-utils and amended.
+* ubifs.h is a selection of definitions from fs/ubifs/ubifs.h from the linux kernel.
+* key.h is copied from fs/ubifs/key.h from the linux kernel.
+* defs.h is a bunch of definitions to smooth things over.
+* lpt.c is a selection of functions copied from fs/ubifs/lpt.c from the linux kernel, and amended.
+* hashtable/* was downloaded from http://www.cl.cam.ac.uk/~cwc22/hashtable/
diff --git a/ubifs-utils/mkfs.ubifs/compr.c b/ubifs-utils/mkfs.ubifs/compr.c
new file mode 100644
index 0000000..34b2f60
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/compr.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy
+ *          Adrian Hunter
+ *          Zoltan Sogor
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <lzo/lzo1x.h>
+#include <linux/types.h>
+
+#define crc32 __zlib_crc32
+#include <zlib.h>
+#undef crc32
+
+#include "compr.h"
+#include "mkfs.ubifs.h"
+
+static void *lzo_mem;
+static unsigned long long errcnt = 0;
+static struct ubifs_info *c = &info_;
+
+#define DEFLATE_DEF_LEVEL     Z_DEFAULT_COMPRESSION
+#define DEFLATE_DEF_WINBITS   11
+#define DEFLATE_DEF_MEMLEVEL  8
+
+static int zlib_deflate(void *in_buf, size_t in_len, void *out_buf,
+			size_t *out_len)
+{
+	z_stream strm;
+
+	strm.zalloc = NULL;
+	strm.zfree = NULL;
+
+	/*
+	 * Match exactly the zlib parameters used by the Linux kernel crypto
+	 * API.
+	 */
+        if (deflateInit2(&strm, DEFLATE_DEF_LEVEL, Z_DEFLATED,
+			 -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL,
+			 Z_DEFAULT_STRATEGY)) {
+		errcnt += 1;
+		return -1;
+	}
+
+	strm.next_in = in_buf;
+	strm.avail_in = in_len;
+	strm.total_in = 0;
+
+	strm.next_out = out_buf;
+	strm.avail_out = *out_len;
+	strm.total_out = 0;
+
+	if (deflate(&strm, Z_FINISH) != Z_STREAM_END) {
+		deflateEnd(&strm);
+		errcnt += 1;
+		return -1;
+	}
+
+	if (deflateEnd(&strm) != Z_OK) {
+		errcnt += 1;
+		return -1;
+	}
+
+	*out_len = strm.total_out;
+
+	return 0;
+}
+
+static int lzo_compress(void *in_buf, size_t in_len, void *out_buf,
+			size_t *out_len)
+{
+	lzo_uint len;
+	int ret;
+
+	len = *out_len;
+	ret = lzo1x_999_compress(in_buf, in_len, out_buf, &len, lzo_mem);
+	*out_len = len;
+
+	if (ret != LZO_E_OK) {
+		errcnt += 1;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int no_compress(void *in_buf, size_t in_len, void *out_buf,
+		       size_t *out_len)
+{
+	memcpy(out_buf, in_buf, in_len);
+	*out_len = in_len;
+	return 0;
+}
+
+static char *zlib_buf;
+
+static int favor_lzo_compress(void *in_buf, size_t in_len, void *out_buf,
+			       size_t *out_len, int *type)
+{
+	int lzo_ret, zlib_ret;
+	size_t lzo_len, zlib_len;
+
+	lzo_len = zlib_len = *out_len;
+	lzo_ret = lzo_compress(in_buf, in_len, out_buf, &lzo_len);
+	zlib_ret = zlib_deflate(in_buf, in_len, zlib_buf, &zlib_len);
+
+	if (lzo_ret && zlib_ret)
+		/* Both compressors failed */
+		return -1;
+
+	if (!lzo_ret && !zlib_ret) {
+		double percent;
+
+		/* Both compressors succeeded */
+		if (lzo_len <= zlib_len )
+			goto select_lzo;
+
+		percent = (double)zlib_len / (double)lzo_len;
+		percent *= 100;
+		if (percent > 100 - c->favor_percent)
+			goto select_lzo;
+		goto select_zlib;
+	}
+
+	if (lzo_ret)
+		/* Only zlib compressor succeeded */
+		goto select_zlib;
+
+	/* Only LZO compressor succeeded */
+
+select_lzo:
+	*out_len = lzo_len;
+	*type = MKFS_UBIFS_COMPR_LZO;
+	return 0;
+
+select_zlib:
+	*out_len = zlib_len;
+	*type = MKFS_UBIFS_COMPR_ZLIB;
+	memcpy(out_buf, zlib_buf, zlib_len);
+	return 0;
+}
+
+int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len,
+		  int type)
+{
+	int ret;
+
+	if (in_len < UBIFS_MIN_COMPR_LEN) {
+		no_compress(in_buf, in_len, out_buf, out_len);
+		return MKFS_UBIFS_COMPR_NONE;
+	}
+
+	if (c->favor_lzo)
+		ret = favor_lzo_compress(in_buf, in_len, out_buf, out_len, &type);
+	else {
+		switch (type) {
+		case MKFS_UBIFS_COMPR_LZO:
+			ret = lzo_compress(in_buf, in_len, out_buf, out_len);
+			break;
+		case MKFS_UBIFS_COMPR_ZLIB:
+			ret = zlib_deflate(in_buf, in_len, out_buf, out_len);
+			break;
+		case MKFS_UBIFS_COMPR_NONE:
+			ret = 1;
+			break;
+		default:
+			errcnt += 1;
+			ret = 1;
+			break;
+		}
+	}
+	if (ret || *out_len >= in_len) {
+		no_compress(in_buf, in_len, out_buf, out_len);
+		return MKFS_UBIFS_COMPR_NONE;
+	}
+	return type;
+}
+
+int init_compression(void)
+{
+	lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
+	if (!lzo_mem)
+		return -1;
+
+	zlib_buf = malloc(UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR);
+	if (!zlib_buf) {
+		free(lzo_mem);
+		return -1;
+	}
+
+	return 0;
+}
+
+void destroy_compression(void)
+{
+	free(zlib_buf);
+	free(lzo_mem);
+	if (errcnt)
+		fprintf(stderr, "%llu compression errors occurred\n", errcnt);
+}
diff --git a/ubifs-utils/mkfs.ubifs/compr.h b/ubifs-utils/mkfs.ubifs/compr.h
new file mode 100644
index 0000000..e3dd95c
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/compr.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy
+ *          Adrian Hunter
+ *          Zoltan Sogor
+ */
+
+#ifndef __UBIFS_COMPRESS_H__
+#define __UBIFS_COMPRESS_H__
+
+/*
+ * Compressors may end-up with more data in the output buffer than in the input
+ * buffer. This constant defined the worst case factor, i.e. we assume that the
+ * output buffer may be at max. WORST_COMPR_FACTOR times larger than input
+ * buffer.
+ */
+#define WORST_COMPR_FACTOR 4
+
+enum compression_type
+{
+	MKFS_UBIFS_COMPR_NONE,
+	MKFS_UBIFS_COMPR_LZO,
+	MKFS_UBIFS_COMPR_ZLIB,
+};
+
+int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len,
+		  int type);
+int init_compression(void);
+void destroy_compression(void);
+
+#endif
diff --git a/ubifs-utils/mkfs.ubifs/crc16.c b/ubifs-utils/mkfs.ubifs/crc16.c
new file mode 100644
index 0000000..a19512e
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/crc16.c
@@ -0,0 +1,56 @@
+/*
+ * This code was taken from the linux kernel. The license is GPL Version 2.
+ */
+
+#include "crc16.h"
+
+/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
+uint16_t const crc16_table[256] = {
+	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+/**
+ * crc16 - compute the CRC-16 for the data buffer
+ * @crc:	previous CRC value
+ * @buffer:	data pointer
+ * @len:	number of bytes in the buffer
+ *
+ * Returns the updated CRC value.
+ */
+uint16_t crc16(uint16_t crc, uint8_t const *buffer, size_t len)
+{
+	while (len--)
+		crc = crc16_byte(crc, *buffer++);
+	return crc;
+}
diff --git a/ubifs-utils/mkfs.ubifs/crc16.h b/ubifs-utils/mkfs.ubifs/crc16.h
new file mode 100644
index 0000000..539d21a
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/crc16.h
@@ -0,0 +1,27 @@
+/*
+ * Implements the standard CRC-16:
+ *   Width 16
+ *   Poly  0x8005 (x^16 + x^15 + x^2 + 1)
+ *   Init  0
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner at wabtec.com>
+ *
+ * This code was taken from the linux kernel. The license is GPL Version 2.
+ */
+
+#ifndef __CRC16_H__
+#define __CRC16_H__
+
+#include <stdlib.h>
+#include <stdint.h>
+
+extern uint16_t const crc16_table[256];
+
+extern uint16_t crc16(uint16_t crc, const uint8_t *buffer, size_t len);
+
+static inline uint16_t crc16_byte(uint16_t crc, const uint8_t data)
+{
+	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
+}
+
+#endif /* __CRC16_H__ */
diff --git a/ubifs-utils/mkfs.ubifs/defs.h b/ubifs-utils/mkfs.ubifs/defs.h
new file mode 100644
index 0000000..1fa3316
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/defs.h
@@ -0,0 +1,92 @@
+/*
+ * Greate deal of the code was taken from the kernel UBIFS implementation, and
+ * this file contains some "glue" definitions.
+ */
+
+#ifndef __UBIFS_DEFS_H__
+#define __UBIFS_DEFS_H__
+
+#define t16(x) ({ \
+	uint16_t __b = (x); \
+	(__LITTLE_ENDIAN==__BYTE_ORDER) ? __b : bswap_16(__b); \
+})
+
+#define t32(x) ({ \
+	uint32_t __b = (x); \
+	(__LITTLE_ENDIAN==__BYTE_ORDER) ? __b : bswap_32(__b); \
+})
+
+#define t64(x) ({ \
+	uint64_t __b = (x); \
+	(__LITTLE_ENDIAN==__BYTE_ORDER) ? __b : bswap_64(__b); \
+})
+
+#define cpu_to_le16(x) ((__le16){t16(x)})
+#define cpu_to_le32(x) ((__le32){t32(x)})
+#define cpu_to_le64(x) ((__le64){t64(x)})
+
+#define le16_to_cpu(x) (t16((x)))
+#define le32_to_cpu(x) (t32((x)))
+#define le64_to_cpu(x) (t64((x)))
+
+#define unlikely(x) (x)
+
+#define ubifs_assert(x) ({})
+
+struct qstr
+{
+	char *name;
+	size_t len;
+};
+
+/**
+ * fls - find last (most-significant) bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as ffs.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+static inline int fls(int x)
+{
+	int r = 32;
+
+	if (!x)
+		return 0;
+	if (!(x & 0xffff0000u)) {
+		x <<= 16;
+		r -= 16;
+	}
+	if (!(x & 0xff000000u)) {
+		x <<= 8;
+		r -= 8;
+	}
+	if (!(x & 0xf0000000u)) {
+		x <<= 4;
+		r -= 4;
+	}
+	if (!(x & 0xc0000000u)) {
+		x <<= 2;
+		r -= 2;
+	}
+	if (!(x & 0x80000000u)) {
+		x <<= 1;
+		r -= 1;
+	}
+	return r;
+}
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+#if INT_MAX != 0x7fffffff
+#error : sizeof(int) must be 4 for this program
+#endif
+
+#if (~0ULL) != 0xffffffffffffffffULL
+#error : sizeof(long long) must be 8 for this program
+#endif
+
+#endif
diff --git a/ubifs-utils/mkfs.ubifs/devtable.c b/ubifs-utils/mkfs.ubifs/devtable.c
new file mode 100644
index 0000000..dee035d
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/devtable.c
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Artem Bityutskiy
+ *
+ * Part of the device table parsing code was taken from the mkfs.jffs2 utility.
+ * The original author of that code is Erik Andersen, hence:
+ *	Copyright (C) 2001, 2002 Erik Andersen <andersen at codepoet.org>
+ */
+
+/*
+ * This file implemented device table support. 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)
+ *
+ * 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.
+ *
+ * Please, refer the device_table.txt file which can be found at MTD utilities
+ * for more information about what the device table is.
+ */
+
+#include "mkfs.ubifs.h"
+#include "hashtable/hashtable.h"
+#include "hashtable/hashtable_itr.h"
+
+/*
+ * The hash table which contains paths to files/directories/device nodes
+ * referred to in the device table. For example, if the device table refers
+ * "/dev/loop0", the @path_htbl will contain "/dev" element.
+ */
+static struct hashtable *path_htbl;
+
+/* Hash function used for hash tables */
+static unsigned int r5_hash(void *s)
+{
+	unsigned int a = 0;
+	const signed char *str = s;
+
+	while (*str) {
+		a += *str << 4;
+		a += *str >> 4;
+		a *= 11;
+		str++;
+	}
+
+	return a;
+}
+
+/*
+ * Check whether 2 keys of a hash table are equivalent. The keys are path/file
+ * names, so we simply use 'strcmp()'.
+ */
+static int is_equivalent(void *k1, void *k2)
+{
+	return !strcmp(k1, k2);
+}
+
+/**
+ * separate_last - separate out the last path component
+ * @buf: the path to split
+ * @len: length of the @buf string
+ * @path: the beginning of path is returned here
+ * @name: the last path component is returned here
+ *
+ * This helper function separates out the the last component of the full path
+ * string. For example, "/dev/loop" would be split on "/dev" and "loop". This
+ * function allocates memory for @path and @name and return the result there.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int separate_last(const char *buf, int len, char **path, char **name)
+{
+	int path_len = len, name_len;
+	const char *p = buf + len, *n;
+
+	while (*--p != '/')
+		path_len -= 1;
+
+	/* Drop the final '/' unless this is the root directory */
+	name_len = len - path_len;
+	n = buf + path_len;
+	if (path_len > 1)
+		path_len -= 1;
+
+	*path = malloc(path_len + 1);
+	if (!*path)
+		return err_msg("cannot allocate %d bytes of memory",
+			       path_len + 1);
+	memcpy(*path, buf, path_len);
+	(*path)[path_len] = '\0';
+
+	*name = malloc(name_len + 1);
+	if (!*name) {
+		free(*path);
+		return err_msg("cannot allocate %d bytes of memory",
+			       name_len + 1);
+	}
+	memcpy(*name, n, name_len + 1);
+
+	return 0;
+}
+
+static int interpret_table_entry(const char *line)
+{
+	char buf[1024], type, *path = NULL, *name = NULL;
+	int len;
+	struct path_htbl_element *ph_elt = NULL;
+	struct name_htbl_element *nh_elt = NULL;
+	unsigned int mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
+	unsigned int start = 0, increment = 0, count = 0;
+
+	if (sscanf(line, "%1023s %c %o %u %u %u %u %u %u %u",
+		   buf, &type, &mode, &uid, &gid, &major, &minor,
+		   &start, &increment, &count) < 0)
+		return sys_err_msg("sscanf failed");
+
+	dbg_msg(3, "name %s, type %c, mode %o, uid %u, gid %u, major %u, "
+		"minor %u, start %u, inc %u, cnt %u",
+		buf, type, mode, uid, gid, major, minor, start,
+		increment, count);
+
+	len = strnlen(buf, 1024);
+	if (len == 1024)
+		return err_msg("too long path");
+
+	if (!strcmp(buf, "/"))
+		return err_msg("device table entries require absolute paths");
+	if (buf[1] == '\0')
+		return err_msg("root directory cannot be created");
+	if (strstr(buf, "//"))
+		return err_msg("'//' cannot be used in the path");
+	if (buf[len - 1] == '/')
+		return err_msg("do not put '/' at the end");
+
+	if (strstr(buf, "/./") || strstr(buf, "/../") ||
+	    !strcmp(buf + len - 2, "/.") || !strcmp(buf + len - 3, "/.."))
+		return err_msg("'.' and '..' cannot be used in the path");
+
+	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:
+			return err_msg("unsupported file type '%c'", type);
+	}
+
+	if (separate_last(buf, len, &path, &name))
+		return -1;
+
+	/*
+	 * Check if this path already exist in the path hash table and add it
+	 * if it is not.
+	 */
+	ph_elt = hashtable_search(path_htbl, path);
+	if (!ph_elt) {
+		dbg_msg(3, "inserting '%s' into path hash table", path);
+		ph_elt = malloc(sizeof(struct path_htbl_element));
+		if (!ph_elt) {
+			err_msg("cannot allocate %zd bytes of memory",
+				sizeof(struct path_htbl_element));
+			goto out_free;
+		}
+
+		if (!hashtable_insert(path_htbl, path, ph_elt)) {
+			err_msg("cannot insert into path hash table");
+			goto out_free;
+		}
+
+		ph_elt->path = path;
+		path = NULL;
+		ph_elt->name_htbl = create_hashtable(128, &r5_hash,
+						     &is_equivalent);
+		if (!ph_elt->name_htbl) {
+			err_msg("cannot create name hash table");
+			goto out_free;
+		}
+	}
+
+	if (increment != 0 && count == 0)
+		return err_msg("count cannot be zero if increment is non-zero");
+
+	/*
+	 * Add the file/directory/device node (last component of the path) to
+	 * the name hashtable. The name hashtable resides in the corresponding
+	 * path hashtable element.
+	 */
+
+	if (count == 0) {
+		/* This entry does not require any iterating */
+		nh_elt = malloc(sizeof(struct name_htbl_element));
+		if (!nh_elt) {
+			err_msg("cannot allocate %zd bytes of memory",
+				sizeof(struct name_htbl_element));
+			goto out_free;
+		}
+
+		nh_elt->mode = mode;
+		nh_elt->uid = uid;
+		nh_elt->gid = gid;
+		nh_elt->dev = makedev(major, minor);
+
+		dbg_msg(3, "inserting '%s' into name hash table (major %d, minor %d)",
+			name, major(nh_elt->dev), minor(nh_elt->dev));
+
+		if (hashtable_search(ph_elt->name_htbl, name))
+			return err_msg("'%s' is referred twice", buf);
+
+		nh_elt->name = name;
+		if (!hashtable_insert(ph_elt->name_htbl, name, nh_elt)) {
+			err_msg("cannot insert into name hash table");
+			goto out_free;
+		}
+	} else {
+		int i, num = start + count, len = strlen(name) + 20;
+		char *nm;
+
+		for (i = start; i < num; i++) {
+			nh_elt = malloc(sizeof(struct name_htbl_element));
+			if (!nh_elt) {
+				err_msg("cannot allocate %zd bytes of memory",
+					sizeof(struct name_htbl_element));
+				goto out_free;
+			}
+
+			nh_elt->mode = mode;
+			nh_elt->uid = uid;
+			nh_elt->gid = gid;
+			nh_elt->dev = makedev(major, minor + (i - start) * increment);
+
+			nm = malloc(len);
+			if (!nm) {
+				err_msg("cannot allocate %d bytes of memory", len);
+				goto out_free;
+			}
+
+			sprintf(nm, "%s%d", name, i);
+			nh_elt->name = nm;
+
+			dbg_msg(3, "inserting '%s' into name hash table (major %d, minor %d)",
+			        nm, major(nh_elt->dev), minor(nh_elt->dev));
+
+			if (hashtable_search(ph_elt->name_htbl, nm)) {
+				err_msg("'%s' is referred twice", buf);
+				free (nm);
+				goto out_free;
+			}
+
+			if (!hashtable_insert(ph_elt->name_htbl, nm, nh_elt)) {
+				err_msg("cannot insert into name hash table");
+				free (nm);
+				goto out_free;
+			}
+		}
+		free(name);
+		name = NULL;
+	}
+
+	return 0;
+
+out_free:
+	free(ph_elt);
+	free(nh_elt);
+	free(path);
+	free(name);
+	return -1;
+}
+
+/**
+ * parse_devtable - parse the device table.
+ * @tbl_file: device table file name
+ *
+ * This function parses the device table and prepare the hash table which will
+ * later be used by mkfs.ubifs to create the specified files/device nodes.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+int parse_devtable(const char *tbl_file)
+{
+	FILE *f;
+	char *line = NULL;
+	struct stat st;
+	size_t len;
+
+	dbg_msg(1, "parsing device table file '%s'", tbl_file);
+
+	path_htbl = create_hashtable(128, &r5_hash, &is_equivalent);
+	if (!path_htbl)
+		return err_msg("cannot create path hash table");
+
+	f = fopen(tbl_file, "r");
+	if (!f)
+		return sys_err_msg("cannot open '%s'", tbl_file);
+
+	if (fstat(fileno(f), &st) < 0) {
+		sys_err_msg("cannot stat '%s'", tbl_file);
+		goto out_close;
+	}
+
+	if (st.st_size < 10) {
+		sys_err_msg("'%s' is too short", tbl_file);
+		goto out_close;
+	}
+
+	/*
+	 * 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
+	 */
+	while (getline(&line, &len, f) != -1) {
+		/* First trim off any white-space */
+		len = strlen(line);
+
+		/* Trim trailing white-space */
+		while (len > 0 && isspace(line[len - 1]))
+			line[--len] = '\0';
+		/* Trim leading white-space */
+		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)) {
+				err_msg("cannot parse '%s'", line);
+				goto out_close;
+			}
+		}
+
+		free(line);
+		line = NULL;
+	}
+
+	dbg_msg(1, "finished parsing");
+	fclose(f);
+	return 0;
+
+out_close:
+	fclose(f);
+	free_devtable_info();
+	return -1;
+}
+
+/**
+ * devtbl_find_path - find a path in the path hash table.
+ * @path: UBIFS path to find.
+ *
+ * This looks up the path hash table. Returns the path hash table element
+ * reference if @path was found and %NULL if not.
+ */
+struct path_htbl_element *devtbl_find_path(const char *path)
+{
+	if (!path_htbl)
+		return NULL;
+
+	return hashtable_search(path_htbl, (void *)path);
+}
+
+/**
+ * devtbl_find_name - find a name in the name hash table.
+ * @ph_etl: path hash table element to find at
+ * @name: name to find
+ *
+ * This looks up the name hash table. Returns the name hash table element
+ * reference if @name found and %NULL if not.
+ */
+struct name_htbl_element *devtbl_find_name(struct path_htbl_element *ph_elt,
+					   const char *name)
+{
+	if (!path_htbl)
+		return NULL;
+
+	return hashtable_search(ph_elt->name_htbl, (void *)name);
+}
+
+/**
+ * override_attributes - override inode attributes.
+ * @st: struct stat object to containing the attributes to override
+ * @ph_elt: path hash table element object
+ * @nh_elt: name hash table element object containing the new values
+ *
+ * The device table file may override attributes like UID of files. For
+ * example, the device table may contain a "/dev" entry, and the UBIFS FS on
+ * the host may contain "/dev" directory. In this case the attributes of the
+ * "/dev" directory inode has to be as the device table specifies.
+ *
+ * Note, the hash element is removed by this function as well.
+ */
+int override_attributes(struct stat *st, struct path_htbl_element *ph_elt,
+			struct name_htbl_element *nh_elt)
+{
+	if (!path_htbl)
+		return 0;
+
+	if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode) ||
+	    S_ISFIFO(st->st_mode))
+		return err_msg("%s/%s both exists at UBIFS root at host, "
+			       "and is referred from the device table",
+			       strcmp(ph_elt->path, "/") ? ph_elt->path : "",
+			       nh_elt->name);
+
+	if ((st->st_mode & S_IFMT) != (nh_elt->mode & S_IFMT))
+		return err_msg("%s/%s is referred from the device table also exists in "
+			       "the UBIFS root directory at host, but the file type is "
+			       "different", strcmp(ph_elt->path, "/") ? ph_elt->path : "",
+			       nh_elt->name);
+
+	dbg_msg(3, "set UID %d, GID %d, mode %o for %s/%s as device table says",
+		nh_elt->uid, nh_elt->gid, nh_elt->mode, ph_elt->path, nh_elt->name);
+
+	st->st_uid = nh_elt->uid;
+	st->st_gid = nh_elt->gid;
+	st->st_mode = nh_elt->mode;
+
+	hashtable_remove(ph_elt->name_htbl, (void *)nh_elt->name);
+	return 0;
+}
+
+/**
+ * first_name_htbl_element - return first element of the name hash table.
+ * @ph_elt: the path hash table the name hash table belongs to
+ * @itr: double pointer to a 'struct hashtable_itr' object where the
+ *       information about further iterations is stored
+ *
+ * This function implements name hash table iteration together with
+ * 'next_name_htbl_element()'. Returns the first name hash table element or
+ * %NULL if the hash table is empty.
+ */
+struct name_htbl_element *
+first_name_htbl_element(struct path_htbl_element *ph_elt,
+			struct hashtable_itr **itr)
+{
+	if (!path_htbl || !ph_elt || hashtable_count(ph_elt->name_htbl) == 0)
+		return NULL;
+
+	*itr = hashtable_iterator(ph_elt->name_htbl);
+	return hashtable_iterator_value(*itr);
+}
+
+/**
+ * first_name_htbl_element - return next element of the name hash table.
+ * @ph_elt: the path hash table the name hash table belongs to
+ * @itr: double pointer to a 'struct hashtable_itr' object where the
+ *       information about further iterations is stored
+ *
+ * This function implements name hash table iteration together with
+ * 'first_name_htbl_element()'. Returns the next name hash table element or
+ * %NULL if there are no more elements.
+ */
+struct name_htbl_element *
+next_name_htbl_element(struct path_htbl_element *ph_elt,
+		       struct hashtable_itr **itr)
+{
+	if (!path_htbl || !ph_elt || !hashtable_iterator_advance(*itr))
+		return NULL;
+
+	return hashtable_iterator_value(*itr);
+}
+
+/**
+ * free_devtable_info - free device table information.
+ *
+ * This function frees the path hash table and the name hash tables.
+ */
+void free_devtable_info(void)
+{
+	struct hashtable_itr *ph_itr;
+	struct path_htbl_element *ph_elt;
+
+	if (!path_htbl)
+		return;
+
+	if (hashtable_count(path_htbl) > 0) {
+		ph_itr = hashtable_iterator(path_htbl);
+		do {
+			ph_elt = hashtable_iterator_value(ph_itr);
+			/*
+			 * Note, since we use the same string for the key and
+			 * @name in the name hash table elements, we do not
+			 * have to iterate name hash table because @name memory
+			 * will be freed when freeing the key.
+			 */
+			hashtable_destroy(ph_elt->name_htbl, 1);
+		} while (hashtable_iterator_advance(ph_itr));
+	}
+	hashtable_destroy(path_htbl, 1);
+}
diff --git a/ubifs-utils/mkfs.ubifs/hashtable/hashtable.c b/ubifs-utils/mkfs.ubifs/hashtable/hashtable.c
new file mode 100644
index 0000000..c1f99ed
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/hashtable/hashtable.c
@@ -0,0 +1,277 @@
+/* Copyright (C) 2004 Christopher Clark <firstname.lastname at cl.cam.ac.uk> */
+
+#define PROGRAM_NAME "hashtable"
+
+#include "common.h"
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+/*
+Credit for primes table: Aaron Krowne
+ http://br.endernet.org/~akrowne/
+ http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
+*/
+static const unsigned int primes[] = {
+53, 97, 193, 389,
+769, 1543, 3079, 6151,
+12289, 24593, 49157, 98317,
+196613, 393241, 786433, 1572869,
+3145739, 6291469, 12582917, 25165843,
+50331653, 100663319, 201326611, 402653189,
+805306457, 1610612741
+};
+const unsigned int prime_table_length = ARRAY_SIZE(primes);
+const float max_load_factor = 0.65;
+
+/*****************************************************************************/
+struct hashtable *
+create_hashtable(unsigned int minsize,
+                 unsigned int (*hashf) (void*),
+                 int (*eqf) (void*,void*))
+{
+    struct hashtable *h;
+    unsigned int pindex, size = primes[0];
+    /* Check requested hashtable isn't too large */
+    if (minsize > (1u << 30)) return NULL;
+    /* Enforce size as prime */
+    for (pindex=0; pindex < prime_table_length; pindex++) {
+        if (primes[pindex] > minsize) { size = primes[pindex]; break; }
+    }
+    h = (struct hashtable *)malloc(sizeof(struct hashtable));
+    if (NULL == h) return NULL; /*oom*/
+    h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
+    if (NULL == h->table) { free(h); return NULL; } /*oom*/
+    memset(h->table, 0, size * sizeof(struct entry *));
+    h->tablelength  = size;
+    h->primeindex   = pindex;
+    h->entrycount   = 0;
+    h->hashfn       = hashf;
+    h->eqfn         = eqf;
+    h->loadlimit    = (unsigned int) ceil(size * max_load_factor);
+    return h;
+}
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k)
+{
+    /* Aim to protect against poor hash functions by adding logic here
+     * - logic taken from java 1.4 hashtable source */
+    unsigned int i = h->hashfn(k);
+    i += ~(i << 9);
+    i ^=  ((i >> 14) | (i << 18)); /* >>> */
+    i +=  (i << 4);
+    i ^=  ((i >> 10) | (i << 22)); /* >>> */
+    return i;
+}
+
+/*****************************************************************************/
+static int
+hashtable_expand(struct hashtable *h)
+{
+    /* Double the size of the table to accomodate more entries */
+    struct entry **newtable;
+    struct entry *e;
+    struct entry **pE;
+    unsigned int newsize, i, index;
+    /* Check we're not hitting max capacity */
+    if (h->primeindex == (prime_table_length - 1)) return 0;
+    newsize = primes[++(h->primeindex)];
+
+    newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
+    if (NULL != newtable)
+    {
+        memset(newtable, 0, newsize * sizeof(struct entry *));
+        /* This algorithm is not 'stable'. ie. it reverses the list
+         * when it transfers entries between the tables */
+        for (i = 0; i < h->tablelength; i++) {
+            while (NULL != (e = h->table[i])) {
+                h->table[i] = e->next;
+                index = indexFor(newsize,e->h);
+                e->next = newtable[index];
+                newtable[index] = e;
+            }
+        }
+        free(h->table);
+        h->table = newtable;
+    }
+    /* Plan B: realloc instead */
+    else
+    {
+        newtable = (struct entry **)
+                   realloc(h->table, newsize * sizeof(struct entry *));
+        if (NULL == newtable) { (h->primeindex)--; return 0; }
+        h->table = newtable;
+        memset(newtable[h->tablelength], 0, newsize - h->tablelength);
+        for (i = 0; i < h->tablelength; i++) {
+            for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
+                index = indexFor(newsize,e->h);
+                if (index == i)
+                {
+                    pE = &(e->next);
+                }
+                else
+                {
+                    *pE = e->next;
+                    e->next = newtable[index];
+                    newtable[index] = e;
+                }
+            }
+        }
+    }
+    h->tablelength = newsize;
+    h->loadlimit   = (unsigned int) ceil(newsize * max_load_factor);
+    return -1;
+}
+
+/*****************************************************************************/
+unsigned int
+hashtable_count(struct hashtable *h)
+{
+    return h->entrycount;
+}
+
+/*****************************************************************************/
+int
+hashtable_insert(struct hashtable *h, void *k, void *v)
+{
+    /* This method allows duplicate keys - but they shouldn't be used */
+    unsigned int index;
+    struct entry *e;
+    if (++(h->entrycount) > h->loadlimit)
+    {
+        /* Ignore the return value. If expand fails, we should
+         * still try cramming just this value into the existing table
+         * -- we may not have memory for a larger table, but one more
+         * element may be ok. Next time we insert, we'll try expanding again.*/
+        hashtable_expand(h);
+    }
+    e = (struct entry *)malloc(sizeof(struct entry));
+    if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
+    e->h = hash(h,k);
+    index = indexFor(h->tablelength,e->h);
+    e->k = k;
+    e->v = v;
+    e->next = h->table[index];
+    h->table[index] = e;
+    return -1;
+}
+
+/*****************************************************************************/
+void * /* returns value associated with key */
+hashtable_search(struct hashtable *h, void *k)
+{
+    struct entry *e;
+    unsigned int hashvalue, index;
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hashvalue);
+    e = h->table[index];
+    while (NULL != e)
+    {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
+        e = e->next;
+    }
+    return NULL;
+}
+
+/*****************************************************************************/
+void * /* returns value associated with key */
+hashtable_remove(struct hashtable *h, void *k)
+{
+    /* TODO: consider compacting the table when the load factor drops enough,
+     *       or provide a 'compact' method. */
+
+    struct entry *e;
+    struct entry **pE;
+    void *v;
+    unsigned int hashvalue, index;
+
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hash(h,k));
+    pE = &(h->table[index]);
+    e = *pE;
+    while (NULL != e)
+    {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+        {
+            *pE = e->next;
+            h->entrycount--;
+            v = e->v;
+            freekey(e->k);
+            free(e);
+            return v;
+        }
+        pE = &(e->next);
+        e = e->next;
+    }
+    return NULL;
+}
+
+/*****************************************************************************/
+/* destroy */
+void
+hashtable_destroy(struct hashtable *h, int free_values)
+{
+    unsigned int i;
+    struct entry *e, *f;
+    struct entry **table = h->table;
+    if (free_values)
+    {
+        for (i = 0; i < h->tablelength; i++)
+        {
+            e = table[i];
+            while (NULL != e)
+            { f = e; e = e->next; freekey(f->k); free(f->v); free(f); }
+        }
+    }
+    else
+    {
+        for (i = 0; i < h->tablelength; i++)
+        {
+            e = table[i];
+            while (NULL != e)
+            { f = e; e = e->next; freekey(f->k); free(f); }
+        }
+    }
+    free(h->table);
+    free(h);
+}
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/ubifs-utils/mkfs.ubifs/hashtable/hashtable.h b/ubifs-utils/mkfs.ubifs/hashtable/hashtable.h
new file mode 100644
index 0000000..c0b0acd
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/hashtable/hashtable.h
@@ -0,0 +1,199 @@
+/* Copyright (C) 2002 Christopher Clark <firstname.lastname at cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_CWC22_H__
+#define __HASHTABLE_CWC22_H__
+
+struct hashtable;
+
+/* Example of use:
+ *
+ *      struct hashtable  *h;
+ *      struct some_key   *k;
+ *      struct some_value *v;
+ *
+ *      static unsigned int         hash_from_key_fn( void *k );
+ *      static int                  keys_equal_fn ( void *key1, void *key2 );
+ *
+ *      h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
+ *      k = (struct some_key *)     malloc(sizeof(struct some_key));
+ *      v = (struct some_value *)   malloc(sizeof(struct some_value));
+ *
+ *      (initialise k and v to suitable values)
+ *
+ *      if (! hashtable_insert(h,k,v) )
+ *      {     exit(-1);               }
+ *
+ *      if (NULL == (found = hashtable_search(h,k) ))
+ *      {    printf("not found!");                  }
+ *
+ *      if (NULL == (found = hashtable_remove(h,k) ))
+ *      {    printf("Not found\n");                 }
+ *
+ */
+
+/* Macros may be used to define type-safe(r) hashtable access functions, with
+ * methods specialized to take known key and value types as parameters.
+ *
+ * Example:
+ *
+ * Insert this at the start of your file:
+ *
+ * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
+ *
+ * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
+ * These operate just like hashtable_insert etc., with the same parameters,
+ * but their function signatures have 'struct some_key *' rather than
+ * 'void *', and hence can generate compile time errors if your program is
+ * supplying incorrect data as a key (and similarly for value).
+ *
+ * Note that the hash and key equality functions passed to create_hashtable
+ * still take 'void *' parameters instead of 'some key *'. This shouldn't be
+ * a difficult issue as they're only defined and passed once, and the other
+ * functions will ensure that only valid keys are supplied to them.
+ *
+ * The cost for this checking is increased code size and runtime overhead
+ * - if performance is important, it may be worth switching back to the
+ * unsafe methods once your program has been debugged with the safe methods.
+ * This just requires switching to some simple alternative defines - eg:
+ * #define insert_some hashtable_insert
+ *
+ */
+
+/*****************************************************************************
+ * create_hashtable
+
+ * @name                    create_hashtable
+ * @param   minsize         minimum initial size of hashtable
+ * @param   hashfunction    function for hashing keys
+ * @param   key_eq_fn       function for determining key equality
+ * @return                  newly created hashtable or NULL on failure
+ */
+
+struct hashtable *
+create_hashtable(unsigned int minsize,
+                 unsigned int (*hashfunction) (void*),
+                 int (*key_eq_fn) (void*,void*));
+
+/*****************************************************************************
+ * hashtable_insert
+
+ * @name        hashtable_insert
+ * @param   h   the hashtable to insert into
+ * @param   k   the key - hashtable claims ownership and will free on removal
+ * @param   v   the value - does not claim ownership
+ * @return      non-zero for successful insertion
+ *
+ * This function will cause the table to expand if the insertion would take
+ * the ratio of entries to table size over the maximum load factor.
+ *
+ * This function does not check for repeated insertions with a duplicate key.
+ * The value returned when using a duplicate key is undefined -- when
+ * the hashtable changes size, the order of retrieval of duplicate key
+ * entries is reversed.
+ * If in doubt, remove before insert.
+ */
+
+int
+hashtable_insert(struct hashtable *h, void *k, void *v);
+
+#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
+int fnname (struct hashtable *h, keytype *k, valuetype *v) \
+{ \
+    return hashtable_insert(h,k,v); \
+}
+
+/*****************************************************************************
+ * hashtable_search
+
+ * @name        hashtable_search
+ * @param   h   the hashtable to search
+ * @param   k   the key to search for  - does not claim ownership
+ * @return      the value associated with the key, or NULL if none found
+ */
+
+void *
+hashtable_search(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
+valuetype * fnname (struct hashtable *h, keytype *k) \
+{ \
+    return (valuetype *) (hashtable_search(h,k)); \
+}
+
+/*****************************************************************************
+ * hashtable_remove
+
+ * @name        hashtable_remove
+ * @param   h   the hashtable to remove the item from
+ * @param   k   the key to search for  - does not claim ownership
+ * @return      the value associated with the key, or NULL if none found
+ */
+
+void * /* returns value */
+hashtable_remove(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
+valuetype * fnname (struct hashtable *h, keytype *k) \
+{ \
+    return (valuetype *) (hashtable_remove(h,k)); \
+}
+
+
+/*****************************************************************************
+ * hashtable_count
+
+ * @name        hashtable_count
+ * @param   h   the hashtable
+ * @return      the number of items stored in the hashtable
+ */
+unsigned int
+hashtable_count(struct hashtable *h);
+
+
+/*****************************************************************************
+ * hashtable_destroy
+
+ * @name        hashtable_destroy
+ * @param   h   the hashtable
+ * @param       free_values     whether to call 'free' on the remaining values
+ */
+
+void
+hashtable_destroy(struct hashtable *h, int free_values);
+
+#endif /* __HASHTABLE_CWC22_H__ */
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.c b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.c
new file mode 100644
index 0000000..d102453
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.c
@@ -0,0 +1,176 @@
+/* Copyright (C) 2002, 2004 Christopher Clark  <firstname.lastname at cl.cam.ac.uk> */
+
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include "hashtable_itr.h"
+#include <stdlib.h> /* defines NULL */
+
+/*****************************************************************************/
+/* hashtable_iterator    - iterator constructor */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h)
+{
+    unsigned int i, tablelength;
+    struct hashtable_itr *itr = (struct hashtable_itr *)
+        malloc(sizeof(struct hashtable_itr));
+    if (NULL == itr) return NULL;
+    itr->h = h;
+    itr->e = NULL;
+    itr->parent = NULL;
+    tablelength = h->tablelength;
+    itr->index = tablelength;
+    if (0 == h->entrycount) return itr;
+
+    for (i = 0; i < tablelength; i++)
+    {
+        if (NULL != h->table[i])
+        {
+            itr->e = h->table[i];
+            itr->index = i;
+            break;
+        }
+    }
+    return itr;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ *           returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr)
+{
+    unsigned int j,tablelength;
+    struct entry **table;
+    struct entry *next;
+    if (NULL == itr->e) return 0; /* stupidity check */
+
+    next = itr->e->next;
+    if (NULL != next)
+    {
+        itr->parent = itr->e;
+        itr->e = next;
+        return -1;
+    }
+    tablelength = itr->h->tablelength;
+    itr->parent = NULL;
+    if (tablelength <= (j = ++(itr->index)))
+    {
+        itr->e = NULL;
+        return 0;
+    }
+    table = itr->h->table;
+    while (NULL == (next = table[j]))
+    {
+        if (++j >= tablelength)
+        {
+            itr->index = tablelength;
+            itr->e = NULL;
+            return 0;
+        }
+    }
+    itr->index = j;
+    itr->e = next;
+    return -1;
+}
+
+/*****************************************************************************/
+/* remove - remove the entry at the current iterator position
+ *          and advance the iterator, if there is a successive
+ *          element.
+ *          If you want the value, read it before you remove:
+ *          beware memory leaks if you don't.
+ *          Returns zero if end of iteration. */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr)
+{
+    struct entry *remember_e, *remember_parent;
+    int ret;
+
+    /* Do the removal */
+    if (NULL == (itr->parent))
+    {
+        /* element is head of a chain */
+        itr->h->table[itr->index] = itr->e->next;
+    } else {
+        /* element is mid-chain */
+        itr->parent->next = itr->e->next;
+    }
+    /* itr->e is now outside the hashtable */
+    remember_e = itr->e;
+    itr->h->entrycount--;
+    freekey(remember_e->k);
+
+    /* Advance the iterator, correcting the parent */
+    remember_parent = itr->parent;
+    ret = hashtable_iterator_advance(itr);
+    if (itr->parent == remember_e) { itr->parent = remember_parent; }
+    free(remember_e);
+    return ret;
+}
+
+/*****************************************************************************/
+int /* returns zero if not found */
+hashtable_iterator_search(struct hashtable_itr *itr,
+                          struct hashtable *h, void *k)
+{
+    struct entry *e, *parent;
+    unsigned int hashvalue, index;
+
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hashvalue);
+
+    e = h->table[index];
+    parent = NULL;
+    while (NULL != e)
+    {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+        {
+            itr->index = index;
+            itr->e = e;
+            itr->parent = parent;
+            itr->h = h;
+            return -1;
+        }
+        parent = e;
+        e = e->next;
+    }
+    return 0;
+}
+
+
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.h b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.h
new file mode 100644
index 0000000..5c94a04
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname at cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_ITR_CWC22__
+#define __HASHTABLE_ITR_CWC22__
+#include "hashtable.h"
+#include "hashtable_private.h" /* needed to enable inlining */
+
+/*****************************************************************************/
+/* This struct is only concrete here to allow the inlining of two of the
+ * accessor functions. */
+struct hashtable_itr
+{
+    struct hashtable *h;
+    struct entry *e;
+    struct entry *parent;
+    unsigned int index;
+};
+
+
+/*****************************************************************************/
+/* hashtable_iterator
+ */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h);
+
+/*****************************************************************************/
+/* hashtable_iterator_key
+ * - return the value of the (key,value) pair at the current position */
+
+static inline void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{
+    return i->e->k;
+}
+
+/*****************************************************************************/
+/* value - return the value of the (key,value) pair at the current position */
+
+static inline void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{
+    return i->e->v;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ *           returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* remove - remove current element and advance the iterator to the next element
+ *          NB: if you need the value to free it, read it before
+ *          removing. ie: beware memory leaks!
+ *          returns zero if advanced to end of table */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* search - overwrite the supplied iterator, to point to the entry
+ *          matching the supplied key.
+            h points to the hashtable to be searched.
+ *          returns zero if not found. */
+int
+hashtable_iterator_search(struct hashtable_itr *itr,
+                          struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
+int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \
+{ \
+    return (hashtable_iterator_search(i,h,k)); \
+}
+
+
+
+#endif /* __HASHTABLE_ITR_CWC22__*/
+
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/ubifs-utils/mkfs.ubifs/hashtable/hashtable_private.h b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_private.h
new file mode 100644
index 0000000..3a558e6
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_private.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname at cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_PRIVATE_CWC22_H__
+#define __HASHTABLE_PRIVATE_CWC22_H__
+
+#include "hashtable.h"
+
+/*****************************************************************************/
+struct entry
+{
+    void *k, *v;
+    unsigned int h;
+    struct entry *next;
+};
+
+struct hashtable {
+    unsigned int tablelength;
+    struct entry **table;
+    unsigned int entrycount;
+    unsigned int loadlimit;
+    unsigned int primeindex;
+    unsigned int (*hashfn) (void *k);
+    int (*eqfn) (void *k1, void *k2);
+};
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k);
+
+/*****************************************************************************/
+/* indexFor */
+static inline unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue) {
+    return (hashvalue % tablelength);
+};
+
+/* Only works if tablelength == 2^N */
+/*static inline unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue)
+{
+    return (hashvalue & (tablelength - 1u));
+}
+*/
+
+/*****************************************************************************/
+#define freekey(X) free(X)
+/*define freekey(X) ; */
+
+
+/*****************************************************************************/
+
+#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/ubifs-utils/mkfs.ubifs/key.h b/ubifs-utils/mkfs.ubifs/key.h
new file mode 100644
index 0000000..d3a02d4
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/key.h
@@ -0,0 +1,189 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+/*
+ * This header contains various key-related definitions and helper function.
+ * UBIFS allows several key schemes, so we access key fields only via these
+ * helpers. At the moment only one key scheme is supported.
+ *
+ * Simple key scheme
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * Keys are 64-bits long. First 32-bits are inode number (parent inode number
+ * in case of direntry key). Next 3 bits are node type. The last 29 bits are
+ * 4KiB offset in case of inode node, and direntry hash in case of a direntry
+ * node. We use "r5" hash borrowed from reiserfs.
+ */
+
+#ifndef __UBIFS_KEY_H__
+#define __UBIFS_KEY_H__
+
+/**
+ * key_mask_hash - mask a valid hash value.
+ * @val: value to be masked
+ *
+ * We use hash values as offset in directories, so values %0 and %1 are
+ * reserved for "." and "..". %2 is reserved for "end of readdir" marker. This
+ * function makes sure the reserved values are not used.
+ */
+static inline uint32_t key_mask_hash(uint32_t hash)
+{
+	hash &= UBIFS_S_KEY_HASH_MASK;
+	if (unlikely(hash <= 2))
+		hash += 3;
+	return hash;
+}
+
+/**
+ * key_r5_hash - R5 hash function (borrowed from reiserfs).
+ * @s: direntry name
+ * @len: name length
+ */
+static inline uint32_t key_r5_hash(const char *s, int len)
+{
+	uint32_t a = 0;
+	const signed char *str = (const signed char *)s;
+
+	len = len;
+	while (*str) {
+		a += *str << 4;
+		a += *str >> 4;
+		a *= 11;
+		str++;
+	}
+
+	return key_mask_hash(a);
+}
+
+/**
+ * key_test_hash - testing hash function.
+ * @str: direntry name
+ * @len: name length
+ */
+static inline uint32_t key_test_hash(const char *str, int len)
+{
+	uint32_t a = 0;
+
+	len = min_t(uint32_t, len, 4);
+	memcpy(&a, str, len);
+	return key_mask_hash(a);
+}
+
+/**
+ * ino_key_init - initialize inode key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ */
+static inline void ino_key_init(union ubifs_key *key, ino_t inum)
+{
+	key->u32[0] = inum;
+	key->u32[1] = UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/**
+ * dent_key_init - initialize directory entry key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: parent inode number
+ * @nm: direntry name and length
+ */
+static inline void dent_key_init(const struct ubifs_info *c,
+				 union ubifs_key *key, ino_t inum,
+				 const struct qstr *nm)
+{
+	uint32_t hash = c->key_hash(nm->name, nm->len);
+
+	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+	key->u32[0] = inum;
+	key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
+}
+
+/**
+ * data_key_init - initialize data key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ * @block: block number
+ */
+static inline void data_key_init(union ubifs_key *key, ino_t inum,
+				 unsigned int block)
+{
+	ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
+	key->u32[0] = inum;
+	key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS);
+}
+
+/**
+ * key_write - transform a key from in-memory format.
+ * @c: UBIFS file-system description object
+ * @from: the key to transform
+ * @to: the key to store the result
+ */
+static inline void key_write(const union ubifs_key *from, void *to)
+{
+	union ubifs_key *t = to;
+
+	t->j32[0] = cpu_to_le32(from->u32[0]);
+	t->j32[1] = cpu_to_le32(from->u32[1]);
+	memset(to + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * key_write_idx - transform a key from in-memory format for the index.
+ * @c: UBIFS file-system description object
+ * @from: the key to transform
+ * @to: the key to store the result
+ */
+static inline void key_write_idx(const union ubifs_key *from, void *to)
+{
+	union ubifs_key *t = to;
+
+	t->j32[0] = cpu_to_le32(from->u32[0]);
+	t->j32[1] = cpu_to_le32(from->u32[1]);
+}
+
+/**
+ * keys_cmp - compare keys.
+ * @c: UBIFS file-system description object
+ * @key1: the first key to compare
+ * @key2: the second key to compare
+ *
+ * This function compares 2 keys and returns %-1 if @key1 is less than
+ * @key2, 0 if the keys are equivalent and %1 if @key1 is greater than @key2.
+ */
+static inline int keys_cmp(const union ubifs_key *key1,
+			   const union ubifs_key *key2)
+{
+	if (key1->u32[0] < key2->u32[0])
+		return -1;
+	if (key1->u32[0] > key2->u32[0])
+		return 1;
+	if (key1->u32[1] < key2->u32[1])
+		return -1;
+	if (key1->u32[1] > key2->u32[1])
+		return 1;
+
+	return 0;
+}
+
+#endif /* !__UBIFS_KEY_H__ */
diff --git a/ubifs-utils/mkfs.ubifs/lpt.c b/ubifs-utils/mkfs.ubifs/lpt.c
new file mode 100644
index 0000000..6aa0b88
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/lpt.c
@@ -0,0 +1,578 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006, 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy
+ */
+
+#include "mkfs.ubifs.h"
+
+/**
+ * do_calc_lpt_geom - calculate sizes for the LPT area.
+ * @c: the UBIFS file-system description object
+ *
+ * Calculate the sizes of LPT bit fields, nodes, and tree, based on the
+ * properties of the flash and whether LPT is "big" (c->big_lpt).
+ */
+static void do_calc_lpt_geom(struct ubifs_info *c)
+{
+	int n, bits, per_leb_wastage;
+	long long sz, tot_wastage;
+
+	c->pnode_cnt = (c->main_lebs + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+
+	n = (c->pnode_cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+	c->nnode_cnt = n;
+	while (n > 1) {
+		n = (n + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+		c->nnode_cnt += n;
+	}
+
+	c->lpt_hght = 1;
+	n = UBIFS_LPT_FANOUT;
+	while (n < c->pnode_cnt) {
+		c->lpt_hght += 1;
+		n <<= UBIFS_LPT_FANOUT_SHIFT;
+	}
+
+	c->space_bits = fls(c->leb_size) - 3;
+	c->lpt_lnum_bits = fls(c->lpt_lebs);
+	c->lpt_offs_bits = fls(c->leb_size - 1);
+	c->lpt_spc_bits = fls(c->leb_size);
+
+	n = (c->max_leb_cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+	c->pcnt_bits = fls(n - 1);
+
+	c->lnum_bits = fls(c->max_leb_cnt - 1);
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       (c->big_lpt ? c->pcnt_bits : 0) +
+	       (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT;
+	c->pnode_sz = (bits + 7) / 8;
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       (c->big_lpt ? c->pcnt_bits : 0) +
+	       (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT;
+	c->nnode_sz = (bits + 7) / 8;
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       c->lpt_lebs * c->lpt_spc_bits * 2;
+	c->ltab_sz = (bits + 7) / 8;
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       c->lnum_bits * c->lsave_cnt;
+	c->lsave_sz = (bits + 7) / 8;
+
+	/* Calculate the minimum LPT size */
+	c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
+	c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
+	c->lpt_sz += c->ltab_sz;
+	c->lpt_sz += c->lsave_sz;
+
+	/* Add wastage */
+	sz = c->lpt_sz;
+	per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz);
+	sz += per_leb_wastage;
+	tot_wastage = per_leb_wastage;
+	while (sz > c->leb_size) {
+		sz += per_leb_wastage;
+		sz -= c->leb_size;
+		tot_wastage += per_leb_wastage;
+	}
+	tot_wastage += ALIGN(sz, c->min_io_size) - sz;
+	c->lpt_sz += tot_wastage;
+}
+
+/**
+ * calc_dflt_lpt_geom - calculate default LPT geometry.
+ * @c: the UBIFS file-system description object
+ * @main_lebs: number of main area LEBs is passed and returned here
+ * @big_lpt: whether the LPT area is "big" is returned here
+ *
+ * The size of the LPT area depends on parameters that themselves are dependent
+ * on the size of the LPT area. This function, successively recalculates the LPT
+ * area geometry until the parameters and resultant geometry are consistent.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt)
+{
+	int i, lebs_needed;
+	long long sz;
+
+	/* Start by assuming the minimum number of LPT LEBs */
+	c->lpt_lebs = UBIFS_MIN_LPT_LEBS;
+	c->main_lebs = *main_lebs - c->lpt_lebs;
+	if (c->main_lebs <= 0)
+		return -EINVAL;
+
+	/* And assume we will use the small LPT model */
+	c->big_lpt = 0;
+
+	/*
+	 * Calculate the geometry based on assumptions above and then see if it
+	 * makes sense
+	 */
+	do_calc_lpt_geom(c);
+
+	/* Small LPT model must have lpt_sz < leb_size */
+	if (c->lpt_sz > c->leb_size) {
+		/* Nope, so try again using big LPT model */
+		c->big_lpt = 1;
+		do_calc_lpt_geom(c);
+	}
+
+	/* Now check there are enough LPT LEBs */
+	for (i = 0; i < 64 ; i++) {
+		sz = c->lpt_sz * 4; /* Allow 4 times the size */
+		sz += c->leb_size - 1;
+		do_div(sz, c->leb_size);
+		lebs_needed = sz;
+		if (lebs_needed > c->lpt_lebs) {
+			/* Not enough LPT LEBs so try again with more */
+			c->lpt_lebs = lebs_needed;
+			c->main_lebs = *main_lebs - c->lpt_lebs;
+			if (c->main_lebs <= 0)
+				return -EINVAL;
+			do_calc_lpt_geom(c);
+			continue;
+		}
+		if (c->ltab_sz > c->leb_size) {
+			err_msg("LPT ltab too big");
+			return -EINVAL;
+		}
+		*main_lebs = c->main_lebs;
+		*big_lpt = c->big_lpt;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/**
+ * pack_bits - pack bit fields end-to-end.
+ * @addr: address at which to pack (passed and next address returned)
+ * @pos: bit position at which to pack (passed and next position returned)
+ * @val: value to pack
+ * @nrbits: number of bits of value to pack (1-32)
+ */
+static void pack_bits(uint8_t **addr, int *pos, uint32_t val, int nrbits)
+{
+	uint8_t *p = *addr;
+	int b = *pos;
+
+	if (b) {
+		*p |= ((uint8_t)val) << b;
+		nrbits += b;
+		if (nrbits > 8) {
+			*++p = (uint8_t)(val >>= (8 - b));
+			if (nrbits > 16) {
+				*++p = (uint8_t)(val >>= 8);
+				if (nrbits > 24) {
+					*++p = (uint8_t)(val >>= 8);
+					if (nrbits > 32)
+						*++p = (uint8_t)(val >>= 8);
+				}
+			}
+		}
+	} else {
+		*p = (uint8_t)val;
+		if (nrbits > 8) {
+			*++p = (uint8_t)(val >>= 8);
+			if (nrbits > 16) {
+				*++p = (uint8_t)(val >>= 8);
+				if (nrbits > 24)
+					*++p = (uint8_t)(val >>= 8);
+			}
+		}
+	}
+	b = nrbits & 7;
+	if (b == 0)
+		p++;
+	*addr = p;
+	*pos = b;
+}
+
+/**
+ * pack_pnode - pack all the bit fields of a pnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @pnode: pnode to pack
+ */
+static void pack_pnode(struct ubifs_info *c, void *buf,
+		       struct ubifs_pnode *pnode)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0;
+	uint16_t crc;
+
+	pack_bits(&addr, &pos, UBIFS_LPT_PNODE, UBIFS_LPT_TYPE_BITS);
+	if (c->big_lpt)
+		pack_bits(&addr, &pos, pnode->num, c->pcnt_bits);
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		pack_bits(&addr, &pos, pnode->lprops[i].free >> 3,
+			  c->space_bits);
+		pack_bits(&addr, &pos, pnode->lprops[i].dirty >> 3,
+			  c->space_bits);
+		if (pnode->lprops[i].flags & LPROPS_INDEX)
+			pack_bits(&addr, &pos, 1, 1);
+		else
+			pack_bits(&addr, &pos, 0, 1);
+	}
+	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+		    c->pnode_sz - UBIFS_LPT_CRC_BYTES);
+	addr = buf;
+	pos = 0;
+	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * pack_nnode - pack all the bit fields of a nnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @nnode: nnode to pack
+ */
+static void pack_nnode(struct ubifs_info *c, void *buf,
+		       struct ubifs_nnode *nnode)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0;
+	uint16_t crc;
+
+	pack_bits(&addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS);
+	if (c->big_lpt)
+		pack_bits(&addr, &pos, nnode->num, c->pcnt_bits);
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		int lnum = nnode->nbranch[i].lnum;
+
+		if (lnum == 0)
+			lnum = c->lpt_last + 1;
+		pack_bits(&addr, &pos, lnum - c->lpt_first, c->lpt_lnum_bits);
+		pack_bits(&addr, &pos, nnode->nbranch[i].offs,
+			  c->lpt_offs_bits);
+	}
+	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+		    c->nnode_sz - UBIFS_LPT_CRC_BYTES);
+	addr = buf;
+	pos = 0;
+	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * pack_ltab - pack the LPT's own lprops table.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @ltab: LPT's own lprops table to pack
+ */
+static void pack_ltab(struct ubifs_info *c, void *buf,
+			 struct ubifs_lpt_lprops *ltab)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0;
+	uint16_t crc;
+
+	pack_bits(&addr, &pos, UBIFS_LPT_LTAB, UBIFS_LPT_TYPE_BITS);
+	for (i = 0; i < c->lpt_lebs; i++) {
+		pack_bits(&addr, &pos, ltab[i].free, c->lpt_spc_bits);
+		pack_bits(&addr, &pos, ltab[i].dirty, c->lpt_spc_bits);
+	}
+	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+		    c->ltab_sz - UBIFS_LPT_CRC_BYTES);
+	addr = buf;
+	pos = 0;
+	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * pack_lsave - pack the LPT's save table.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @lsave: LPT's save table to pack
+ */
+static void pack_lsave(struct ubifs_info *c, void *buf, int *lsave)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0;
+	uint16_t crc;
+
+	pack_bits(&addr, &pos, UBIFS_LPT_LSAVE, UBIFS_LPT_TYPE_BITS);
+	for (i = 0; i < c->lsave_cnt; i++)
+		pack_bits(&addr, &pos, lsave[i], c->lnum_bits);
+	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+		    c->lsave_sz - UBIFS_LPT_CRC_BYTES);
+	addr = buf;
+	pos = 0;
+	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * set_ltab - set LPT LEB properties.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number
+ * @free: amount of free space
+ * @dirty: amount of dirty space
+ */
+static void set_ltab(struct ubifs_info *c, int lnum, int free, int dirty)
+{
+	dbg_msg(3, "LEB %d free %d dirty %d to %d %d",
+		lnum, c->ltab[lnum - c->lpt_first].free,
+		c->ltab[lnum - c->lpt_first].dirty, free, dirty);
+	c->ltab[lnum - c->lpt_first].free = free;
+	c->ltab[lnum - c->lpt_first].dirty = dirty;
+}
+
+/**
+ * calc_nnode_num - calculate nnode number.
+ * @row: the row in the tree (root is zero)
+ * @col: the column in the row (leftmost is zero)
+ *
+ * The nnode number is a number that uniquely identifies a nnode and can be used
+ * easily to traverse the tree from the root to that nnode.
+ *
+ * This function calculates and returns the nnode number for the nnode at @row
+ * and @col.
+ */
+static int calc_nnode_num(int row, int col)
+{
+	int num, bits;
+
+	num = 1;
+	while (row--) {
+		bits = (col & (UBIFS_LPT_FANOUT - 1));
+		col >>= UBIFS_LPT_FANOUT_SHIFT;
+		num <<= UBIFS_LPT_FANOUT_SHIFT;
+		num |= bits;
+	}
+	return num;
+}
+
+/**
+ * create_lpt - create LPT.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int create_lpt(struct ubifs_info *c)
+{
+	int lnum, err = 0, i, j, cnt, len, alen, row;
+	int blnum, boffs, bsz, bcnt;
+	struct ubifs_pnode *pnode = NULL;
+	struct ubifs_nnode *nnode = NULL;
+	void *buf = NULL, *p;
+	int *lsave = NULL;
+
+	pnode = malloc(sizeof(struct ubifs_pnode));
+	nnode = malloc(sizeof(struct ubifs_nnode));
+	buf = malloc(c->leb_size);
+	lsave = malloc(sizeof(int) * c->lsave_cnt);
+	if (!pnode || !nnode || !buf || !lsave) {
+		err = -ENOMEM;
+		goto out;
+	}
+	memset(pnode, 0 , sizeof(struct ubifs_pnode));
+	memset(nnode, 0 , sizeof(struct ubifs_nnode));
+
+	c->lscan_lnum = c->main_first;
+
+	lnum = c->lpt_first;
+	p = buf;
+	len = 0;
+	/* Number of leaf nodes (pnodes) */
+	cnt = (c->main_lebs + UBIFS_LPT_FANOUT - 1) >> UBIFS_LPT_FANOUT_SHIFT;
+	//printf("pnode_cnt=%d\n",cnt);
+
+	/*
+	 * To calculate the internal node branches, we keep information about
+	 * the level below.
+	 */
+	blnum = lnum; /* LEB number of level below */
+	boffs = 0; /* Offset of level below */
+	bcnt = cnt; /* Number of nodes in level below */
+	bsz = c->pnode_sz; /* Size of nodes in level below */
+
+	/* Add pnodes */
+	for (i = 0; i < cnt; i++) {
+		if (len + c->pnode_sz > c->leb_size) {
+			alen = ALIGN(len, c->min_io_size);
+			set_ltab(c, lnum, c->leb_size - alen, alen - len);
+			memset(p, 0xff, alen - len);
+			err = write_leb(lnum++, alen, buf);
+			if (err)
+				goto out;
+			p = buf;
+			len = 0;
+		}
+		/* Fill in the pnode */
+		for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
+			int k = (i << UBIFS_LPT_FANOUT_SHIFT) + j;
+
+			if (k < c->main_lebs)
+				pnode->lprops[j] = c->lpt[k];
+			else {
+				pnode->lprops[j].free = c->leb_size;
+				pnode->lprops[j].dirty = 0;
+				pnode->lprops[j].flags = 0;
+			}
+		}
+		pack_pnode(c, p, pnode);
+		p += c->pnode_sz;
+		len += c->pnode_sz;
+		/*
+		 * pnodes are simply numbered left to right starting at zero,
+		 * which means the pnode number can be used easily to traverse
+		 * down the tree to the corresponding pnode.
+		 */
+		pnode->num += 1;
+	}
+
+	row = c->lpt_hght - 1;
+	/* Add all nnodes, one level at a time */
+	while (1) {
+		/* Number of internal nodes (nnodes) at next level */
+		cnt = (cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+		if (cnt == 0)
+			cnt = 1;
+		for (i = 0; i < cnt; i++) {
+			if (len + c->nnode_sz > c->leb_size) {
+				alen = ALIGN(len, c->min_io_size);
+				set_ltab(c, lnum, c->leb_size - alen,
+					    alen - len);
+				memset(p, 0xff, alen - len);
+				err = write_leb(lnum++, alen, buf);
+				if (err)
+					goto out;
+				p = buf;
+				len = 0;
+			}
+			/* The root is on row zero */
+			if (row == 0) {
+				c->lpt_lnum = lnum;
+				c->lpt_offs = len;
+			}
+			/* Set branches to the level below */
+			for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
+				if (bcnt) {
+					if (boffs + bsz > c->leb_size) {
+						blnum += 1;
+						boffs = 0;
+					}
+					nnode->nbranch[j].lnum = blnum;
+					nnode->nbranch[j].offs = boffs;
+					boffs += bsz;
+					bcnt--;
+				} else {
+					nnode->nbranch[j].lnum = 0;
+					nnode->nbranch[j].offs = 0;
+				}
+			}
+			nnode->num = calc_nnode_num(row, i);
+			pack_nnode(c, p, nnode);
+			p += c->nnode_sz;
+			len += c->nnode_sz;
+		}
+		/* Row zero  is the top row */
+		if (row == 0)
+			break;
+		/* Update the information about the level below */
+		bcnt = cnt;
+		bsz = c->nnode_sz;
+		row -= 1;
+	}
+
+	if (c->big_lpt) {
+		/* Need to add LPT's save table */
+		if (len + c->lsave_sz > c->leb_size) {
+			alen = ALIGN(len, c->min_io_size);
+			set_ltab(c, lnum, c->leb_size - alen, alen - len);
+			memset(p, 0xff, alen - len);
+			err = write_leb(lnum++, alen, buf);
+			if (err)
+				goto out;
+			p = buf;
+			len = 0;
+		}
+
+		c->lsave_lnum = lnum;
+		c->lsave_offs = len;
+
+		for (i = 0; i < c->lsave_cnt; i++)
+			lsave[i] = c->main_first + i;
+
+		pack_lsave(c, p, lsave);
+		p += c->lsave_sz;
+		len += c->lsave_sz;
+	}
+
+	/* Need to add LPT's own LEB properties table */
+	if (len + c->ltab_sz > c->leb_size) {
+		alen = ALIGN(len, c->min_io_size);
+		set_ltab(c, lnum, c->leb_size - alen, alen - len);
+		memset(p, 0xff, alen - len);
+		err = write_leb(lnum++, alen, buf);
+		if (err)
+			goto out;
+		p = buf;
+		len = 0;
+	}
+
+	c->ltab_lnum = lnum;
+	c->ltab_offs = len;
+
+	/* Update ltab before packing it */
+	len += c->ltab_sz;
+	alen = ALIGN(len, c->min_io_size);
+	set_ltab(c, lnum, c->leb_size - alen, alen - len);
+
+	pack_ltab(c, p, c->ltab);
+	p += c->ltab_sz;
+
+	/* Write remaining buffer */
+	memset(p, 0xff, alen - len);
+	err = write_leb(lnum, alen, buf);
+	if (err)
+		goto out;
+
+	c->nhead_lnum = lnum;
+	c->nhead_offs = ALIGN(len, c->min_io_size);
+
+	dbg_msg(1, "lpt_sz:         %lld", c->lpt_sz);
+	dbg_msg(1, "space_bits:     %d", c->space_bits);
+	dbg_msg(1, "lpt_lnum_bits:  %d", c->lpt_lnum_bits);
+	dbg_msg(1, "lpt_offs_bits:  %d", c->lpt_offs_bits);
+	dbg_msg(1, "lpt_spc_bits:   %d", c->lpt_spc_bits);
+	dbg_msg(1, "pcnt_bits:      %d", c->pcnt_bits);
+	dbg_msg(1, "lnum_bits:      %d", c->lnum_bits);
+	dbg_msg(1, "pnode_sz:       %d", c->pnode_sz);
+	dbg_msg(1, "nnode_sz:       %d", c->nnode_sz);
+	dbg_msg(1, "ltab_sz:        %d", c->ltab_sz);
+	dbg_msg(1, "lsave_sz:       %d", c->lsave_sz);
+	dbg_msg(1, "lsave_cnt:      %d", c->lsave_cnt);
+	dbg_msg(1, "lpt_hght:       %d", c->lpt_hght);
+	dbg_msg(1, "big_lpt:        %d", c->big_lpt);
+	dbg_msg(1, "LPT root is at  %d:%d", c->lpt_lnum, c->lpt_offs);
+	dbg_msg(1, "LPT head is at  %d:%d", c->nhead_lnum, c->nhead_offs);
+	dbg_msg(1, "LPT ltab is at  %d:%d", c->ltab_lnum, c->ltab_offs);
+	if (c->big_lpt)
+		dbg_msg(1, "LPT lsave is at %d:%d",
+		        c->lsave_lnum, c->lsave_offs);
+out:
+	free(lsave);
+	free(buf);
+	free(nnode);
+	free(pnode);
+	return err;
+}
diff --git a/ubifs-utils/mkfs.ubifs/lpt.h b/ubifs-utils/mkfs.ubifs/lpt.h
new file mode 100644
index 0000000..4cde59d
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/lpt.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy
+ *          Adrian Hunter
+ */
+
+#ifndef __UBIFS_LPT_H__
+#define __UBIFS_LPT_H__
+
+int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt);
+int create_lpt(struct ubifs_info *c);
+
+#endif
diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
new file mode 100644
index 0000000..ca17e2b
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
@@ -0,0 +1,2324 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy
+ *          Zoltan Sogor
+ */
+
+#define _XOPEN_SOURCE 500 /* For realpath() */
+
+#include "mkfs.ubifs.h"
+#include <crc32.h>
+#include "common.h"
+
+/* Size (prime number) of hash table for link counting */
+#define HASH_TABLE_SIZE 10099
+
+/* The node buffer must allow for worst case compression */
+#define NODE_BUFFER_SIZE (UBIFS_DATA_NODE_SZ + \
+			  UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
+
+/* Default time granularity in nanoseconds */
+#define DEFAULT_TIME_GRAN 1000000000
+
+/**
+ * struct idx_entry - index entry.
+ * @next: next index entry (NULL at end of list)
+ * @prev: previous index entry (NULL at beginning of list)
+ * @key: key
+ * @name: directory entry name used for sorting colliding keys by name
+ * @lnum: LEB number
+ * @offs: offset
+ * @len: length
+ *
+ * The index is recorded as a linked list which is sorted and used to create
+ * the bottom level of the on-flash index tree. The remaining levels of the
+ * index tree are each built from the level below.
+ */
+struct idx_entry {
+	struct idx_entry *next;
+	struct idx_entry *prev;
+	union ubifs_key key;
+	char *name;
+	int lnum;
+	int offs;
+	int len;
+};
+
+/**
+ * struct inum_mapping - inode number mapping for link counting.
+ * @next: next inum_mapping (NULL at end of list)
+ * @prev: previous inum_mapping (NULL at beginning of list)
+ * @dev: source device on which the source inode number resides
+ * @inum: source inode number of the file
+ * @use_inum: target inode number of the file
+ * @use_nlink: number of links
+ * @path_name: a path name of the file
+ * @st: struct stat object containing inode attributes which have to be used
+ *      when the inode is being created (actually only UID, GID, access
+ *      mode, major and minor device numbers)
+ *
+ * If a file has more than one hard link, then the number of hard links that
+ * exist in the source directory hierarchy must be counted to exclude the
+ * possibility that the file is linked from outside the source directory
+ * hierarchy.
+ *
+ * The inum_mappings are stored in a hash_table of linked lists.
+ */
+struct inum_mapping {
+	struct inum_mapping *next;
+	struct inum_mapping *prev;
+	dev_t dev;
+	ino_t inum;
+	ino_t use_inum;
+	unsigned int use_nlink;
+	char *path_name;
+	struct stat st;
+};
+
+/*
+ * Because we copy functions from the kernel, we use a subset of the UBIFS
+ * file-system description object struct ubifs_info.
+ */
+struct ubifs_info info_;
+static struct ubifs_info *c = &info_;
+static libubi_t ubi;
+
+/* Debug levels are: 0 (none), 1 (statistics), 2 (files) ,3 (more details) */
+int debug_level;
+int verbose;
+int yes;
+
+static char *root;
+static int root_len;
+static struct stat root_st;
+static char *output;
+static int out_fd;
+static int out_ubi;
+static int squash_owner;
+
+/* The 'head' (position) which nodes are written */
+static int head_lnum;
+static int head_offs;
+static int head_flags;
+
+/* The index list */
+static struct idx_entry *idx_list_first;
+static struct idx_entry *idx_list_last;
+static size_t idx_cnt;
+
+/* Global buffers */
+static void *leb_buf;
+static void *node_buf;
+static void *block_buf;
+
+/* Hash table for inode link counting */
+static struct inum_mapping **hash_table;
+
+/* Inode creation sequence number */
+static unsigned long long creat_sqnum;
+
+static const char *optstring = "d:r:m:o:D:yh?vVe:c:g:f:Fp:k:x:X:j:R:l:j:UQq";
+
+static const struct option longopts[] = {
+	{"root",               1, NULL, 'r'},
+	{"min-io-size",        1, NULL, 'm'},
+	{"leb-size",           1, NULL, 'e'},
+	{"max-leb-cnt",        1, NULL, 'c'},
+	{"output",             1, NULL, 'o'},
+	{"devtable",           1, NULL, 'D'},
+	{"yes",                0, NULL, 'y'},
+	{"help",               0, NULL, 'h'},
+	{"verbose",            0, NULL, 'v'},
+	{"version",            0, NULL, 'V'},
+	{"debug-level",        1, NULL, 'g'},
+	{"jrn-size",           1, NULL, 'j'},
+	{"reserved",           1, NULL, 'R'},
+	{"compr",              1, NULL, 'x'},
+	{"favor-percent",      1, NULL, 'X'},
+	{"fanout",             1, NULL, 'f'},
+	{"space-fixup",        0, NULL, 'F'},
+	{"keyhash",            1, NULL, 'k'},
+	{"log-lebs",           1, NULL, 'l'},
+	{"orph-lebs",          1, NULL, 'p'},
+	{"squash-uids" ,       0, NULL, 'U'},
+	{NULL, 0, NULL, 0}
+};
+
+static const char *helptext =
+"Usage: mkfs.ubifs [OPTIONS] target\n"
+"Make a UBIFS file system image from an existing directory tree\n\n"
+"Examples:\n"
+"Build file system from directory /opt/img, writting the result in the ubifs.img file\n"
+"\tmkfs.ubifs -m 512 -e 128KiB -c 100 -r /opt/img ubifs.img\n"
+"The same, but writting directly to an UBI volume\n"
+"\tmkfs.ubifs -r /opt/img /dev/ubi0_0\n"
+"Creating an empty UBIFS filesystem on an UBI volume\n"
+"\tmkfs.ubifs /dev/ubi0_0\n\n"
+"Options:\n"
+"-r, -d, --root=DIR       build file system from directory DIR\n"
+"-m, --min-io-size=SIZE   minimum I/O unit size\n"
+"-e, --leb-size=SIZE      logical erase block size\n"
+"-c, --max-leb-cnt=COUNT  maximum logical erase block count\n"
+"-o, --output=FILE        output to FILE\n"
+"-j, --jrn-size=SIZE      journal size\n"
+"-R, --reserved=SIZE      how much space should be reserved for the super-user\n"
+"-x, --compr=TYPE         compression type - \"lzo\", \"favor_lzo\", \"zlib\" or\n"
+"                         \"none\" (default: \"lzo\")\n"
+"-X, --favor-percent      may only be used with favor LZO compression and defines\n"
+"                         how many percent better zlib should compress to make\n"
+"                         mkfs.ubifs use zlib instead of LZO (default 20%)\n"
+"-f, --fanout=NUM         fanout NUM (default: 8)\n"
+"-F, --space-fixup        file-system free space has to be fixed up on first mount\n"
+"                         (requires kernel version 3.0 or greater)\n"
+"-k, --keyhash=TYPE       key hash type - \"r5\" or \"test\" (default: \"r5\")\n"
+"-p, --orph-lebs=COUNT    count of erase blocks for orphans (default: 1)\n"
+"-D, --devtable=FILE      use device table FILE\n"
+"-U, --squash-uids        squash owners making all files owned by root\n"
+"-l, --log-lebs=COUNT     count of erase blocks for the log (used only for\n"
+"                         debugging)\n"
+"-y, --yes                assume the answer is \"yes\" for all questions\n"
+"-v, --verbose            verbose operation\n"
+"-V, --version            display version information\n"
+"-g, --debug=LEVEL        display debug information (0 - none, 1 - statistics,\n"
+"                         2 - files, 3 - more details)\n"
+"-h, --help               display this help text\n\n"
+"Note, SIZE is specified in bytes, but it may also be specified in Kilobytes,\n"
+"Megabytes, and Gigabytes if a KiB, MiB, or GiB suffix is used.\n\n"
+"If you specify \"lzo\" or \"zlib\" compressors, mkfs.ubifs will use this compressor\n"
+"for all data. The \"none\" disables any data compression. The \"favor_lzo\" is not\n"
+"really a separate compressor. It is just a method of combining \"lzo\" and \"zlib\"\n"
+"compressors. Namely, mkfs.ubifs tries to compress data with both \"lzo\" and \"zlib\"\n"
+"compressors, then it compares which compressor is better. If \"zlib\" compresses 20\n"
+"or more percent better than \"lzo\", mkfs.ubifs chooses \"lzo\", otherwise it chooses\n"
+"\"zlib\". The \"--favor-percent\" may specify arbitrary threshold instead of the\n"
+"default 20%.\n\n"
+"The -F parameter is used to set the \"fix up free space\" flag in the superblock,\n"
+"which forces UBIFS to \"fixup\" all the free space which it is going to use. This\n"
+"option is useful to work-around the problem of double free space programming: if the\n"
+"flasher program which flashes the UBI image is unable to skip NAND pages containing\n"
+"only 0xFF bytes, the effect is that some NAND pages are written to twice - first time\n"
+"when flashing the image and the second time when UBIFS is mounted and writes useful\n"
+"data there. A proper UBI-aware flasher should skip such NAND pages, though. Note, this\n"
+"flag may make the first mount very slow, because the \"free space fixup\" procedure\n"
+"takes time. This feature is supported by the Linux kernel starting from version 3.0.\n";
+
+/**
+ * make_path - make a path name from a directory and a name.
+ * @dir: directory path name
+ * @name: name
+ */
+static char *make_path(const char *dir, const char *name)
+{
+	char *s;
+
+	s = malloc(strlen(dir) + strlen(name) + 2);
+	if (!s)
+		return NULL;
+	strcpy(s, dir);
+	if (dir[strlen(dir) - 1] != '/')
+		strcat(s, "/");
+	strcat(s, name);
+	return s;
+}
+
+/**
+ * is_contained - determine if a file is beneath a directory.
+ * @file: file path name
+ * @dir: directory path name
+ *
+ * This function returns %1 if @file is accessible from the @dir directory and
+ * %0 otherwise. In case of error, returns %-1.
+ */
+static int is_contained(const char *file, const char *dir)
+{
+	char *real_file = NULL;
+	char *real_dir = NULL;
+	char *file_base, *copy;
+	int ret = -1;
+
+	/* Make a copy of the file path because 'dirname()' can modify it */
+	copy = strdup(file);
+	if (!copy)
+		return -1;
+	file_base = dirname(copy);
+
+	/* Turn the paths into the canonical form */
+	real_file = malloc(PATH_MAX);
+	if (!real_file)
+		goto out_free;
+
+	real_dir = malloc(PATH_MAX);
+	if (!real_dir)
+		goto out_free;
+
+	if (!realpath(file_base, real_file)) {
+		perror("Could not canonicalize file path");
+		goto out_free;
+	}
+	if (!realpath(dir, real_dir)) {
+		perror("Could not canonicalize directory");
+		goto out_free;
+	}
+
+	ret = !!strstr(real_file, real_dir);
+
+out_free:
+	free(copy);
+	free(real_file);
+	free(real_dir);
+	return ret;
+}
+
+/**
+ * calc_min_log_lebs - calculate the minimum number of log LEBs needed.
+ * @max_bud_bytes: journal size (buds only)
+ */
+static int calc_min_log_lebs(unsigned long long max_bud_bytes)
+{
+	int buds, log_lebs;
+	unsigned long long log_size;
+
+	buds = (max_bud_bytes + c->leb_size - 1) / c->leb_size;
+	log_size = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size);
+	log_size *= buds;
+	log_size += ALIGN(UBIFS_CS_NODE_SZ +
+			  UBIFS_REF_NODE_SZ * (c->jhead_cnt + 2),
+			  c->min_io_size);
+	log_lebs = (log_size + c->leb_size - 1) / c->leb_size;
+	log_lebs += 1;
+	return log_lebs;
+}
+
+/**
+ * add_space_overhead - add UBIFS overhead.
+ * @size: flash space which should be visible to the user
+ *
+ * UBIFS has overhead, and if we need to reserve @size bytes for the user data,
+ * we have to reserve more flash space, to compensate the overhead. This
+ * function calculates and returns the amount of physical flash space which
+ * should be reserved to provide @size bytes for the user.
+ */
+static long long add_space_overhead(long long size)
+{
+        int divisor, factor, f, max_idx_node_sz;
+
+        /*
+	 * Do the opposite to what the 'ubifs_reported_space()' kernel UBIFS
+	 * function does.
+         */
+	max_idx_node_sz =  ubifs_idx_node_sz(c, c->fanout);
+        f = c->fanout > 3 ? c->fanout >> 1 : 2;
+        divisor = UBIFS_BLOCK_SIZE;
+        factor = UBIFS_MAX_DATA_NODE_SZ;
+        factor += (max_idx_node_sz * 3) / (f - 1);
+        size *= factor;
+        return size / divisor;
+}
+
+static int validate_options(void)
+{
+	int tmp;
+
+	if (!output)
+		return err_msg("no output file or UBI volume specified");
+	if (root) {
+		tmp = is_contained(output, root);
+		if (tmp < 0)
+			return err_msg("failed to perform output file root check");
+		else if (tmp)
+			return err_msg("output file cannot be in the UBIFS root "
+			               "directory");
+	}
+	if (!is_power_of_2(c->min_io_size))
+		return err_msg("min. I/O unit size should be power of 2");
+	if (c->leb_size < c->min_io_size)
+		return err_msg("min. I/O unit cannot be larger than LEB size");
+	if (c->leb_size < UBIFS_MIN_LEB_SZ)
+		return err_msg("too small LEB size %d, minimum is %d",
+			       c->leb_size, UBIFS_MIN_LEB_SZ);
+	if (c->leb_size % c->min_io_size)
+		return err_msg("LEB should be multiple of min. I/O units");
+	if (c->leb_size % 8)
+		return err_msg("LEB size has to be multiple of 8");
+	if (c->leb_size > UBIFS_MAX_LEB_SZ)
+		return err_msg("too large LEB size %d, maximum is %d",
+				c->leb_size, UBIFS_MAX_LEB_SZ);
+	if (c->max_leb_cnt < UBIFS_MIN_LEB_CNT)
+		return err_msg("too low max. count of LEBs, minimum is %d",
+			       UBIFS_MIN_LEB_CNT);
+	if (c->fanout < UBIFS_MIN_FANOUT)
+		return err_msg("too low fanout, minimum is %d",
+			       UBIFS_MIN_FANOUT);
+	tmp = c->leb_size - UBIFS_IDX_NODE_SZ;
+	tmp /= UBIFS_BRANCH_SZ + UBIFS_MAX_KEY_LEN;
+	if (c->fanout > tmp)
+		return err_msg("too high fanout, maximum is %d", tmp);
+	if (c->log_lebs < UBIFS_MIN_LOG_LEBS)
+		return err_msg("too few log LEBs, minimum is %d",
+			       UBIFS_MIN_LOG_LEBS);
+	if (c->log_lebs >= c->max_leb_cnt - UBIFS_MIN_LEB_CNT)
+		return err_msg("too many log LEBs, maximum is %d",
+			       c->max_leb_cnt - UBIFS_MIN_LEB_CNT);
+	if (c->orph_lebs < UBIFS_MIN_ORPH_LEBS)
+		return err_msg("too few orphan LEBs, minimum is %d",
+			       UBIFS_MIN_ORPH_LEBS);
+	if (c->orph_lebs >= c->max_leb_cnt - UBIFS_MIN_LEB_CNT)
+		return err_msg("too many orphan LEBs, maximum is %d",
+			       c->max_leb_cnt - UBIFS_MIN_LEB_CNT);
+	tmp = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs;
+	tmp += c->orph_lebs + 4;
+	if (tmp > c->max_leb_cnt)
+		return err_msg("too low max. count of LEBs, expected at "
+			       "least %d", tmp);
+	tmp = calc_min_log_lebs(c->max_bud_bytes);
+	if (c->log_lebs < calc_min_log_lebs(c->max_bud_bytes))
+		return err_msg("too few log LEBs, expected at least %d", tmp);
+	if (c->rp_size >= ((long long)c->leb_size * c->max_leb_cnt) / 2)
+		return err_msg("too much reserved space %lld", c->rp_size);
+	return 0;
+}
+
+/**
+ * get_multiplier - convert size specifier to an integer multiplier.
+ * @str: the size specifier string
+ *
+ * This function parses the @str size specifier, which may be one of
+ * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
+ * size multiplier in case of success and %-1 in case of failure.
+ */
+static int get_multiplier(const char *str)
+{
+	if (!str)
+		return 1;
+
+	/* Remove spaces before the specifier */
+	while (*str == ' ' || *str == '\t')
+		str += 1;
+
+	if (!strcmp(str, "KiB"))
+		return 1024;
+	if (!strcmp(str, "MiB"))
+		return 1024 * 1024;
+	if (!strcmp(str, "GiB"))
+		return 1024 * 1024 * 1024;
+
+	return -1;
+}
+
+/**
+ * get_bytes - convert a string containing amount of bytes into an
+ *             integer.
+ * @str: string to convert
+ *
+ * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB' size
+ * specifiers. Returns positive amount of bytes in case of success and %-1 in
+ * case of failure.
+ */
+static long long get_bytes(const char *str)
+{
+	char *endp;
+	long long bytes = strtoull(str, &endp, 0);
+
+	if (endp == str || bytes < 0)
+		return err_msg("incorrect amount of bytes: \"%s\"", str);
+
+	if (*endp != '\0') {
+		int mult = get_multiplier(endp);
+
+		if (mult == -1)
+			return err_msg("bad size specifier: \"%s\" - "
+				       "should be 'KiB', 'MiB' or 'GiB'", endp);
+		bytes *= mult;
+	}
+
+	return bytes;
+}
+/**
+ * open_ubi - open the UBI volume.
+ * @node: name of the UBI volume character device to fetch information about
+ *
+ * Returns %0 in case of success and %-1 in case of failure
+ */
+static int open_ubi(const char *node)
+{
+	struct stat st;
+
+	if (stat(node, &st) || !S_ISCHR(st.st_mode))
+		return -1;
+
+	ubi = libubi_open();
+	if (!ubi)
+		return -1;
+	if (ubi_get_vol_info(ubi, node, &c->vi))
+		return -1;
+	if (ubi_get_dev_info1(ubi, c->vi.dev_num, &c->di))
+		return -1;
+	return 0;
+}
+
+static int get_options(int argc, char**argv)
+{
+	int opt, i;
+	const char *tbl_file = NULL;
+	struct stat st;
+	char *endp;
+
+	c->fanout = 8;
+	c->orph_lebs = 1;
+	c->key_hash = key_r5_hash;
+	c->key_len = UBIFS_SK_LEN;
+	c->default_compr = UBIFS_COMPR_LZO;
+	c->favor_percent = 20;
+	c->lsave_cnt = 256;
+	c->leb_size = -1;
+	c->min_io_size = -1;
+	c->max_leb_cnt = -1;
+	c->max_bud_bytes = -1;
+	c->log_lebs = -1;
+
+	while (1) {
+		opt = getopt_long(argc, argv, optstring, longopts, &i);
+		if (opt == -1)
+			break;
+		switch (opt) {
+		case 'r':
+		case 'd':
+			root_len = strlen(optarg);
+			root = malloc(root_len + 2);
+			if (!root)
+				return err_msg("cannot allocate memory");
+
+			/*
+			 * The further code expects '/' at the end of the root
+			 * UBIFS directory on the host.
+			 */
+			memcpy(root, optarg, root_len);
+			if (root[root_len - 1] != '/')
+				root[root_len++] = '/';
+			root[root_len] = 0;
+
+			/* Make sure the root directory exists */
+			if (stat(root, &st))
+				return sys_err_msg("bad root directory '%s'",
+						   root);
+			break;
+		case 'm':
+			c->min_io_size = get_bytes(optarg);
+			if (c->min_io_size <= 0)
+				return err_msg("bad min. I/O size");
+			break;
+		case 'e':
+			c->leb_size = get_bytes(optarg);
+			if (c->leb_size <= 0)
+				return err_msg("bad LEB size");
+			break;
+		case 'c':
+			c->max_leb_cnt = get_bytes(optarg);
+			if (c->max_leb_cnt <= 0)
+				return err_msg("bad maximum LEB count");
+			break;
+		case 'o':
+			output = xstrdup(optarg);
+			break;
+		case 'D':
+			tbl_file = optarg;
+			if (stat(tbl_file, &st) < 0)
+				return sys_err_msg("bad device table file '%s'",
+						   tbl_file);
+			break;
+		case 'y':
+			yes = 1;
+			break;
+		case 'h':
+		case '?':
+			printf("%s", helptext);
+			exit(0);
+		case 'v':
+			verbose = 1;
+			break;
+		case 'V':
+			common_print_version();
+			exit(0);
+		case 'g':
+			debug_level = strtol(optarg, &endp, 0);
+			if (*endp != '\0' || endp == optarg ||
+			    debug_level < 0 || debug_level > 3)
+				return err_msg("bad debugging level '%s'",
+					       optarg);
+			break;
+		case 'f':
+			c->fanout = strtol(optarg, &endp, 0);
+			if (*endp != '\0' || endp == optarg || c->fanout <= 0)
+				return err_msg("bad fanout %s", optarg);
+			break;
+		case 'F':
+			c->space_fixup = 1;
+			break;
+		case 'l':
+			c->log_lebs = strtol(optarg, &endp, 0);
+			if (*endp != '\0' || endp == optarg || c->log_lebs <= 0)
+				return err_msg("bad count of log LEBs '%s'",
+					       optarg);
+			break;
+		case 'p':
+			c->orph_lebs = strtol(optarg, &endp, 0);
+			if (*endp != '\0' || endp == optarg ||
+			    c->orph_lebs <= 0)
+				return err_msg("bad orphan LEB count '%s'",
+					       optarg);
+			break;
+		case 'k':
+			if (strcmp(optarg, "r5") == 0) {
+				c->key_hash = key_r5_hash;
+				c->key_hash_type = UBIFS_KEY_HASH_R5;
+			} else if (strcmp(optarg, "test") == 0) {
+				c->key_hash = key_test_hash;
+				c->key_hash_type = UBIFS_KEY_HASH_TEST;
+			} else
+				return err_msg("bad key hash");
+			break;
+		case 'x':
+			if (strcmp(optarg, "favor_lzo") == 0)
+				c->favor_lzo = 1;
+			else if (strcmp(optarg, "zlib") == 0)
+				c->default_compr = UBIFS_COMPR_ZLIB;
+			else if (strcmp(optarg, "none") == 0)
+				c->default_compr = UBIFS_COMPR_NONE;
+			else if (strcmp(optarg, "lzo") != 0)
+				return err_msg("bad compressor name");
+			break;
+		case 'X':
+			c->favor_percent = strtol(optarg, &endp, 0);
+			if (*endp != '\0' || endp == optarg ||
+			    c->favor_percent <= 0 || c->favor_percent >= 100)
+				return err_msg("bad favor LZO percent '%s'",
+					       optarg);
+			break;
+		case 'j':
+			c->max_bud_bytes = get_bytes(optarg);
+			if (c->max_bud_bytes <= 0)
+				return err_msg("bad maximum amount of buds");
+			break;
+		case 'R':
+			c->rp_size = get_bytes(optarg);
+			if (c->rp_size < 0)
+				return err_msg("bad reserved bytes count");
+			break;
+		case 'U':
+			squash_owner = 1;
+			break;
+		}
+	}
+
+	if (optind != argc && !output)
+		output = xstrdup(argv[optind]);
+
+	if (!output)
+		return err_msg("not output device or file specified");
+
+	out_ubi = !open_ubi(output);
+
+	if (out_ubi) {
+		c->min_io_size = c->di.min_io_size;
+		c->leb_size = c->vi.leb_size;
+		if (c->max_leb_cnt == -1)
+			c->max_leb_cnt = c->vi.rsvd_lebs;
+	}
+
+	if (c->min_io_size == -1)
+		return err_msg("min. I/O unit was not specified "
+			       "(use -h for help)");
+
+	if (c->leb_size == -1)
+		return err_msg("LEB size was not specified (use -h for help)");
+
+	if (c->max_leb_cnt == -1)
+		return err_msg("Maximum count of LEBs was not specified "
+			       "(use -h for help)");
+
+	if (c->max_bud_bytes == -1) {
+		int lebs;
+
+		lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+		lebs -= c->orph_lebs;
+		if (c->log_lebs != -1)
+			lebs -= c->log_lebs;
+		else
+			lebs -= UBIFS_MIN_LOG_LEBS;
+		/*
+		 * We do not know lprops geometry so far, so assume minimum
+		 * count of lprops LEBs.
+		 */
+		lebs -= UBIFS_MIN_LPT_LEBS;
+		/* Make the journal about 12.5% of main area lebs */
+		c->max_bud_bytes = (lebs / 8) * (long long)c->leb_size;
+		/* Make the max journal size 8MiB */
+		if (c->max_bud_bytes > 8 * 1024 * 1024)
+			c->max_bud_bytes = 8 * 1024 * 1024;
+		if (c->max_bud_bytes < 4 * c->leb_size)
+			c->max_bud_bytes = 4 * c->leb_size;
+	}
+
+	if (c->log_lebs == -1) {
+		c->log_lebs = calc_min_log_lebs(c->max_bud_bytes);
+		c->log_lebs += 2;
+	}
+
+	if (c->min_io_size < 8)
+		c->min_io_size = 8;
+	c->rp_size = add_space_overhead(c->rp_size);
+
+	if (verbose) {
+		printf("mkfs.ubifs\n");
+		printf("\troot:         %s\n", root);
+		printf("\tmin_io_size:  %d\n", c->min_io_size);
+		printf("\tleb_size:     %d\n", c->leb_size);
+		printf("\tmax_leb_cnt:  %d\n", c->max_leb_cnt);
+		printf("\toutput:       %s\n", output);
+		printf("\tjrn_size:     %llu\n", c->max_bud_bytes);
+		printf("\treserved:     %llu\n", c->rp_size);
+		switch (c->default_compr) {
+		case UBIFS_COMPR_LZO:
+			printf("\tcompr:        lzo\n");
+			break;
+		case UBIFS_COMPR_ZLIB:
+			printf("\tcompr:        zlib\n");
+			break;
+		case UBIFS_COMPR_NONE:
+			printf("\tcompr:        none\n");
+			break;
+		}
+		printf("\tkeyhash:      %s\n", (c->key_hash == key_r5_hash) ?
+						"r5" : "test");
+		printf("\tfanout:       %d\n", c->fanout);
+		printf("\torph_lebs:    %d\n", c->orph_lebs);
+		printf("\tspace_fixup:  %d\n", c->space_fixup);
+	}
+
+	if (validate_options())
+		return -1;
+
+	if (tbl_file && parse_devtable(tbl_file))
+		return err_msg("cannot parse device table file '%s'", tbl_file);
+
+	return 0;
+}
+
+/**
+ * prepare_node - fill in the common header.
+ * @node: node
+ * @len: node length
+ */
+static void prepare_node(void *node, int len)
+{
+	uint32_t crc;
+	struct ubifs_ch *ch = node;
+
+	ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
+	ch->len = cpu_to_le32(len);
+	ch->group_type = UBIFS_NO_NODE_GROUP;
+	ch->sqnum = cpu_to_le64(++c->max_sqnum);
+	ch->padding[0] = ch->padding[1] = 0;
+	crc = mtd_crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
+	ch->crc = cpu_to_le32(crc);
+}
+
+/**
+ * write_leb - copy the image of a LEB to the output target.
+ * @lnum: LEB number
+ * @len: length of data in the buffer
+ * @buf: buffer (must be at least c->leb_size bytes)
+ */
+int write_leb(int lnum, int len, void *buf)
+{
+	off_t pos = (off_t)lnum * c->leb_size;
+
+	dbg_msg(3, "LEB %d len %d", lnum, len);
+	memset(buf + len, 0xff, c->leb_size - len);
+	if (out_ubi)
+		if (ubi_leb_change_start(ubi, out_fd, lnum, c->leb_size))
+			return sys_err_msg("ubi_leb_change_start failed");
+
+	if (lseek(out_fd, pos, SEEK_SET) != pos)
+		return sys_err_msg("lseek failed seeking %"PRIdoff_t, pos);
+
+	if (write(out_fd, buf, c->leb_size) != c->leb_size)
+		return sys_err_msg("write failed writing %d bytes at pos %"PRIdoff_t,
+				   c->leb_size, pos);
+
+	return 0;
+}
+
+/**
+ * write_empty_leb - copy the image of an empty LEB to the output target.
+ * @lnum: LEB number
+ */
+static int write_empty_leb(int lnum)
+{
+	return write_leb(lnum, 0, leb_buf);
+}
+
+/**
+ * do_pad - pad a buffer to the minimum I/O size.
+ * @buf: buffer
+ * @len: buffer length
+ */
+static int do_pad(void *buf, int len)
+{
+	int pad_len, alen = ALIGN(len, 8), wlen = ALIGN(alen, c->min_io_size);
+	uint32_t crc;
+
+	memset(buf + len, 0xff, alen - len);
+	pad_len = wlen - alen;
+	dbg_msg(3, "len %d pad_len %d", len, pad_len);
+	buf += alen;
+	if (pad_len >= (int)UBIFS_PAD_NODE_SZ) {
+		struct ubifs_ch *ch = buf;
+		struct ubifs_pad_node *pad_node = buf;
+
+		ch->magic      = cpu_to_le32(UBIFS_NODE_MAGIC);
+		ch->node_type  = UBIFS_PAD_NODE;
+		ch->group_type = UBIFS_NO_NODE_GROUP;
+		ch->padding[0] = ch->padding[1] = 0;
+		ch->sqnum      = cpu_to_le64(0);
+		ch->len        = cpu_to_le32(UBIFS_PAD_NODE_SZ);
+
+		pad_len -= UBIFS_PAD_NODE_SZ;
+		pad_node->pad_len = cpu_to_le32(pad_len);
+
+		crc = mtd_crc32(UBIFS_CRC32_INIT, buf + 8,
+				  UBIFS_PAD_NODE_SZ - 8);
+		ch->crc = cpu_to_le32(crc);
+
+		memset(buf + UBIFS_PAD_NODE_SZ, 0, pad_len);
+	} else if (pad_len > 0)
+		memset(buf, UBIFS_PADDING_BYTE, pad_len);
+
+	return wlen;
+}
+
+/**
+ * write_node - write a node to a LEB.
+ * @node: node
+ * @len: node length
+ * @lnum: LEB number
+ */
+static int write_node(void *node, int len, int lnum)
+{
+	prepare_node(node, len);
+
+	memcpy(leb_buf, node, len);
+
+	len = do_pad(leb_buf, len);
+
+	return write_leb(lnum, len, leb_buf);
+}
+
+/**
+ * calc_dark - calculate LEB dark space size.
+ * @c: the UBIFS file-system description object
+ * @spc: amount of free and dirty space in the LEB
+ *
+ * This function calculates amount of dark space in an LEB which has @spc bytes
+ * of free and dirty space. Returns the calculations result.
+ *
+ * Dark space is the space which is not always usable - it depends on which
+ * nodes are written in which order. E.g., if an LEB has only 512 free bytes,
+ * it is dark space, because it cannot fit a large data node. So UBIFS cannot
+ * count on this LEB and treat these 512 bytes as usable because it is not true
+ * if, for example, only big chunks of uncompressible data will be written to
+ * the FS.
+ */
+static int calc_dark(struct ubifs_info *c, int spc)
+{
+	if (spc < c->dark_wm)
+		return spc;
+
+	/*
+	 * If we have slightly more space then the dark space watermark, we can
+	 * anyway safely assume it we'll be able to write a node of the
+	 * smallest size there.
+	 */
+	if (spc - c->dark_wm < (int)MIN_WRITE_SZ)
+		return spc - MIN_WRITE_SZ;
+
+	return c->dark_wm;
+}
+
+/**
+ * set_lprops - set the LEB property values for a LEB.
+ * @lnum: LEB number
+ * @offs: end offset of data in the LEB
+ * @flags: LEB property flags
+ */
+static void set_lprops(int lnum, int offs, int flags)
+{
+	int i = lnum - c->main_first, free, dirty;
+	int a = max_t(int, c->min_io_size, 8);
+
+	free = c->leb_size - ALIGN(offs, a);
+	dirty = c->leb_size - free - ALIGN(offs, 8);
+	dbg_msg(3, "LEB %d free %d dirty %d flags %d", lnum, free, dirty,
+		flags);
+	if (i < c->main_lebs) {
+		c->lpt[i].free = free;
+		c->lpt[i].dirty = dirty;
+		c->lpt[i].flags = flags;
+	}
+	c->lst.total_free += free;
+	c->lst.total_dirty += dirty;
+	if (flags & LPROPS_INDEX)
+		c->lst.idx_lebs += 1;
+	else {
+		int spc;
+
+		spc = free + dirty;
+		if (spc < c->dead_wm)
+			c->lst.total_dead += spc;
+		else
+			c->lst.total_dark += calc_dark(c, spc);
+		c->lst.total_used += c->leb_size - spc;
+	}
+}
+
+/**
+ * add_to_index - add a node key and position to the index.
+ * @key: node key
+ * @lnum: node LEB number
+ * @offs: node offset
+ * @len: node length
+ */
+static int add_to_index(union ubifs_key *key, char *name, int lnum, int offs,
+			int len)
+{
+	struct idx_entry *e;
+
+	dbg_msg(3, "LEB %d offs %d len %d", lnum, offs, len);
+	e = malloc(sizeof(struct idx_entry));
+	if (!e)
+		return err_msg("out of memory");
+	e->next = NULL;
+	e->prev = idx_list_last;
+	e->key = *key;
+	e->name = name;
+	e->lnum = lnum;
+	e->offs = offs;
+	e->len = len;
+	if (!idx_list_first)
+		idx_list_first = e;
+	if (idx_list_last)
+		idx_list_last->next = e;
+	idx_list_last = e;
+	idx_cnt += 1;
+	return 0;
+}
+
+/**
+ * flush_nodes - write the current head and move the head to the next LEB.
+ */
+static int flush_nodes(void)
+{
+	int len, err;
+
+	if (!head_offs)
+		return 0;
+	len = do_pad(leb_buf, head_offs);
+	err = write_leb(head_lnum, len, leb_buf);
+	if (err)
+		return err;
+	set_lprops(head_lnum, head_offs, head_flags);
+	head_lnum += 1;
+	head_offs = 0;
+	return 0;
+}
+
+/**
+ * reserve_space - reserve space for a node on the head.
+ * @len: node length
+ * @lnum: LEB number is returned here
+ * @offs: offset is returned here
+ */
+static int reserve_space(int len, int *lnum, int *offs)
+{
+	int err;
+
+	if (len > c->leb_size - head_offs) {
+		err = flush_nodes();
+		if (err)
+			return err;
+	}
+	*lnum = head_lnum;
+	*offs = head_offs;
+	head_offs += ALIGN(len, 8);
+	return 0;
+}
+
+/**
+ * add_node - write a node to the head.
+ * @key: node key
+ * @node: node
+ * @len: node length
+ */
+static int add_node(union ubifs_key *key, char *name, void *node, int len)
+{
+	int err, lnum, offs;
+
+	prepare_node(node, len);
+
+	err = reserve_space(len, &lnum, &offs);
+	if (err)
+		return err;
+
+	memcpy(leb_buf + offs, node, len);
+	memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len);
+
+	add_to_index(key, name, lnum, offs, len);
+
+	return 0;
+}
+
+/**
+ * add_inode_with_data - write an inode.
+ * @st: stat information of source inode
+ * @inum: target inode number
+ * @data: inode data (for special inodes e.g. symlink path etc)
+ * @data_len: inode data length
+ * @flags: source inode flags
+ */
+static int add_inode_with_data(struct stat *st, ino_t inum, void *data,
+			       unsigned int data_len, int flags)
+{
+	struct ubifs_ino_node *ino = node_buf;
+	union ubifs_key key;
+	int len, use_flags = 0;
+
+	if (c->default_compr != UBIFS_COMPR_NONE)
+		use_flags |= UBIFS_COMPR_FL;
+	if (flags & FS_COMPR_FL)
+		use_flags |= UBIFS_COMPR_FL;
+	if (flags & FS_SYNC_FL)
+		use_flags |= UBIFS_SYNC_FL;
+	if (flags & FS_IMMUTABLE_FL)
+		use_flags |= UBIFS_IMMUTABLE_FL;
+	if (flags & FS_APPEND_FL)
+		use_flags |= UBIFS_APPEND_FL;
+	if (flags & FS_DIRSYNC_FL && S_ISDIR(st->st_mode))
+		use_flags |= UBIFS_DIRSYNC_FL;
+
+	memset(ino, 0, UBIFS_INO_NODE_SZ);
+
+	ino_key_init(&key, inum);
+	ino->ch.node_type = UBIFS_INO_NODE;
+	key_write(&key, &ino->key);
+	ino->creat_sqnum = cpu_to_le64(creat_sqnum);
+	ino->size       = cpu_to_le64(st->st_size);
+	ino->nlink      = cpu_to_le32(st->st_nlink);
+	/*
+	 * The time fields are updated assuming the default time granularity
+	 * of 1 second. To support finer granularities, utime() would be needed.
+	 */
+	ino->atime_sec  = cpu_to_le64(st->st_atime);
+	ino->ctime_sec  = cpu_to_le64(st->st_ctime);
+	ino->mtime_sec  = cpu_to_le64(st->st_mtime);
+	ino->atime_nsec = 0;
+	ino->ctime_nsec = 0;
+	ino->mtime_nsec = 0;
+	ino->uid        = cpu_to_le32(st->st_uid);
+	ino->gid        = cpu_to_le32(st->st_gid);
+	ino->mode       = cpu_to_le32(st->st_mode);
+	ino->flags      = cpu_to_le32(use_flags);
+	ino->data_len   = cpu_to_le32(data_len);
+	ino->compr_type = cpu_to_le16(c->default_compr);
+	if (data_len)
+		memcpy(&ino->data, data, data_len);
+
+	len = UBIFS_INO_NODE_SZ + data_len;
+
+	return add_node(&key, NULL, ino, len);
+}
+
+/**
+ * add_inode - write an inode.
+ * @st: stat information of source inode
+ * @inum: target inode number
+ * @flags: source inode flags
+ */
+static int add_inode(struct stat *st, ino_t inum, int flags)
+{
+	return add_inode_with_data(st, inum, NULL, 0, flags);
+}
+
+/**
+ * add_dir_inode - write an inode for a directory.
+ * @dir: source directory
+ * @inum: target inode number
+ * @size: target directory size
+ * @nlink: target directory link count
+ * @st: struct stat object describing attributes (except size and nlink) of the
+ *      target inode to create
+ *
+ * Note, this function may be called with %NULL @dir, when the directory which
+ * is being created does not exist at the host file system, but is defined by
+ * the device table.
+ */
+static int add_dir_inode(DIR *dir, ino_t inum, loff_t size, unsigned int nlink,
+			 struct stat *st)
+{
+	int fd, flags = 0;
+
+	st->st_size = size;
+	st->st_nlink = nlink;
+
+	if (dir) {
+		fd = dirfd(dir);
+		if (fd == -1)
+			return sys_err_msg("dirfd failed");
+		if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1)
+			flags = 0;
+	}
+
+	return add_inode(st, inum, flags);
+}
+
+/**
+ * add_dev_inode - write an inode for a character or block device.
+ * @st: stat information of source inode
+ * @inum: target inode number
+ * @flags: source inode flags
+ */
+static int add_dev_inode(struct stat *st, ino_t inum, int flags)
+{
+	union ubifs_dev_desc dev;
+
+	dev.huge = cpu_to_le64(makedev(major(st->st_rdev), minor(st->st_rdev)));
+	return add_inode_with_data(st, inum, &dev, 8, flags);
+}
+
+/**
+ * add_symlink_inode - write an inode for a symbolic link.
+ * @path_name: path name of symbolic link inode itself (not the link target)
+ * @st: stat information of source inode
+ * @inum: target inode number
+ * @flags: source inode flags
+ */
+static int add_symlink_inode(const char *path_name, struct stat *st, ino_t inum,
+			     int flags)
+{
+	char buf[UBIFS_MAX_INO_DATA + 2];
+	ssize_t len;
+
+	/* Take the symlink as is */
+	len = readlink(path_name, buf, UBIFS_MAX_INO_DATA + 1);
+	if (len <= 0)
+		return sys_err_msg("readlink failed for %s", path_name);
+	if (len > UBIFS_MAX_INO_DATA)
+		return err_msg("symlink too long for %s", path_name);
+
+	return add_inode_with_data(st, inum, buf, len, flags);
+}
+
+/**
+ * add_dent_node - write a directory entry node.
+ * @dir_inum: target inode number of directory
+ * @name: directory entry name
+ * @inum: target inode number of the directory entry
+ * @type: type of the target inode
+ */
+static int add_dent_node(ino_t dir_inum, const char *name, ino_t inum,
+			 unsigned char type)
+{
+	struct ubifs_dent_node *dent = node_buf;
+	union ubifs_key key;
+	struct qstr dname;
+	char *kname;
+	int len;
+
+	dbg_msg(3, "%s ino %lu type %u dir ino %lu", name, (unsigned long)inum,
+		(unsigned int)type, (unsigned long)dir_inum);
+	memset(dent, 0, UBIFS_DENT_NODE_SZ);
+
+	dname.name = (void *)name;
+	dname.len = strlen(name);
+
+	dent->ch.node_type = UBIFS_DENT_NODE;
+
+	dent_key_init(c, &key, dir_inum, &dname);
+	key_write(&key, dent->key);
+	dent->inum = cpu_to_le64(inum);
+	dent->padding1 = 0;
+	dent->type = type;
+	dent->nlen = cpu_to_le16(dname.len);
+	memcpy(dent->name, dname.name, dname.len);
+	dent->name[dname.len] = '\0';
+
+	len = UBIFS_DENT_NODE_SZ + dname.len + 1;
+
+	kname = strdup(name);
+	if (!kname)
+		return err_msg("cannot allocate memory");
+
+	return add_node(&key, kname, dent, len);
+}
+
+/**
+ * lookup_inum_mapping - add an inode mapping for link counting.
+ * @dev: source device on which source inode number resides
+ * @inum: source inode number
+ */
+static struct inum_mapping *lookup_inum_mapping(dev_t dev, ino_t inum)
+{
+	struct inum_mapping *im;
+	unsigned int k;
+
+	k = inum % HASH_TABLE_SIZE;
+	im = hash_table[k];
+	while (im) {
+		if (im->dev == dev && im->inum == inum)
+			return im;
+		im = im->next;
+	}
+	im = malloc(sizeof(struct inum_mapping));
+	if (!im)
+		return NULL;
+	im->next = hash_table[k];
+	im->prev = NULL;
+	im->dev = dev;
+	im->inum = inum;
+	im->use_inum = 0;
+	im->use_nlink = 0;
+	if (hash_table[k])
+		hash_table[k]->prev = im;
+	hash_table[k] = im;
+	return im;
+}
+
+/**
+ * all_zero - does a buffer contain only zero bytes.
+ * @buf: buffer
+ * @len: buffer length
+ */
+static int all_zero(void *buf, int len)
+{
+	unsigned char *p = buf;
+
+	while (len--)
+		if (*p++ != 0)
+			return 0;
+	return 1;
+}
+
+/**
+ * add_file - write the data of a file and its inode to the output file.
+ * @path_name: source path name
+ * @st: source inode stat information
+ * @inum: target inode number
+ * @flags: source inode flags
+ */
+static int add_file(const char *path_name, struct stat *st, ino_t inum,
+		    int flags)
+{
+	struct ubifs_data_node *dn = node_buf;
+	void *buf = block_buf;
+	loff_t file_size = 0;
+	ssize_t ret, bytes_read;
+	union ubifs_key key;
+	int fd, dn_len, err, compr_type, use_compr;
+	unsigned int block_no = 0;
+	size_t out_len;
+
+	fd = open(path_name, O_RDONLY | O_LARGEFILE);
+	if (fd == -1)
+		return sys_err_msg("failed to open file '%s'", path_name);
+	do {
+		/* Read next block */
+		bytes_read = 0;
+		do {
+			ret = read(fd, buf + bytes_read,
+				   UBIFS_BLOCK_SIZE - bytes_read);
+			if (ret == -1) {
+				sys_err_msg("failed to read file '%s'",
+					    path_name);
+				close(fd);
+				return 1;
+			}
+			bytes_read += ret;
+		} while (ret != 0 && bytes_read != UBIFS_BLOCK_SIZE);
+		if (bytes_read == 0)
+			break;
+		file_size += bytes_read;
+		/* Skip holes */
+		if (all_zero(buf, bytes_read)) {
+			block_no += 1;
+			continue;
+		}
+		/* Make data node */
+		memset(dn, 0, UBIFS_DATA_NODE_SZ);
+		data_key_init(&key, inum, block_no++);
+		dn->ch.node_type = UBIFS_DATA_NODE;
+		key_write(&key, &dn->key);
+		dn->size = cpu_to_le32(bytes_read);
+		out_len = NODE_BUFFER_SIZE - UBIFS_DATA_NODE_SZ;
+		if (c->default_compr == UBIFS_COMPR_NONE &&
+		    (flags & FS_COMPR_FL))
+			use_compr = UBIFS_COMPR_LZO;
+		else
+			use_compr = c->default_compr;
+		compr_type = compress_data(buf, bytes_read, &dn->data,
+					   &out_len, use_compr);
+		dn->compr_type = cpu_to_le16(compr_type);
+		dn_len = UBIFS_DATA_NODE_SZ + out_len;
+		/* Add data node to file system */
+		err = add_node(&key, NULL, dn, dn_len);
+		if (err) {
+			close(fd);
+			return err;
+		}
+	} while (ret != 0);
+	if (close(fd) == -1)
+		return sys_err_msg("failed to close file '%s'", path_name);
+	if (file_size != st->st_size)
+		return err_msg("file size changed during writing file '%s'",
+			       path_name);
+	return add_inode(st, inum, flags);
+}
+
+/**
+ * add_non_dir - write a non-directory to the output file.
+ * @path_name: source path name
+ * @inum: target inode number is passed and returned here (due to link counting)
+ * @nlink: number of links if known otherwise zero
+ * @type: UBIFS inode type is returned here
+ * @st: struct stat object containing inode attributes which should be use when
+ *      creating the UBIFS inode
+ */
+static int add_non_dir(const char *path_name, ino_t *inum, unsigned int nlink,
+		       unsigned char *type, struct stat *st)
+{
+	int fd, flags = 0;
+
+	dbg_msg(2, "%s", path_name);
+
+	if (S_ISREG(st->st_mode)) {
+		fd = open(path_name, O_RDONLY);
+		if (fd == -1)
+			return sys_err_msg("failed to open file '%s'",
+					   path_name);
+		if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1)
+			flags = 0;
+		if (close(fd) == -1)
+			return sys_err_msg("failed to close file '%s'",
+					   path_name);
+		*type = UBIFS_ITYPE_REG;
+	} else if (S_ISCHR(st->st_mode))
+		*type = UBIFS_ITYPE_CHR;
+	else if (S_ISBLK(st->st_mode))
+		*type = UBIFS_ITYPE_BLK;
+	else if (S_ISLNK(st->st_mode))
+		*type = UBIFS_ITYPE_LNK;
+	else if (S_ISSOCK(st->st_mode))
+		*type = UBIFS_ITYPE_SOCK;
+	else if (S_ISFIFO(st->st_mode))
+		*type = UBIFS_ITYPE_FIFO;
+	else
+		return err_msg("file '%s' has unknown inode type", path_name);
+
+	if (nlink)
+		st->st_nlink = nlink;
+	else if (st->st_nlink > 1) {
+		/*
+		 * If the number of links is greater than 1, then add this file
+		 * later when we know the number of links that we actually have.
+		 * For now, we just put the inode mapping in the hash table.
+		 */
+		struct inum_mapping *im;
+
+		im = lookup_inum_mapping(st->st_dev, st->st_ino);
+		if (!im)
+			return err_msg("out of memory");
+		if (im->use_nlink == 0) {
+			/* New entry */
+			im->use_inum = *inum;
+			im->use_nlink = 1;
+			im->path_name = malloc(strlen(path_name) + 1);
+			if (!im->path_name)
+				return err_msg("out of memory");
+			strcpy(im->path_name, path_name);
+		} else {
+			/* Existing entry */
+			*inum = im->use_inum;
+			im->use_nlink += 1;
+			/* Return unused inode number */
+			c->highest_inum -= 1;
+		}
+
+		memcpy(&im->st, st, sizeof(struct stat));
+		return 0;
+	} else
+		st->st_nlink = 1;
+
+	creat_sqnum = ++c->max_sqnum;
+
+	if (S_ISREG(st->st_mode))
+		return add_file(path_name, st, *inum, flags);
+	if (S_ISCHR(st->st_mode))
+		return add_dev_inode(st, *inum, flags);
+	if (S_ISBLK(st->st_mode))
+		return add_dev_inode(st, *inum, flags);
+	if (S_ISLNK(st->st_mode))
+		return add_symlink_inode(path_name, st, *inum, flags);
+	if (S_ISSOCK(st->st_mode))
+		return add_inode(st, *inum, flags);
+	if (S_ISFIFO(st->st_mode))
+		return add_inode(st, *inum, flags);
+
+	return err_msg("file '%s' has unknown inode type", path_name);
+}
+
+/**
+ * add_directory - write a directory tree to the output file.
+ * @dir_name: directory path name
+ * @dir_inum: UBIFS inode number of directory
+ * @st: directory inode statistics
+ * @non_existing: non-zero if this function is called for a directory which
+ *                does not exist on the host file-system and it is being
+ *                created because it is defined in the device table file.
+ */
+static int add_directory(const char *dir_name, ino_t dir_inum, struct stat *st,
+			 int non_existing)
+{
+	struct dirent *entry;
+	DIR *dir = NULL;
+	int err = 0;
+	loff_t size = UBIFS_INO_NODE_SZ;
+	char *name = NULL;
+	unsigned int nlink = 2;
+	struct path_htbl_element *ph_elt;
+	struct name_htbl_element *nh_elt = NULL;
+	struct hashtable_itr *itr;
+	ino_t inum;
+	unsigned char type;
+	unsigned long long dir_creat_sqnum = ++c->max_sqnum;
+
+	dbg_msg(2, "%s", dir_name);
+	if (!non_existing) {
+		dir = opendir(dir_name);
+		if (dir == NULL)
+			return sys_err_msg("cannot open directory '%s'",
+					   dir_name);
+	}
+
+	/*
+	 * Check whether this directory contains files which should be
+	 * added/changed because they were specified in the device table.
+	 * @ph_elt will be non-zero if yes.
+	 */
+	ph_elt = devtbl_find_path(dir_name + root_len - 1);
+
+	/*
+	 * Before adding the directory itself, we have to iterate over all the
+	 * entries the device table adds to this directory and create them.
+	 */
+	for (; !non_existing;) {
+		struct stat dent_st;
+
+		errno = 0;
+		entry = readdir(dir);
+		if (!entry) {
+			if (errno == 0)
+				break;
+			sys_err_msg("error reading directory '%s'", dir_name);
+			err = -1;
+			break;
+		}
+
+		if (strcmp(".", entry->d_name) == 0)
+			continue;
+		if (strcmp("..", entry->d_name) == 0)
+			continue;
+
+		if (ph_elt)
+			/*
+			 * This directory was referred to at the device table
+			 * file. Check if this directory entry is referred at
+			 * too.
+			 */
+			nh_elt = devtbl_find_name(ph_elt, entry->d_name);
+
+		/*
+		 * We are going to create the file corresponding to this
+		 * directory entry (@entry->d_name). We use 'struct stat'
+		 * object to pass information about file attributes (actually
+		 * only about UID, GID, mode, major, and minor). Get attributes
+		 * for this file from the UBIFS rootfs on the host.
+		 */
+		free(name);
+		name = make_path(dir_name, entry->d_name);
+		if (lstat(name, &dent_st) == -1) {
+			sys_err_msg("lstat failed for file '%s'", name);
+			goto out_free;
+		}
+
+		if (squash_owner)
+			/*
+			 * Squash UID/GID. But the device table may override
+			 * this.
+			 */
+			dent_st.st_uid = dent_st.st_gid = 0;
+
+		/*
+		 * And if the device table describes the same file, override
+		 * the attributes. However, this is not allowed for device node
+		 * files.
+		 */
+		if (nh_elt && override_attributes(&dent_st, ph_elt, nh_elt))
+			goto out_free;
+
+		inum = ++c->highest_inum;
+
+		if (S_ISDIR(dent_st.st_mode)) {
+			err = add_directory(name, inum, &dent_st, 0);
+			if (err)
+				goto out_free;
+			nlink += 1;
+			type = UBIFS_ITYPE_DIR;
+		} else {
+			err = add_non_dir(name, &inum, 0, &type, &dent_st);
+			if (err)
+				goto out_free;
+		}
+
+		err = add_dent_node(dir_inum, entry->d_name, inum, type);
+		if (err)
+			goto out_free;
+		size += ALIGN(UBIFS_DENT_NODE_SZ + strlen(entry->d_name) + 1,
+			      8);
+	}
+
+	/*
+	 * OK, we have created all files in this directory (recursively), let's
+	 * also create all files described in the device table. All t
+	 */
+	nh_elt = first_name_htbl_element(ph_elt, &itr);
+	while (nh_elt) {
+		struct stat fake_st;
+
+		/*
+		 * We prohibit creating regular files using the device table,
+		 * the device table may only re-define attributes of regular
+		 * files.
+		 */
+		if (S_ISREG(nh_elt->mode)) {
+			err_msg("Bad device table entry %s/%s - it is "
+				"prohibited to create regular files "
+				"via device table",
+				strcmp(ph_elt->path, "/") ? ph_elt->path : "",
+				nh_elt->name);
+			goto out_free;
+		}
+
+		memcpy(&fake_st, &root_st, sizeof(struct stat));
+		fake_st.st_uid  = nh_elt->uid;
+		fake_st.st_uid  = nh_elt->uid;
+		fake_st.st_mode = nh_elt->mode;
+		fake_st.st_rdev = nh_elt->dev;
+		fake_st.st_nlink = 1;
+
+		free(name);
+		name = make_path(dir_name, nh_elt->name);
+		inum = ++c->highest_inum;
+
+		if (S_ISDIR(nh_elt->mode)) {
+			err = add_directory(name, inum, &fake_st, 1);
+			if (err)
+				goto out_free;
+			nlink += 1;
+			type = UBIFS_ITYPE_DIR;
+		} else {
+			err = add_non_dir(name, &inum, 0, &type, &fake_st);
+			if (err)
+				goto out_free;
+		}
+
+		err = add_dent_node(dir_inum, nh_elt->name, inum, type);
+		if (err)
+			goto out_free;
+		size += ALIGN(UBIFS_DENT_NODE_SZ + strlen(nh_elt->name) + 1, 8);
+
+		nh_elt = next_name_htbl_element(ph_elt, &itr);
+	}
+
+	creat_sqnum = dir_creat_sqnum;
+
+	err = add_dir_inode(dir, dir_inum, size, nlink, st);
+	if (err)
+		goto out_free;
+
+	free(name);
+	if (!non_existing && closedir(dir) == -1)
+		return sys_err_msg("error closing directory '%s'", dir_name);
+
+	return 0;
+
+out_free:
+	free(name);
+	if (!non_existing)
+		closedir(dir);
+	return -1;
+}
+
+/**
+ * add_multi_linked_files - write all the files for which we counted links.
+ */
+static int add_multi_linked_files(void)
+{
+	int i, err;
+
+	for (i = 0; i < HASH_TABLE_SIZE; i++) {
+		struct inum_mapping *im;
+		unsigned char type = 0;
+
+		for (im = hash_table[i]; im; im = im->next) {
+			dbg_msg(2, "%s", im->path_name);
+			err = add_non_dir(im->path_name, &im->use_inum,
+					  im->use_nlink, &type, &im->st);
+			if (err)
+				return err;
+		}
+	}
+	return 0;
+}
+
+/**
+ * write_data - write the files and directories.
+ */
+static int write_data(void)
+{
+	int err;
+	mode_t mode = S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+
+	if (root) {
+		err = stat(root, &root_st);
+		if (err)
+			return sys_err_msg("bad root file-system directory '%s'",
+					   root);
+	} else {
+		root_st.st_mtime = time(NULL);
+		root_st.st_atime = root_st.st_ctime = root_st.st_mtime;
+		root_st.st_mode = mode;
+	}
+
+	head_flags = 0;
+	err = add_directory(root, UBIFS_ROOT_INO, &root_st, !root);
+	if (err)
+		return err;
+	err = add_multi_linked_files();
+	if (err)
+		return err;
+	return flush_nodes();
+}
+
+static int namecmp(const char *name1, const char *name2)
+{
+	size_t len1 = strlen(name1), len2 = strlen(name2);
+	size_t clen = (len1 < len2) ? len1 : len2;
+	int cmp;
+
+	cmp = memcmp(name1, name2, clen);
+	if (cmp)
+		return cmp;
+	return (len1 < len2) ? -1 : 1;
+}
+
+static int cmp_idx(const void *a, const void *b)
+{
+	const struct idx_entry *e1 = *(const struct idx_entry **)a;
+	const struct idx_entry *e2 = *(const struct idx_entry **)b;
+	int cmp;
+
+	cmp = keys_cmp(&e1->key, &e2->key);
+	if (cmp)
+		return cmp;
+	return namecmp(e1->name, e2->name);
+}
+
+/**
+ * add_idx_node - write an index node to the head.
+ * @node: index node
+ * @child_cnt: number of children of this index node
+ */
+static int add_idx_node(void *node, int child_cnt)
+{
+	int err, lnum, offs, len;
+
+	len = ubifs_idx_node_sz(c, child_cnt);
+
+	prepare_node(node, len);
+
+	err = reserve_space(len, &lnum, &offs);
+	if (err)
+		return err;
+
+	memcpy(leb_buf + offs, node, len);
+	memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len);
+
+	c->old_idx_sz += ALIGN(len, 8);
+
+	dbg_msg(3, "at %d:%d len %d index size %llu", lnum, offs, len,
+		c->old_idx_sz);
+
+	/* The last index node written will be the root */
+	c->zroot.lnum = lnum;
+	c->zroot.offs = offs;
+	c->zroot.len = len;
+
+	return 0;
+}
+
+/**
+ * write_index - write out the index.
+ */
+static int write_index(void)
+{
+	size_t sz, i, cnt, idx_sz, pstep, bcnt;
+	struct idx_entry **idx_ptr, **p;
+	struct ubifs_idx_node *idx;
+	struct ubifs_branch *br;
+	int child_cnt = 0, j, level, blnum, boffs, blen, blast_len, err;
+
+	dbg_msg(1, "leaf node count: %zd", idx_cnt);
+
+	/* Reset the head for the index */
+	head_flags = LPROPS_INDEX;
+	/* Allocate index node */
+	idx_sz = ubifs_idx_node_sz(c, c->fanout);
+	idx = malloc(idx_sz);
+	if (!idx)
+		return err_msg("out of memory");
+	/* Make an array of pointers to sort the index list */
+	sz = idx_cnt * sizeof(struct idx_entry *);
+	if (sz / sizeof(struct idx_entry *) != idx_cnt) {
+		free(idx);
+		return err_msg("index is too big (%zu entries)", idx_cnt);
+	}
+	idx_ptr = malloc(sz);
+	if (!idx_ptr) {
+		free(idx);
+		return err_msg("out of memory - needed %zu bytes for index",
+			       sz);
+	}
+	idx_ptr[0] = idx_list_first;
+	for (i = 1; i < idx_cnt; i++)
+		idx_ptr[i] = idx_ptr[i - 1]->next;
+	qsort(idx_ptr, idx_cnt, sizeof(struct idx_entry *), cmp_idx);
+	/* Write level 0 index nodes */
+	cnt = idx_cnt / c->fanout;
+	if (idx_cnt % c->fanout)
+		cnt += 1;
+	p = idx_ptr;
+	blnum = head_lnum;
+	boffs = head_offs;
+	for (i = 0; i < cnt; i++) {
+		/*
+		 * Calculate the child count. All index nodes are created full
+		 * except for the last index node on each row.
+		 */
+		if (i == cnt - 1) {
+			child_cnt = idx_cnt % c->fanout;
+			if (child_cnt == 0)
+				child_cnt = c->fanout;
+		} else
+			child_cnt = c->fanout;
+		memset(idx, 0, idx_sz);
+		idx->ch.node_type = UBIFS_IDX_NODE;
+		idx->child_cnt = cpu_to_le16(child_cnt);
+		idx->level = cpu_to_le16(0);
+		for (j = 0; j < child_cnt; j++, p++) {
+			br = ubifs_idx_branch(c, idx, j);
+			key_write_idx(&(*p)->key, &br->key);
+			br->lnum = cpu_to_le32((*p)->lnum);
+			br->offs = cpu_to_le32((*p)->offs);
+			br->len = cpu_to_le32((*p)->len);
+		}
+		add_idx_node(idx, child_cnt);
+	}
+	/* Write level 1 index nodes and above */
+	level = 0;
+	pstep = 1;
+	while (cnt > 1) {
+		/*
+		 * 'blast_len' is the length of the last index node in the level
+		 * below.
+		 */
+		blast_len = ubifs_idx_node_sz(c, child_cnt);
+		/* 'bcnt' is the number of index nodes in the level below */
+		bcnt = cnt;
+		/* 'cnt' is the number of index nodes in this level */
+		cnt = (cnt + c->fanout - 1) / c->fanout;
+		if (cnt == 0)
+			cnt = 1;
+		level += 1;
+		/*
+		 * The key of an index node is the same as the key of its first
+		 * child. Thus we can get the key by stepping along the bottom
+		 * level 'p' with an increasing large step 'pstep'.
+		 */
+		p = idx_ptr;
+		pstep *= c->fanout;
+		for (i = 0; i < cnt; i++) {
+			/*
+			 * Calculate the child count. All index nodes are
+			 * created full except for the last index node on each
+			 * row.
+			 */
+			if (i == cnt - 1) {
+				child_cnt = bcnt % c->fanout;
+				if (child_cnt == 0)
+					child_cnt = c->fanout;
+			} else
+				child_cnt = c->fanout;
+			memset(idx, 0, idx_sz);
+			idx->ch.node_type = UBIFS_IDX_NODE;
+			idx->child_cnt = cpu_to_le16(child_cnt);
+			idx->level = cpu_to_le16(level);
+			for (j = 0; j < child_cnt; j++) {
+				size_t bn = i * c->fanout + j;
+
+				/*
+				 * The length of the index node in the level
+				 * below is 'idx_sz' except when it is the last
+				 * node on the row. i.e. all the others on the
+				 * row are full.
+				 */
+				if (bn == bcnt - 1)
+					blen = blast_len;
+				else
+					blen = idx_sz;
+				/*
+				 * 'blnum' and 'boffs' hold the position of the
+				 * index node on the level below.
+				 */
+				if (boffs + blen > c->leb_size) {
+					blnum += 1;
+					boffs = 0;
+				}
+				/*
+				 * Fill in the branch with the key and position
+				 * of the index node from the level below.
+				 */
+				br = ubifs_idx_branch(c, idx, j);
+				key_write_idx(&(*p)->key, &br->key);
+				br->lnum = cpu_to_le32(blnum);
+				br->offs = cpu_to_le32(boffs);
+				br->len = cpu_to_le32(blen);
+				/*
+				 * Step to the next index node on the level
+				 * below.
+				 */
+				boffs += ALIGN(blen, 8);
+				p += pstep;
+			}
+			add_idx_node(idx, child_cnt);
+		}
+	}
+
+	/* Free stuff */
+	for (i = 0; i < idx_cnt; i++)
+		free(idx_ptr[i]);
+	free(idx_ptr);
+	free(idx);
+
+	dbg_msg(1, "zroot is at %d:%d len %d", c->zroot.lnum, c->zroot.offs,
+		c->zroot.len);
+
+	/* Set the index head */
+	c->ihead_lnum = head_lnum;
+	c->ihead_offs = ALIGN(head_offs, c->min_io_size);
+	dbg_msg(1, "ihead is at %d:%d", c->ihead_lnum, c->ihead_offs);
+
+	/* Flush the last index LEB */
+	err = flush_nodes();
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/**
+ * set_gc_lnum - set the LEB number reserved for the garbage collector.
+ */
+static int set_gc_lnum(void)
+{
+	int err;
+
+	c->gc_lnum = head_lnum++;
+	err = write_empty_leb(c->gc_lnum);
+	if (err)
+		return err;
+	set_lprops(c->gc_lnum, 0, 0);
+	c->lst.empty_lebs += 1;
+	return 0;
+}
+
+/**
+ * finalize_leb_cnt - now that we know how many LEBs we used.
+ */
+static int finalize_leb_cnt(void)
+{
+	c->leb_cnt = head_lnum;
+	if (c->leb_cnt > c->max_leb_cnt)
+		return err_msg("max_leb_cnt too low (%d needed)", c->leb_cnt);
+	c->main_lebs = c->leb_cnt - c->main_first;
+	if (verbose) {
+		printf("\tsuper lebs:   %d\n", UBIFS_SB_LEBS);
+		printf("\tmaster lebs:  %d\n", UBIFS_MST_LEBS);
+		printf("\tlog_lebs:     %d\n", c->log_lebs);
+		printf("\tlpt_lebs:     %d\n", c->lpt_lebs);
+		printf("\torph_lebs:    %d\n", c->orph_lebs);
+		printf("\tmain_lebs:    %d\n", c->main_lebs);
+		printf("\tgc lebs:      %d\n", 1);
+		printf("\tindex lebs:   %d\n", c->lst.idx_lebs);
+		printf("\tleb_cnt:      %d\n", c->leb_cnt);
+	}
+	dbg_msg(1, "total_free:  %llu", c->lst.total_free);
+	dbg_msg(1, "total_dirty: %llu", c->lst.total_dirty);
+	dbg_msg(1, "total_used:  %llu", c->lst.total_used);
+	dbg_msg(1, "total_dead:  %llu", c->lst.total_dead);
+	dbg_msg(1, "total_dark:  %llu", c->lst.total_dark);
+	dbg_msg(1, "index size:  %llu", c->old_idx_sz);
+	dbg_msg(1, "empty_lebs:  %d", c->lst.empty_lebs);
+	return 0;
+}
+
+/**
+ * write_super - write the super block.
+ */
+static int write_super(void)
+{
+	struct ubifs_sb_node sup;
+
+	memset(&sup, 0, UBIFS_SB_NODE_SZ);
+
+	sup.ch.node_type  = UBIFS_SB_NODE;
+	sup.key_hash      = c->key_hash_type;
+	sup.min_io_size   = cpu_to_le32(c->min_io_size);
+	sup.leb_size      = cpu_to_le32(c->leb_size);
+	sup.leb_cnt       = cpu_to_le32(c->leb_cnt);
+	sup.max_leb_cnt   = cpu_to_le32(c->max_leb_cnt);
+	sup.max_bud_bytes = cpu_to_le64(c->max_bud_bytes);
+	sup.log_lebs      = cpu_to_le32(c->log_lebs);
+	sup.lpt_lebs      = cpu_to_le32(c->lpt_lebs);
+	sup.orph_lebs     = cpu_to_le32(c->orph_lebs);
+	sup.jhead_cnt     = cpu_to_le32(c->jhead_cnt);
+	sup.fanout        = cpu_to_le32(c->fanout);
+	sup.lsave_cnt     = cpu_to_le32(c->lsave_cnt);
+	sup.fmt_version   = cpu_to_le32(UBIFS_FORMAT_VERSION);
+	sup.default_compr = cpu_to_le16(c->default_compr);
+	sup.rp_size       = cpu_to_le64(c->rp_size);
+	sup.time_gran     = cpu_to_le32(DEFAULT_TIME_GRAN);
+	uuid_generate_random(sup.uuid);
+	if (verbose) {
+		char s[40];
+
+		uuid_unparse_upper(sup.uuid, s);
+		printf("\tUUID:         %s\n", s);
+	}
+	if (c->big_lpt)
+		sup.flags |= cpu_to_le32(UBIFS_FLG_BIGLPT);
+	if (c->space_fixup)
+		sup.flags |= cpu_to_le32(UBIFS_FLG_SPACE_FIXUP);
+
+	return write_node(&sup, UBIFS_SB_NODE_SZ, UBIFS_SB_LNUM);
+}
+
+/**
+ * write_master - write the master node.
+ */
+static int write_master(void)
+{
+	struct ubifs_mst_node mst;
+	int err;
+
+	memset(&mst, 0, UBIFS_MST_NODE_SZ);
+
+	mst.ch.node_type = UBIFS_MST_NODE;
+	mst.log_lnum     = cpu_to_le32(UBIFS_LOG_LNUM);
+	mst.highest_inum = cpu_to_le64(c->highest_inum);
+	mst.cmt_no       = cpu_to_le64(0);
+	mst.flags        = cpu_to_le32(UBIFS_MST_NO_ORPHS);
+	mst.root_lnum    = cpu_to_le32(c->zroot.lnum);
+	mst.root_offs    = cpu_to_le32(c->zroot.offs);
+	mst.root_len     = cpu_to_le32(c->zroot.len);
+	mst.gc_lnum      = cpu_to_le32(c->gc_lnum);
+	mst.ihead_lnum   = cpu_to_le32(c->ihead_lnum);
+	mst.ihead_offs   = cpu_to_le32(c->ihead_offs);
+	mst.index_size   = cpu_to_le64(c->old_idx_sz);
+	mst.lpt_lnum     = cpu_to_le32(c->lpt_lnum);
+	mst.lpt_offs     = cpu_to_le32(c->lpt_offs);
+	mst.nhead_lnum   = cpu_to_le32(c->nhead_lnum);
+	mst.nhead_offs   = cpu_to_le32(c->nhead_offs);
+	mst.ltab_lnum    = cpu_to_le32(c->ltab_lnum);
+	mst.ltab_offs    = cpu_to_le32(c->ltab_offs);
+	mst.lsave_lnum   = cpu_to_le32(c->lsave_lnum);
+	mst.lsave_offs   = cpu_to_le32(c->lsave_offs);
+	mst.lscan_lnum   = cpu_to_le32(c->lscan_lnum);
+	mst.empty_lebs   = cpu_to_le32(c->lst.empty_lebs);
+	mst.idx_lebs     = cpu_to_le32(c->lst.idx_lebs);
+	mst.total_free   = cpu_to_le64(c->lst.total_free);
+	mst.total_dirty  = cpu_to_le64(c->lst.total_dirty);
+	mst.total_used   = cpu_to_le64(c->lst.total_used);
+	mst.total_dead   = cpu_to_le64(c->lst.total_dead);
+	mst.total_dark   = cpu_to_le64(c->lst.total_dark);
+	mst.leb_cnt      = cpu_to_le32(c->leb_cnt);
+
+	err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM);
+	if (err)
+		return err;
+
+	err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/**
+ * write_log - write an empty log.
+ */
+static int write_log(void)
+{
+	struct ubifs_cs_node cs;
+	int err, i, lnum;
+
+	lnum = UBIFS_LOG_LNUM;
+
+	cs.ch.node_type = UBIFS_CS_NODE;
+	cs.cmt_no = cpu_to_le64(0);
+
+	err = write_node(&cs, UBIFS_CS_NODE_SZ, lnum);
+	if (err)
+		return err;
+
+	lnum += 1;
+
+	for (i = 1; i < c->log_lebs; i++, lnum++) {
+		err = write_empty_leb(lnum);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * write_lpt - write the LEB properties tree.
+ */
+static int write_lpt(void)
+{
+	int err, lnum;
+
+	err = create_lpt(c);
+	if (err)
+		return err;
+
+	lnum = c->nhead_lnum + 1;
+	while (lnum <= c->lpt_last) {
+		err = write_empty_leb(lnum++);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * write_orphan_area - write an empty orphan area.
+ */
+static int write_orphan_area(void)
+{
+	int err, i, lnum;
+
+	lnum = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs;
+	for (i = 0; i < c->orph_lebs; i++, lnum++) {
+		err = write_empty_leb(lnum);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+/**
+ * check_volume_empty - check if the UBI volume is empty.
+ *
+ * This function checks if the UBI volume is empty by looking if its LEBs are
+ * mapped or not.
+ *
+ * Returns %0 in case of success, %1 is the volume is not empty,
+ * and a negative error code in case of failure.
+ */
+static int check_volume_empty(void)
+{
+	int lnum, err;
+
+	for (lnum = 0; lnum < c->vi.rsvd_lebs; lnum++) {
+		err = ubi_is_mapped(out_fd, lnum);
+		if (err < 0)
+			return err;
+		if (err == 1)
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ * open_target - open the output target.
+ *
+ * Open the output target. The target can be an UBI volume
+ * or a file.
+ *
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int open_target(void)
+{
+	if (out_ubi) {
+		out_fd = open(output, O_RDWR | O_EXCL);
+
+		if (out_fd == -1)
+			return sys_err_msg("cannot open the UBI volume '%s'",
+					   output);
+		if (ubi_set_property(out_fd, UBI_VOL_PROP_DIRECT_WRITE, 1))
+			return sys_err_msg("ubi_set_property failed");
+
+		if (!yes && check_volume_empty()) {
+			if (!prompt("UBI volume is not empty.  Format anyways?", false))
+				return err_msg("UBI volume is not empty");
+		}
+	} else {
+		out_fd = open(output, O_CREAT | O_RDWR | O_TRUNC,
+			      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+		if (out_fd == -1)
+			return sys_err_msg("cannot create output file '%s'",
+					   output);
+	}
+	return 0;
+}
+
+
+/**
+ * close_target - close the output target.
+ *
+ * Close the output target. If the target was an UBI
+ * volume, also close libubi.
+ *
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int close_target(void)
+{
+	if (ubi)
+		libubi_close(ubi);
+	if (out_fd >= 0 && close(out_fd) == -1)
+		return sys_err_msg("cannot close the target '%s'", output);
+	if (output)
+		free(output);
+	return 0;
+}
+
+/**
+ * init - initialize things.
+ */
+static int init(void)
+{
+	int err, i, main_lebs, big_lpt = 0, sz;
+
+	c->highest_inum = UBIFS_FIRST_INO;
+
+	c->jhead_cnt = 1;
+
+	main_lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+	main_lebs -= c->log_lebs + c->orph_lebs;
+
+	err = calc_dflt_lpt_geom(c, &main_lebs, &big_lpt);
+	if (err)
+		return err;
+
+	c->main_first = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs +
+			c->orph_lebs;
+	head_lnum = c->main_first;
+	head_offs = 0;
+
+	c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs;
+	c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
+
+	c->lpt = malloc(c->main_lebs * sizeof(struct ubifs_lprops));
+	if (!c->lpt)
+		return err_msg("unable to allocate LPT");
+
+	c->ltab = malloc(c->lpt_lebs * sizeof(struct ubifs_lprops));
+	if (!c->ltab)
+		return err_msg("unable to allocate LPT ltab");
+
+	/* Initialize LPT's own lprops */
+	for (i = 0; i < c->lpt_lebs; i++) {
+		c->ltab[i].free = c->leb_size;
+		c->ltab[i].dirty = 0;
+	}
+
+	c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size);
+	c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size);
+	dbg_msg(1, "dead_wm %d  dark_wm %d", c->dead_wm, c->dark_wm);
+
+	leb_buf = malloc(c->leb_size);
+	if (!leb_buf)
+		return err_msg("out of memory");
+
+	node_buf = malloc(NODE_BUFFER_SIZE);
+	if (!node_buf)
+		return err_msg("out of memory");
+
+	block_buf = malloc(UBIFS_BLOCK_SIZE);
+	if (!block_buf)
+		return err_msg("out of memory");
+
+	sz = sizeof(struct inum_mapping *) * HASH_TABLE_SIZE;
+	hash_table = malloc(sz);
+	if (!hash_table)
+		return err_msg("out of memory");
+	memset(hash_table, 0, sz);
+
+	err = init_compression();
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static void destroy_hash_table(void)
+{
+	int i;
+
+	for (i = 0; i < HASH_TABLE_SIZE; i++) {
+		struct inum_mapping *im, *q;
+
+		for (im = hash_table[i]; im; ) {
+			q = im;
+			im = im->next;
+			free(q->path_name);
+			free(q);
+		}
+	}
+}
+
+/**
+ * deinit - deinitialize things.
+ */
+static void deinit(void)
+{
+	free(c->lpt);
+	free(c->ltab);
+	free(leb_buf);
+	free(node_buf);
+	free(block_buf);
+	destroy_hash_table();
+	free(hash_table);
+	destroy_compression();
+	free_devtable_info();
+}
+
+/**
+ * mkfs - make the file system.
+ *
+ * Each on-flash area has a corresponding function to create it. The order of
+ * the functions reflects what information must be known to complete each stage.
+ * As a consequence the output file is not written sequentially. No effort has
+ * been made to make efficient use of memory or to allow for the possibility of
+ * incremental updates to the output file.
+ */
+static int mkfs(void)
+{
+	int err = 0;
+
+	err = init();
+	if (err)
+		goto out;
+
+	err = write_data();
+	if (err)
+		goto out;
+
+	err = set_gc_lnum();
+	if (err)
+		goto out;
+
+	err = write_index();
+	if (err)
+		goto out;
+
+	err = finalize_leb_cnt();
+	if (err)
+		goto out;
+
+	err = write_lpt();
+	if (err)
+		goto out;
+
+	err = write_super();
+	if (err)
+		goto out;
+
+	err = write_master();
+	if (err)
+		goto out;
+
+	err = write_log();
+	if (err)
+		goto out;
+
+	err = write_orphan_area();
+
+out:
+	deinit();
+	return err;
+}
+
+int main(int argc, char *argv[])
+{
+	int err;
+
+	err = get_options(argc, argv);
+	if (err)
+		return err;
+
+	err = open_target();
+	if (err)
+		return err;
+
+	err = mkfs();
+	if (err) {
+		close_target();
+		return err;
+	}
+
+	err = close_target();
+	if (err)
+		return err;
+
+	if (verbose)
+		printf("Success!\n");
+
+	return 0;
+}
diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
new file mode 100644
index 0000000..944a159
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy
+ *          Adrian Hunter
+ *          Zoltan Sogor
+ */
+
+#ifndef __MKFS_UBIFS_H__
+#define __MKFS_UBIFS_H__
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+#include <stdint.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <libgen.h>
+#include <ctype.h>
+#include <uuid/uuid.h>
+#include <sys/file.h>
+
+#include <mtd/ubifs-media.h>
+
+/* common.h requires the PROGRAM_NAME macro */
+#define PROGRAM_NAME "mkfs.ubifs"
+#include "common.h"
+
+#include "libubi.h"
+#include "defs.h"
+#include "crc16.h"
+#include "ubifs.h"
+#include "key.h"
+#include "lpt.h"
+#include "compr.h"
+
+/*
+ * Compression flags are duplicated so that compr.c can compile without ubifs.h.
+ * Here we make sure they are the same.
+ */
+#if MKFS_UBIFS_COMPR_NONE != UBIFS_COMPR_NONE
+#error MKFS_UBIFS_COMPR_NONE != UBIFS_COMPR_NONE
+#endif
+#if MKFS_UBIFS_COMPR_LZO != UBIFS_COMPR_LZO
+#error MKFS_UBIFS_COMPR_LZO != UBIFS_COMPR_LZO
+#endif
+#if MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB
+#error MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB
+#endif
+
+extern int verbose;
+extern int debug_level;
+
+#define dbg_msg(lvl, fmt, ...) do {if (debug_level >= lvl)                \
+	printf("mkfs.ubifs: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__); \
+} while(0)
+
+#define err_msg(fmt, ...) ({                                \
+	fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__); \
+	-1;                                                 \
+})
+
+#define sys_err_msg(fmt, ...) ({                                         \
+	int err_ = errno;                                                \
+	fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__);              \
+	fprintf(stderr, "       %s (error %d)\n", strerror(err_), err_); \
+	-1;                                                              \
+})
+
+/**
+ * struct path_htbl_element - an element of the path hash table.
+ * @path: the UBIFS path the element describes (the key of the element)
+ * @name_htbl: one more (nested) hash table containing names of all
+ *             files/directories/device nodes which should be created at this
+ *             path
+ *
+ * See device table handling for more information.
+ */
+struct path_htbl_element {
+	const char *path;
+	struct hashtable *name_htbl;
+};
+
+/**
+ * struct name_htbl_element - an element in the name hash table
+ * @name: name of the file/directory/device node (the key of the element)
+ * @mode: accsess rights and file type
+ * @uid: user ID
+ * @gid: group ID
+ * @major: device node major number
+ * @minor: device node minor number
+ *
+ * This is an element of the name hash table. Name hash table sits in the path
+ * hash table elements and describes file names which should be created/changed
+ * at this path.
+ */
+struct name_htbl_element {
+	const char *name;
+	unsigned int mode;
+	unsigned int uid;
+	unsigned int gid;
+	dev_t dev;
+};
+
+extern struct ubifs_info info_;
+
+struct hashtable_itr;
+
+int write_leb(int lnum, int len, void *buf);
+int parse_devtable(const char *tbl_file);
+struct path_htbl_element *devtbl_find_path(const char *path);
+struct name_htbl_element *devtbl_find_name(struct path_htbl_element *ph_elt,
+					   const char *name);
+int override_attributes(struct stat *st, struct path_htbl_element *ph_elt,
+			struct name_htbl_element *nh_elt);
+struct name_htbl_element *
+first_name_htbl_element(struct path_htbl_element *ph_elt,
+			struct hashtable_itr **itr);
+struct name_htbl_element *
+next_name_htbl_element(struct path_htbl_element *ph_elt,
+		       struct hashtable_itr **itr);
+void free_devtable_info(void);
+
+#endif
diff --git a/ubifs-utils/mkfs.ubifs/ubifs.h b/ubifs-utils/mkfs.ubifs/ubifs.h
new file mode 100644
index 0000000..434b651
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/ubifs.h
@@ -0,0 +1,441 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy
+ *          Adrian Hunter
+ *          Zoltan Sogor
+ */
+
+#ifndef __UBIFS_H__
+#define __UBIFS_H__
+
+/* Maximum logical eraseblock size in bytes */
+#define UBIFS_MAX_LEB_SZ (2*1024*1024)
+
+/* Minimum amount of data UBIFS writes to the flash */
+#define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8)
+
+/* Largest key size supported in this implementation */
+#define CUR_MAX_KEY_LEN UBIFS_SK_LEN
+
+/*
+ * There is no notion of truncation key because truncation nodes do not exist
+ * in TNC. However, when replaying, it is handy to introduce fake "truncation"
+ * keys for truncation nodes because the code becomes simpler. So we define
+ * %UBIFS_TRUN_KEY type.
+ */
+#define UBIFS_TRUN_KEY UBIFS_KEY_TYPES_CNT
+
+/* The below union makes it easier to deal with keys */
+union ubifs_key
+{
+	uint8_t u8[CUR_MAX_KEY_LEN];
+	uint32_t u32[CUR_MAX_KEY_LEN/4];
+	uint64_t u64[CUR_MAX_KEY_LEN/8];
+	__le32 j32[CUR_MAX_KEY_LEN/4];
+};
+
+/*
+ * LEB properties flags.
+ *
+ * LPROPS_UNCAT: not categorized
+ * LPROPS_DIRTY: dirty > 0, not index
+ * LPROPS_DIRTY_IDX: dirty + free > UBIFS_CH_SZ and index
+ * LPROPS_FREE: free > 0, not empty, not index
+ * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs
+ * LPROPS_EMPTY: LEB is empty, not taken
+ * LPROPS_FREEABLE: free + dirty == leb_size, not index, not taken
+ * LPROPS_FRDI_IDX: free + dirty == leb_size and index, may be taken
+ * LPROPS_CAT_MASK: mask for the LEB categories above
+ * LPROPS_TAKEN: LEB was taken (this flag is not saved on the media)
+ * LPROPS_INDEX: LEB contains indexing nodes (this flag also exists on flash)
+ */
+enum {
+	LPROPS_UNCAT     =  0,
+	LPROPS_DIRTY     =  1,
+	LPROPS_DIRTY_IDX =  2,
+	LPROPS_FREE      =  3,
+	LPROPS_HEAP_CNT  =  3,
+	LPROPS_EMPTY     =  4,
+	LPROPS_FREEABLE  =  5,
+	LPROPS_FRDI_IDX  =  6,
+	LPROPS_CAT_MASK  = 15,
+	LPROPS_TAKEN     = 16,
+	LPROPS_INDEX     = 32,
+};
+
+/**
+ * struct ubifs_lprops - logical eraseblock properties.
+ * @free: amount of free space in bytes
+ * @dirty: amount of dirty space in bytes
+ * @flags: LEB properties flags (see above)
+ */
+struct ubifs_lprops
+{
+	int free;
+	int dirty;
+	int flags;
+};
+
+/**
+ * struct ubifs_lpt_lprops - LPT logical eraseblock properties.
+ * @free: amount of free space in bytes
+ * @dirty: amount of dirty space in bytes
+ */
+struct ubifs_lpt_lprops
+{
+	int free;
+	int dirty;
+};
+
+struct ubifs_nnode;
+
+/**
+ * struct ubifs_cnode - LEB Properties Tree common node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (zero for pnodes, greater than zero for nnodes)
+ * @num: node number
+ */
+struct ubifs_cnode
+{
+	struct ubifs_nnode *parent;
+	struct ubifs_cnode *cnext;
+	unsigned long flags;
+	int iip;
+	int level;
+	int num;
+};
+
+/**
+ * struct ubifs_pnode - LEB Properties Tree leaf node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (always zero for pnodes)
+ * @num: node number
+ * @lprops: LEB properties array
+ */
+struct ubifs_pnode
+{
+	struct ubifs_nnode *parent;
+	struct ubifs_cnode *cnext;
+	unsigned long flags;
+	int iip;
+	int level;
+	int num;
+	struct ubifs_lprops lprops[UBIFS_LPT_FANOUT];
+};
+
+/**
+ * struct ubifs_nbranch - LEB Properties Tree internal node branch.
+ * @lnum: LEB number of child
+ * @offs: offset of child
+ * @nnode: nnode child
+ * @pnode: pnode child
+ * @cnode: cnode child
+ */
+struct ubifs_nbranch
+{
+	int lnum;
+	int offs;
+	union
+	{
+		struct ubifs_nnode *nnode;
+		struct ubifs_pnode *pnode;
+		struct ubifs_cnode *cnode;
+	};
+};
+
+/**
+ * struct ubifs_nnode - LEB Properties Tree internal node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (always greater than zero for nnodes)
+ * @num: node number
+ * @nbranch: branches to child nodes
+ */
+struct ubifs_nnode
+{
+	struct ubifs_nnode *parent;
+	struct ubifs_cnode *cnext;
+	unsigned long flags;
+	int iip;
+	int level;
+	int num;
+	struct ubifs_nbranch nbranch[UBIFS_LPT_FANOUT];
+};
+
+/**
+ * struct ubifs_lp_stats - statistics of eraseblocks in the main area.
+ * @empty_lebs: number of empty LEBs
+ * @taken_empty_lebs: number of taken LEBs
+ * @idx_lebs: number of indexing LEBs
+ * @total_free: total free space in bytes
+ * @total_dirty: total dirty space in bytes
+ * @total_used: total used space in bytes (includes only data LEBs)
+ * @total_dead: total dead space in bytes (includes only data LEBs)
+ * @total_dark: total dark space in bytes (includes only data LEBs)
+ */
+struct ubifs_lp_stats {
+	int empty_lebs;
+	int taken_empty_lebs;
+	int idx_lebs;
+	long long total_free;
+	long long total_dirty;
+	long long total_used;
+	long long total_dead;
+	long long total_dark;
+};
+
+/**
+ * struct ubifs_zbranch - key/coordinate/length branch stored in znodes.
+ * @key: key
+ * @znode: znode address in memory
+ * @lnum: LEB number of the indexing node
+ * @offs: offset of the indexing node within @lnum
+ * @len: target node length
+ */
+struct ubifs_zbranch
+{
+	union ubifs_key key;
+	struct ubifs_znode *znode;
+	int lnum;
+	int offs;
+	int len;
+};
+
+/**
+ * struct ubifs_znode - in-memory representation of an indexing node.
+ * @parent: parent znode or NULL if it is the root
+ * @cnext: next znode to commit
+ * @flags: flags
+ * @time: last access time (seconds)
+ * @level: level of the entry in the TNC tree
+ * @child_cnt: count of child znodes
+ * @iip: index in parent's zbranch array
+ * @alt: lower bound of key range has altered i.e. child inserted at slot 0
+ * @zbranch: array of znode branches (@c->fanout elements)
+ */
+struct ubifs_znode
+{
+	struct ubifs_znode *parent;
+	struct ubifs_znode *cnext;
+	unsigned long flags;
+	unsigned long time;
+	int level;
+	int child_cnt;
+	int iip;
+	int alt;
+#ifdef CONFIG_UBIFS_FS_DEBUG
+	int lnum, offs, len;
+#endif
+	struct ubifs_zbranch zbranch[];
+};
+
+/**
+ * struct ubifs_info - UBIFS file-system description data structure
+ * (per-superblock).
+ *
+ * @highest_inum: highest used inode number
+ * @max_sqnum: current global sequence number
+ *
+ * @jhead_cnt: count of journal heads
+ * @max_bud_bytes: maximum number of bytes allowed in buds
+ *
+ * @zroot: zbranch which points to the root index node and znode
+ * @ihead_lnum: LEB number of index head
+ * @ihead_offs: offset of index head
+ *
+ * @log_lebs: number of logical eraseblocks in the log
+ * @lpt_lebs: number of LEBs used for lprops table
+ * @lpt_first: first LEB of the lprops table area
+ * @lpt_last: last LEB of the lprops table area
+ * @main_lebs: count of LEBs in the main area
+ * @main_first: first LEB of the main area
+ * @default_compr: default compression type
+ * @favor_lzo: favor LZO compression method
+ * @favor_percent: lzo vs. zlib threshold used in case favor LZO
+ *
+ * @key_hash_type: type of the key hash
+ * @key_hash: direntry key hash function
+ * @key_fmt: key format
+ * @key_len: key length
+ * @fanout: fanout of the index tree (number of links per indexing node)
+ *
+ * @min_io_size: minimal input/output unit size
+ * @leb_size: logical eraseblock size in bytes
+ * @leb_cnt: count of logical eraseblocks
+ * @max_leb_cnt: maximum count of logical eraseblocks
+ *
+ * @old_idx_sz: size of index on flash
+ * @lst: lprops statistics
+ *
+ * @dead_wm: LEB dead space watermark
+ * @dark_wm: LEB dark space watermark
+ *
+ * @di: UBI device information
+ * @vi: UBI volume information
+ *
+ * @gc_lnum: LEB number used for garbage collection
+ * @rp_size: reserved pool size
+ *
+ * @space_bits: number of bits needed to record free or dirty space
+ * @lpt_lnum_bits: number of bits needed to record a LEB number in the LPT
+ * @lpt_offs_bits: number of bits needed to record an offset in the LPT
+ * @lpt_spc_bits: number of bits needed to space in the LPT
+ * @pcnt_bits: number of bits needed to record pnode or nnode number
+ * @lnum_bits: number of bits needed to record LEB number
+ * @nnode_sz: size of on-flash nnode
+ * @pnode_sz: size of on-flash pnode
+ * @ltab_sz: size of on-flash LPT lprops table
+ * @lsave_sz: size of on-flash LPT save table
+ * @pnode_cnt: number of pnodes
+ * @nnode_cnt: number of nnodes
+ * @lpt_hght: height of the LPT
+ *
+ * @lpt_lnum: LEB number of the root nnode of the LPT
+ * @lpt_offs: offset of the root nnode of the LPT
+ * @nhead_lnum: LEB number of LPT head
+ * @nhead_offs: offset of LPT head
+ * @big_lpt: flag that LPT is too big to write whole during commit
+ * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
+ * @lpt_sz: LPT size
+ *
+ * @ltab_lnum: LEB number of LPT's own lprops table
+ * @ltab_offs: offset of LPT's own lprops table
+ * @lpt: lprops table
+ * @ltab: LPT's own lprops table
+ * @lsave_cnt: number of LEB numbers in LPT's save table
+ * @lsave_lnum: LEB number of LPT's save table
+ * @lsave_offs: offset of LPT's save table
+ * @lsave: LPT's save table
+ * @lscan_lnum: LEB number of last LPT scan
+ */
+struct ubifs_info
+{
+	ino_t highest_inum;
+	unsigned long long max_sqnum;
+
+	int jhead_cnt;
+	long long max_bud_bytes;
+
+	struct ubifs_zbranch zroot;
+	int ihead_lnum;
+	int ihead_offs;
+
+	int log_lebs;
+	int lpt_lebs;
+	int lpt_first;
+	int lpt_last;
+	int orph_lebs;
+	int main_lebs;
+	int main_first;
+	int default_compr;
+	int favor_lzo;
+	int favor_percent;
+
+	uint8_t key_hash_type;
+	uint32_t (*key_hash)(const char *str, int len);
+	int key_fmt;
+	int key_len;
+	int fanout;
+
+	int min_io_size;
+	int leb_size;
+	int leb_cnt;
+	int max_leb_cnt;
+
+	unsigned long long old_idx_sz;
+	struct ubifs_lp_stats lst;
+
+	int dead_wm;
+	int dark_wm;
+
+	struct ubi_dev_info di;
+	struct ubi_vol_info vi;
+
+	int gc_lnum;
+	long long rp_size;
+
+	int space_bits;
+	int lpt_lnum_bits;
+	int lpt_offs_bits;
+	int lpt_spc_bits;
+	int pcnt_bits;
+	int lnum_bits;
+	int nnode_sz;
+	int pnode_sz;
+	int ltab_sz;
+	int lsave_sz;
+	int pnode_cnt;
+	int nnode_cnt;
+	int lpt_hght;
+
+	int lpt_lnum;
+	int lpt_offs;
+	int nhead_lnum;
+	int nhead_offs;
+	int big_lpt;
+	int space_fixup;
+	long long lpt_sz;
+
+	int ltab_lnum;
+	int ltab_offs;
+	struct ubifs_lprops *lpt;
+	struct ubifs_lpt_lprops *ltab;
+	int lsave_cnt;
+	int lsave_lnum;
+	int lsave_offs;
+	int *lsave;
+	int lscan_lnum;
+
+};
+
+/**
+ * ubifs_idx_node_sz - return index node size.
+ * @c: the UBIFS file-system description object
+ * @child_cnt: number of children of this index node
+ */
+static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt)
+{
+	return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt;
+}
+
+/**
+ * ubifs_idx_branch - return pointer to an index branch.
+ * @c: the UBIFS file-system description object
+ * @idx: index node
+ * @bnum: branch number
+ */
+static inline
+struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
+				      const struct ubifs_idx_node *idx,
+				      int bnum)
+{
+	return (struct ubifs_branch *)((void *)idx->branches +
+				       (UBIFS_BRANCH_SZ + c->key_len) * bnum);
+}
+
+#endif /* __UBIFS_H__ */
-- 
1.8.4.2




More information about the linux-mtd mailing list