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

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


Really sorry for the large path, will resend it with `git format-patch -m `

On 10/15/2015 12:04 PM, Dongsheng Yang wrote:
> * 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__ */
>




More information about the linux-mtd mailing list