All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils
@ 2015-10-15  4:04 Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source Dongsheng Yang
                   ` (27 more replies)
  0 siblings, 28 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Hi guys,
	This is the v2 for ubifs_dump. No big changes at all,
only addressed two problems mentioned by Richard and David.

Hi Richard,
	I am sorry you need to rebase your work. But that
would not be a problem I believe, the v2 here is almost same
with v1. 

https://github.com/yangdongsheng/mtd-utils.git ubifs_dump_v2

changelog:
	-v1:
		- fix a problem in error path pointed by David
		- correct width of data in media by Richard
Thanx
Yang


Dongsheng Yang (27):
  mtd-utils: Restructure the mtd-utils source.
  ubifs: pick some common definitions into ubifs_common.h
  ubifs: move the all io related code into io.[h|c]
  ubifs: remove the including of mkfs.ubifs.h in lpt.c
  ubifs: cut off the dependence from compr.o to mkfs.ubifs
  ubifs: cut off the dependence from devtable to mkfs.ubifs.h
  ubifs: introduce ubifs-utils/include and ubifs-utils/lib
  ubifs: move more functions into io lib
  ubifs: introduce a new tool ubifs_dump
  ubifs: introduce list.h
  ubifs: copy some important data in ubifs.h from kernel to ubifs-utils
  ubifs: copy some important functions in key.h from kernel to
    ubifs-utils
  ubifs: ubifs_dump: add dump_ch and dump_node functions
  ubifs: defs.h: introduce some compatible definition for printk class
  ubifs: io: introduce ubifs_read function to read ubi volume
  ubifs: ubifs_dump: dump super block
  ubifs: introduce scan for ubifs-utils
  ubifs: add some more compatible definitions in defs.h
  ubifs: ubifs_dump: dump master node
  ubifs: ubifs_dump: dump log area
  ubifs: introduce lprops lib
  ubifs: lpt: implement functions to scan lpt
  ubifs: ubifs_dump: dump lpt area
  ubifs: ubifs_dump: dump index area
  ubifs: defs.h: introduce some compatible definitions about integer
    such as __u16
  ubifs: introduce hexdump lib
  ubifs: ubifs_dump: dump data in hex format

 MAKEDEV                                  |   41 -
 Makefile                                 |   76 +-
 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/COPYING                      |  340 +++++
 ubifs-utils/README                       |    9 +
 ubifs-utils/include/compr.h              |   45 +
 ubifs-utils/include/crc16.h              |   27 +
 ubifs-utils/include/defs.h               |  215 +++
 ubifs-utils/include/devtable.h           |   55 +
 ubifs-utils/include/hashtable.h          |  199 +++
 ubifs-utils/include/hashtable_itr.h      |  112 ++
 ubifs-utils/include/hashtable_private.h  |   85 ++
 ubifs-utils/include/hexdump.h            |   21 +
 ubifs-utils/include/io.h                 |   21 +
 ubifs-utils/include/key.h                |  263 ++++
 ubifs-utils/include/list.h               |  484 +++++++
 ubifs-utils/include/lprops.h             |    6 +
 ubifs-utils/include/lpt.h                |   32 +
 ubifs-utils/include/scan.h               |    8 +
 ubifs-utils/include/ubifs.h              |  527 +++++++
 ubifs-utils/include/ubifs_common.h       |   50 +
 ubifs-utils/lib/compr.c                  |  213 +++
 ubifs-utils/lib/crc16.c                  |   56 +
 ubifs-utils/lib/devtable.c               |  525 +++++++
 ubifs-utils/lib/hashtable.c              |  277 ++++
 ubifs-utils/lib/hashtable_itr.c          |  176 +++
 ubifs-utils/lib/hexdump.c                |  200 +++
 ubifs-utils/lib/io.c                     |  152 ++
 ubifs-utils/lib/lprops.c                 |   79 +
 ubifs-utils/lib/lpt.c                    | 1275 ++++++++++++++++
 ubifs-utils/lib/scan.c                   |  318 ++++
 ubifs-utils/mkfs.ubifs/.gitignore        |    1 +
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.c      | 2202 ++++++++++++++++++++++++++++
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.h      |   54 +
 ubifs-utils/ubifs_dump/ubifs_dump.c      | 1038 +++++++++++++
 139 files changed, 22441 insertions(+), 19229 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/COPYING
 create mode 100644 ubifs-utils/README
 create mode 100644 ubifs-utils/include/compr.h
 create mode 100644 ubifs-utils/include/crc16.h
 create mode 100644 ubifs-utils/include/defs.h
 create mode 100644 ubifs-utils/include/devtable.h
 create mode 100644 ubifs-utils/include/hashtable.h
 create mode 100644 ubifs-utils/include/hashtable_itr.h
 create mode 100644 ubifs-utils/include/hashtable_private.h
 create mode 100644 ubifs-utils/include/hexdump.h
 create mode 100644 ubifs-utils/include/io.h
 create mode 100644 ubifs-utils/include/key.h
 create mode 100644 ubifs-utils/include/list.h
 create mode 100644 ubifs-utils/include/lprops.h
 create mode 100644 ubifs-utils/include/lpt.h
 create mode 100644 ubifs-utils/include/scan.h
 create mode 100644 ubifs-utils/include/ubifs.h
 create mode 100644 ubifs-utils/include/ubifs_common.h
 create mode 100644 ubifs-utils/lib/compr.c
 create mode 100644 ubifs-utils/lib/crc16.c
 create mode 100644 ubifs-utils/lib/devtable.c
 create mode 100644 ubifs-utils/lib/hashtable.c
 create mode 100644 ubifs-utils/lib/hashtable_itr.c
 create mode 100644 ubifs-utils/lib/hexdump.c
 create mode 100644 ubifs-utils/lib/io.c
 create mode 100644 ubifs-utils/lib/lprops.c
 create mode 100644 ubifs-utils/lib/lpt.c
 create mode 100644 ubifs-utils/lib/scan.c
 create mode 100644 ubifs-utils/mkfs.ubifs/.gitignore
 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/ubifs_dump/ubifs_dump.c

-- 
1.8.4.2

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source.
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:06   ` Dongsheng Yang
  2015-10-15  4:10   ` [RESEND PATCH " Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 02/27] ubifs: pick some common definitions into ubifs_common.h Dongsheng Yang
                   ` (26 subsequent siblings)
  27 siblings, 2 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

* 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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@lineo.com>
+ *           2002 Axis Communications AB
+ *           2001, 2002 Erik Andersen <andersen@codepoet.org>
+ *           2004 University of Szeged, Hungary
+ *           2006 KaiGai Kohei <kaigai@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@schleef.org>.
+ *
+ * Major architectural rewrite by Erik Andersen <andersen@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@suse.de>
+  (C) 2002  David Woodhouse <dwmw2@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@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@inf.u-szeged.hu>,
+ *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                     Patrik Kluba <pajko@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@inf.u-szeged.hu>,
+ *                     Ferenc Havasi <havasi@inf.u-szeged.hu>
+ *                     University of Szeged, Hungary
+ *                2006 KaiGai Kohei <kaigai@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@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@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@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 = &part;
+
+	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@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@lineo.com>
- *           2002 Axis Communications AB
- *           2001, 2002 Erik Andersen <andersen@codepoet.org>
- *           2004 University of Szeged, Hungary
- *           2006 KaiGai Kohei <kaigai@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@schleef.org>.
- *
- * Major architectural rewrite by Erik Andersen <andersen@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.
-\f
-		    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.)
-\f
-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.
-\f
-  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.
-\f
-  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
-\f
-	    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@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@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@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@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@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@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@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@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 = &part;
-
-	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@infradead.org)
+ *                     Steven J. Hill (sjhill@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@realitydiluted.com)
+ *		  2003 Thomas Gleixner (tglx@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@infradead.org)
- *                     Steven J. Hill (sjhill@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@realitydiluted.com)
- *		  2003 Thomas Gleixner (tglx@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@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@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@suse.de>
-  (C) 2002  David Woodhouse <dwmw2@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@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@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@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@inf.u-szeged.hu>,
- *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
- *                     Patrik Kluba <pajko@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@inf.u-szeged.hu>,
- *                     Ferenc Havasi <havasi@inf.u-szeged.hu>
- *                     University of Szeged, Hungary
- *                2006 KaiGai Kohei <kaigai@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.
+\f
+		    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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+	    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@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@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@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@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@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@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@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_PRIVATE_CWC22_H__
+#define __HASHTABLE_PRIVATE_CWC22_H__
+
+#include "hashtable.h"
+
+/*****************************************************************************/
+struct entry
+{
+    void *k, *v;
+    unsigned int h;
+    struct entry *next;
+};
+
+struct hashtable {
+    unsigned int tablelength;
+    struct entry **table;
+    unsigned int entrycount;
+    unsigned int loadlimit;
+    unsigned int primeindex;
+    unsigned int (*hashfn) (void *k);
+    int (*eqfn) (void *k1, void *k2);
+};
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k);
+
+/*****************************************************************************/
+/* indexFor */
+static inline unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue) {
+    return (hashvalue % tablelength);
+};
+
+/* Only works if tablelength == 2^N */
+/*static inline unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue)
+{
+    return (hashvalue & (tablelength - 1u));
+}
+*/
+
+/*****************************************************************************/
+#define freekey(X) free(X)
+/*define freekey(X) ; */
+
+
+/*****************************************************************************/
+
+#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/ubifs-utils/mkfs.ubifs/key.h b/ubifs-utils/mkfs.ubifs/key.h
new file mode 100644
index 0000000..d3a02d4
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/key.h
@@ -0,0 +1,189 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+/*
+ * This header contains various key-related definitions and helper function.
+ * UBIFS allows several key schemes, so we access key fields only via these
+ * helpers. At the moment only one key scheme is supported.
+ *
+ * Simple key scheme
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * Keys are 64-bits long. First 32-bits are inode number (parent inode number
+ * in case of direntry key). Next 3 bits are node type. The last 29 bits are
+ * 4KiB offset in case of inode node, and direntry hash in case of a direntry
+ * node. We use "r5" hash borrowed from reiserfs.
+ */
+
+#ifndef __UBIFS_KEY_H__
+#define __UBIFS_KEY_H__
+
+/**
+ * key_mask_hash - mask a valid hash value.
+ * @val: value to be masked
+ *
+ * We use hash values as offset in directories, so values %0 and %1 are
+ * reserved for "." and "..". %2 is reserved for "end of readdir" marker. This
+ * function makes sure the reserved values are not used.
+ */
+static inline uint32_t key_mask_hash(uint32_t hash)
+{
+	hash &= UBIFS_S_KEY_HASH_MASK;
+	if (unlikely(hash <= 2))
+		hash += 3;
+	return hash;
+}
+
+/**
+ * key_r5_hash - R5 hash function (borrowed from reiserfs).
+ * @s: direntry name
+ * @len: name length
+ */
+static inline uint32_t key_r5_hash(const char *s, int len)
+{
+	uint32_t a = 0;
+	const signed char *str = (const signed char *)s;
+
+	len = len;
+	while (*str) {
+		a += *str << 4;
+		a += *str >> 4;
+		a *= 11;
+		str++;
+	}
+
+	return key_mask_hash(a);
+}
+
+/**
+ * key_test_hash - testing hash function.
+ * @str: direntry name
+ * @len: name length
+ */
+static inline uint32_t key_test_hash(const char *str, int len)
+{
+	uint32_t a = 0;
+
+	len = min_t(uint32_t, len, 4);
+	memcpy(&a, str, len);
+	return key_mask_hash(a);
+}
+
+/**
+ * ino_key_init - initialize inode key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ */
+static inline void ino_key_init(union ubifs_key *key, ino_t inum)
+{
+	key->u32[0] = inum;
+	key->u32[1] = UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/**
+ * dent_key_init - initialize directory entry key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: parent inode number
+ * @nm: direntry name and length
+ */
+static inline void dent_key_init(const struct ubifs_info *c,
+				 union ubifs_key *key, ino_t inum,
+				 const struct qstr *nm)
+{
+	uint32_t hash = c->key_hash(nm->name, nm->len);
+
+	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+	key->u32[0] = inum;
+	key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
+}
+
+/**
+ * data_key_init - initialize data key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ * @block: block number
+ */
+static inline void data_key_init(union ubifs_key *key, ino_t inum,
+				 unsigned int block)
+{
+	ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
+	key->u32[0] = inum;
+	key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS);
+}
+
+/**
+ * key_write - transform a key from in-memory format.
+ * @c: UBIFS file-system description object
+ * @from: the key to transform
+ * @to: the key to store the result
+ */
+static inline void key_write(const union ubifs_key *from, void *to)
+{
+	union ubifs_key *t = to;
+
+	t->j32[0] = cpu_to_le32(from->u32[0]);
+	t->j32[1] = cpu_to_le32(from->u32[1]);
+	memset(to + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * key_write_idx - transform a key from in-memory format for the index.
+ * @c: UBIFS file-system description object
+ * @from: the key to transform
+ * @to: the key to store the result
+ */
+static inline void key_write_idx(const union ubifs_key *from, void *to)
+{
+	union ubifs_key *t = to;
+
+	t->j32[0] = cpu_to_le32(from->u32[0]);
+	t->j32[1] = cpu_to_le32(from->u32[1]);
+}
+
+/**
+ * keys_cmp - compare keys.
+ * @c: UBIFS file-system description object
+ * @key1: the first key to compare
+ * @key2: the second key to compare
+ *
+ * This function compares 2 keys and returns %-1 if @key1 is less than
+ * @key2, 0 if the keys are equivalent and %1 if @key1 is greater than @key2.
+ */
+static inline int keys_cmp(const union ubifs_key *key1,
+			   const union ubifs_key *key2)
+{
+	if (key1->u32[0] < key2->u32[0])
+		return -1;
+	if (key1->u32[0] > key2->u32[0])
+		return 1;
+	if (key1->u32[1] < key2->u32[1])
+		return -1;
+	if (key1->u32[1] > key2->u32[1])
+		return 1;
+
+	return 0;
+}
+
+#endif /* !__UBIFS_KEY_H__ */
diff --git a/ubifs-utils/mkfs.ubifs/lpt.c b/ubifs-utils/mkfs.ubifs/lpt.c
new file mode 100644
index 0000000..6aa0b88
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/lpt.c
@@ -0,0 +1,578 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006, 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy
+ */
+
+#include "mkfs.ubifs.h"
+
+/**
+ * do_calc_lpt_geom - calculate sizes for the LPT area.
+ * @c: the UBIFS file-system description object
+ *
+ * Calculate the sizes of LPT bit fields, nodes, and tree, based on the
+ * properties of the flash and whether LPT is "big" (c->big_lpt).
+ */
+static void do_calc_lpt_geom(struct ubifs_info *c)
+{
+	int n, bits, per_leb_wastage;
+	long long sz, tot_wastage;
+
+	c->pnode_cnt = (c->main_lebs + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+
+	n = (c->pnode_cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+	c->nnode_cnt = n;
+	while (n > 1) {
+		n = (n + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+		c->nnode_cnt += n;
+	}
+
+	c->lpt_hght = 1;
+	n = UBIFS_LPT_FANOUT;
+	while (n < c->pnode_cnt) {
+		c->lpt_hght += 1;
+		n <<= UBIFS_LPT_FANOUT_SHIFT;
+	}
+
+	c->space_bits = fls(c->leb_size) - 3;
+	c->lpt_lnum_bits = fls(c->lpt_lebs);
+	c->lpt_offs_bits = fls(c->leb_size - 1);
+	c->lpt_spc_bits = fls(c->leb_size);
+
+	n = (c->max_leb_cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+	c->pcnt_bits = fls(n - 1);
+
+	c->lnum_bits = fls(c->max_leb_cnt - 1);
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       (c->big_lpt ? c->pcnt_bits : 0) +
+	       (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT;
+	c->pnode_sz = (bits + 7) / 8;
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       (c->big_lpt ? c->pcnt_bits : 0) +
+	       (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT;
+	c->nnode_sz = (bits + 7) / 8;
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       c->lpt_lebs * c->lpt_spc_bits * 2;
+	c->ltab_sz = (bits + 7) / 8;
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       c->lnum_bits * c->lsave_cnt;
+	c->lsave_sz = (bits + 7) / 8;
+
+	/* Calculate the minimum LPT size */
+	c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
+	c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
+	c->lpt_sz += c->ltab_sz;
+	c->lpt_sz += c->lsave_sz;
+
+	/* Add wastage */
+	sz = c->lpt_sz;
+	per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz);
+	sz += per_leb_wastage;
+	tot_wastage = per_leb_wastage;
+	while (sz > c->leb_size) {
+		sz += per_leb_wastage;
+		sz -= c->leb_size;
+		tot_wastage += per_leb_wastage;
+	}
+	tot_wastage += ALIGN(sz, c->min_io_size) - sz;
+	c->lpt_sz += tot_wastage;
+}
+
+/**
+ * calc_dflt_lpt_geom - calculate default LPT geometry.
+ * @c: the UBIFS file-system description object
+ * @main_lebs: number of main area LEBs is passed and returned here
+ * @big_lpt: whether the LPT area is "big" is returned here
+ *
+ * The size of the LPT area depends on parameters that themselves are dependent
+ * on the size of the LPT area. This function, successively recalculates the LPT
+ * area geometry until the parameters and resultant geometry are consistent.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt)
+{
+	int i, lebs_needed;
+	long long sz;
+
+	/* Start by assuming the minimum number of LPT LEBs */
+	c->lpt_lebs = UBIFS_MIN_LPT_LEBS;
+	c->main_lebs = *main_lebs - c->lpt_lebs;
+	if (c->main_lebs <= 0)
+		return -EINVAL;
+
+	/* And assume we will use the small LPT model */
+	c->big_lpt = 0;
+
+	/*
+	 * Calculate the geometry based on assumptions above and then see if it
+	 * makes sense
+	 */
+	do_calc_lpt_geom(c);
+
+	/* Small LPT model must have lpt_sz < leb_size */
+	if (c->lpt_sz > c->leb_size) {
+		/* Nope, so try again using big LPT model */
+		c->big_lpt = 1;
+		do_calc_lpt_geom(c);
+	}
+
+	/* Now check there are enough LPT LEBs */
+	for (i = 0; i < 64 ; i++) {
+		sz = c->lpt_sz * 4; /* Allow 4 times the size */
+		sz += c->leb_size - 1;
+		do_div(sz, c->leb_size);
+		lebs_needed = sz;
+		if (lebs_needed > c->lpt_lebs) {
+			/* Not enough LPT LEBs so try again with more */
+			c->lpt_lebs = lebs_needed;
+			c->main_lebs = *main_lebs - c->lpt_lebs;
+			if (c->main_lebs <= 0)
+				return -EINVAL;
+			do_calc_lpt_geom(c);
+			continue;
+		}
+		if (c->ltab_sz > c->leb_size) {
+			err_msg("LPT ltab too big");
+			return -EINVAL;
+		}
+		*main_lebs = c->main_lebs;
+		*big_lpt = c->big_lpt;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/**
+ * pack_bits - pack bit fields end-to-end.
+ * @addr: address at which to pack (passed and next address returned)
+ * @pos: bit position at which to pack (passed and next position returned)
+ * @val: value to pack
+ * @nrbits: number of bits of value to pack (1-32)
+ */
+static void pack_bits(uint8_t **addr, int *pos, uint32_t val, int nrbits)
+{
+	uint8_t *p = *addr;
+	int b = *pos;
+
+	if (b) {
+		*p |= ((uint8_t)val) << b;
+		nrbits += b;
+		if (nrbits > 8) {
+			*++p = (uint8_t)(val >>= (8 - b));
+			if (nrbits > 16) {
+				*++p = (uint8_t)(val >>= 8);
+				if (nrbits > 24) {
+					*++p = (uint8_t)(val >>= 8);
+					if (nrbits > 32)
+						*++p = (uint8_t)(val >>= 8);
+				}
+			}
+		}
+	} else {
+		*p = (uint8_t)val;
+		if (nrbits > 8) {
+			*++p = (uint8_t)(val >>= 8);
+			if (nrbits > 16) {
+				*++p = (uint8_t)(val >>= 8);
+				if (nrbits > 24)
+					*++p = (uint8_t)(val >>= 8);
+			}
+		}
+	}
+	b = nrbits & 7;
+	if (b == 0)
+		p++;
+	*addr = p;
+	*pos = b;
+}
+
+/**
+ * pack_pnode - pack all the bit fields of a pnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @pnode: pnode to pack
+ */
+static void pack_pnode(struct ubifs_info *c, void *buf,
+		       struct ubifs_pnode *pnode)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0;
+	uint16_t crc;
+
+	pack_bits(&addr, &pos, UBIFS_LPT_PNODE, UBIFS_LPT_TYPE_BITS);
+	if (c->big_lpt)
+		pack_bits(&addr, &pos, pnode->num, c->pcnt_bits);
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		pack_bits(&addr, &pos, pnode->lprops[i].free >> 3,
+			  c->space_bits);
+		pack_bits(&addr, &pos, pnode->lprops[i].dirty >> 3,
+			  c->space_bits);
+		if (pnode->lprops[i].flags & LPROPS_INDEX)
+			pack_bits(&addr, &pos, 1, 1);
+		else
+			pack_bits(&addr, &pos, 0, 1);
+	}
+	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+		    c->pnode_sz - UBIFS_LPT_CRC_BYTES);
+	addr = buf;
+	pos = 0;
+	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * pack_nnode - pack all the bit fields of a nnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @nnode: nnode to pack
+ */
+static void pack_nnode(struct ubifs_info *c, void *buf,
+		       struct ubifs_nnode *nnode)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0;
+	uint16_t crc;
+
+	pack_bits(&addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS);
+	if (c->big_lpt)
+		pack_bits(&addr, &pos, nnode->num, c->pcnt_bits);
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		int lnum = nnode->nbranch[i].lnum;
+
+		if (lnum == 0)
+			lnum = c->lpt_last + 1;
+		pack_bits(&addr, &pos, lnum - c->lpt_first, c->lpt_lnum_bits);
+		pack_bits(&addr, &pos, nnode->nbranch[i].offs,
+			  c->lpt_offs_bits);
+	}
+	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+		    c->nnode_sz - UBIFS_LPT_CRC_BYTES);
+	addr = buf;
+	pos = 0;
+	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * pack_ltab - pack the LPT's own lprops table.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @ltab: LPT's own lprops table to pack
+ */
+static void pack_ltab(struct ubifs_info *c, void *buf,
+			 struct ubifs_lpt_lprops *ltab)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0;
+	uint16_t crc;
+
+	pack_bits(&addr, &pos, UBIFS_LPT_LTAB, UBIFS_LPT_TYPE_BITS);
+	for (i = 0; i < c->lpt_lebs; i++) {
+		pack_bits(&addr, &pos, ltab[i].free, c->lpt_spc_bits);
+		pack_bits(&addr, &pos, ltab[i].dirty, c->lpt_spc_bits);
+	}
+	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+		    c->ltab_sz - UBIFS_LPT_CRC_BYTES);
+	addr = buf;
+	pos = 0;
+	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * pack_lsave - pack the LPT's save table.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @lsave: LPT's save table to pack
+ */
+static void pack_lsave(struct ubifs_info *c, void *buf, int *lsave)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0;
+	uint16_t crc;
+
+	pack_bits(&addr, &pos, UBIFS_LPT_LSAVE, UBIFS_LPT_TYPE_BITS);
+	for (i = 0; i < c->lsave_cnt; i++)
+		pack_bits(&addr, &pos, lsave[i], c->lnum_bits);
+	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+		    c->lsave_sz - UBIFS_LPT_CRC_BYTES);
+	addr = buf;
+	pos = 0;
+	pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * set_ltab - set LPT LEB properties.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number
+ * @free: amount of free space
+ * @dirty: amount of dirty space
+ */
+static void set_ltab(struct ubifs_info *c, int lnum, int free, int dirty)
+{
+	dbg_msg(3, "LEB %d free %d dirty %d to %d %d",
+		lnum, c->ltab[lnum - c->lpt_first].free,
+		c->ltab[lnum - c->lpt_first].dirty, free, dirty);
+	c->ltab[lnum - c->lpt_first].free = free;
+	c->ltab[lnum - c->lpt_first].dirty = dirty;
+}
+
+/**
+ * calc_nnode_num - calculate nnode number.
+ * @row: the row in the tree (root is zero)
+ * @col: the column in the row (leftmost is zero)
+ *
+ * The nnode number is a number that uniquely identifies a nnode and can be used
+ * easily to traverse the tree from the root to that nnode.
+ *
+ * This function calculates and returns the nnode number for the nnode at @row
+ * and @col.
+ */
+static int calc_nnode_num(int row, int col)
+{
+	int num, bits;
+
+	num = 1;
+	while (row--) {
+		bits = (col & (UBIFS_LPT_FANOUT - 1));
+		col >>= UBIFS_LPT_FANOUT_SHIFT;
+		num <<= UBIFS_LPT_FANOUT_SHIFT;
+		num |= bits;
+	}
+	return num;
+}
+
+/**
+ * create_lpt - create LPT.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int create_lpt(struct ubifs_info *c)
+{
+	int lnum, err = 0, i, j, cnt, len, alen, row;
+	int blnum, boffs, bsz, bcnt;
+	struct ubifs_pnode *pnode = NULL;
+	struct ubifs_nnode *nnode = NULL;
+	void *buf = NULL, *p;
+	int *lsave = NULL;
+
+	pnode = malloc(sizeof(struct ubifs_pnode));
+	nnode = malloc(sizeof(struct ubifs_nnode));
+	buf = malloc(c->leb_size);
+	lsave = malloc(sizeof(int) * c->lsave_cnt);
+	if (!pnode || !nnode || !buf || !lsave) {
+		err = -ENOMEM;
+		goto out;
+	}
+	memset(pnode, 0 , sizeof(struct ubifs_pnode));
+	memset(nnode, 0 , sizeof(struct ubifs_nnode));
+
+	c->lscan_lnum = c->main_first;
+
+	lnum = c->lpt_first;
+	p = buf;
+	len = 0;
+	/* Number of leaf nodes (pnodes) */
+	cnt = (c->main_lebs + UBIFS_LPT_FANOUT - 1) >> UBIFS_LPT_FANOUT_SHIFT;
+	//printf("pnode_cnt=%d\n",cnt);
+
+	/*
+	 * To calculate the internal node branches, we keep information about
+	 * the level below.
+	 */
+	blnum = lnum; /* LEB number of level below */
+	boffs = 0; /* Offset of level below */
+	bcnt = cnt; /* Number of nodes in level below */
+	bsz = c->pnode_sz; /* Size of nodes in level below */
+
+	/* Add pnodes */
+	for (i = 0; i < cnt; i++) {
+		if (len + c->pnode_sz > c->leb_size) {
+			alen = ALIGN(len, c->min_io_size);
+			set_ltab(c, lnum, c->leb_size - alen, alen - len);
+			memset(p, 0xff, alen - len);
+			err = write_leb(lnum++, alen, buf);
+			if (err)
+				goto out;
+			p = buf;
+			len = 0;
+		}
+		/* Fill in the pnode */
+		for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
+			int k = (i << UBIFS_LPT_FANOUT_SHIFT) + j;
+
+			if (k < c->main_lebs)
+				pnode->lprops[j] = c->lpt[k];
+			else {
+				pnode->lprops[j].free = c->leb_size;
+				pnode->lprops[j].dirty = 0;
+				pnode->lprops[j].flags = 0;
+			}
+		}
+		pack_pnode(c, p, pnode);
+		p += c->pnode_sz;
+		len += c->pnode_sz;
+		/*
+		 * pnodes are simply numbered left to right starting at zero,
+		 * which means the pnode number can be used easily to traverse
+		 * down the tree to the corresponding pnode.
+		 */
+		pnode->num += 1;
+	}
+
+	row = c->lpt_hght - 1;
+	/* Add all nnodes, one level at a time */
+	while (1) {
+		/* Number of internal nodes (nnodes) at next level */
+		cnt = (cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+		if (cnt == 0)
+			cnt = 1;
+		for (i = 0; i < cnt; i++) {
+			if (len + c->nnode_sz > c->leb_size) {
+				alen = ALIGN(len, c->min_io_size);
+				set_ltab(c, lnum, c->leb_size - alen,
+					    alen - len);
+				memset(p, 0xff, alen - len);
+				err = write_leb(lnum++, alen, buf);
+				if (err)
+					goto out;
+				p = buf;
+				len = 0;
+			}
+			/* The root is on row zero */
+			if (row == 0) {
+				c->lpt_lnum = lnum;
+				c->lpt_offs = len;
+			}
+			/* Set branches to the level below */
+			for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
+				if (bcnt) {
+					if (boffs + bsz > c->leb_size) {
+						blnum += 1;
+						boffs = 0;
+					}
+					nnode->nbranch[j].lnum = blnum;
+					nnode->nbranch[j].offs = boffs;
+					boffs += bsz;
+					bcnt--;
+				} else {
+					nnode->nbranch[j].lnum = 0;
+					nnode->nbranch[j].offs = 0;
+				}
+			}
+			nnode->num = calc_nnode_num(row, i);
+			pack_nnode(c, p, nnode);
+			p += c->nnode_sz;
+			len += c->nnode_sz;
+		}
+		/* Row zero  is the top row */
+		if (row == 0)
+			break;
+		/* Update the information about the level below */
+		bcnt = cnt;
+		bsz = c->nnode_sz;
+		row -= 1;
+	}
+
+	if (c->big_lpt) {
+		/* Need to add LPT's save table */
+		if (len + c->lsave_sz > c->leb_size) {
+			alen = ALIGN(len, c->min_io_size);
+			set_ltab(c, lnum, c->leb_size - alen, alen - len);
+			memset(p, 0xff, alen - len);
+			err = write_leb(lnum++, alen, buf);
+			if (err)
+				goto out;
+			p = buf;
+			len = 0;
+		}
+
+		c->lsave_lnum = lnum;
+		c->lsave_offs = len;
+
+		for (i = 0; i < c->lsave_cnt; i++)
+			lsave[i] = c->main_first + i;
+
+		pack_lsave(c, p, lsave);
+		p += c->lsave_sz;
+		len += c->lsave_sz;
+	}
+
+	/* Need to add LPT's own LEB properties table */
+	if (len + c->ltab_sz > c->leb_size) {
+		alen = ALIGN(len, c->min_io_size);
+		set_ltab(c, lnum, c->leb_size - alen, alen - len);
+		memset(p, 0xff, alen - len);
+		err = write_leb(lnum++, alen, buf);
+		if (err)
+			goto out;
+		p = buf;
+		len = 0;
+	}
+
+	c->ltab_lnum = lnum;
+	c->ltab_offs = len;
+
+	/* Update ltab before packing it */
+	len += c->ltab_sz;
+	alen = ALIGN(len, c->min_io_size);
+	set_ltab(c, lnum, c->leb_size - alen, alen - len);
+
+	pack_ltab(c, p, c->ltab);
+	p += c->ltab_sz;
+
+	/* Write remaining buffer */
+	memset(p, 0xff, alen - len);
+	err = write_leb(lnum, alen, buf);
+	if (err)
+		goto out;
+
+	c->nhead_lnum = lnum;
+	c->nhead_offs = ALIGN(len, c->min_io_size);
+
+	dbg_msg(1, "lpt_sz:         %lld", c->lpt_sz);
+	dbg_msg(1, "space_bits:     %d", c->space_bits);
+	dbg_msg(1, "lpt_lnum_bits:  %d", c->lpt_lnum_bits);
+	dbg_msg(1, "lpt_offs_bits:  %d", c->lpt_offs_bits);
+	dbg_msg(1, "lpt_spc_bits:   %d", c->lpt_spc_bits);
+	dbg_msg(1, "pcnt_bits:      %d", c->pcnt_bits);
+	dbg_msg(1, "lnum_bits:      %d", c->lnum_bits);
+	dbg_msg(1, "pnode_sz:       %d", c->pnode_sz);
+	dbg_msg(1, "nnode_sz:       %d", c->nnode_sz);
+	dbg_msg(1, "ltab_sz:        %d", c->ltab_sz);
+	dbg_msg(1, "lsave_sz:       %d", c->lsave_sz);
+	dbg_msg(1, "lsave_cnt:      %d", c->lsave_cnt);
+	dbg_msg(1, "lpt_hght:       %d", c->lpt_hght);
+	dbg_msg(1, "big_lpt:        %d", c->big_lpt);
+	dbg_msg(1, "LPT root is at  %d:%d", c->lpt_lnum, c->lpt_offs);
+	dbg_msg(1, "LPT head is at  %d:%d", c->nhead_lnum, c->nhead_offs);
+	dbg_msg(1, "LPT ltab is at  %d:%d", c->ltab_lnum, c->ltab_offs);
+	if (c->big_lpt)
+		dbg_msg(1, "LPT lsave is at %d:%d",
+		        c->lsave_lnum, c->lsave_offs);
+out:
+	free(lsave);
+	free(buf);
+	free(nnode);
+	free(pnode);
+	return err;
+}
diff --git a/ubifs-utils/mkfs.ubifs/lpt.h b/ubifs-utils/mkfs.ubifs/lpt.h
new file mode 100644
index 0000000..4cde59d
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/lpt.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy
+ *          Adrian Hunter
+ */
+
+#ifndef __UBIFS_LPT_H__
+#define __UBIFS_LPT_H__
+
+int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt);
+int create_lpt(struct ubifs_info *c);
+
+#endif
diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
new file mode 100644
index 0000000..ca17e2b
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
@@ -0,0 +1,2324 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy
+ *          Zoltan Sogor
+ */
+
+#define _XOPEN_SOURCE 500 /* For realpath() */
+
+#include "mkfs.ubifs.h"
+#include <crc32.h>
+#include "common.h"
+
+/* Size (prime number) of hash table for link counting */
+#define HASH_TABLE_SIZE 10099
+
+/* The node buffer must allow for worst case compression */
+#define NODE_BUFFER_SIZE (UBIFS_DATA_NODE_SZ + \
+			  UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
+
+/* Default time granularity in nanoseconds */
+#define DEFAULT_TIME_GRAN 1000000000
+
+/**
+ * struct idx_entry - index entry.
+ * @next: next index entry (NULL at end of list)
+ * @prev: previous index entry (NULL at beginning of list)
+ * @key: key
+ * @name: directory entry name used for sorting colliding keys by name
+ * @lnum: LEB number
+ * @offs: offset
+ * @len: length
+ *
+ * The index is recorded as a linked list which is sorted and used to create
+ * the bottom level of the on-flash index tree. The remaining levels of the
+ * index tree are each built from the level below.
+ */
+struct idx_entry {
+	struct idx_entry *next;
+	struct idx_entry *prev;
+	union ubifs_key key;
+	char *name;
+	int lnum;
+	int offs;
+	int len;
+};
+
+/**
+ * struct inum_mapping - inode number mapping for link counting.
+ * @next: next inum_mapping (NULL at end of list)
+ * @prev: previous inum_mapping (NULL at beginning of list)
+ * @dev: source device on which the source inode number resides
+ * @inum: source inode number of the file
+ * @use_inum: target inode number of the file
+ * @use_nlink: number of links
+ * @path_name: a path name of the file
+ * @st: struct stat object containing inode attributes which have to be used
+ *      when the inode is being created (actually only UID, GID, access
+ *      mode, major and minor device numbers)
+ *
+ * If a file has more than one hard link, then the number of hard links that
+ * exist in the source directory hierarchy must be counted to exclude the
+ * possibility that the file is linked from outside the source directory
+ * hierarchy.
+ *
+ * The inum_mappings are stored in a hash_table of linked lists.
+ */
+struct inum_mapping {
+	struct inum_mapping *next;
+	struct inum_mapping *prev;
+	dev_t dev;
+	ino_t inum;
+	ino_t use_inum;
+	unsigned int use_nlink;
+	char *path_name;
+	struct stat st;
+};
+
+/*
+ * Because we copy functions from the kernel, we use a subset of the UBIFS
+ * file-system description object struct ubifs_info.
+ */
+struct ubifs_info info_;
+static struct ubifs_info *c = &info_;
+static libubi_t ubi;
+
+/* Debug levels are: 0 (none), 1 (statistics), 2 (files) ,3 (more details) */
+int debug_level;
+int verbose;
+int yes;
+
+static char *root;
+static int root_len;
+static struct stat root_st;
+static char *output;
+static int out_fd;
+static int out_ubi;
+static int squash_owner;
+
+/* The 'head' (position) which nodes are written */
+static int head_lnum;
+static int head_offs;
+static int head_flags;
+
+/* The index list */
+static struct idx_entry *idx_list_first;
+static struct idx_entry *idx_list_last;
+static size_t idx_cnt;
+
+/* Global buffers */
+static void *leb_buf;
+static void *node_buf;
+static void *block_buf;
+
+/* Hash table for inode link counting */
+static struct inum_mapping **hash_table;
+
+/* Inode creation sequence number */
+static unsigned long long creat_sqnum;
+
+static const char *optstring = "d:r:m:o:D:yh?vVe:c:g:f:Fp:k:x:X:j:R:l:j:UQq";
+
+static const struct option longopts[] = {
+	{"root",               1, NULL, 'r'},
+	{"min-io-size",        1, NULL, 'm'},
+	{"leb-size",           1, NULL, 'e'},
+	{"max-leb-cnt",        1, NULL, 'c'},
+	{"output",             1, NULL, 'o'},
+	{"devtable",           1, NULL, 'D'},
+	{"yes",                0, NULL, 'y'},
+	{"help",               0, NULL, 'h'},
+	{"verbose",            0, NULL, 'v'},
+	{"version",            0, NULL, 'V'},
+	{"debug-level",        1, NULL, 'g'},
+	{"jrn-size",           1, NULL, 'j'},
+	{"reserved",           1, NULL, 'R'},
+	{"compr",              1, NULL, 'x'},
+	{"favor-percent",      1, NULL, 'X'},
+	{"fanout",             1, NULL, 'f'},
+	{"space-fixup",        0, NULL, 'F'},
+	{"keyhash",            1, NULL, 'k'},
+	{"log-lebs",           1, NULL, 'l'},
+	{"orph-lebs",          1, NULL, 'p'},
+	{"squash-uids" ,       0, NULL, 'U'},
+	{NULL, 0, NULL, 0}
+};
+
+static const char *helptext =
+"Usage: mkfs.ubifs [OPTIONS] target\n"
+"Make a UBIFS file system image from an existing directory tree\n\n"
+"Examples:\n"
+"Build file system from directory /opt/img, writting the result in the ubifs.img file\n"
+"\tmkfs.ubifs -m 512 -e 128KiB -c 100 -r /opt/img ubifs.img\n"
+"The same, but writting directly to an UBI volume\n"
+"\tmkfs.ubifs -r /opt/img /dev/ubi0_0\n"
+"Creating an empty UBIFS filesystem on an UBI volume\n"
+"\tmkfs.ubifs /dev/ubi0_0\n\n"
+"Options:\n"
+"-r, -d, --root=DIR       build file system from directory DIR\n"
+"-m, --min-io-size=SIZE   minimum I/O unit size\n"
+"-e, --leb-size=SIZE      logical erase block size\n"
+"-c, --max-leb-cnt=COUNT  maximum logical erase block count\n"
+"-o, --output=FILE        output to FILE\n"
+"-j, --jrn-size=SIZE      journal size\n"
+"-R, --reserved=SIZE      how much space should be reserved for the super-user\n"
+"-x, --compr=TYPE         compression type - \"lzo\", \"favor_lzo\", \"zlib\" or\n"
+"                         \"none\" (default: \"lzo\")\n"
+"-X, --favor-percent      may only be used with favor LZO compression and defines\n"
+"                         how many percent better zlib should compress to make\n"
+"                         mkfs.ubifs use zlib instead of LZO (default 20%)\n"
+"-f, --fanout=NUM         fanout NUM (default: 8)\n"
+"-F, --space-fixup        file-system free space has to be fixed up on first mount\n"
+"                         (requires kernel version 3.0 or greater)\n"
+"-k, --keyhash=TYPE       key hash type - \"r5\" or \"test\" (default: \"r5\")\n"
+"-p, --orph-lebs=COUNT    count of erase blocks for orphans (default: 1)\n"
+"-D, --devtable=FILE      use device table FILE\n"
+"-U, --squash-uids        squash owners making all files owned by root\n"
+"-l, --log-lebs=COUNT     count of erase blocks for the log (used only for\n"
+"                         debugging)\n"
+"-y, --yes                assume the answer is \"yes\" for all questions\n"
+"-v, --verbose            verbose operation\n"
+"-V, --version            display version information\n"
+"-g, --debug=LEVEL        display debug information (0 - none, 1 - statistics,\n"
+"                         2 - files, 3 - more details)\n"
+"-h, --help               display this help text\n\n"
+"Note, SIZE is specified in bytes, but it may also be specified in Kilobytes,\n"
+"Megabytes, and Gigabytes if a KiB, MiB, or GiB suffix is used.\n\n"
+"If you specify \"lzo\" or \"zlib\" compressors, mkfs.ubifs will use this compressor\n"
+"for all data. The \"none\" disables any data compression. The \"favor_lzo\" is not\n"
+"really a separate compressor. It is just a method of combining \"lzo\" and \"zlib\"\n"
+"compressors. Namely, mkfs.ubifs tries to compress data with both \"lzo\" and \"zlib\"\n"
+"compressors, then it compares which compressor is better. If \"zlib\" compresses 20\n"
+"or more percent better than \"lzo\", mkfs.ubifs chooses \"lzo\", otherwise it chooses\n"
+"\"zlib\". The \"--favor-percent\" may specify arbitrary threshold instead of the\n"
+"default 20%.\n\n"
+"The -F parameter is used to set the \"fix up free space\" flag in the superblock,\n"
+"which forces UBIFS to \"fixup\" all the free space which it is going to use. This\n"
+"option is useful to work-around the problem of double free space programming: if the\n"
+"flasher program which flashes the UBI image is unable to skip NAND pages containing\n"
+"only 0xFF bytes, the effect is that some NAND pages are written to twice - first time\n"
+"when flashing the image and the second time when UBIFS is mounted and writes useful\n"
+"data there. A proper UBI-aware flasher should skip such NAND pages, though. Note, this\n"
+"flag may make the first mount very slow, because the \"free space fixup\" procedure\n"
+"takes time. This feature is supported by the Linux kernel starting from version 3.0.\n";
+
+/**
+ * make_path - make a path name from a directory and a name.
+ * @dir: directory path name
+ * @name: name
+ */
+static char *make_path(const char *dir, const char *name)
+{
+	char *s;
+
+	s = malloc(strlen(dir) + strlen(name) + 2);
+	if (!s)
+		return NULL;
+	strcpy(s, dir);
+	if (dir[strlen(dir) - 1] != '/')
+		strcat(s, "/");
+	strcat(s, name);
+	return s;
+}
+
+/**
+ * is_contained - determine if a file is beneath a directory.
+ * @file: file path name
+ * @dir: directory path name
+ *
+ * This function returns %1 if @file is accessible from the @dir directory and
+ * %0 otherwise. In case of error, returns %-1.
+ */
+static int is_contained(const char *file, const char *dir)
+{
+	char *real_file = NULL;
+	char *real_dir = NULL;
+	char *file_base, *copy;
+	int ret = -1;
+
+	/* Make a copy of the file path because 'dirname()' can modify it */
+	copy = strdup(file);
+	if (!copy)
+		return -1;
+	file_base = dirname(copy);
+
+	/* Turn the paths into the canonical form */
+	real_file = malloc(PATH_MAX);
+	if (!real_file)
+		goto out_free;
+
+	real_dir = malloc(PATH_MAX);
+	if (!real_dir)
+		goto out_free;
+
+	if (!realpath(file_base, real_file)) {
+		perror("Could not canonicalize file path");
+		goto out_free;
+	}
+	if (!realpath(dir, real_dir)) {
+		perror("Could not canonicalize directory");
+		goto out_free;
+	}
+
+	ret = !!strstr(real_file, real_dir);
+
+out_free:
+	free(copy);
+	free(real_file);
+	free(real_dir);
+	return ret;
+}
+
+/**
+ * calc_min_log_lebs - calculate the minimum number of log LEBs needed.
+ * @max_bud_bytes: journal size (buds only)
+ */
+static int calc_min_log_lebs(unsigned long long max_bud_bytes)
+{
+	int buds, log_lebs;
+	unsigned long long log_size;
+
+	buds = (max_bud_bytes + c->leb_size - 1) / c->leb_size;
+	log_size = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size);
+	log_size *= buds;
+	log_size += ALIGN(UBIFS_CS_NODE_SZ +
+			  UBIFS_REF_NODE_SZ * (c->jhead_cnt + 2),
+			  c->min_io_size);
+	log_lebs = (log_size + c->leb_size - 1) / c->leb_size;
+	log_lebs += 1;
+	return log_lebs;
+}
+
+/**
+ * add_space_overhead - add UBIFS overhead.
+ * @size: flash space which should be visible to the user
+ *
+ * UBIFS has overhead, and if we need to reserve @size bytes for the user data,
+ * we have to reserve more flash space, to compensate the overhead. This
+ * function calculates and returns the amount of physical flash space which
+ * should be reserved to provide @size bytes for the user.
+ */
+static long long add_space_overhead(long long size)
+{
+        int divisor, factor, f, max_idx_node_sz;
+
+        /*
+	 * Do the opposite to what the 'ubifs_reported_space()' kernel UBIFS
+	 * function does.
+         */
+	max_idx_node_sz =  ubifs_idx_node_sz(c, c->fanout);
+        f = c->fanout > 3 ? c->fanout >> 1 : 2;
+        divisor = UBIFS_BLOCK_SIZE;
+        factor = UBIFS_MAX_DATA_NODE_SZ;
+        factor += (max_idx_node_sz * 3) / (f - 1);
+        size *= factor;
+        return size / divisor;
+}
+
+static int validate_options(void)
+{
+	int tmp;
+
+	if (!output)
+		return err_msg("no output file or UBI volume specified");
+	if (root) {
+		tmp = is_contained(output, root);
+		if (tmp < 0)
+			return err_msg("failed to perform output file root check");
+		else if (tmp)
+			return err_msg("output file cannot be in the UBIFS root "
+			               "directory");
+	}
+	if (!is_power_of_2(c->min_io_size))
+		return err_msg("min. I/O unit size should be power of 2");
+	if (c->leb_size < c->min_io_size)
+		return err_msg("min. I/O unit cannot be larger than LEB size");
+	if (c->leb_size < UBIFS_MIN_LEB_SZ)
+		return err_msg("too small LEB size %d, minimum is %d",
+			       c->leb_size, UBIFS_MIN_LEB_SZ);
+	if (c->leb_size % c->min_io_size)
+		return err_msg("LEB should be multiple of min. I/O units");
+	if (c->leb_size % 8)
+		return err_msg("LEB size has to be multiple of 8");
+	if (c->leb_size > UBIFS_MAX_LEB_SZ)
+		return err_msg("too large LEB size %d, maximum is %d",
+				c->leb_size, UBIFS_MAX_LEB_SZ);
+	if (c->max_leb_cnt < UBIFS_MIN_LEB_CNT)
+		return err_msg("too low max. count of LEBs, minimum is %d",
+			       UBIFS_MIN_LEB_CNT);
+	if (c->fanout < UBIFS_MIN_FANOUT)
+		return err_msg("too low fanout, minimum is %d",
+			       UBIFS_MIN_FANOUT);
+	tmp = c->leb_size - UBIFS_IDX_NODE_SZ;
+	tmp /= UBIFS_BRANCH_SZ + UBIFS_MAX_KEY_LEN;
+	if (c->fanout > tmp)
+		return err_msg("too high fanout, maximum is %d", tmp);
+	if (c->log_lebs < UBIFS_MIN_LOG_LEBS)
+		return err_msg("too few log LEBs, minimum is %d",
+			       UBIFS_MIN_LOG_LEBS);
+	if (c->log_lebs >= c->max_leb_cnt - UBIFS_MIN_LEB_CNT)
+		return err_msg("too many log LEBs, maximum is %d",
+			       c->max_leb_cnt - UBIFS_MIN_LEB_CNT);
+	if (c->orph_lebs < UBIFS_MIN_ORPH_LEBS)
+		return err_msg("too few orphan LEBs, minimum is %d",
+			       UBIFS_MIN_ORPH_LEBS);
+	if (c->orph_lebs >= c->max_leb_cnt - UBIFS_MIN_LEB_CNT)
+		return err_msg("too many orphan LEBs, maximum is %d",
+			       c->max_leb_cnt - UBIFS_MIN_LEB_CNT);
+	tmp = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs;
+	tmp += c->orph_lebs + 4;
+	if (tmp > c->max_leb_cnt)
+		return err_msg("too low max. count of LEBs, expected at "
+			       "least %d", tmp);
+	tmp = calc_min_log_lebs(c->max_bud_bytes);
+	if (c->log_lebs < calc_min_log_lebs(c->max_bud_bytes))
+		return err_msg("too few log LEBs, expected at least %d", tmp);
+	if (c->rp_size >= ((long long)c->leb_size * c->max_leb_cnt) / 2)
+		return err_msg("too much reserved space %lld", c->rp_size);
+	return 0;
+}
+
+/**
+ * get_multiplier - convert size specifier to an integer multiplier.
+ * @str: the size specifier string
+ *
+ * This function parses the @str size specifier, which may be one of
+ * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
+ * size multiplier in case of success and %-1 in case of failure.
+ */
+static int get_multiplier(const char *str)
+{
+	if (!str)
+		return 1;
+
+	/* Remove spaces before the specifier */
+	while (*str == ' ' || *str == '\t')
+		str += 1;
+
+	if (!strcmp(str, "KiB"))
+		return 1024;
+	if (!strcmp(str, "MiB"))
+		return 1024 * 1024;
+	if (!strcmp(str, "GiB"))
+		return 1024 * 1024 * 1024;
+
+	return -1;
+}
+
+/**
+ * get_bytes - convert a string containing amount of bytes into an
+ *             integer.
+ * @str: string to convert
+ *
+ * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB' size
+ * specifiers. Returns positive amount of bytes in case of success and %-1 in
+ * case of failure.
+ */
+static long long get_bytes(const char *str)
+{
+	char *endp;
+	long long bytes = strtoull(str, &endp, 0);
+
+	if (endp == str || bytes < 0)
+		return err_msg("incorrect amount of bytes: \"%s\"", str);
+
+	if (*endp != '\0') {
+		int mult = get_multiplier(endp);
+
+		if (mult == -1)
+			return err_msg("bad size specifier: \"%s\" - "
+				       "should be 'KiB', 'MiB' or 'GiB'", endp);
+		bytes *= mult;
+	}
+
+	return bytes;
+}
+/**
+ * open_ubi - open the UBI volume.
+ * @node: name of the UBI volume character device to fetch information about
+ *
+ * Returns %0 in case of success and %-1 in case of failure
+ */
+static int open_ubi(const char *node)
+{
+	struct stat st;
+
+	if (stat(node, &st) || !S_ISCHR(st.st_mode))
+		return -1;
+
+	ubi = libubi_open();
+	if (!ubi)
+		return -1;
+	if (ubi_get_vol_info(ubi, node, &c->vi))
+		return -1;
+	if (ubi_get_dev_info1(ubi, c->vi.dev_num, &c->di))
+		return -1;
+	return 0;
+}
+
+static int get_options(int argc, char**argv)
+{
+	int opt, i;
+	const char *tbl_file = NULL;
+	struct stat st;
+	char *endp;
+
+	c->fanout = 8;
+	c->orph_lebs = 1;
+	c->key_hash = key_r5_hash;
+	c->key_len = UBIFS_SK_LEN;
+	c->default_compr = UBIFS_COMPR_LZO;
+	c->favor_percent = 20;
+	c->lsave_cnt = 256;
+	c->leb_size = -1;
+	c->min_io_size = -1;
+	c->max_leb_cnt = -1;
+	c->max_bud_bytes = -1;
+	c->log_lebs = -1;
+
+	while (1) {
+		opt = getopt_long(argc, argv, optstring, longopts, &i);
+		if (opt == -1)
+			break;
+		switch (opt) {
+		case 'r':
+		case 'd':
+			root_len = strlen(optarg);
+			root = malloc(root_len + 2);
+			if (!root)
+				return err_msg("cannot allocate memory");
+
+			/*
+			 * The further code expects '/' at the end of the root
+			 * UBIFS directory on the host.
+			 */
+			memcpy(root, optarg, root_len);
+			if (root[root_len - 1] != '/')
+				root[root_len++] = '/';
+			root[root_len] = 0;
+
+			/* Make sure the root directory exists */
+			if (stat(root, &st))
+				return sys_err_msg("bad root directory '%s'",
+						   root);
+			break;
+		case 'm':
+			c->min_io_size = get_bytes(optarg);
+			if (c->min_io_size <= 0)
+				return err_msg("bad min. I/O size");
+			break;
+		case 'e':
+			c->leb_size = get_bytes(optarg);
+			if (c->leb_size <= 0)
+				return err_msg("bad LEB size");
+			break;
+		case 'c':
+			c->max_leb_cnt = get_bytes(optarg);
+			if (c->max_leb_cnt <= 0)
+				return err_msg("bad maximum LEB count");
+			break;
+		case 'o':
+			output = xstrdup(optarg);
+			break;
+		case 'D':
+			tbl_file = optarg;
+			if (stat(tbl_file, &st) < 0)
+				return sys_err_msg("bad device table file '%s'",
+						   tbl_file);
+			break;
+		case 'y':
+			yes = 1;
+			break;
+		case 'h':
+		case '?':
+			printf("%s", helptext);
+			exit(0);
+		case 'v':
+			verbose = 1;
+			break;
+		case 'V':
+			common_print_version();
+			exit(0);
+		case 'g':
+			debug_level = strtol(optarg, &endp, 0);
+			if (*endp != '\0' || endp == optarg ||
+			    debug_level < 0 || debug_level > 3)
+				return err_msg("bad debugging level '%s'",
+					       optarg);
+			break;
+		case 'f':
+			c->fanout = strtol(optarg, &endp, 0);
+			if (*endp != '\0' || endp == optarg || c->fanout <= 0)
+				return err_msg("bad fanout %s", optarg);
+			break;
+		case 'F':
+			c->space_fixup = 1;
+			break;
+		case 'l':
+			c->log_lebs = strtol(optarg, &endp, 0);
+			if (*endp != '\0' || endp == optarg || c->log_lebs <= 0)
+				return err_msg("bad count of log LEBs '%s'",
+					       optarg);
+			break;
+		case 'p':
+			c->orph_lebs = strtol(optarg, &endp, 0);
+			if (*endp != '\0' || endp == optarg ||
+			    c->orph_lebs <= 0)
+				return err_msg("bad orphan LEB count '%s'",
+					       optarg);
+			break;
+		case 'k':
+			if (strcmp(optarg, "r5") == 0) {
+				c->key_hash = key_r5_hash;
+				c->key_hash_type = UBIFS_KEY_HASH_R5;
+			} else if (strcmp(optarg, "test") == 0) {
+				c->key_hash = key_test_hash;
+				c->key_hash_type = UBIFS_KEY_HASH_TEST;
+			} else
+				return err_msg("bad key hash");
+			break;
+		case 'x':
+			if (strcmp(optarg, "favor_lzo") == 0)
+				c->favor_lzo = 1;
+			else if (strcmp(optarg, "zlib") == 0)
+				c->default_compr = UBIFS_COMPR_ZLIB;
+			else if (strcmp(optarg, "none") == 0)
+				c->default_compr = UBIFS_COMPR_NONE;
+			else if (strcmp(optarg, "lzo") != 0)
+				return err_msg("bad compressor name");
+			break;
+		case 'X':
+			c->favor_percent = strtol(optarg, &endp, 0);
+			if (*endp != '\0' || endp == optarg ||
+			    c->favor_percent <= 0 || c->favor_percent >= 100)
+				return err_msg("bad favor LZO percent '%s'",
+					       optarg);
+			break;
+		case 'j':
+			c->max_bud_bytes = get_bytes(optarg);
+			if (c->max_bud_bytes <= 0)
+				return err_msg("bad maximum amount of buds");
+			break;
+		case 'R':
+			c->rp_size = get_bytes(optarg);
+			if (c->rp_size < 0)
+				return err_msg("bad reserved bytes count");
+			break;
+		case 'U':
+			squash_owner = 1;
+			break;
+		}
+	}
+
+	if (optind != argc && !output)
+		output = xstrdup(argv[optind]);
+
+	if (!output)
+		return err_msg("not output device or file specified");
+
+	out_ubi = !open_ubi(output);
+
+	if (out_ubi) {
+		c->min_io_size = c->di.min_io_size;
+		c->leb_size = c->vi.leb_size;
+		if (c->max_leb_cnt == -1)
+			c->max_leb_cnt = c->vi.rsvd_lebs;
+	}
+
+	if (c->min_io_size == -1)
+		return err_msg("min. I/O unit was not specified "
+			       "(use -h for help)");
+
+	if (c->leb_size == -1)
+		return err_msg("LEB size was not specified (use -h for help)");
+
+	if (c->max_leb_cnt == -1)
+		return err_msg("Maximum count of LEBs was not specified "
+			       "(use -h for help)");
+
+	if (c->max_bud_bytes == -1) {
+		int lebs;
+
+		lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+		lebs -= c->orph_lebs;
+		if (c->log_lebs != -1)
+			lebs -= c->log_lebs;
+		else
+			lebs -= UBIFS_MIN_LOG_LEBS;
+		/*
+		 * We do not know lprops geometry so far, so assume minimum
+		 * count of lprops LEBs.
+		 */
+		lebs -= UBIFS_MIN_LPT_LEBS;
+		/* Make the journal about 12.5% of main area lebs */
+		c->max_bud_bytes = (lebs / 8) * (long long)c->leb_size;
+		/* Make the max journal size 8MiB */
+		if (c->max_bud_bytes > 8 * 1024 * 1024)
+			c->max_bud_bytes = 8 * 1024 * 1024;
+		if (c->max_bud_bytes < 4 * c->leb_size)
+			c->max_bud_bytes = 4 * c->leb_size;
+	}
+
+	if (c->log_lebs == -1) {
+		c->log_lebs = calc_min_log_lebs(c->max_bud_bytes);
+		c->log_lebs += 2;
+	}
+
+	if (c->min_io_size < 8)
+		c->min_io_size = 8;
+	c->rp_size = add_space_overhead(c->rp_size);
+
+	if (verbose) {
+		printf("mkfs.ubifs\n");
+		printf("\troot:         %s\n", root);
+		printf("\tmin_io_size:  %d\n", c->min_io_size);
+		printf("\tleb_size:     %d\n", c->leb_size);
+		printf("\tmax_leb_cnt:  %d\n", c->max_leb_cnt);
+		printf("\toutput:       %s\n", output);
+		printf("\tjrn_size:     %llu\n", c->max_bud_bytes);
+		printf("\treserved:     %llu\n", c->rp_size);
+		switch (c->default_compr) {
+		case UBIFS_COMPR_LZO:
+			printf("\tcompr:        lzo\n");
+			break;
+		case UBIFS_COMPR_ZLIB:
+			printf("\tcompr:        zlib\n");
+			break;
+		case UBIFS_COMPR_NONE:
+			printf("\tcompr:        none\n");
+			break;
+		}
+		printf("\tkeyhash:      %s\n", (c->key_hash == key_r5_hash) ?
+						"r5" : "test");
+		printf("\tfanout:       %d\n", c->fanout);
+		printf("\torph_lebs:    %d\n", c->orph_lebs);
+		printf("\tspace_fixup:  %d\n", c->space_fixup);
+	}
+
+	if (validate_options())
+		return -1;
+
+	if (tbl_file && parse_devtable(tbl_file))
+		return err_msg("cannot parse device table file '%s'", tbl_file);
+
+	return 0;
+}
+
+/**
+ * prepare_node - fill in the common header.
+ * @node: node
+ * @len: node length
+ */
+static void prepare_node(void *node, int len)
+{
+	uint32_t crc;
+	struct ubifs_ch *ch = node;
+
+	ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
+	ch->len = cpu_to_le32(len);
+	ch->group_type = UBIFS_NO_NODE_GROUP;
+	ch->sqnum = cpu_to_le64(++c->max_sqnum);
+	ch->padding[0] = ch->padding[1] = 0;
+	crc = mtd_crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
+	ch->crc = cpu_to_le32(crc);
+}
+
+/**
+ * write_leb - copy the image of a LEB to the output target.
+ * @lnum: LEB number
+ * @len: length of data in the buffer
+ * @buf: buffer (must be at least c->leb_size bytes)
+ */
+int write_leb(int lnum, int len, void *buf)
+{
+	off_t pos = (off_t)lnum * c->leb_size;
+
+	dbg_msg(3, "LEB %d len %d", lnum, len);
+	memset(buf + len, 0xff, c->leb_size - len);
+	if (out_ubi)
+		if (ubi_leb_change_start(ubi, out_fd, lnum, c->leb_size))
+			return sys_err_msg("ubi_leb_change_start failed");
+
+	if (lseek(out_fd, pos, SEEK_SET) != pos)
+		return sys_err_msg("lseek failed seeking %"PRIdoff_t, pos);
+
+	if (write(out_fd, buf, c->leb_size) != c->leb_size)
+		return sys_err_msg("write failed writing %d bytes at pos %"PRIdoff_t,
+				   c->leb_size, pos);
+
+	return 0;
+}
+
+/**
+ * write_empty_leb - copy the image of an empty LEB to the output target.
+ * @lnum: LEB number
+ */
+static int write_empty_leb(int lnum)
+{
+	return write_leb(lnum, 0, leb_buf);
+}
+
+/**
+ * do_pad - pad a buffer to the minimum I/O size.
+ * @buf: buffer
+ * @len: buffer length
+ */
+static int do_pad(void *buf, int len)
+{
+	int pad_len, alen = ALIGN(len, 8), wlen = ALIGN(alen, c->min_io_size);
+	uint32_t crc;
+
+	memset(buf + len, 0xff, alen - len);
+	pad_len = wlen - alen;
+	dbg_msg(3, "len %d pad_len %d", len, pad_len);
+	buf += alen;
+	if (pad_len >= (int)UBIFS_PAD_NODE_SZ) {
+		struct ubifs_ch *ch = buf;
+		struct ubifs_pad_node *pad_node = buf;
+
+		ch->magic      = cpu_to_le32(UBIFS_NODE_MAGIC);
+		ch->node_type  = UBIFS_PAD_NODE;
+		ch->group_type = UBIFS_NO_NODE_GROUP;
+		ch->padding[0] = ch->padding[1] = 0;
+		ch->sqnum      = cpu_to_le64(0);
+		ch->len        = cpu_to_le32(UBIFS_PAD_NODE_SZ);
+
+		pad_len -= UBIFS_PAD_NODE_SZ;
+		pad_node->pad_len = cpu_to_le32(pad_len);
+
+		crc = mtd_crc32(UBIFS_CRC32_INIT, buf + 8,
+				  UBIFS_PAD_NODE_SZ - 8);
+		ch->crc = cpu_to_le32(crc);
+
+		memset(buf + UBIFS_PAD_NODE_SZ, 0, pad_len);
+	} else if (pad_len > 0)
+		memset(buf, UBIFS_PADDING_BYTE, pad_len);
+
+	return wlen;
+}
+
+/**
+ * write_node - write a node to a LEB.
+ * @node: node
+ * @len: node length
+ * @lnum: LEB number
+ */
+static int write_node(void *node, int len, int lnum)
+{
+	prepare_node(node, len);
+
+	memcpy(leb_buf, node, len);
+
+	len = do_pad(leb_buf, len);
+
+	return write_leb(lnum, len, leb_buf);
+}
+
+/**
+ * calc_dark - calculate LEB dark space size.
+ * @c: the UBIFS file-system description object
+ * @spc: amount of free and dirty space in the LEB
+ *
+ * This function calculates amount of dark space in an LEB which has @spc bytes
+ * of free and dirty space. Returns the calculations result.
+ *
+ * Dark space is the space which is not always usable - it depends on which
+ * nodes are written in which order. E.g., if an LEB has only 512 free bytes,
+ * it is dark space, because it cannot fit a large data node. So UBIFS cannot
+ * count on this LEB and treat these 512 bytes as usable because it is not true
+ * if, for example, only big chunks of uncompressible data will be written to
+ * the FS.
+ */
+static int calc_dark(struct ubifs_info *c, int spc)
+{
+	if (spc < c->dark_wm)
+		return spc;
+
+	/*
+	 * If we have slightly more space then the dark space watermark, we can
+	 * anyway safely assume it we'll be able to write a node of the
+	 * smallest size there.
+	 */
+	if (spc - c->dark_wm < (int)MIN_WRITE_SZ)
+		return spc - MIN_WRITE_SZ;
+
+	return c->dark_wm;
+}
+
+/**
+ * set_lprops - set the LEB property values for a LEB.
+ * @lnum: LEB number
+ * @offs: end offset of data in the LEB
+ * @flags: LEB property flags
+ */
+static void set_lprops(int lnum, int offs, int flags)
+{
+	int i = lnum - c->main_first, free, dirty;
+	int a = max_t(int, c->min_io_size, 8);
+
+	free = c->leb_size - ALIGN(offs, a);
+	dirty = c->leb_size - free - ALIGN(offs, 8);
+	dbg_msg(3, "LEB %d free %d dirty %d flags %d", lnum, free, dirty,
+		flags);
+	if (i < c->main_lebs) {
+		c->lpt[i].free = free;
+		c->lpt[i].dirty = dirty;
+		c->lpt[i].flags = flags;
+	}
+	c->lst.total_free += free;
+	c->lst.total_dirty += dirty;
+	if (flags & LPROPS_INDEX)
+		c->lst.idx_lebs += 1;
+	else {
+		int spc;
+
+		spc = free + dirty;
+		if (spc < c->dead_wm)
+			c->lst.total_dead += spc;
+		else
+			c->lst.total_dark += calc_dark(c, spc);
+		c->lst.total_used += c->leb_size - spc;
+	}
+}
+
+/**
+ * add_to_index - add a node key and position to the index.
+ * @key: node key
+ * @lnum: node LEB number
+ * @offs: node offset
+ * @len: node length
+ */
+static int add_to_index(union ubifs_key *key, char *name, int lnum, int offs,
+			int len)
+{
+	struct idx_entry *e;
+
+	dbg_msg(3, "LEB %d offs %d len %d", lnum, offs, len);
+	e = malloc(sizeof(struct idx_entry));
+	if (!e)
+		return err_msg("out of memory");
+	e->next = NULL;
+	e->prev = idx_list_last;
+	e->key = *key;
+	e->name = name;
+	e->lnum = lnum;
+	e->offs = offs;
+	e->len = len;
+	if (!idx_list_first)
+		idx_list_first = e;
+	if (idx_list_last)
+		idx_list_last->next = e;
+	idx_list_last = e;
+	idx_cnt += 1;
+	return 0;
+}
+
+/**
+ * flush_nodes - write the current head and move the head to the next LEB.
+ */
+static int flush_nodes(void)
+{
+	int len, err;
+
+	if (!head_offs)
+		return 0;
+	len = do_pad(leb_buf, head_offs);
+	err = write_leb(head_lnum, len, leb_buf);
+	if (err)
+		return err;
+	set_lprops(head_lnum, head_offs, head_flags);
+	head_lnum += 1;
+	head_offs = 0;
+	return 0;
+}
+
+/**
+ * reserve_space - reserve space for a node on the head.
+ * @len: node length
+ * @lnum: LEB number is returned here
+ * @offs: offset is returned here
+ */
+static int reserve_space(int len, int *lnum, int *offs)
+{
+	int err;
+
+	if (len > c->leb_size - head_offs) {
+		err = flush_nodes();
+		if (err)
+			return err;
+	}
+	*lnum = head_lnum;
+	*offs = head_offs;
+	head_offs += ALIGN(len, 8);
+	return 0;
+}
+
+/**
+ * add_node - write a node to the head.
+ * @key: node key
+ * @node: node
+ * @len: node length
+ */
+static int add_node(union ubifs_key *key, char *name, void *node, int len)
+{
+	int err, lnum, offs;
+
+	prepare_node(node, len);
+
+	err = reserve_space(len, &lnum, &offs);
+	if (err)
+		return err;
+
+	memcpy(leb_buf + offs, node, len);
+	memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len);
+
+	add_to_index(key, name, lnum, offs, len);
+
+	return 0;
+}
+
+/**
+ * add_inode_with_data - write an inode.
+ * @st: stat information of source inode
+ * @inum: target inode number
+ * @data: inode data (for special inodes e.g. symlink path etc)
+ * @data_len: inode data length
+ * @flags: source inode flags
+ */
+static int add_inode_with_data(struct stat *st, ino_t inum, void *data,
+			       unsigned int data_len, int flags)
+{
+	struct ubifs_ino_node *ino = node_buf;
+	union ubifs_key key;
+	int len, use_flags = 0;
+
+	if (c->default_compr != UBIFS_COMPR_NONE)
+		use_flags |= UBIFS_COMPR_FL;
+	if (flags & FS_COMPR_FL)
+		use_flags |= UBIFS_COMPR_FL;
+	if (flags & FS_SYNC_FL)
+		use_flags |= UBIFS_SYNC_FL;
+	if (flags & FS_IMMUTABLE_FL)
+		use_flags |= UBIFS_IMMUTABLE_FL;
+	if (flags & FS_APPEND_FL)
+		use_flags |= UBIFS_APPEND_FL;
+	if (flags & FS_DIRSYNC_FL && S_ISDIR(st->st_mode))
+		use_flags |= UBIFS_DIRSYNC_FL;
+
+	memset(ino, 0, UBIFS_INO_NODE_SZ);
+
+	ino_key_init(&key, inum);
+	ino->ch.node_type = UBIFS_INO_NODE;
+	key_write(&key, &ino->key);
+	ino->creat_sqnum = cpu_to_le64(creat_sqnum);
+	ino->size       = cpu_to_le64(st->st_size);
+	ino->nlink      = cpu_to_le32(st->st_nlink);
+	/*
+	 * The time fields are updated assuming the default time granularity
+	 * of 1 second. To support finer granularities, utime() would be needed.
+	 */
+	ino->atime_sec  = cpu_to_le64(st->st_atime);
+	ino->ctime_sec  = cpu_to_le64(st->st_ctime);
+	ino->mtime_sec  = cpu_to_le64(st->st_mtime);
+	ino->atime_nsec = 0;
+	ino->ctime_nsec = 0;
+	ino->mtime_nsec = 0;
+	ino->uid        = cpu_to_le32(st->st_uid);
+	ino->gid        = cpu_to_le32(st->st_gid);
+	ino->mode       = cpu_to_le32(st->st_mode);
+	ino->flags      = cpu_to_le32(use_flags);
+	ino->data_len   = cpu_to_le32(data_len);
+	ino->compr_type = cpu_to_le16(c->default_compr);
+	if (data_len)
+		memcpy(&ino->data, data, data_len);
+
+	len = UBIFS_INO_NODE_SZ + data_len;
+
+	return add_node(&key, NULL, ino, len);
+}
+
+/**
+ * add_inode - write an inode.
+ * @st: stat information of source inode
+ * @inum: target inode number
+ * @flags: source inode flags
+ */
+static int add_inode(struct stat *st, ino_t inum, int flags)
+{
+	return add_inode_with_data(st, inum, NULL, 0, flags);
+}
+
+/**
+ * add_dir_inode - write an inode for a directory.
+ * @dir: source directory
+ * @inum: target inode number
+ * @size: target directory size
+ * @nlink: target directory link count
+ * @st: struct stat object describing attributes (except size and nlink) of the
+ *      target inode to create
+ *
+ * Note, this function may be called with %NULL @dir, when the directory which
+ * is being created does not exist at the host file system, but is defined by
+ * the device table.
+ */
+static int add_dir_inode(DIR *dir, ino_t inum, loff_t size, unsigned int nlink,
+			 struct stat *st)
+{
+	int fd, flags = 0;
+
+	st->st_size = size;
+	st->st_nlink = nlink;
+
+	if (dir) {
+		fd = dirfd(dir);
+		if (fd == -1)
+			return sys_err_msg("dirfd failed");
+		if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1)
+			flags = 0;
+	}
+
+	return add_inode(st, inum, flags);
+}
+
+/**
+ * add_dev_inode - write an inode for a character or block device.
+ * @st: stat information of source inode
+ * @inum: target inode number
+ * @flags: source inode flags
+ */
+static int add_dev_inode(struct stat *st, ino_t inum, int flags)
+{
+	union ubifs_dev_desc dev;
+
+	dev.huge = cpu_to_le64(makedev(major(st->st_rdev), minor(st->st_rdev)));
+	return add_inode_with_data(st, inum, &dev, 8, flags);
+}
+
+/**
+ * add_symlink_inode - write an inode for a symbolic link.
+ * @path_name: path name of symbolic link inode itself (not the link target)
+ * @st: stat information of source inode
+ * @inum: target inode number
+ * @flags: source inode flags
+ */
+static int add_symlink_inode(const char *path_name, struct stat *st, ino_t inum,
+			     int flags)
+{
+	char buf[UBIFS_MAX_INO_DATA + 2];
+	ssize_t len;
+
+	/* Take the symlink as is */
+	len = readlink(path_name, buf, UBIFS_MAX_INO_DATA + 1);
+	if (len <= 0)
+		return sys_err_msg("readlink failed for %s", path_name);
+	if (len > UBIFS_MAX_INO_DATA)
+		return err_msg("symlink too long for %s", path_name);
+
+	return add_inode_with_data(st, inum, buf, len, flags);
+}
+
+/**
+ * add_dent_node - write a directory entry node.
+ * @dir_inum: target inode number of directory
+ * @name: directory entry name
+ * @inum: target inode number of the directory entry
+ * @type: type of the target inode
+ */
+static int add_dent_node(ino_t dir_inum, const char *name, ino_t inum,
+			 unsigned char type)
+{
+	struct ubifs_dent_node *dent = node_buf;
+	union ubifs_key key;
+	struct qstr dname;
+	char *kname;
+	int len;
+
+	dbg_msg(3, "%s ino %lu type %u dir ino %lu", name, (unsigned long)inum,
+		(unsigned int)type, (unsigned long)dir_inum);
+	memset(dent, 0, UBIFS_DENT_NODE_SZ);
+
+	dname.name = (void *)name;
+	dname.len = strlen(name);
+
+	dent->ch.node_type = UBIFS_DENT_NODE;
+
+	dent_key_init(c, &key, dir_inum, &dname);
+	key_write(&key, dent->key);
+	dent->inum = cpu_to_le64(inum);
+	dent->padding1 = 0;
+	dent->type = type;
+	dent->nlen = cpu_to_le16(dname.len);
+	memcpy(dent->name, dname.name, dname.len);
+	dent->name[dname.len] = '\0';
+
+	len = UBIFS_DENT_NODE_SZ + dname.len + 1;
+
+	kname = strdup(name);
+	if (!kname)
+		return err_msg("cannot allocate memory");
+
+	return add_node(&key, kname, dent, len);
+}
+
+/**
+ * lookup_inum_mapping - add an inode mapping for link counting.
+ * @dev: source device on which source inode number resides
+ * @inum: source inode number
+ */
+static struct inum_mapping *lookup_inum_mapping(dev_t dev, ino_t inum)
+{
+	struct inum_mapping *im;
+	unsigned int k;
+
+	k = inum % HASH_TABLE_SIZE;
+	im = hash_table[k];
+	while (im) {
+		if (im->dev == dev && im->inum == inum)
+			return im;
+		im = im->next;
+	}
+	im = malloc(sizeof(struct inum_mapping));
+	if (!im)
+		return NULL;
+	im->next = hash_table[k];
+	im->prev = NULL;
+	im->dev = dev;
+	im->inum = inum;
+	im->use_inum = 0;
+	im->use_nlink = 0;
+	if (hash_table[k])
+		hash_table[k]->prev = im;
+	hash_table[k] = im;
+	return im;
+}
+
+/**
+ * all_zero - does a buffer contain only zero bytes.
+ * @buf: buffer
+ * @len: buffer length
+ */
+static int all_zero(void *buf, int len)
+{
+	unsigned char *p = buf;
+
+	while (len--)
+		if (*p++ != 0)
+			return 0;
+	return 1;
+}
+
+/**
+ * add_file - write the data of a file and its inode to the output file.
+ * @path_name: source path name
+ * @st: source inode stat information
+ * @inum: target inode number
+ * @flags: source inode flags
+ */
+static int add_file(const char *path_name, struct stat *st, ino_t inum,
+		    int flags)
+{
+	struct ubifs_data_node *dn = node_buf;
+	void *buf = block_buf;
+	loff_t file_size = 0;
+	ssize_t ret, bytes_read;
+	union ubifs_key key;
+	int fd, dn_len, err, compr_type, use_compr;
+	unsigned int block_no = 0;
+	size_t out_len;
+
+	fd = open(path_name, O_RDONLY | O_LARGEFILE);
+	if (fd == -1)
+		return sys_err_msg("failed to open file '%s'", path_name);
+	do {
+		/* Read next block */
+		bytes_read = 0;
+		do {
+			ret = read(fd, buf + bytes_read,
+				   UBIFS_BLOCK_SIZE - bytes_read);
+			if (ret == -1) {
+				sys_err_msg("failed to read file '%s'",
+					    path_name);
+				close(fd);
+				return 1;
+			}
+			bytes_read += ret;
+		} while (ret != 0 && bytes_read != UBIFS_BLOCK_SIZE);
+		if (bytes_read == 0)
+			break;
+		file_size += bytes_read;
+		/* Skip holes */
+		if (all_zero(buf, bytes_read)) {
+			block_no += 1;
+			continue;
+		}
+		/* Make data node */
+		memset(dn, 0, UBIFS_DATA_NODE_SZ);
+		data_key_init(&key, inum, block_no++);
+		dn->ch.node_type = UBIFS_DATA_NODE;
+		key_write(&key, &dn->key);
+		dn->size = cpu_to_le32(bytes_read);
+		out_len = NODE_BUFFER_SIZE - UBIFS_DATA_NODE_SZ;
+		if (c->default_compr == UBIFS_COMPR_NONE &&
+		    (flags & FS_COMPR_FL))
+			use_compr = UBIFS_COMPR_LZO;
+		else
+			use_compr = c->default_compr;
+		compr_type = compress_data(buf, bytes_read, &dn->data,
+					   &out_len, use_compr);
+		dn->compr_type = cpu_to_le16(compr_type);
+		dn_len = UBIFS_DATA_NODE_SZ + out_len;
+		/* Add data node to file system */
+		err = add_node(&key, NULL, dn, dn_len);
+		if (err) {
+			close(fd);
+			return err;
+		}
+	} while (ret != 0);
+	if (close(fd) == -1)
+		return sys_err_msg("failed to close file '%s'", path_name);
+	if (file_size != st->st_size)
+		return err_msg("file size changed during writing file '%s'",
+			       path_name);
+	return add_inode(st, inum, flags);
+}
+
+/**
+ * add_non_dir - write a non-directory to the output file.
+ * @path_name: source path name
+ * @inum: target inode number is passed and returned here (due to link counting)
+ * @nlink: number of links if known otherwise zero
+ * @type: UBIFS inode type is returned here
+ * @st: struct stat object containing inode attributes which should be use when
+ *      creating the UBIFS inode
+ */
+static int add_non_dir(const char *path_name, ino_t *inum, unsigned int nlink,
+		       unsigned char *type, struct stat *st)
+{
+	int fd, flags = 0;
+
+	dbg_msg(2, "%s", path_name);
+
+	if (S_ISREG(st->st_mode)) {
+		fd = open(path_name, O_RDONLY);
+		if (fd == -1)
+			return sys_err_msg("failed to open file '%s'",
+					   path_name);
+		if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1)
+			flags = 0;
+		if (close(fd) == -1)
+			return sys_err_msg("failed to close file '%s'",
+					   path_name);
+		*type = UBIFS_ITYPE_REG;
+	} else if (S_ISCHR(st->st_mode))
+		*type = UBIFS_ITYPE_CHR;
+	else if (S_ISBLK(st->st_mode))
+		*type = UBIFS_ITYPE_BLK;
+	else if (S_ISLNK(st->st_mode))
+		*type = UBIFS_ITYPE_LNK;
+	else if (S_ISSOCK(st->st_mode))
+		*type = UBIFS_ITYPE_SOCK;
+	else if (S_ISFIFO(st->st_mode))
+		*type = UBIFS_ITYPE_FIFO;
+	else
+		return err_msg("file '%s' has unknown inode type", path_name);
+
+	if (nlink)
+		st->st_nlink = nlink;
+	else if (st->st_nlink > 1) {
+		/*
+		 * If the number of links is greater than 1, then add this file
+		 * later when we know the number of links that we actually have.
+		 * For now, we just put the inode mapping in the hash table.
+		 */
+		struct inum_mapping *im;
+
+		im = lookup_inum_mapping(st->st_dev, st->st_ino);
+		if (!im)
+			return err_msg("out of memory");
+		if (im->use_nlink == 0) {
+			/* New entry */
+			im->use_inum = *inum;
+			im->use_nlink = 1;
+			im->path_name = malloc(strlen(path_name) + 1);
+			if (!im->path_name)
+				return err_msg("out of memory");
+			strcpy(im->path_name, path_name);
+		} else {
+			/* Existing entry */
+			*inum = im->use_inum;
+			im->use_nlink += 1;
+			/* Return unused inode number */
+			c->highest_inum -= 1;
+		}
+
+		memcpy(&im->st, st, sizeof(struct stat));
+		return 0;
+	} else
+		st->st_nlink = 1;
+
+	creat_sqnum = ++c->max_sqnum;
+
+	if (S_ISREG(st->st_mode))
+		return add_file(path_name, st, *inum, flags);
+	if (S_ISCHR(st->st_mode))
+		return add_dev_inode(st, *inum, flags);
+	if (S_ISBLK(st->st_mode))
+		return add_dev_inode(st, *inum, flags);
+	if (S_ISLNK(st->st_mode))
+		return add_symlink_inode(path_name, st, *inum, flags);
+	if (S_ISSOCK(st->st_mode))
+		return add_inode(st, *inum, flags);
+	if (S_ISFIFO(st->st_mode))
+		return add_inode(st, *inum, flags);
+
+	return err_msg("file '%s' has unknown inode type", path_name);
+}
+
+/**
+ * add_directory - write a directory tree to the output file.
+ * @dir_name: directory path name
+ * @dir_inum: UBIFS inode number of directory
+ * @st: directory inode statistics
+ * @non_existing: non-zero if this function is called for a directory which
+ *                does not exist on the host file-system and it is being
+ *                created because it is defined in the device table file.
+ */
+static int add_directory(const char *dir_name, ino_t dir_inum, struct stat *st,
+			 int non_existing)
+{
+	struct dirent *entry;
+	DIR *dir = NULL;
+	int err = 0;
+	loff_t size = UBIFS_INO_NODE_SZ;
+	char *name = NULL;
+	unsigned int nlink = 2;
+	struct path_htbl_element *ph_elt;
+	struct name_htbl_element *nh_elt = NULL;
+	struct hashtable_itr *itr;
+	ino_t inum;
+	unsigned char type;
+	unsigned long long dir_creat_sqnum = ++c->max_sqnum;
+
+	dbg_msg(2, "%s", dir_name);
+	if (!non_existing) {
+		dir = opendir(dir_name);
+		if (dir == NULL)
+			return sys_err_msg("cannot open directory '%s'",
+					   dir_name);
+	}
+
+	/*
+	 * Check whether this directory contains files which should be
+	 * added/changed because they were specified in the device table.
+	 * @ph_elt will be non-zero if yes.
+	 */
+	ph_elt = devtbl_find_path(dir_name + root_len - 1);
+
+	/*
+	 * Before adding the directory itself, we have to iterate over all the
+	 * entries the device table adds to this directory and create them.
+	 */
+	for (; !non_existing;) {
+		struct stat dent_st;
+
+		errno = 0;
+		entry = readdir(dir);
+		if (!entry) {
+			if (errno == 0)
+				break;
+			sys_err_msg("error reading directory '%s'", dir_name);
+			err = -1;
+			break;
+		}
+
+		if (strcmp(".", entry->d_name) == 0)
+			continue;
+		if (strcmp("..", entry->d_name) == 0)
+			continue;
+
+		if (ph_elt)
+			/*
+			 * This directory was referred to at the device table
+			 * file. Check if this directory entry is referred at
+			 * too.
+			 */
+			nh_elt = devtbl_find_name(ph_elt, entry->d_name);
+
+		/*
+		 * We are going to create the file corresponding to this
+		 * directory entry (@entry->d_name). We use 'struct stat'
+		 * object to pass information about file attributes (actually
+		 * only about UID, GID, mode, major, and minor). Get attributes
+		 * for this file from the UBIFS rootfs on the host.
+		 */
+		free(name);
+		name = make_path(dir_name, entry->d_name);
+		if (lstat(name, &dent_st) == -1) {
+			sys_err_msg("lstat failed for file '%s'", name);
+			goto out_free;
+		}
+
+		if (squash_owner)
+			/*
+			 * Squash UID/GID. But the device table may override
+			 * this.
+			 */
+			dent_st.st_uid = dent_st.st_gid = 0;
+
+		/*
+		 * And if the device table describes the same file, override
+		 * the attributes. However, this is not allowed for device node
+		 * files.
+		 */
+		if (nh_elt && override_attributes(&dent_st, ph_elt, nh_elt))
+			goto out_free;
+
+		inum = ++c->highest_inum;
+
+		if (S_ISDIR(dent_st.st_mode)) {
+			err = add_directory(name, inum, &dent_st, 0);
+			if (err)
+				goto out_free;
+			nlink += 1;
+			type = UBIFS_ITYPE_DIR;
+		} else {
+			err = add_non_dir(name, &inum, 0, &type, &dent_st);
+			if (err)
+				goto out_free;
+		}
+
+		err = add_dent_node(dir_inum, entry->d_name, inum, type);
+		if (err)
+			goto out_free;
+		size += ALIGN(UBIFS_DENT_NODE_SZ + strlen(entry->d_name) + 1,
+			      8);
+	}
+
+	/*
+	 * OK, we have created all files in this directory (recursively), let's
+	 * also create all files described in the device table. All t
+	 */
+	nh_elt = first_name_htbl_element(ph_elt, &itr);
+	while (nh_elt) {
+		struct stat fake_st;
+
+		/*
+		 * We prohibit creating regular files using the device table,
+		 * the device table may only re-define attributes of regular
+		 * files.
+		 */
+		if (S_ISREG(nh_elt->mode)) {
+			err_msg("Bad device table entry %s/%s - it is "
+				"prohibited to create regular files "
+				"via device table",
+				strcmp(ph_elt->path, "/") ? ph_elt->path : "",
+				nh_elt->name);
+			goto out_free;
+		}
+
+		memcpy(&fake_st, &root_st, sizeof(struct stat));
+		fake_st.st_uid  = nh_elt->uid;
+		fake_st.st_uid  = nh_elt->uid;
+		fake_st.st_mode = nh_elt->mode;
+		fake_st.st_rdev = nh_elt->dev;
+		fake_st.st_nlink = 1;
+
+		free(name);
+		name = make_path(dir_name, nh_elt->name);
+		inum = ++c->highest_inum;
+
+		if (S_ISDIR(nh_elt->mode)) {
+			err = add_directory(name, inum, &fake_st, 1);
+			if (err)
+				goto out_free;
+			nlink += 1;
+			type = UBIFS_ITYPE_DIR;
+		} else {
+			err = add_non_dir(name, &inum, 0, &type, &fake_st);
+			if (err)
+				goto out_free;
+		}
+
+		err = add_dent_node(dir_inum, nh_elt->name, inum, type);
+		if (err)
+			goto out_free;
+		size += ALIGN(UBIFS_DENT_NODE_SZ + strlen(nh_elt->name) + 1, 8);
+
+		nh_elt = next_name_htbl_element(ph_elt, &itr);
+	}
+
+	creat_sqnum = dir_creat_sqnum;
+
+	err = add_dir_inode(dir, dir_inum, size, nlink, st);
+	if (err)
+		goto out_free;
+
+	free(name);
+	if (!non_existing && closedir(dir) == -1)
+		return sys_err_msg("error closing directory '%s'", dir_name);
+
+	return 0;
+
+out_free:
+	free(name);
+	if (!non_existing)
+		closedir(dir);
+	return -1;
+}
+
+/**
+ * add_multi_linked_files - write all the files for which we counted links.
+ */
+static int add_multi_linked_files(void)
+{
+	int i, err;
+
+	for (i = 0; i < HASH_TABLE_SIZE; i++) {
+		struct inum_mapping *im;
+		unsigned char type = 0;
+
+		for (im = hash_table[i]; im; im = im->next) {
+			dbg_msg(2, "%s", im->path_name);
+			err = add_non_dir(im->path_name, &im->use_inum,
+					  im->use_nlink, &type, &im->st);
+			if (err)
+				return err;
+		}
+	}
+	return 0;
+}
+
+/**
+ * write_data - write the files and directories.
+ */
+static int write_data(void)
+{
+	int err;
+	mode_t mode = S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+
+	if (root) {
+		err = stat(root, &root_st);
+		if (err)
+			return sys_err_msg("bad root file-system directory '%s'",
+					   root);
+	} else {
+		root_st.st_mtime = time(NULL);
+		root_st.st_atime = root_st.st_ctime = root_st.st_mtime;
+		root_st.st_mode = mode;
+	}
+
+	head_flags = 0;
+	err = add_directory(root, UBIFS_ROOT_INO, &root_st, !root);
+	if (err)
+		return err;
+	err = add_multi_linked_files();
+	if (err)
+		return err;
+	return flush_nodes();
+}
+
+static int namecmp(const char *name1, const char *name2)
+{
+	size_t len1 = strlen(name1), len2 = strlen(name2);
+	size_t clen = (len1 < len2) ? len1 : len2;
+	int cmp;
+
+	cmp = memcmp(name1, name2, clen);
+	if (cmp)
+		return cmp;
+	return (len1 < len2) ? -1 : 1;
+}
+
+static int cmp_idx(const void *a, const void *b)
+{
+	const struct idx_entry *e1 = *(const struct idx_entry **)a;
+	const struct idx_entry *e2 = *(const struct idx_entry **)b;
+	int cmp;
+
+	cmp = keys_cmp(&e1->key, &e2->key);
+	if (cmp)
+		return cmp;
+	return namecmp(e1->name, e2->name);
+}
+
+/**
+ * add_idx_node - write an index node to the head.
+ * @node: index node
+ * @child_cnt: number of children of this index node
+ */
+static int add_idx_node(void *node, int child_cnt)
+{
+	int err, lnum, offs, len;
+
+	len = ubifs_idx_node_sz(c, child_cnt);
+
+	prepare_node(node, len);
+
+	err = reserve_space(len, &lnum, &offs);
+	if (err)
+		return err;
+
+	memcpy(leb_buf + offs, node, len);
+	memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len);
+
+	c->old_idx_sz += ALIGN(len, 8);
+
+	dbg_msg(3, "at %d:%d len %d index size %llu", lnum, offs, len,
+		c->old_idx_sz);
+
+	/* The last index node written will be the root */
+	c->zroot.lnum = lnum;
+	c->zroot.offs = offs;
+	c->zroot.len = len;
+
+	return 0;
+}
+
+/**
+ * write_index - write out the index.
+ */
+static int write_index(void)
+{
+	size_t sz, i, cnt, idx_sz, pstep, bcnt;
+	struct idx_entry **idx_ptr, **p;
+	struct ubifs_idx_node *idx;
+	struct ubifs_branch *br;
+	int child_cnt = 0, j, level, blnum, boffs, blen, blast_len, err;
+
+	dbg_msg(1, "leaf node count: %zd", idx_cnt);
+
+	/* Reset the head for the index */
+	head_flags = LPROPS_INDEX;
+	/* Allocate index node */
+	idx_sz = ubifs_idx_node_sz(c, c->fanout);
+	idx = malloc(idx_sz);
+	if (!idx)
+		return err_msg("out of memory");
+	/* Make an array of pointers to sort the index list */
+	sz = idx_cnt * sizeof(struct idx_entry *);
+	if (sz / sizeof(struct idx_entry *) != idx_cnt) {
+		free(idx);
+		return err_msg("index is too big (%zu entries)", idx_cnt);
+	}
+	idx_ptr = malloc(sz);
+	if (!idx_ptr) {
+		free(idx);
+		return err_msg("out of memory - needed %zu bytes for index",
+			       sz);
+	}
+	idx_ptr[0] = idx_list_first;
+	for (i = 1; i < idx_cnt; i++)
+		idx_ptr[i] = idx_ptr[i - 1]->next;
+	qsort(idx_ptr, idx_cnt, sizeof(struct idx_entry *), cmp_idx);
+	/* Write level 0 index nodes */
+	cnt = idx_cnt / c->fanout;
+	if (idx_cnt % c->fanout)
+		cnt += 1;
+	p = idx_ptr;
+	blnum = head_lnum;
+	boffs = head_offs;
+	for (i = 0; i < cnt; i++) {
+		/*
+		 * Calculate the child count. All index nodes are created full
+		 * except for the last index node on each row.
+		 */
+		if (i == cnt - 1) {
+			child_cnt = idx_cnt % c->fanout;
+			if (child_cnt == 0)
+				child_cnt = c->fanout;
+		} else
+			child_cnt = c->fanout;
+		memset(idx, 0, idx_sz);
+		idx->ch.node_type = UBIFS_IDX_NODE;
+		idx->child_cnt = cpu_to_le16(child_cnt);
+		idx->level = cpu_to_le16(0);
+		for (j = 0; j < child_cnt; j++, p++) {
+			br = ubifs_idx_branch(c, idx, j);
+			key_write_idx(&(*p)->key, &br->key);
+			br->lnum = cpu_to_le32((*p)->lnum);
+			br->offs = cpu_to_le32((*p)->offs);
+			br->len = cpu_to_le32((*p)->len);
+		}
+		add_idx_node(idx, child_cnt);
+	}
+	/* Write level 1 index nodes and above */
+	level = 0;
+	pstep = 1;
+	while (cnt > 1) {
+		/*
+		 * 'blast_len' is the length of the last index node in the level
+		 * below.
+		 */
+		blast_len = ubifs_idx_node_sz(c, child_cnt);
+		/* 'bcnt' is the number of index nodes in the level below */
+		bcnt = cnt;
+		/* 'cnt' is the number of index nodes in this level */
+		cnt = (cnt + c->fanout - 1) / c->fanout;
+		if (cnt == 0)
+			cnt = 1;
+		level += 1;
+		/*
+		 * The key of an index node is the same as the key of its first
+		 * child. Thus we can get the key by stepping along the bottom
+		 * level 'p' with an increasing large step 'pstep'.
+		 */
+		p = idx_ptr;
+		pstep *= c->fanout;
+		for (i = 0; i < cnt; i++) {
+			/*
+			 * Calculate the child count. All index nodes are
+			 * created full except for the last index node on each
+			 * row.
+			 */
+			if (i == cnt - 1) {
+				child_cnt = bcnt % c->fanout;
+				if (child_cnt == 0)
+					child_cnt = c->fanout;
+			} else
+				child_cnt = c->fanout;
+			memset(idx, 0, idx_sz);
+			idx->ch.node_type = UBIFS_IDX_NODE;
+			idx->child_cnt = cpu_to_le16(child_cnt);
+			idx->level = cpu_to_le16(level);
+			for (j = 0; j < child_cnt; j++) {
+				size_t bn = i * c->fanout + j;
+
+				/*
+				 * The length of the index node in the level
+				 * below is 'idx_sz' except when it is the last
+				 * node on the row. i.e. all the others on the
+				 * row are full.
+				 */
+				if (bn == bcnt - 1)
+					blen = blast_len;
+				else
+					blen = idx_sz;
+				/*
+				 * 'blnum' and 'boffs' hold the position of the
+				 * index node on the level below.
+				 */
+				if (boffs + blen > c->leb_size) {
+					blnum += 1;
+					boffs = 0;
+				}
+				/*
+				 * Fill in the branch with the key and position
+				 * of the index node from the level below.
+				 */
+				br = ubifs_idx_branch(c, idx, j);
+				key_write_idx(&(*p)->key, &br->key);
+				br->lnum = cpu_to_le32(blnum);
+				br->offs = cpu_to_le32(boffs);
+				br->len = cpu_to_le32(blen);
+				/*
+				 * Step to the next index node on the level
+				 * below.
+				 */
+				boffs += ALIGN(blen, 8);
+				p += pstep;
+			}
+			add_idx_node(idx, child_cnt);
+		}
+	}
+
+	/* Free stuff */
+	for (i = 0; i < idx_cnt; i++)
+		free(idx_ptr[i]);
+	free(idx_ptr);
+	free(idx);
+
+	dbg_msg(1, "zroot is at %d:%d len %d", c->zroot.lnum, c->zroot.offs,
+		c->zroot.len);
+
+	/* Set the index head */
+	c->ihead_lnum = head_lnum;
+	c->ihead_offs = ALIGN(head_offs, c->min_io_size);
+	dbg_msg(1, "ihead is at %d:%d", c->ihead_lnum, c->ihead_offs);
+
+	/* Flush the last index LEB */
+	err = flush_nodes();
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/**
+ * set_gc_lnum - set the LEB number reserved for the garbage collector.
+ */
+static int set_gc_lnum(void)
+{
+	int err;
+
+	c->gc_lnum = head_lnum++;
+	err = write_empty_leb(c->gc_lnum);
+	if (err)
+		return err;
+	set_lprops(c->gc_lnum, 0, 0);
+	c->lst.empty_lebs += 1;
+	return 0;
+}
+
+/**
+ * finalize_leb_cnt - now that we know how many LEBs we used.
+ */
+static int finalize_leb_cnt(void)
+{
+	c->leb_cnt = head_lnum;
+	if (c->leb_cnt > c->max_leb_cnt)
+		return err_msg("max_leb_cnt too low (%d needed)", c->leb_cnt);
+	c->main_lebs = c->leb_cnt - c->main_first;
+	if (verbose) {
+		printf("\tsuper lebs:   %d\n", UBIFS_SB_LEBS);
+		printf("\tmaster lebs:  %d\n", UBIFS_MST_LEBS);
+		printf("\tlog_lebs:     %d\n", c->log_lebs);
+		printf("\tlpt_lebs:     %d\n", c->lpt_lebs);
+		printf("\torph_lebs:    %d\n", c->orph_lebs);
+		printf("\tmain_lebs:    %d\n", c->main_lebs);
+		printf("\tgc lebs:      %d\n", 1);
+		printf("\tindex lebs:   %d\n", c->lst.idx_lebs);
+		printf("\tleb_cnt:      %d\n", c->leb_cnt);
+	}
+	dbg_msg(1, "total_free:  %llu", c->lst.total_free);
+	dbg_msg(1, "total_dirty: %llu", c->lst.total_dirty);
+	dbg_msg(1, "total_used:  %llu", c->lst.total_used);
+	dbg_msg(1, "total_dead:  %llu", c->lst.total_dead);
+	dbg_msg(1, "total_dark:  %llu", c->lst.total_dark);
+	dbg_msg(1, "index size:  %llu", c->old_idx_sz);
+	dbg_msg(1, "empty_lebs:  %d", c->lst.empty_lebs);
+	return 0;
+}
+
+/**
+ * write_super - write the super block.
+ */
+static int write_super(void)
+{
+	struct ubifs_sb_node sup;
+
+	memset(&sup, 0, UBIFS_SB_NODE_SZ);
+
+	sup.ch.node_type  = UBIFS_SB_NODE;
+	sup.key_hash      = c->key_hash_type;
+	sup.min_io_size   = cpu_to_le32(c->min_io_size);
+	sup.leb_size      = cpu_to_le32(c->leb_size);
+	sup.leb_cnt       = cpu_to_le32(c->leb_cnt);
+	sup.max_leb_cnt   = cpu_to_le32(c->max_leb_cnt);
+	sup.max_bud_bytes = cpu_to_le64(c->max_bud_bytes);
+	sup.log_lebs      = cpu_to_le32(c->log_lebs);
+	sup.lpt_lebs      = cpu_to_le32(c->lpt_lebs);
+	sup.orph_lebs     = cpu_to_le32(c->orph_lebs);
+	sup.jhead_cnt     = cpu_to_le32(c->jhead_cnt);
+	sup.fanout        = cpu_to_le32(c->fanout);
+	sup.lsave_cnt     = cpu_to_le32(c->lsave_cnt);
+	sup.fmt_version   = cpu_to_le32(UBIFS_FORMAT_VERSION);
+	sup.default_compr = cpu_to_le16(c->default_compr);
+	sup.rp_size       = cpu_to_le64(c->rp_size);
+	sup.time_gran     = cpu_to_le32(DEFAULT_TIME_GRAN);
+	uuid_generate_random(sup.uuid);
+	if (verbose) {
+		char s[40];
+
+		uuid_unparse_upper(sup.uuid, s);
+		printf("\tUUID:         %s\n", s);
+	}
+	if (c->big_lpt)
+		sup.flags |= cpu_to_le32(UBIFS_FLG_BIGLPT);
+	if (c->space_fixup)
+		sup.flags |= cpu_to_le32(UBIFS_FLG_SPACE_FIXUP);
+
+	return write_node(&sup, UBIFS_SB_NODE_SZ, UBIFS_SB_LNUM);
+}
+
+/**
+ * write_master - write the master node.
+ */
+static int write_master(void)
+{
+	struct ubifs_mst_node mst;
+	int err;
+
+	memset(&mst, 0, UBIFS_MST_NODE_SZ);
+
+	mst.ch.node_type = UBIFS_MST_NODE;
+	mst.log_lnum     = cpu_to_le32(UBIFS_LOG_LNUM);
+	mst.highest_inum = cpu_to_le64(c->highest_inum);
+	mst.cmt_no       = cpu_to_le64(0);
+	mst.flags        = cpu_to_le32(UBIFS_MST_NO_ORPHS);
+	mst.root_lnum    = cpu_to_le32(c->zroot.lnum);
+	mst.root_offs    = cpu_to_le32(c->zroot.offs);
+	mst.root_len     = cpu_to_le32(c->zroot.len);
+	mst.gc_lnum      = cpu_to_le32(c->gc_lnum);
+	mst.ihead_lnum   = cpu_to_le32(c->ihead_lnum);
+	mst.ihead_offs   = cpu_to_le32(c->ihead_offs);
+	mst.index_size   = cpu_to_le64(c->old_idx_sz);
+	mst.lpt_lnum     = cpu_to_le32(c->lpt_lnum);
+	mst.lpt_offs     = cpu_to_le32(c->lpt_offs);
+	mst.nhead_lnum   = cpu_to_le32(c->nhead_lnum);
+	mst.nhead_offs   = cpu_to_le32(c->nhead_offs);
+	mst.ltab_lnum    = cpu_to_le32(c->ltab_lnum);
+	mst.ltab_offs    = cpu_to_le32(c->ltab_offs);
+	mst.lsave_lnum   = cpu_to_le32(c->lsave_lnum);
+	mst.lsave_offs   = cpu_to_le32(c->lsave_offs);
+	mst.lscan_lnum   = cpu_to_le32(c->lscan_lnum);
+	mst.empty_lebs   = cpu_to_le32(c->lst.empty_lebs);
+	mst.idx_lebs     = cpu_to_le32(c->lst.idx_lebs);
+	mst.total_free   = cpu_to_le64(c->lst.total_free);
+	mst.total_dirty  = cpu_to_le64(c->lst.total_dirty);
+	mst.total_used   = cpu_to_le64(c->lst.total_used);
+	mst.total_dead   = cpu_to_le64(c->lst.total_dead);
+	mst.total_dark   = cpu_to_le64(c->lst.total_dark);
+	mst.leb_cnt      = cpu_to_le32(c->leb_cnt);
+
+	err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM);
+	if (err)
+		return err;
+
+	err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/**
+ * write_log - write an empty log.
+ */
+static int write_log(void)
+{
+	struct ubifs_cs_node cs;
+	int err, i, lnum;
+
+	lnum = UBIFS_LOG_LNUM;
+
+	cs.ch.node_type = UBIFS_CS_NODE;
+	cs.cmt_no = cpu_to_le64(0);
+
+	err = write_node(&cs, UBIFS_CS_NODE_SZ, lnum);
+	if (err)
+		return err;
+
+	lnum += 1;
+
+	for (i = 1; i < c->log_lebs; i++, lnum++) {
+		err = write_empty_leb(lnum);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * write_lpt - write the LEB properties tree.
+ */
+static int write_lpt(void)
+{
+	int err, lnum;
+
+	err = create_lpt(c);
+	if (err)
+		return err;
+
+	lnum = c->nhead_lnum + 1;
+	while (lnum <= c->lpt_last) {
+		err = write_empty_leb(lnum++);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * write_orphan_area - write an empty orphan area.
+ */
+static int write_orphan_area(void)
+{
+	int err, i, lnum;
+
+	lnum = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs;
+	for (i = 0; i < c->orph_lebs; i++, lnum++) {
+		err = write_empty_leb(lnum);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+/**
+ * check_volume_empty - check if the UBI volume is empty.
+ *
+ * This function checks if the UBI volume is empty by looking if its LEBs are
+ * mapped or not.
+ *
+ * Returns %0 in case of success, %1 is the volume is not empty,
+ * and a negative error code in case of failure.
+ */
+static int check_volume_empty(void)
+{
+	int lnum, err;
+
+	for (lnum = 0; lnum < c->vi.rsvd_lebs; lnum++) {
+		err = ubi_is_mapped(out_fd, lnum);
+		if (err < 0)
+			return err;
+		if (err == 1)
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ * open_target - open the output target.
+ *
+ * Open the output target. The target can be an UBI volume
+ * or a file.
+ *
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int open_target(void)
+{
+	if (out_ubi) {
+		out_fd = open(output, O_RDWR | O_EXCL);
+
+		if (out_fd == -1)
+			return sys_err_msg("cannot open the UBI volume '%s'",
+					   output);
+		if (ubi_set_property(out_fd, UBI_VOL_PROP_DIRECT_WRITE, 1))
+			return sys_err_msg("ubi_set_property failed");
+
+		if (!yes && check_volume_empty()) {
+			if (!prompt("UBI volume is not empty.  Format anyways?", false))
+				return err_msg("UBI volume is not empty");
+		}
+	} else {
+		out_fd = open(output, O_CREAT | O_RDWR | O_TRUNC,
+			      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+		if (out_fd == -1)
+			return sys_err_msg("cannot create output file '%s'",
+					   output);
+	}
+	return 0;
+}
+
+
+/**
+ * close_target - close the output target.
+ *
+ * Close the output target. If the target was an UBI
+ * volume, also close libubi.
+ *
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int close_target(void)
+{
+	if (ubi)
+		libubi_close(ubi);
+	if (out_fd >= 0 && close(out_fd) == -1)
+		return sys_err_msg("cannot close the target '%s'", output);
+	if (output)
+		free(output);
+	return 0;
+}
+
+/**
+ * init - initialize things.
+ */
+static int init(void)
+{
+	int err, i, main_lebs, big_lpt = 0, sz;
+
+	c->highest_inum = UBIFS_FIRST_INO;
+
+	c->jhead_cnt = 1;
+
+	main_lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+	main_lebs -= c->log_lebs + c->orph_lebs;
+
+	err = calc_dflt_lpt_geom(c, &main_lebs, &big_lpt);
+	if (err)
+		return err;
+
+	c->main_first = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs +
+			c->orph_lebs;
+	head_lnum = c->main_first;
+	head_offs = 0;
+
+	c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs;
+	c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
+
+	c->lpt = malloc(c->main_lebs * sizeof(struct ubifs_lprops));
+	if (!c->lpt)
+		return err_msg("unable to allocate LPT");
+
+	c->ltab = malloc(c->lpt_lebs * sizeof(struct ubifs_lprops));
+	if (!c->ltab)
+		return err_msg("unable to allocate LPT ltab");
+
+	/* Initialize LPT's own lprops */
+	for (i = 0; i < c->lpt_lebs; i++) {
+		c->ltab[i].free = c->leb_size;
+		c->ltab[i].dirty = 0;
+	}
+
+	c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size);
+	c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size);
+	dbg_msg(1, "dead_wm %d  dark_wm %d", c->dead_wm, c->dark_wm);
+
+	leb_buf = malloc(c->leb_size);
+	if (!leb_buf)
+		return err_msg("out of memory");
+
+	node_buf = malloc(NODE_BUFFER_SIZE);
+	if (!node_buf)
+		return err_msg("out of memory");
+
+	block_buf = malloc(UBIFS_BLOCK_SIZE);
+	if (!block_buf)
+		return err_msg("out of memory");
+
+	sz = sizeof(struct inum_mapping *) * HASH_TABLE_SIZE;
+	hash_table = malloc(sz);
+	if (!hash_table)
+		return err_msg("out of memory");
+	memset(hash_table, 0, sz);
+
+	err = init_compression();
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static void destroy_hash_table(void)
+{
+	int i;
+
+	for (i = 0; i < HASH_TABLE_SIZE; i++) {
+		struct inum_mapping *im, *q;
+
+		for (im = hash_table[i]; im; ) {
+			q = im;
+			im = im->next;
+			free(q->path_name);
+			free(q);
+		}
+	}
+}
+
+/**
+ * deinit - deinitialize things.
+ */
+static void deinit(void)
+{
+	free(c->lpt);
+	free(c->ltab);
+	free(leb_buf);
+	free(node_buf);
+	free(block_buf);
+	destroy_hash_table();
+	free(hash_table);
+	destroy_compression();
+	free_devtable_info();
+}
+
+/**
+ * mkfs - make the file system.
+ *
+ * Each on-flash area has a corresponding function to create it. The order of
+ * the functions reflects what information must be known to complete each stage.
+ * As a consequence the output file is not written sequentially. No effort has
+ * been made to make efficient use of memory or to allow for the possibility of
+ * incremental updates to the output file.
+ */
+static int mkfs(void)
+{
+	int err = 0;
+
+	err = init();
+	if (err)
+		goto out;
+
+	err = write_data();
+	if (err)
+		goto out;
+
+	err = set_gc_lnum();
+	if (err)
+		goto out;
+
+	err = write_index();
+	if (err)
+		goto out;
+
+	err = finalize_leb_cnt();
+	if (err)
+		goto out;
+
+	err = write_lpt();
+	if (err)
+		goto out;
+
+	err = write_super();
+	if (err)
+		goto out;
+
+	err = write_master();
+	if (err)
+		goto out;
+
+	err = write_log();
+	if (err)
+		goto out;
+
+	err = write_orphan_area();
+
+out:
+	deinit();
+	return err;
+}
+
+int main(int argc, char *argv[])
+{
+	int err;
+
+	err = get_options(argc, argv);
+	if (err)
+		return err;
+
+	err = open_target();
+	if (err)
+		return err;
+
+	err = mkfs();
+	if (err) {
+		close_target();
+		return err;
+	}
+
+	err = close_target();
+	if (err)
+		return err;
+
+	if (verbose)
+		printf("Success!\n");
+
+	return 0;
+}
diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
new file mode 100644
index 0000000..944a159
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy
+ *          Adrian Hunter
+ *          Zoltan Sogor
+ */
+
+#ifndef __MKFS_UBIFS_H__
+#define __MKFS_UBIFS_H__
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+#include <stdint.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <libgen.h>
+#include <ctype.h>
+#include <uuid/uuid.h>
+#include <sys/file.h>
+
+#include <mtd/ubifs-media.h>
+
+/* common.h requires the PROGRAM_NAME macro */
+#define PROGRAM_NAME "mkfs.ubifs"
+#include "common.h"
+
+#include "libubi.h"
+#include "defs.h"
+#include "crc16.h"
+#include "ubifs.h"
+#include "key.h"
+#include "lpt.h"
+#include "compr.h"
+
+/*
+ * Compression flags are duplicated so that compr.c can compile without ubifs.h.
+ * Here we make sure they are the same.
+ */
+#if MKFS_UBIFS_COMPR_NONE != UBIFS_COMPR_NONE
+#error MKFS_UBIFS_COMPR_NONE != UBIFS_COMPR_NONE
+#endif
+#if MKFS_UBIFS_COMPR_LZO != UBIFS_COMPR_LZO
+#error MKFS_UBIFS_COMPR_LZO != UBIFS_COMPR_LZO
+#endif
+#if MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB
+#error MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB
+#endif
+
+extern int verbose;
+extern int debug_level;
+
+#define dbg_msg(lvl, fmt, ...) do {if (debug_level >= lvl)                \
+	printf("mkfs.ubifs: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__); \
+} while(0)
+
+#define err_msg(fmt, ...) ({                                \
+	fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__); \
+	-1;                                                 \
+})
+
+#define sys_err_msg(fmt, ...) ({                                         \
+	int err_ = errno;                                                \
+	fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__);              \
+	fprintf(stderr, "       %s (error %d)\n", strerror(err_), err_); \
+	-1;                                                              \
+})
+
+/**
+ * struct path_htbl_element - an element of the path hash table.
+ * @path: the UBIFS path the element describes (the key of the element)
+ * @name_htbl: one more (nested) hash table containing names of all
+ *             files/directories/device nodes which should be created at this
+ *             path
+ *
+ * See device table handling for more information.
+ */
+struct path_htbl_element {
+	const char *path;
+	struct hashtable *name_htbl;
+};
+
+/**
+ * struct name_htbl_element - an element in the name hash table
+ * @name: name of the file/directory/device node (the key of the element)
+ * @mode: accsess rights and file type
+ * @uid: user ID
+ * @gid: group ID
+ * @major: device node major number
+ * @minor: device node minor number
+ *
+ * This is an element of the name hash table. Name hash table sits in the path
+ * hash table elements and describes file names which should be created/changed
+ * at this path.
+ */
+struct name_htbl_element {
+	const char *name;
+	unsigned int mode;
+	unsigned int uid;
+	unsigned int gid;
+	dev_t dev;
+};
+
+extern struct ubifs_info info_;
+
+struct hashtable_itr;
+
+int write_leb(int lnum, int len, void *buf);
+int parse_devtable(const char *tbl_file);
+struct path_htbl_element *devtbl_find_path(const char *path);
+struct name_htbl_element *devtbl_find_name(struct path_htbl_element *ph_elt,
+					   const char *name);
+int override_attributes(struct stat *st, struct path_htbl_element *ph_elt,
+			struct name_htbl_element *nh_elt);
+struct name_htbl_element *
+first_name_htbl_element(struct path_htbl_element *ph_elt,
+			struct hashtable_itr **itr);
+struct name_htbl_element *
+next_name_htbl_element(struct path_htbl_element *ph_elt,
+		       struct hashtable_itr **itr);
+void free_devtable_info(void);
+
+#endif
diff --git a/ubifs-utils/mkfs.ubifs/ubifs.h b/ubifs-utils/mkfs.ubifs/ubifs.h
new file mode 100644
index 0000000..434b651
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/ubifs.h
@@ -0,0 +1,441 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy
+ *          Adrian Hunter
+ *          Zoltan Sogor
+ */
+
+#ifndef __UBIFS_H__
+#define __UBIFS_H__
+
+/* Maximum logical eraseblock size in bytes */
+#define UBIFS_MAX_LEB_SZ (2*1024*1024)
+
+/* Minimum amount of data UBIFS writes to the flash */
+#define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8)
+
+/* Largest key size supported in this implementation */
+#define CUR_MAX_KEY_LEN UBIFS_SK_LEN
+
+/*
+ * There is no notion of truncation key because truncation nodes do not exist
+ * in TNC. However, when replaying, it is handy to introduce fake "truncation"
+ * keys for truncation nodes because the code becomes simpler. So we define
+ * %UBIFS_TRUN_KEY type.
+ */
+#define UBIFS_TRUN_KEY UBIFS_KEY_TYPES_CNT
+
+/* The below union makes it easier to deal with keys */
+union ubifs_key
+{
+	uint8_t u8[CUR_MAX_KEY_LEN];
+	uint32_t u32[CUR_MAX_KEY_LEN/4];
+	uint64_t u64[CUR_MAX_KEY_LEN/8];
+	__le32 j32[CUR_MAX_KEY_LEN/4];
+};
+
+/*
+ * LEB properties flags.
+ *
+ * LPROPS_UNCAT: not categorized
+ * LPROPS_DIRTY: dirty > 0, not index
+ * LPROPS_DIRTY_IDX: dirty + free > UBIFS_CH_SZ and index
+ * LPROPS_FREE: free > 0, not empty, not index
+ * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs
+ * LPROPS_EMPTY: LEB is empty, not taken
+ * LPROPS_FREEABLE: free + dirty == leb_size, not index, not taken
+ * LPROPS_FRDI_IDX: free + dirty == leb_size and index, may be taken
+ * LPROPS_CAT_MASK: mask for the LEB categories above
+ * LPROPS_TAKEN: LEB was taken (this flag is not saved on the media)
+ * LPROPS_INDEX: LEB contains indexing nodes (this flag also exists on flash)
+ */
+enum {
+	LPROPS_UNCAT     =  0,
+	LPROPS_DIRTY     =  1,
+	LPROPS_DIRTY_IDX =  2,
+	LPROPS_FREE      =  3,
+	LPROPS_HEAP_CNT  =  3,
+	LPROPS_EMPTY     =  4,
+	LPROPS_FREEABLE  =  5,
+	LPROPS_FRDI_IDX  =  6,
+	LPROPS_CAT_MASK  = 15,
+	LPROPS_TAKEN     = 16,
+	LPROPS_INDEX     = 32,
+};
+
+/**
+ * struct ubifs_lprops - logical eraseblock properties.
+ * @free: amount of free space in bytes
+ * @dirty: amount of dirty space in bytes
+ * @flags: LEB properties flags (see above)
+ */
+struct ubifs_lprops
+{
+	int free;
+	int dirty;
+	int flags;
+};
+
+/**
+ * struct ubifs_lpt_lprops - LPT logical eraseblock properties.
+ * @free: amount of free space in bytes
+ * @dirty: amount of dirty space in bytes
+ */
+struct ubifs_lpt_lprops
+{
+	int free;
+	int dirty;
+};
+
+struct ubifs_nnode;
+
+/**
+ * struct ubifs_cnode - LEB Properties Tree common node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (zero for pnodes, greater than zero for nnodes)
+ * @num: node number
+ */
+struct ubifs_cnode
+{
+	struct ubifs_nnode *parent;
+	struct ubifs_cnode *cnext;
+	unsigned long flags;
+	int iip;
+	int level;
+	int num;
+};
+
+/**
+ * struct ubifs_pnode - LEB Properties Tree leaf node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (always zero for pnodes)
+ * @num: node number
+ * @lprops: LEB properties array
+ */
+struct ubifs_pnode
+{
+	struct ubifs_nnode *parent;
+	struct ubifs_cnode *cnext;
+	unsigned long flags;
+	int iip;
+	int level;
+	int num;
+	struct ubifs_lprops lprops[UBIFS_LPT_FANOUT];
+};
+
+/**
+ * struct ubifs_nbranch - LEB Properties Tree internal node branch.
+ * @lnum: LEB number of child
+ * @offs: offset of child
+ * @nnode: nnode child
+ * @pnode: pnode child
+ * @cnode: cnode child
+ */
+struct ubifs_nbranch
+{
+	int lnum;
+	int offs;
+	union
+	{
+		struct ubifs_nnode *nnode;
+		struct ubifs_pnode *pnode;
+		struct ubifs_cnode *cnode;
+	};
+};
+
+/**
+ * struct ubifs_nnode - LEB Properties Tree internal node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (always greater than zero for nnodes)
+ * @num: node number
+ * @nbranch: branches to child nodes
+ */
+struct ubifs_nnode
+{
+	struct ubifs_nnode *parent;
+	struct ubifs_cnode *cnext;
+	unsigned long flags;
+	int iip;
+	int level;
+	int num;
+	struct ubifs_nbranch nbranch[UBIFS_LPT_FANOUT];
+};
+
+/**
+ * struct ubifs_lp_stats - statistics of eraseblocks in the main area.
+ * @empty_lebs: number of empty LEBs
+ * @taken_empty_lebs: number of taken LEBs
+ * @idx_lebs: number of indexing LEBs
+ * @total_free: total free space in bytes
+ * @total_dirty: total dirty space in bytes
+ * @total_used: total used space in bytes (includes only data LEBs)
+ * @total_dead: total dead space in bytes (includes only data LEBs)
+ * @total_dark: total dark space in bytes (includes only data LEBs)
+ */
+struct ubifs_lp_stats {
+	int empty_lebs;
+	int taken_empty_lebs;
+	int idx_lebs;
+	long long total_free;
+	long long total_dirty;
+	long long total_used;
+	long long total_dead;
+	long long total_dark;
+};
+
+/**
+ * struct ubifs_zbranch - key/coordinate/length branch stored in znodes.
+ * @key: key
+ * @znode: znode address in memory
+ * @lnum: LEB number of the indexing node
+ * @offs: offset of the indexing node within @lnum
+ * @len: target node length
+ */
+struct ubifs_zbranch
+{
+	union ubifs_key key;
+	struct ubifs_znode *znode;
+	int lnum;
+	int offs;
+	int len;
+};
+
+/**
+ * struct ubifs_znode - in-memory representation of an indexing node.
+ * @parent: parent znode or NULL if it is the root
+ * @cnext: next znode to commit
+ * @flags: flags
+ * @time: last access time (seconds)
+ * @level: level of the entry in the TNC tree
+ * @child_cnt: count of child znodes
+ * @iip: index in parent's zbranch array
+ * @alt: lower bound of key range has altered i.e. child inserted at slot 0
+ * @zbranch: array of znode branches (@c->fanout elements)
+ */
+struct ubifs_znode
+{
+	struct ubifs_znode *parent;
+	struct ubifs_znode *cnext;
+	unsigned long flags;
+	unsigned long time;
+	int level;
+	int child_cnt;
+	int iip;
+	int alt;
+#ifdef CONFIG_UBIFS_FS_DEBUG
+	int lnum, offs, len;
+#endif
+	struct ubifs_zbranch zbranch[];
+};
+
+/**
+ * struct ubifs_info - UBIFS file-system description data structure
+ * (per-superblock).
+ *
+ * @highest_inum: highest used inode number
+ * @max_sqnum: current global sequence number
+ *
+ * @jhead_cnt: count of journal heads
+ * @max_bud_bytes: maximum number of bytes allowed in buds
+ *
+ * @zroot: zbranch which points to the root index node and znode
+ * @ihead_lnum: LEB number of index head
+ * @ihead_offs: offset of index head
+ *
+ * @log_lebs: number of logical eraseblocks in the log
+ * @lpt_lebs: number of LEBs used for lprops table
+ * @lpt_first: first LEB of the lprops table area
+ * @lpt_last: last LEB of the lprops table area
+ * @main_lebs: count of LEBs in the main area
+ * @main_first: first LEB of the main area
+ * @default_compr: default compression type
+ * @favor_lzo: favor LZO compression method
+ * @favor_percent: lzo vs. zlib threshold used in case favor LZO
+ *
+ * @key_hash_type: type of the key hash
+ * @key_hash: direntry key hash function
+ * @key_fmt: key format
+ * @key_len: key length
+ * @fanout: fanout of the index tree (number of links per indexing node)
+ *
+ * @min_io_size: minimal input/output unit size
+ * @leb_size: logical eraseblock size in bytes
+ * @leb_cnt: count of logical eraseblocks
+ * @max_leb_cnt: maximum count of logical eraseblocks
+ *
+ * @old_idx_sz: size of index on flash
+ * @lst: lprops statistics
+ *
+ * @dead_wm: LEB dead space watermark
+ * @dark_wm: LEB dark space watermark
+ *
+ * @di: UBI device information
+ * @vi: UBI volume information
+ *
+ * @gc_lnum: LEB number used for garbage collection
+ * @rp_size: reserved pool size
+ *
+ * @space_bits: number of bits needed to record free or dirty space
+ * @lpt_lnum_bits: number of bits needed to record a LEB number in the LPT
+ * @lpt_offs_bits: number of bits needed to record an offset in the LPT
+ * @lpt_spc_bits: number of bits needed to space in the LPT
+ * @pcnt_bits: number of bits needed to record pnode or nnode number
+ * @lnum_bits: number of bits needed to record LEB number
+ * @nnode_sz: size of on-flash nnode
+ * @pnode_sz: size of on-flash pnode
+ * @ltab_sz: size of on-flash LPT lprops table
+ * @lsave_sz: size of on-flash LPT save table
+ * @pnode_cnt: number of pnodes
+ * @nnode_cnt: number of nnodes
+ * @lpt_hght: height of the LPT
+ *
+ * @lpt_lnum: LEB number of the root nnode of the LPT
+ * @lpt_offs: offset of the root nnode of the LPT
+ * @nhead_lnum: LEB number of LPT head
+ * @nhead_offs: offset of LPT head
+ * @big_lpt: flag that LPT is too big to write whole during commit
+ * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
+ * @lpt_sz: LPT size
+ *
+ * @ltab_lnum: LEB number of LPT's own lprops table
+ * @ltab_offs: offset of LPT's own lprops table
+ * @lpt: lprops table
+ * @ltab: LPT's own lprops table
+ * @lsave_cnt: number of LEB numbers in LPT's save table
+ * @lsave_lnum: LEB number of LPT's save table
+ * @lsave_offs: offset of LPT's save table
+ * @lsave: LPT's save table
+ * @lscan_lnum: LEB number of last LPT scan
+ */
+struct ubifs_info
+{
+	ino_t highest_inum;
+	unsigned long long max_sqnum;
+
+	int jhead_cnt;
+	long long max_bud_bytes;
+
+	struct ubifs_zbranch zroot;
+	int ihead_lnum;
+	int ihead_offs;
+
+	int log_lebs;
+	int lpt_lebs;
+	int lpt_first;
+	int lpt_last;
+	int orph_lebs;
+	int main_lebs;
+	int main_first;
+	int default_compr;
+	int favor_lzo;
+	int favor_percent;
+
+	uint8_t key_hash_type;
+	uint32_t (*key_hash)(const char *str, int len);
+	int key_fmt;
+	int key_len;
+	int fanout;
+
+	int min_io_size;
+	int leb_size;
+	int leb_cnt;
+	int max_leb_cnt;
+
+	unsigned long long old_idx_sz;
+	struct ubifs_lp_stats lst;
+
+	int dead_wm;
+	int dark_wm;
+
+	struct ubi_dev_info di;
+	struct ubi_vol_info vi;
+
+	int gc_lnum;
+	long long rp_size;
+
+	int space_bits;
+	int lpt_lnum_bits;
+	int lpt_offs_bits;
+	int lpt_spc_bits;
+	int pcnt_bits;
+	int lnum_bits;
+	int nnode_sz;
+	int pnode_sz;
+	int ltab_sz;
+	int lsave_sz;
+	int pnode_cnt;
+	int nnode_cnt;
+	int lpt_hght;
+
+	int lpt_lnum;
+	int lpt_offs;
+	int nhead_lnum;
+	int nhead_offs;
+	int big_lpt;
+	int space_fixup;
+	long long lpt_sz;
+
+	int ltab_lnum;
+	int ltab_offs;
+	struct ubifs_lprops *lpt;
+	struct ubifs_lpt_lprops *ltab;
+	int lsave_cnt;
+	int lsave_lnum;
+	int lsave_offs;
+	int *lsave;
+	int lscan_lnum;
+
+};
+
+/**
+ * ubifs_idx_node_sz - return index node size.
+ * @c: the UBIFS file-system description object
+ * @child_cnt: number of children of this index node
+ */
+static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt)
+{
+	return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt;
+}
+
+/**
+ * ubifs_idx_branch - return pointer to an index branch.
+ * @c: the UBIFS file-system description object
+ * @idx: index node
+ * @bnum: branch number
+ */
+static inline
+struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
+				      const struct ubifs_idx_node *idx,
+				      int bnum)
+{
+	return (struct ubifs_branch *)((void *)idx->branches +
+				       (UBIFS_BRANCH_SZ + c->key_len) * bnum);
+}
+
+#endif /* __UBIFS_H__ */
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 02/27] ubifs: pick some common definitions into ubifs_common.h
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 03/27] ubifs: move the all io related code into io.[h|c] Dongsheng Yang
                   ` (25 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Currently, lpt.c is including mkfs.ubifs.h. That make
the lpt depend on mkfs.ubifs. It's not good if we want
to introduce some more tools for ubifs, such as fsck.ubifs.

This patch start to cut off the dependence from libs, such
as lpt, devtable, to mkfs.ubifs.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.h   | 46 +-------------------------------
 ubifs-utils/mkfs.ubifs/ubifs_common.h | 50 +++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 45 deletions(-)
 create mode 100644 ubifs-utils/mkfs.ubifs/ubifs_common.h

diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
index 944a159..d6d46a2 100644
--- a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
@@ -23,37 +23,12 @@
 #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>
+#include "ubifs_common.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"
@@ -74,25 +49,6 @@
 #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)
diff --git a/ubifs-utils/mkfs.ubifs/ubifs_common.h b/ubifs-utils/mkfs.ubifs/ubifs_common.h
new file mode 100644
index 0000000..958c20a
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/ubifs_common.h
@@ -0,0 +1,50 @@
+#ifndef __UBIFS_COMMON_H__
+#define __UBIFS_COMMON_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>
+
+#include "libubi.h"
+#include "defs.h"
+
+extern int verbose;
+extern int debug_level;
+
+#define dbg_msg(lvl, fmt, ...) do {if (debug_level >= lvl)                \
+	printf("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;                                                              \
+})
+#endif
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 03/27] ubifs: move the all io related code into io.[h|c]
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 02/27] ubifs: pick some common definitions into ubifs_common.h Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 04/27] ubifs: remove the including of mkfs.ubifs.h in lpt.c Dongsheng Yang
                   ` (24 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

To cut off the dependence from common lib to mkfs.ubifs,
this patch refactor the io related functions into a new
lib named as io.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 Makefile                            |  2 +-
 ubifs-utils/mkfs.ubifs/io.c         | 33 +++++++++++++++++++++++++++++++++
 ubifs-utils/mkfs.ubifs/io.h         | 15 +++++++++++++++
 ubifs-utils/mkfs.ubifs/lpt.c        | 10 +++++-----
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.c | 34 +++-------------------------------
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.h |  2 +-
 6 files changed, 58 insertions(+), 38 deletions(-)
 create mode 100644 ubifs-utils/mkfs.ubifs/io.c
 create mode 100644 ubifs-utils/mkfs.ubifs/io.h

diff --git a/Makefile b/Makefile
index bb40929..843108c 100644
--- a/Makefile
+++ b/Makefile
@@ -129,7 +129,7 @@ $(foreach v,$(UBI_BINS),$(eval $(call mkdep,ubi-utils/,$(v),libubi.a ubiutils-co
 #
 # Utils in ubifs-utils subdir
 #
-obj-mkfs.ubifs = crc16.o lpt.o compr.o devtable.o \
+obj-mkfs.ubifs = crc16.o lpt.o compr.o devtable.o io.o\
 	hashtable/hashtable.o hashtable/hashtable_itr.o
 LDFLAGS_mkfs.ubifs = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
 LDLIBS_mkfs.ubifs = -lz -llzo2 -lm -luuid
diff --git a/ubifs-utils/mkfs.ubifs/io.c b/ubifs-utils/mkfs.ubifs/io.c
new file mode 100644
index 0000000..7aba0a6
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/io.c
@@ -0,0 +1,33 @@
+#include "io.h"
+#define PROGRAM_NAME "ubifs-io"
+#include <common.h>
+
+int out_fd;
+int out_ubi;
+libubi_t ubi;
+
+/**
+ * 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(struct ubifs_info *c, 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;
+}
diff --git a/ubifs-utils/mkfs.ubifs/io.h b/ubifs-utils/mkfs.ubifs/io.h
new file mode 100644
index 0000000..e24d0c6
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/io.h
@@ -0,0 +1,15 @@
+/**
+ * Header file for the io to ubi volume
+ */
+#ifndef __UBIFS_IO_H__
+#define __UBIFS_IO_H__
+
+#include "ubifs_common.h"
+#include "ubifs.h"
+
+extern int out_fd;
+extern int out_ubi;
+extern libubi_t ubi;
+
+int write_leb(struct ubifs_info *c, int lnum, int len, void *buf);
+#endif
diff --git a/ubifs-utils/mkfs.ubifs/lpt.c b/ubifs-utils/mkfs.ubifs/lpt.c
index 6aa0b88..cee221c 100644
--- a/ubifs-utils/mkfs.ubifs/lpt.c
+++ b/ubifs-utils/mkfs.ubifs/lpt.c
@@ -410,7 +410,7 @@ int create_lpt(struct ubifs_info *c)
 			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);
+			err = write_leb(c, lnum++, alen, buf);
 			if (err)
 				goto out;
 			p = buf;
@@ -452,7 +452,7 @@ int create_lpt(struct ubifs_info *c)
 				set_ltab(c, lnum, c->leb_size - alen,
 					    alen - len);
 				memset(p, 0xff, alen - len);
-				err = write_leb(lnum++, alen, buf);
+				err = write_leb(c, lnum++, alen, buf);
 				if (err)
 					goto out;
 				p = buf;
@@ -499,7 +499,7 @@ int create_lpt(struct ubifs_info *c)
 			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);
+			err = write_leb(c, lnum++, alen, buf);
 			if (err)
 				goto out;
 			p = buf;
@@ -522,7 +522,7 @@ int create_lpt(struct ubifs_info *c)
 		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);
+		err = write_leb(c, lnum++, alen, buf);
 		if (err)
 			goto out;
 		p = buf;
@@ -542,7 +542,7 @@ int create_lpt(struct ubifs_info *c)
 
 	/* Write remaining buffer */
 	memset(p, 0xff, alen - len);
-	err = write_leb(lnum, alen, buf);
+	err = write_leb(c, lnum, alen, buf);
 	if (err)
 		goto out;
 
diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
index ca17e2b..8e7e4b8 100644
--- a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
@@ -97,7 +97,6 @@ struct inum_mapping {
  */
 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;
@@ -108,8 +107,6 @@ 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 */
@@ -739,31 +736,6 @@ static void prepare_node(void *node, int len)
 	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.
@@ -771,7 +743,7 @@ int write_leb(int lnum, int len, void *buf)
  */
 static int write_empty_leb(int lnum)
 {
-	return write_leb(lnum, 0, leb_buf);
+	return write_leb(c, lnum, 0, leb_buf);
 }
 
 /**
@@ -827,7 +799,7 @@ static int write_node(void *node, int len, int lnum)
 
 	len = do_pad(leb_buf, len);
 
-	return write_leb(lnum, len, leb_buf);
+	return write_leb(c, lnum, len, leb_buf);
 }
 
 /**
@@ -939,7 +911,7 @@ static int flush_nodes(void)
 	if (!head_offs)
 		return 0;
 	len = do_pad(leb_buf, head_offs);
-	err = write_leb(head_lnum, len, leb_buf);
+	err = write_leb(c, head_lnum, len, leb_buf);
 	if (err)
 		return err;
 	set_lprops(head_lnum, head_offs, head_flags);
diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
index d6d46a2..ba646a6 100644
--- a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
@@ -34,6 +34,7 @@
 #include "key.h"
 #include "lpt.h"
 #include "compr.h"
+#include "io.h"
 
 /*
  * Compression flags are duplicated so that compr.c can compile without ubifs.h.
@@ -88,7 +89,6 @@ 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,
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 04/27] ubifs: remove the including of mkfs.ubifs.h in lpt.c
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (2 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 03/27] ubifs: move the all io related code into io.[h|c] Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 05/27] ubifs: cut off the dependence from compr.o to mkfs.ubifs Dongsheng Yang
                   ` (23 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

As we have a ubifs_common.h and a seperate io lib, then
remove the including of mkfs.ubifs.h in lpt.c

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/mkfs.ubifs/lpt.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/ubifs-utils/mkfs.ubifs/lpt.c b/ubifs-utils/mkfs.ubifs/lpt.c
index cee221c..100d747 100644
--- a/ubifs-utils/mkfs.ubifs/lpt.c
+++ b/ubifs-utils/mkfs.ubifs/lpt.c
@@ -20,7 +20,16 @@
  *          Artem Bityutskiy
  */
 
-#include "mkfs.ubifs.h"
+#include "ubifs_common.h"
+
+/* common.h requires the PROGRAM_NAME macro */
+#define PROGRAM_NAME "ubifs-lpt"
+#include "common.h"
+
+#include "crc16.h"
+#include "ubifs.h"
+#include "lpt.h"
+#include "io.h"
 
 /**
  * do_calc_lpt_geom - calculate sizes for the LPT area.
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 05/27] ubifs: cut off the dependence from compr.o to mkfs.ubifs
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (3 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 04/27] ubifs: remove the including of mkfs.ubifs.h in lpt.c Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 06/27] ubifs: cut off the dependence from devtable to mkfs.ubifs.h Dongsheng Yang
                   ` (22 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

remove the including of mkfs.ubifs.h in compr lib and
drop the reference of globle variable info_ from compr to mkfs.ubifs.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/mkfs.ubifs/compr.c      | 20 +++++++-------------
 ubifs-utils/mkfs.ubifs/compr.h      |  3 +--
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.c |  8 ++++++--
 3 files changed, 14 insertions(+), 17 deletions(-)

diff --git a/ubifs-utils/mkfs.ubifs/compr.c b/ubifs-utils/mkfs.ubifs/compr.c
index 34b2f60..35cc447 100644
--- a/ubifs-utils/mkfs.ubifs/compr.c
+++ b/ubifs-utils/mkfs.ubifs/compr.c
@@ -20,23 +20,17 @@
  *          Zoltan Sogor
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
+#include "ubifs_common.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
@@ -114,7 +108,7 @@ static int no_compress(void *in_buf, size_t in_len, void *out_buf,
 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)
+				size_t *out_len, int *type, int lzo_percent)
 {
 	int lzo_ret, zlib_ret;
 	size_t lzo_len, zlib_len;
@@ -136,7 +130,7 @@ static int favor_lzo_compress(void *in_buf, size_t in_len, void *out_buf,
 
 		percent = (double)zlib_len / (double)lzo_len;
 		percent *= 100;
-		if (percent > 100 - c->favor_percent)
+		if (percent > 100 - lzo_percent)
 			goto select_lzo;
 		goto select_zlib;
 	}
@@ -159,8 +153,8 @@ select_zlib:
 	return 0;
 }
 
-int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len,
-		  int type)
+int compress_data(void *in_buf, size_t in_len, void *out_buf,
+		size_t *out_len, int type, int lzo_percent)
 {
 	int ret;
 
@@ -169,8 +163,8 @@ int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len,
 		return MKFS_UBIFS_COMPR_NONE;
 	}
 
-	if (c->favor_lzo)
-		ret = favor_lzo_compress(in_buf, in_len, out_buf, out_len, &type);
+	if (lzo_percent)
+		ret = favor_lzo_compress(in_buf, in_len, out_buf, out_len, &type, lzo_percent);
 	else {
 		switch (type) {
 		case MKFS_UBIFS_COMPR_LZO:
diff --git a/ubifs-utils/mkfs.ubifs/compr.h b/ubifs-utils/mkfs.ubifs/compr.h
index e3dd95c..d44a2ba 100644
--- a/ubifs-utils/mkfs.ubifs/compr.h
+++ b/ubifs-utils/mkfs.ubifs/compr.h
@@ -38,8 +38,7 @@ enum compression_type
 	MKFS_UBIFS_COMPR_ZLIB,
 };
 
-int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len,
-		  int type);
+int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len, int type, int lzo_percent);
 int init_compression(void);
 void destroy_compression(void);
 
diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
index 8e7e4b8..9795282 100644
--- a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
@@ -1251,8 +1251,12 @@ static int add_file(const char *path_name, struct stat *st, ino_t inum,
 			use_compr = UBIFS_COMPR_LZO;
 		else
 			use_compr = c->default_compr;
-		compr_type = compress_data(buf, bytes_read, &dn->data,
-					   &out_len, use_compr);
+		if (c->favor_lzo)
+			compr_type = compress_data(buf, bytes_read, &dn->data,
+					   &out_len, use_compr, c->favor_percent);
+		else
+			compr_type = compress_data(buf, bytes_read, &dn->data,
+					   &out_len, use_compr, 0);
 		dn->compr_type = cpu_to_le16(compr_type);
 		dn_len = UBIFS_DATA_NODE_SZ + out_len;
 		/* Add data node to file system */
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 06/27] ubifs: cut off the dependence from devtable to mkfs.ubifs.h
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (4 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 05/27] ubifs: cut off the dependence from compr.o to mkfs.ubifs Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 07/27] ubifs: introduce ubifs-utils/include and ubifs-utils/lib Dongsheng Yang
                   ` (21 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Refactor the devtable related definitions in mkfs.ubifs.h
to a new devtable.h

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/mkfs.ubifs/devtable.c   |  3 +-
 ubifs-utils/mkfs.ubifs/devtable.h   | 55 +++++++++++++++++++++++++++++++++++++
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.h | 54 +-----------------------------------
 3 files changed, 58 insertions(+), 54 deletions(-)
 create mode 100644 ubifs-utils/mkfs.ubifs/devtable.h

diff --git a/ubifs-utils/mkfs.ubifs/devtable.c b/ubifs-utils/mkfs.ubifs/devtable.c
index dee035d..1fc0256 100644
--- a/ubifs-utils/mkfs.ubifs/devtable.c
+++ b/ubifs-utils/mkfs.ubifs/devtable.c
@@ -44,7 +44,8 @@
  * for more information about what the device table is.
  */
 
-#include "mkfs.ubifs.h"
+#include "ubifs_common.h"
+#include "devtable.h"
 #include "hashtable/hashtable.h"
 #include "hashtable/hashtable_itr.h"
 
diff --git a/ubifs-utils/mkfs.ubifs/devtable.h b/ubifs-utils/mkfs.ubifs/devtable.h
new file mode 100644
index 0000000..987d4d4
--- /dev/null
+++ b/ubifs-utils/mkfs.ubifs/devtable.h
@@ -0,0 +1,55 @@
+#include "ubifs_common.h"
+
+/**
+ * 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 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);
+
diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
index ba646a6..1963e12 100644
--- a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
@@ -34,6 +34,7 @@
 #include "key.h"
 #include "lpt.h"
 #include "compr.h"
+#include "devtable.h"
 #include "io.h"
 
 /*
@@ -50,57 +51,4 @@
 #error MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB
 #endif
 
-/**
- * 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 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
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 07/27] ubifs: introduce ubifs-utils/include and ubifs-utils/lib
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (5 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 06/27] ubifs: cut off the dependence from devtable to mkfs.ubifs.h Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 08/27] ubifs: move more functions into io lib Dongsheng Yang
                   ` (20 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Restructure the ubifs-utils/, introducing ubifs-utils/include
and ubifs-utils/lib to make the ubifs-utils/ better for scalability.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 Makefile                                           |   7 +-
 ubifs-utils/COPYING                                | 340 ++++++++++++
 ubifs-utils/README                                 |   9 +
 ubifs-utils/include/compr.h                        |  45 ++
 ubifs-utils/include/crc16.h                        |  27 +
 ubifs-utils/include/defs.h                         |  92 ++++
 ubifs-utils/include/devtable.h                     |  55 ++
 ubifs-utils/include/hashtable.h                    | 199 +++++++
 ubifs-utils/include/hashtable_itr.h                | 112 ++++
 ubifs-utils/include/hashtable_private.h            |  85 +++
 ubifs-utils/include/io.h                           |  15 +
 ubifs-utils/include/key.h                          | 189 +++++++
 ubifs-utils/include/lpt.h                          |  28 +
 ubifs-utils/include/ubifs.h                        | 441 ++++++++++++++++
 ubifs-utils/include/ubifs_common.h                 |  50 ++
 ubifs-utils/lib/compr.c                            | 213 ++++++++
 ubifs-utils/lib/crc16.c                            |  56 ++
 ubifs-utils/lib/devtable.c                         | 525 ++++++++++++++++++
 ubifs-utils/lib/hashtable.c                        | 277 ++++++++++
 ubifs-utils/lib/hashtable_itr.c                    | 176 ++++++
 ubifs-utils/lib/io.c                               |  33 ++
 ubifs-utils/lib/lpt.c                              | 587 +++++++++++++++++++++
 ubifs-utils/mkfs.ubifs/COPYING                     | 340 ------------
 ubifs-utils/mkfs.ubifs/README                      |   9 -
 ubifs-utils/mkfs.ubifs/compr.c                     | 213 --------
 ubifs-utils/mkfs.ubifs/compr.h                     |  45 --
 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                  | 525 ------------------
 ubifs-utils/mkfs.ubifs/devtable.h                  |  55 --
 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/io.c                        |  33 --
 ubifs-utils/mkfs.ubifs/io.h                        |  15 -
 ubifs-utils/mkfs.ubifs/key.h                       | 189 -------
 ubifs-utils/mkfs.ubifs/lpt.c                       | 587 ---------------------
 ubifs-utils/mkfs.ubifs/lpt.h                       |  28 -
 ubifs-utils/mkfs.ubifs/ubifs.h                     | 441 ----------------
 ubifs-utils/mkfs.ubifs/ubifs_common.h              |  50 --
 43 files changed, 3558 insertions(+), 3557 deletions(-)
 create mode 100644 ubifs-utils/COPYING
 create mode 100644 ubifs-utils/README
 create mode 100644 ubifs-utils/include/compr.h
 create mode 100644 ubifs-utils/include/crc16.h
 create mode 100644 ubifs-utils/include/defs.h
 create mode 100644 ubifs-utils/include/devtable.h
 create mode 100644 ubifs-utils/include/hashtable.h
 create mode 100644 ubifs-utils/include/hashtable_itr.h
 create mode 100644 ubifs-utils/include/hashtable_private.h
 create mode 100644 ubifs-utils/include/io.h
 create mode 100644 ubifs-utils/include/key.h
 create mode 100644 ubifs-utils/include/lpt.h
 create mode 100644 ubifs-utils/include/ubifs.h
 create mode 100644 ubifs-utils/include/ubifs_common.h
 create mode 100644 ubifs-utils/lib/compr.c
 create mode 100644 ubifs-utils/lib/crc16.c
 create mode 100644 ubifs-utils/lib/devtable.c
 create mode 100644 ubifs-utils/lib/hashtable.c
 create mode 100644 ubifs-utils/lib/hashtable_itr.c
 create mode 100644 ubifs-utils/lib/io.c
 create mode 100644 ubifs-utils/lib/lpt.c
 delete mode 100644 ubifs-utils/mkfs.ubifs/COPYING
 delete mode 100644 ubifs-utils/mkfs.ubifs/README
 delete mode 100644 ubifs-utils/mkfs.ubifs/compr.c
 delete mode 100644 ubifs-utils/mkfs.ubifs/compr.h
 delete mode 100644 ubifs-utils/mkfs.ubifs/crc16.c
 delete mode 100644 ubifs-utils/mkfs.ubifs/crc16.h
 delete mode 100644 ubifs-utils/mkfs.ubifs/defs.h
 delete mode 100644 ubifs-utils/mkfs.ubifs/devtable.c
 delete mode 100644 ubifs-utils/mkfs.ubifs/devtable.h
 delete mode 100644 ubifs-utils/mkfs.ubifs/hashtable/hashtable.c
 delete mode 100644 ubifs-utils/mkfs.ubifs/hashtable/hashtable.h
 delete mode 100644 ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.c
 delete mode 100644 ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.h
 delete mode 100644 ubifs-utils/mkfs.ubifs/hashtable/hashtable_private.h
 delete mode 100644 ubifs-utils/mkfs.ubifs/io.c
 delete mode 100644 ubifs-utils/mkfs.ubifs/io.h
 delete mode 100644 ubifs-utils/mkfs.ubifs/key.h
 delete mode 100644 ubifs-utils/mkfs.ubifs/lpt.c
 delete mode 100644 ubifs-utils/mkfs.ubifs/lpt.h
 delete mode 100644 ubifs-utils/mkfs.ubifs/ubifs.h
 delete mode 100644 ubifs-utils/mkfs.ubifs/ubifs_common.h

diff --git a/Makefile b/Makefile
index 843108c..ae02aac 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 
 VERSION = 1.5.1
 
-CPPFLAGS += -D_GNU_SOURCE -I./include -I$(BUILDDIR)/include -I./ubi-utils/include $(ZLIBCPPFLAGS) $(LZOCPPFLAGS) $(UUIDCPPFLAGS)
+CPPFLAGS += -D_GNU_SOURCE -I./include -I$(BUILDDIR)/include -I./ubi-utils/include -I./ubifs-utils/include $(ZLIBCPPFLAGS) $(LZOCPPFLAGS) $(UUIDCPPFLAGS)
 
 ifeq ($(WITHOUT_XATTR), 1)
   CPPFLAGS += -DWITHOUT_XATTR
@@ -129,8 +129,9 @@ $(foreach v,$(UBI_BINS),$(eval $(call mkdep,ubi-utils/,$(v),libubi.a ubiutils-co
 #
 # Utils in ubifs-utils subdir
 #
-obj-mkfs.ubifs = crc16.o lpt.o compr.o devtable.o io.o\
-	hashtable/hashtable.o hashtable/hashtable_itr.o
+$(foreach v,crc16.o lpt.o compr.o devtable.o io.o hashtable.o hashtable_itr.o,$(eval UBIFS_LIBS += ../lib/$(v)))
+
+obj-mkfs.ubifs = $(UBIFS_LIBS)
 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/ubifs-utils/COPYING b/ubifs-utils/COPYING
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/ubifs-utils/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.
+\f
+		    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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+	    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/README b/ubifs-utils/README
new file mode 100644
index 0000000..7e19939
--- /dev/null
+++ b/ubifs-utils/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/include/compr.h b/ubifs-utils/include/compr.h
new file mode 100644
index 0000000..d44a2ba
--- /dev/null
+++ b/ubifs-utils/include/compr.h
@@ -0,0 +1,45 @@
+/*
+ * 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 lzo_percent);
+int init_compression(void);
+void destroy_compression(void);
+
+#endif
diff --git a/ubifs-utils/include/crc16.h b/ubifs-utils/include/crc16.h
new file mode 100644
index 0000000..539d21a
--- /dev/null
+++ b/ubifs-utils/include/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@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/include/defs.h b/ubifs-utils/include/defs.h
new file mode 100644
index 0000000..1fa3316
--- /dev/null
+++ b/ubifs-utils/include/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/include/devtable.h b/ubifs-utils/include/devtable.h
new file mode 100644
index 0000000..987d4d4
--- /dev/null
+++ b/ubifs-utils/include/devtable.h
@@ -0,0 +1,55 @@
+#include "ubifs_common.h"
+
+/**
+ * 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 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);
+
diff --git a/ubifs-utils/include/hashtable.h b/ubifs-utils/include/hashtable.h
new file mode 100644
index 0000000..c0b0acd
--- /dev/null
+++ b/ubifs-utils/include/hashtable.h
@@ -0,0 +1,199 @@
+/* Copyright (C) 2002 Christopher Clark <firstname.lastname@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/include/hashtable_itr.h b/ubifs-utils/include/hashtable_itr.h
new file mode 100644
index 0000000..5c94a04
--- /dev/null
+++ b/ubifs-utils/include/hashtable_itr.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@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/include/hashtable_private.h b/ubifs-utils/include/hashtable_private.h
new file mode 100644
index 0000000..3a558e6
--- /dev/null
+++ b/ubifs-utils/include/hashtable_private.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@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/include/io.h b/ubifs-utils/include/io.h
new file mode 100644
index 0000000..e24d0c6
--- /dev/null
+++ b/ubifs-utils/include/io.h
@@ -0,0 +1,15 @@
+/**
+ * Header file for the io to ubi volume
+ */
+#ifndef __UBIFS_IO_H__
+#define __UBIFS_IO_H__
+
+#include "ubifs_common.h"
+#include "ubifs.h"
+
+extern int out_fd;
+extern int out_ubi;
+extern libubi_t ubi;
+
+int write_leb(struct ubifs_info *c, int lnum, int len, void *buf);
+#endif
diff --git a/ubifs-utils/include/key.h b/ubifs-utils/include/key.h
new file mode 100644
index 0000000..d3a02d4
--- /dev/null
+++ b/ubifs-utils/include/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/include/lpt.h b/ubifs-utils/include/lpt.h
new file mode 100644
index 0000000..4cde59d
--- /dev/null
+++ b/ubifs-utils/include/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/include/ubifs.h b/ubifs-utils/include/ubifs.h
new file mode 100644
index 0000000..434b651
--- /dev/null
+++ b/ubifs-utils/include/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__ */
diff --git a/ubifs-utils/include/ubifs_common.h b/ubifs-utils/include/ubifs_common.h
new file mode 100644
index 0000000..958c20a
--- /dev/null
+++ b/ubifs-utils/include/ubifs_common.h
@@ -0,0 +1,50 @@
+#ifndef __UBIFS_COMMON_H__
+#define __UBIFS_COMMON_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>
+
+#include "libubi.h"
+#include "defs.h"
+
+extern int verbose;
+extern int debug_level;
+
+#define dbg_msg(lvl, fmt, ...) do {if (debug_level >= lvl)                \
+	printf("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;                                                              \
+})
+#endif
diff --git a/ubifs-utils/lib/compr.c b/ubifs-utils/lib/compr.c
new file mode 100644
index 0000000..35cc447
--- /dev/null
+++ b/ubifs-utils/lib/compr.c
@@ -0,0 +1,213 @@
+/*
+ * 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 "ubifs_common.h"
+#include <lzo/lzo1x.h>
+
+#define crc32 __zlib_crc32
+#include <zlib.h>
+#undef crc32
+
+#include "compr.h"
+
+static void *lzo_mem;
+static unsigned long long errcnt = 0;
+
+#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_percent)
+{
+	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 - lzo_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 lzo_percent)
+{
+	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 (lzo_percent)
+		ret = favor_lzo_compress(in_buf, in_len, out_buf, out_len, &type, lzo_percent);
+	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/lib/crc16.c b/ubifs-utils/lib/crc16.c
new file mode 100644
index 0000000..a19512e
--- /dev/null
+++ b/ubifs-utils/lib/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/lib/devtable.c b/ubifs-utils/lib/devtable.c
new file mode 100644
index 0000000..e6ec319
--- /dev/null
+++ b/ubifs-utils/lib/devtable.c
@@ -0,0 +1,525 @@
+/*
+ * 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@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 "ubifs_common.h"
+#include "devtable.h"
+#include "hashtable.h"
+#include "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/lib/hashtable.c b/ubifs-utils/lib/hashtable.c
new file mode 100644
index 0000000..c1f99ed
--- /dev/null
+++ b/ubifs-utils/lib/hashtable.c
@@ -0,0 +1,277 @@
+/* Copyright (C) 2004 Christopher Clark <firstname.lastname@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/lib/hashtable_itr.c b/ubifs-utils/lib/hashtable_itr.c
new file mode 100644
index 0000000..d102453
--- /dev/null
+++ b/ubifs-utils/lib/hashtable_itr.c
@@ -0,0 +1,176 @@
+/* Copyright (C) 2002, 2004 Christopher Clark  <firstname.lastname@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/lib/io.c b/ubifs-utils/lib/io.c
new file mode 100644
index 0000000..7aba0a6
--- /dev/null
+++ b/ubifs-utils/lib/io.c
@@ -0,0 +1,33 @@
+#include "io.h"
+#define PROGRAM_NAME "ubifs-io"
+#include <common.h>
+
+int out_fd;
+int out_ubi;
+libubi_t ubi;
+
+/**
+ * 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(struct ubifs_info *c, 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;
+}
diff --git a/ubifs-utils/lib/lpt.c b/ubifs-utils/lib/lpt.c
new file mode 100644
index 0000000..100d747
--- /dev/null
+++ b/ubifs-utils/lib/lpt.c
@@ -0,0 +1,587 @@
+/*
+ * 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 "ubifs_common.h"
+
+/* common.h requires the PROGRAM_NAME macro */
+#define PROGRAM_NAME "ubifs-lpt"
+#include "common.h"
+
+#include "crc16.h"
+#include "ubifs.h"
+#include "lpt.h"
+#include "io.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(c, 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(c, 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(c, 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(c, 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(c, 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/COPYING b/ubifs-utils/mkfs.ubifs/COPYING
deleted file mode 100644
index 60549be..0000000
--- a/ubifs-utils/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.
-\f
-		    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.)
-\f
-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.
-\f
-  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.
-\f
-  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
-\f
-	    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
deleted file mode 100644
index 7e19939..0000000
--- a/ubifs-utils/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/ubifs-utils/mkfs.ubifs/compr.c b/ubifs-utils/mkfs.ubifs/compr.c
deleted file mode 100644
index 35cc447..0000000
--- a/ubifs-utils/mkfs.ubifs/compr.c
+++ /dev/null
@@ -1,213 +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 "ubifs_common.h"
-#include <lzo/lzo1x.h>
-
-#define crc32 __zlib_crc32
-#include <zlib.h>
-#undef crc32
-
-#include "compr.h"
-
-static void *lzo_mem;
-static unsigned long long errcnt = 0;
-
-#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_percent)
-{
-	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 - lzo_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 lzo_percent)
-{
-	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 (lzo_percent)
-		ret = favor_lzo_compress(in_buf, in_len, out_buf, out_len, &type, lzo_percent);
-	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
deleted file mode 100644
index d44a2ba..0000000
--- a/ubifs-utils/mkfs.ubifs/compr.h
+++ /dev/null
@@ -1,45 +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 lzo_percent);
-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
deleted file mode 100644
index a19512e..0000000
--- a/ubifs-utils/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/ubifs-utils/mkfs.ubifs/crc16.h b/ubifs-utils/mkfs.ubifs/crc16.h
deleted file mode 100644
index 539d21a..0000000
--- a/ubifs-utils/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@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
deleted file mode 100644
index 1fa3316..0000000
--- a/ubifs-utils/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/ubifs-utils/mkfs.ubifs/devtable.c b/ubifs-utils/mkfs.ubifs/devtable.c
deleted file mode 100644
index 1fc0256..0000000
--- a/ubifs-utils/mkfs.ubifs/devtable.c
+++ /dev/null
@@ -1,525 +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@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 "ubifs_common.h"
-#include "devtable.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/devtable.h b/ubifs-utils/mkfs.ubifs/devtable.h
deleted file mode 100644
index 987d4d4..0000000
--- a/ubifs-utils/mkfs.ubifs/devtable.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#include "ubifs_common.h"
-
-/**
- * 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 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);
-
diff --git a/ubifs-utils/mkfs.ubifs/hashtable/hashtable.c b/ubifs-utils/mkfs.ubifs/hashtable/hashtable.c
deleted file mode 100644
index c1f99ed..0000000
--- a/ubifs-utils/mkfs.ubifs/hashtable/hashtable.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/* Copyright (C) 2004 Christopher Clark <firstname.lastname@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
deleted file mode 100644
index c0b0acd..0000000
--- a/ubifs-utils/mkfs.ubifs/hashtable/hashtable.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/* Copyright (C) 2002 Christopher Clark <firstname.lastname@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
deleted file mode 100644
index d102453..0000000
--- a/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/* Copyright (C) 2002, 2004 Christopher Clark  <firstname.lastname@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
deleted file mode 100644
index 5c94a04..0000000
--- a/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@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
deleted file mode 100644
index 3a558e6..0000000
--- a/ubifs-utils/mkfs.ubifs/hashtable/hashtable_private.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@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/io.c b/ubifs-utils/mkfs.ubifs/io.c
deleted file mode 100644
index 7aba0a6..0000000
--- a/ubifs-utils/mkfs.ubifs/io.c
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "io.h"
-#define PROGRAM_NAME "ubifs-io"
-#include <common.h>
-
-int out_fd;
-int out_ubi;
-libubi_t ubi;
-
-/**
- * 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(struct ubifs_info *c, 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;
-}
diff --git a/ubifs-utils/mkfs.ubifs/io.h b/ubifs-utils/mkfs.ubifs/io.h
deleted file mode 100644
index e24d0c6..0000000
--- a/ubifs-utils/mkfs.ubifs/io.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Header file for the io to ubi volume
- */
-#ifndef __UBIFS_IO_H__
-#define __UBIFS_IO_H__
-
-#include "ubifs_common.h"
-#include "ubifs.h"
-
-extern int out_fd;
-extern int out_ubi;
-extern libubi_t ubi;
-
-int write_leb(struct ubifs_info *c, int lnum, int len, void *buf);
-#endif
diff --git a/ubifs-utils/mkfs.ubifs/key.h b/ubifs-utils/mkfs.ubifs/key.h
deleted file mode 100644
index d3a02d4..0000000
--- a/ubifs-utils/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/ubifs-utils/mkfs.ubifs/lpt.c b/ubifs-utils/mkfs.ubifs/lpt.c
deleted file mode 100644
index 100d747..0000000
--- a/ubifs-utils/mkfs.ubifs/lpt.c
+++ /dev/null
@@ -1,587 +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 "ubifs_common.h"
-
-/* common.h requires the PROGRAM_NAME macro */
-#define PROGRAM_NAME "ubifs-lpt"
-#include "common.h"
-
-#include "crc16.h"
-#include "ubifs.h"
-#include "lpt.h"
-#include "io.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(c, 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(c, 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(c, 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(c, 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(c, 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
deleted file mode 100644
index 4cde59d..0000000
--- a/ubifs-utils/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/ubifs-utils/mkfs.ubifs/ubifs.h b/ubifs-utils/mkfs.ubifs/ubifs.h
deleted file mode 100644
index 434b651..0000000
--- a/ubifs-utils/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/ubifs-utils/mkfs.ubifs/ubifs_common.h b/ubifs-utils/mkfs.ubifs/ubifs_common.h
deleted file mode 100644
index 958c20a..0000000
--- a/ubifs-utils/mkfs.ubifs/ubifs_common.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef __UBIFS_COMMON_H__
-#define __UBIFS_COMMON_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>
-
-#include "libubi.h"
-#include "defs.h"
-
-extern int verbose;
-extern int debug_level;
-
-#define dbg_msg(lvl, fmt, ...) do {if (debug_level >= lvl)                \
-	printf("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;                                                              \
-})
-#endif
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 08/27] ubifs: move more functions into io lib
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (6 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 07/27] ubifs: introduce ubifs-utils/include and ubifs-utils/lib Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 09/27] ubifs: introduce a new tool ubifs_dump Dongsheng Yang
                   ` (19 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Move some common functions in mkfs.ubifs.c to io.c
to let others can use them.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/io.h            |   4 ++
 ubifs-utils/lib/io.c                | 101 +++++++++++++++++++++++++++++++++++
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.c | 102 +-----------------------------------
 3 files changed, 107 insertions(+), 100 deletions(-)

diff --git a/ubifs-utils/include/io.h b/ubifs-utils/include/io.h
index e24d0c6..920645d 100644
--- a/ubifs-utils/include/io.h
+++ b/ubifs-utils/include/io.h
@@ -10,6 +10,10 @@
 extern int out_fd;
 extern int out_ubi;
 extern libubi_t ubi;
+extern char *output;
 
 int write_leb(struct ubifs_info *c, int lnum, int len, void *buf);
+int close_target(void);
+int open_target(struct ubifs_info *c, int yes);
+int open_ubi(struct ubifs_info *c, const char *node);
 #endif
diff --git a/ubifs-utils/lib/io.c b/ubifs-utils/lib/io.c
index 7aba0a6..9817d2a 100644
--- a/ubifs-utils/lib/io.c
+++ b/ubifs-utils/lib/io.c
@@ -5,6 +5,107 @@
 int out_fd;
 int out_ubi;
 libubi_t ubi;
+char *output;
+
+/**
+ * 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(struct ubifs_info *c)
+{
+	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_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
+ */
+int open_ubi(struct ubifs_info *c, 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;
+}
+
+/**
+ * open_target - open the output target.
+ * @yes: always ansure yes
+ *
+ * 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.
+ */
+int open_target(struct ubifs_info *c, int yes)
+{
+	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(c)) {
+			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.
+ */
+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;
+}
+
 
 /**
  * write_leb - copy the image of a LEB to the output target.
diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
index 9795282..b19646f 100644
--- a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
@@ -106,7 +106,6 @@ int yes;
 static char *root;
 static int root_len;
 static struct stat root_st;
-static char *output;
 static int squash_owner;
 
 /* The 'head' (position) which nodes are written */
@@ -446,28 +445,6 @@ static long long get_bytes(const char *str)
 
 	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)
 {
@@ -629,7 +606,7 @@ static int get_options(int argc, char**argv)
 	if (!output)
 		return err_msg("not output device or file specified");
 
-	out_ubi = !open_ubi(output);
+	out_ubi = !open_ubi(c, output);
 
 	if (out_ubi) {
 		c->min_io_size = c->di.min_io_size;
@@ -2038,81 +2015,6 @@ static int write_orphan_area(void)
 	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.
@@ -2279,7 +2181,7 @@ int main(int argc, char *argv[])
 	if (err)
 		return err;
 
-	err = open_target();
+	err = open_target(c, yes);
 	if (err)
 		return err;
 
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 09/27] ubifs: introduce a new tool ubifs_dump
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (7 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 08/27] ubifs: move more functions into io lib Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 10/27] ubifs: introduce list.h Dongsheng Yang
                   ` (18 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Init a new tool named as ubifs_dump

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 Makefile                            |  8 ++++-
 ubifs-utils/ubifs_dump/ubifs_dump.c | 68 +++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 1 deletion(-)
 create mode 100644 ubifs-utils/ubifs_dump/ubifs_dump.c

diff --git a/Makefile b/Makefile
index ae02aac..cad71dc 100644
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,8 @@ UBI_BINS = \
 	ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \
 	ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock
 UBIFS_BINS = \
-	mkfs.ubifs/mkfs.ubifs
+	mkfs.ubifs/mkfs.ubifs \
+	ubifs_dump/ubifs_dump
 JFFSX_BINS = \
 	mkfs.jffs2 sumtool jffs2reader jffs2dump
 FLASH_BINS = \
@@ -131,6 +132,11 @@ $(foreach v,$(UBI_BINS),$(eval $(call mkdep,ubi-utils/,$(v),libubi.a ubiutils-co
 #
 $(foreach v,crc16.o lpt.o compr.o devtable.o io.o hashtable.o hashtable_itr.o,$(eval UBIFS_LIBS += ../lib/$(v)))
 
+obj-ubifs_dump = $(UBIFS_LIBS)
+LDFLAGS_ubifs_dump = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
+LDLIBS_ubifs_dump = -lz -llzo2 -lm -luuid
+$(call mkdep,ubifs-utils/ubifs_dump/,ubifs_dump,,ubi-utils/libubi.a)
+
 obj-mkfs.ubifs = $(UBIFS_LIBS)
 LDFLAGS_mkfs.ubifs = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
 LDLIBS_mkfs.ubifs = -lz -llzo2 -lm -luuid
diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
new file mode 100644
index 0000000..bbe1269
--- /dev/null
+++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
@@ -0,0 +1,68 @@
+#include "ubifs_common.h"
+#define PROGRAM_NAME "ubifs-dump"
+#include "common.h"
+#include "io.h"
+
+static const char *optstring = "";
+
+static const struct option longopts[] = {
+	{NULL, 0, NULL, 0}
+};
+
+struct ubifs_info info_;
+static struct ubifs_info *c = &info_;
+
+static int get_options(int argc, char**argv)
+{
+	int opt, i;
+
+	while (1) {
+		opt = getopt_long(argc, argv, optstring, longopts, &i);
+		if (opt == -1)
+			break;
+		switch (opt) {
+		default:
+			break;
+		}
+	}
+
+	if (optind != argc && !output)
+		output = xstrdup(argv[optind]);
+
+	if (!output)
+		return err_msg("not output device or file specified");
+
+	if (open_ubi(c, output))
+		return err_msg("open ubi (%s) failed.", output);
+
+	return 0;
+}
+
+static int dump()
+{
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int err;
+
+	err = get_options(argc, argv);
+	if (err)
+		return err;
+	err = open_target(c, 1);
+	if (err)
+		return err;
+
+	err = dump();
+	if (err) {
+		close_target();
+		return err;
+	}
+
+	err = close_target();
+	if (err)
+		return err;
+
+	return 0;
+}
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 10/27] ubifs: introduce list.h
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (8 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 09/27] ubifs: introduce a new tool ubifs_dump Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 11/27] ubifs: copy some important data in ubifs.h from kernel to ubifs-utils Dongsheng Yang
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Copy the list.h from kernel to ubifs-utils/

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/list.h | 484 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 484 insertions(+)
 create mode 100644 ubifs-utils/include/list.h

diff --git a/ubifs-utils/include/list.h b/ubifs-utils/include/list.h
new file mode 100644
index 0000000..0cffa33
--- /dev/null
+++ b/ubifs-utils/include/list.h
@@ -0,0 +1,484 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#define LIST_POISON1  ((struct list_head *) 0x00100100)
+#define LIST_POISON2  ((struct list_head *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+	list->next = list;
+	list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void __list_add(struct list_head *xnew,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = xnew;
+	xnew->next = next;
+	xnew->prev = prev;
+	prev->next = xnew;
+}
+#else
+extern void __list_add(struct list_head *xnew,
+			      struct list_head *prev,
+			      struct list_head *next);
+#endif
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void list_add(struct list_head *xnew, struct list_head *head)
+{
+	__list_add(xnew, head, head->next);
+}
+#else
+extern void list_add(struct list_head *xnew, struct list_head *head);
+#endif
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *xnew, struct list_head *head)
+{
+	__list_add(xnew, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = LIST_POISON1;
+	entry->prev = LIST_POISON2;
+}
+#else
+extern void list_del(struct list_head *entry);
+#endif
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ * Note: if 'old' was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+				struct list_head *xnew)
+{
+	xnew->next = old->next;
+	xnew->next->prev = xnew;
+	xnew->prev = old->prev;
+	xnew->prev->next = xnew;
+}
+
+static inline void list_replace_init(struct list_head *old,
+					struct list_head *xnew)
+{
+	list_replace(old, xnew);
+	INIT_LIST_HEAD(old);
+}
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+				  struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+				const struct list_head *head)
+{
+	return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+	return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+	struct list_head *next = head->next;
+	return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(const struct list_head *list,
+				 struct list_head *prev,
+				 struct list_head *next)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+
+	first->prev = prev;
+	prev->next = first;
+
+	last->next = next;
+	next->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head, head->next);
+}
+
+/**
+ * list_splice_tail - join two lists, each list being a queue
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice_tail(struct list_head *list,
+				struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head->prev, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head, head->next);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_splice_tail_init - join two lists and reinitialise the emptied list
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * Each of the lists is a queue.
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_tail_init(struct list_head *list,
+					 struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head->prev, head);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr:	the list head to take the element from.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+	list_entry((ptr)->next, type, member)
+
+/**
+ * list_next_entry - get the next element from a list
+ * @ptr:	the list head to take the element from.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Note, that next is expected to be not null.
+ */
+#define list_next_entry(ptr, member) \
+	list_entry((ptr)->member.next, typeof(*ptr), member)
+
+/**
+ * list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); \
+        	pos = pos->next)
+
+/**
+ * __list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev	-	iterate over a list backwards
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev; pos != (head); \
+        	pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#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))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)			\
+	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
+	     &pos->member != (head); 	\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
+ * @pos:	the type * to use as a start point
+ * @head:	the head of the list
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
+ */
+#define list_prepare_entry(pos, head, member) \
+	((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) 		\
+	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) 			\
+	for (; &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) 		\
+	for (pos = list_entry(pos->member.next, typeof(*pos), member), 		\
+		n = list_entry(pos->member.next, typeof(*pos), member);		\
+	     &pos->member != (head);						\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) 			\
+	for (n = list_entry(pos->member.next, typeof(*pos), member);		\
+	     &pos->member != (head);						\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member)		\
+	for (pos = list_entry((head)->prev, typeof(*pos), member),	\
+		n = list_entry(pos->member.prev, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+#endif
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 11/27] ubifs: copy some important data in ubifs.h from kernel to ubifs-utils
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (9 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 10/27] ubifs: introduce list.h Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 12/27] ubifs: copy some important functions in key.h " Dongsheng Yang
                   ` (16 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

There are some definitions in ubifs.h in kernel we need but
not in userspace currently. Then copy it here.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/ubifs.h | 96 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 91 insertions(+), 5 deletions(-)

diff --git a/ubifs-utils/include/ubifs.h b/ubifs-utils/include/ubifs.h
index 434b651..3696f1a 100644
--- a/ubifs-utils/include/ubifs.h
+++ b/ubifs-utils/include/ubifs.h
@@ -25,6 +25,10 @@
 #ifndef __UBIFS_H__
 #define __UBIFS_H__
 
+#include "defs.h"
+#include "list.h"
+#include "libubi.h"
+
 /* Maximum logical eraseblock size in bytes */
 #define UBIFS_MAX_LEB_SZ (2*1024*1024)
 
@@ -34,6 +38,7 @@
 /* Largest key size supported in this implementation */
 #define CUR_MAX_KEY_LEN UBIFS_SK_LEN
 
+#define NONDATA_JHEADS_CNT 2
 /*
  * 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"
@@ -41,6 +46,7 @@
  * %UBIFS_TRUN_KEY type.
  */
 #define UBIFS_TRUN_KEY UBIFS_KEY_TYPES_CNT
+#define UBIFS_INVALID_KEY UBIFS_KEY_TYPES_CNT
 
 /* The below union makes it easier to deal with keys */
 union ubifs_key
@@ -85,25 +91,34 @@ enum {
  * @free: amount of free space in bytes
  * @dirty: amount of dirty space in bytes
  * @flags: LEB properties flags (see above)
+ * @lnum: LEB number
+ * @list: list of same-category lprops (for LPROPS_EMPTY and LPROPS_FREEABLE)
+ * @hpos: heap position in heap of same-category lprops (other categories)
  */
-struct ubifs_lprops
-{
+struct ubifs_lprops {
 	int free;
 	int dirty;
 	int flags;
+	int lnum;
+	union {
+		struct list_head list;
+		int hpos;
+	};
 };
 
 /**
  * struct ubifs_lpt_lprops - LPT logical eraseblock properties.
  * @free: amount of free space in bytes
  * @dirty: amount of dirty space in bytes
+ * @tgc: trivial GC flag (1 => unmap after commit end)
+ * @cmt: commit flag (1 => reserved for commit)
  */
-struct ubifs_lpt_lprops
-{
+struct ubifs_lpt_lprops {
 	int free;
 	int dirty;
+	unsigned tgc:1;
+	unsigned cmt:1;
 };
-
 struct ubifs_nnode;
 
 /**
@@ -254,6 +269,12 @@ struct ubifs_znode
 	struct ubifs_zbranch zbranch[];
 };
 
+enum {
+	LPT_SCAN_CONTINUE = 0,
+	LPT_SCAN_ADD = 1,
+	LPT_SCAN_STOP = 2,
+};
+
 /**
  * struct ubifs_info - UBIFS file-system description data structure
  * (per-superblock).
@@ -392,6 +413,7 @@ struct ubifs_info
 	int pnode_cnt;
 	int nnode_cnt;
 	int lpt_hght;
+	void *lpt_nod_buf;
 
 	int lpt_lnum;
 	int lpt_offs;
@@ -411,8 +433,68 @@ struct ubifs_info
 	int *lsave;
 	int lscan_lnum;
 
+	struct ubifs_nnode *nroot;
+	struct ubifs_cnode *lpt_cnext;
+
+	int min_idx_node_sz;
+	int max_idx_node_sz;
+
+	int max_znode_sz;
+};
+/**
+ * struct ubifs_scan_node - UBIFS scanned node information.
+ * @list: list of scanned nodes
+ * @key: key of node scanned (if it has one)
+ * @sqnum: sequence number
+ * @type: type of node scanned
+ * @offs: offset with LEB of node scanned
+ * @len: length of node scanned
+ * @node: raw node
+ */
+struct ubifs_scan_node {
+	struct list_head list;
+	union ubifs_key key;
+	unsigned long long sqnum;
+	int type;
+	int offs;
+	int len;
+	void *node;
+};
+
+/**
+ * struct ubifs_scan_leb - UBIFS scanned LEB information.
+ * @lnum: logical eraseblock number
+ * @nodes_cnt: number of nodes scanned
+ * @nodes: list of struct ubifs_scan_node
+ * @endpt: end point (and therefore the start of empty space)
+ * @buf: buffer containing entire LEB scanned
+ */
+struct ubifs_scan_leb {
+	int lnum;
+	int nodes_cnt;
+	struct list_head nodes;
+	int endpt;
+	void *buf;
 };
 
+/*
+ * 'ubifs_scan_a_node()' return values.
+ *
+ * SCANNED_GARBAGE:  scanned garbage
+ * SCANNED_EMPTY_SPACE: scanned empty space
+ * SCANNED_A_NODE: scanned a valid node
+ * SCANNED_A_CORRUPT_NODE: scanned a corrupted node
+ * SCANNED_A_BAD_PAD_NODE: scanned a padding node with invalid pad length
+ *
+ * Greater than zero means: 'scanned that number of padding bytes'
+ */
+enum {
+	SCANNED_GARBAGE        = 0,
+	SCANNED_EMPTY_SPACE    = -1,
+	SCANNED_A_NODE         = -2,
+	SCANNED_A_CORRUPT_NODE = -3,
+	SCANNED_A_BAD_PAD_NODE = -4,
+};
 /**
  * ubifs_idx_node_sz - return index node size.
  * @c: the UBIFS file-system description object
@@ -438,4 +520,8 @@ struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
 				       (UBIFS_BRANCH_SZ + c->key_len) * bnum);
 }
 
+/* Callback used by the 'ubifs_lpt_scan_nolock()' function */
+typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
+				       const struct ubifs_lprops *lprops,
+				       int in_tree, void *data);
 #endif /* __UBIFS_H__ */
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 12/27] ubifs: copy some important functions in key.h from kernel to ubifs-utils
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (10 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 11/27] ubifs: copy some important data in ubifs.h from kernel to ubifs-utils Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 13/27] ubifs: ubifs_dump: add dump_ch and dump_node functions Dongsheng Yang
                   ` (15 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

We need some more functions in key.h, then copy it from kernel.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/key.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 75 insertions(+), 1 deletion(-)

diff --git a/ubifs-utils/include/key.h b/ubifs-utils/include/key.h
index d3a02d4..779981a 100644
--- a/ubifs-utils/include/key.h
+++ b/ubifs-utils/include/key.h
@@ -37,6 +37,8 @@
 #ifndef __UBIFS_KEY_H__
 #define __UBIFS_KEY_H__
 
+#include "defs.h"
+
 /**
  * key_mask_hash - mask a valid hash value.
  * @val: value to be masked
@@ -107,7 +109,7 @@ static inline void ino_key_init(union ubifs_key *key, ino_t inum)
  * @inum: parent inode number
  * @nm: direntry name and length
  */
-static inline void dent_key_init(const struct ubifs_info *c,
+static inline void dent_key_init(const struct ubifs_info *c __attribute__((unused)),
 				 union ubifs_key *key, ino_t inum,
 				 const struct qstr *nm)
 {
@@ -186,4 +188,76 @@ static inline int keys_cmp(const union ubifs_key *key1,
 	return 0;
 }
 
+/**
+ * key_read - transform a key to 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_read(const struct ubifs_info *c __attribute__((unused)), const void *from,
+			    union ubifs_key *to)
+{
+	const union ubifs_key *f = from;
+
+	to->u32[0] = le32_to_cpu(f->j32[0]);
+	to->u32[1] = le32_to_cpu(f->j32[1]);
+}
+
+/**
+ * invalid_key_init - initialize invalid node key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ *
+ * This is a helper function which marks a @key object as invalid.
+ */
+static inline void invalid_key_init(const struct ubifs_info *c __attribute__((unused)),
+				    union ubifs_key *key)
+{
+	key->u32[0] = 0xDEADBEAF;
+	key->u32[1] = UBIFS_INVALID_KEY;
+}
+/**
+ * key_type - get key type.
+ * @c: UBIFS file-system description object
+ * @key: key to get type of
+ */
+static inline int key_type(const struct ubifs_info *c __attribute__((unused)),
+			   const union ubifs_key *key)
+{
+	return key->u32[1] >> UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/*
+ * key_hash - get directory entry hash.
+ * @c: UBIFS file-system description object
+ * @key: the key to get hash from
+ */
+static inline uint32_t key_hash(const struct ubifs_info *c __attribute__((unused)),
+				const union ubifs_key *key)
+{
+	return key->u32[1] & UBIFS_S_KEY_HASH_MASK;
+}
+
+/**
+ * key_inum - fetch inode number from key.
+ * @c: UBIFS file-system description object
+ * @k: key to fetch inode number from
+ */
+static inline ino_t key_inum(const struct ubifs_info *c __attribute__((unused)), const void *k)
+{
+	const union ubifs_key *key = k;
+
+	return key->u32[0];
+}
+
+/**
+ * key_block - get data block number.
+ * @c: UBIFS file-system description object
+ * @key: the key to get the block number from
+ */
+static inline unsigned int key_block(const struct ubifs_info *c __attribute__((unused)),
+				     const union ubifs_key *key)
+{
+	return key->u32[1] & UBIFS_S_KEY_BLOCK_MASK;
+}
 #endif /* !__UBIFS_KEY_H__ */
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 13/27] ubifs: ubifs_dump: add dump_ch and dump_node functions
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (11 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 12/27] ubifs: copy some important functions in key.h " Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 14/27] ubifs: defs.h: introduce some compatible definition for printk class Dongsheng Yang
                   ` (14 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/ubifs_dump/ubifs_dump.c | 337 ++++++++++++++++++++++++++++++++++++
 1 file changed, 337 insertions(+)

diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
index bbe1269..a510aeb 100644
--- a/ubifs-utils/ubifs_dump/ubifs_dump.c
+++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
@@ -1,7 +1,11 @@
 #include "ubifs_common.h"
 #define PROGRAM_NAME "ubifs-dump"
 #include "common.h"
+
 #include "io.h"
+#include "key.h"
+
+#define DBG_KEY_BUF_LEN		48
 
 static const char *optstring = "";
 
@@ -38,6 +42,339 @@ static int get_options(int argc, char**argv)
 	return 0;
 }
 
+static const char *node_type_to_str[] = {
+		"UBIFS_INO_NODE",
+		"UBIFS_DATA_NODE",
+		"UBIFS_DENT_NODE",
+		"UBIFS_XENT_NODE",
+		"UBIFS_TRUN_NODE",
+		"UBIFS_PAD_NODE",
+		"UBIFS_SB_NODE",
+		"UBIFS_MST_NODE",
+		"UBIFS_REF_NODE",
+		"UBIFS_IDX_NODE",
+		"UBIFS_CS_NODE",
+		"UBIFS_ORPH_NODE"
+};
+
+static const char *get_key_type(int type)
+{
+	return node_type_to_str[type];
+}
+
+static const char *group_type_to_str[] = {
+		"UBIFS_NO_NODE_GROUP",
+		"UBIFS_IN_NODE_GROUP",
+		"UBIFS_LAST_OF_NODE_GROUP"
+};
+
+static const char *hash_type_to_str[] = {
+		"UBIFS_KEY_HASH_R5",
+		"UBIFS_KEY_HASH_TEST"
+};
+
+static const char *compr_type_to_str[] = {
+		"UBIFS_COMPR_NONE",
+		"UBIFS_COMPR_LZO",
+		"UBIFS_COMPR_ZLIB",
+		"UBIFS_COMPR_TYPES_CNT",
+};
+
+static const char *key_fmt_to_str[] = {
+	"UBIFS_SIMPLE_KEY_FMT"
+};
+
+const char *dbg_snprintf_key(const struct ubifs_info *c,
+			     const union ubifs_key *key, char *buffer, int len)
+{
+	char *p = buffer;
+	int type = key_type(c, key);
+
+	if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
+		switch (type) {
+
+		case UBIFS_INO_KEY:
+			len -= snprintf(p, len, "(%lu, %s)",
+					(unsigned long)key_inum(c, key),
+					get_key_type(type));
+			break;
+		case UBIFS_DENT_KEY:
+		case UBIFS_XENT_KEY:
+			len -= snprintf(p, len, "(%lu, %s, %#08x)",
+					(unsigned long)key_inum(c, key),
+					get_key_type(type), key_hash(c, key));
+			break;
+		case UBIFS_DATA_KEY:
+			len -= snprintf(p, len, "(%lu, %s, %u)",
+					(unsigned long)key_inum(c, key),
+					get_key_type(type), key_block(c, key));
+			break;
+		case UBIFS_TRUN_KEY:
+			len -= snprintf(p, len, "(%lu, %s)",
+					(unsigned long)key_inum(c, key),
+					get_key_type(type));
+			break;
+		default:
+			len -= snprintf(p, len, "(bad key type: %#08x, %#08x)",
+					key->u32[0], key->u32[1]);
+		}
+	} else
+		len -= snprintf(p, len, "bad key format %d", c->key_fmt);
+	ubifs_assert(len > 0);
+	return p;
+}
+
+static void show_ch(const struct ubifs_ch *ch) 
+{ 
+	printf("\tCommon header: \n");
+        printf("\tmagic \t\t\t\t%#x\n", le32_to_cpu(ch->magic)); 
+        printf("\tcrc \t\t\t\t%#x\n", le32_to_cpu(ch->crc)); 
+        printf("\tnode_type \t\t\t%d (%s)\n", ch->node_type, 
+               node_type_to_str[ch->node_type]); 
+        printf("\tgroup_type \t\t\t%d (%s)\n", ch->group_type, 
+               group_type_to_str[ch->group_type]); 
+        printf("\tsqnum \t\t\t\t%llu\n", 
+               (unsigned long long)le64_to_cpu(ch->sqnum)); 
+        printf("\tlen \t\t\t\t%u\n", le32_to_cpu(ch->len)); 
+} 
+
+void dump_node(const struct ubifs_info *c, const void *node)
+{
+	int i, n;
+	union ubifs_key key;
+	const struct ubifs_ch *ch = node;
+	char key_buf[DBG_KEY_BUF_LEN];
+
+	show_ch(node);
+
+	switch (ch->node_type) {
+	case UBIFS_PAD_NODE:
+	{
+		const struct ubifs_pad_node *pad = node;
+
+		printf("\t\tpad_len \t\t\t%u\n", le32_to_cpu(pad->pad_len));
+		break;
+	}
+	case UBIFS_SB_NODE:
+	{
+		const struct ubifs_sb_node *sup = node;
+		unsigned int sup_flags = le32_to_cpu(sup->flags);
+		char uuid[40];
+
+		uuid_unparse_upper(sup->uuid, uuid);
+		printf("\t\tUUID \t\t\t\t%s\n", uuid);
+		printf("\t\tkey_hash \t\t\t%d (%s)\n",
+		       (int)sup->key_hash, hash_type_to_str[sup->key_hash]);
+		printf("\t\tkey_fmt \t\t\t%d (%s)\n",
+		       (int)sup->key_fmt, key_fmt_to_str[sup->key_fmt]);
+		printf("\t\tflags \t\t\t\t%#x\n", sup_flags);
+		printf("\t\tbig_lpt \t\t\t%u\n",
+		       !!(sup_flags & UBIFS_FLG_BIGLPT));
+		printf("\t\tspace_fixup \t\t\t%u\n",
+		       !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
+		printf("\t\tmin_io_size \t\t\t%u\n", le32_to_cpu(sup->min_io_size));
+		printf("\t\tleb_size \t\t\t%u\n", le32_to_cpu(sup->leb_size));
+		printf("\t\tleb_cnt \t\t\t%u\n", le32_to_cpu(sup->leb_cnt));
+		printf("\t\tmax_leb_cnt \t\t\t%u\n", le32_to_cpu(sup->max_leb_cnt));
+		printf("\t\tmax_bud_bytes \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(sup->max_bud_bytes));
+		printf("\t\tlog_lebs \t\t\t%u\n", le32_to_cpu(sup->log_lebs));
+		printf("\t\tlpt_lebs \t\t\t%u\n", le32_to_cpu(sup->lpt_lebs));
+		printf("\t\torph_lebs \t\t\t%u\n", le32_to_cpu(sup->orph_lebs));
+		printf("\t\tjhead_cnt \t\t\t%u\n", le32_to_cpu(sup->jhead_cnt));
+		printf("\t\tfanout \t\t\t\t%u\n", le32_to_cpu(sup->fanout));
+		printf("\t\tlsave_cnt \t\t\t%u\n", le32_to_cpu(sup->lsave_cnt));
+		printf("\t\tdefault_compr \t\t\t%u\n",
+		       (int)le16_to_cpu(sup->default_compr));
+		printf("\t\trp_size \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(sup->rp_size));
+		printf("\t\trp_uid \t\t\t\t%u\n", le32_to_cpu(sup->rp_uid));
+		printf("\t\trp_gid \t\t\t\t%u\n", le32_to_cpu(sup->rp_gid));
+		printf("\t\tfmt_version \t\t\t%u\n", le32_to_cpu(sup->fmt_version));
+		printf("\t\ttime_gran \t\t\t%u\n", le32_to_cpu(sup->time_gran));
+		break;
+	}
+	case UBIFS_MST_NODE:
+	{
+		const struct ubifs_mst_node *mst = node;
+
+		printf("\t\thighest_inum \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(mst->highest_inum));
+		printf("\t\tcommit number \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(mst->cmt_no));
+		printf("\t\tflags \t\t\t\t%#x\n", le32_to_cpu(mst->flags));
+		printf("\t\tlog_lnum \t\t\t%u\n", le32_to_cpu(mst->log_lnum));
+		printf("\t\troot_lnum \t\t\t%u\n", le32_to_cpu(mst->root_lnum));
+		printf("\t\troot_offs \t\t\t%u\n", le32_to_cpu(mst->root_offs));
+		printf("\t\troot_len \t\t\t%u\n", le32_to_cpu(mst->root_len));
+		printf("\t\tgc_lnum \t\t\t%u\n", le32_to_cpu(mst->gc_lnum));
+		printf("\t\tihead_lnum \t\t\t%u\n", le32_to_cpu(mst->ihead_lnum));
+		printf("\t\tihead_offs \t\t\t%u\n", le32_to_cpu(mst->ihead_offs));
+		printf("\t\tindex_size \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(mst->index_size));
+		printf("\t\tlpt_lnum \t\t\t%u\n", le32_to_cpu(mst->lpt_lnum));
+		printf("\t\tlpt_offs \t\t\t%u\n", le32_to_cpu(mst->lpt_offs));
+		printf("\t\tnhead_lnum \t\t\t%u\n", le32_to_cpu(mst->nhead_lnum));
+		printf("\t\tnhead_offs \t\t\t%u\n", le32_to_cpu(mst->nhead_offs));
+		printf("\t\tltab_lnum \t\t\t%u\n", le32_to_cpu(mst->ltab_lnum));
+		printf("\t\tltab_offs \t\t\t%u\n", le32_to_cpu(mst->ltab_offs));
+		printf("\t\tlsave_lnum \t\t\t%u\n", le32_to_cpu(mst->lsave_lnum));
+		printf("\t\tlsave_offs \t\t\t%u\n", le32_to_cpu(mst->lsave_offs));
+		printf("\t\tlscan_lnum \t\t\t%u\n", le32_to_cpu(mst->lscan_lnum));
+		printf("\t\tleb_cnt \t\t\t%u\n", le32_to_cpu(mst->leb_cnt));
+		printf("\t\tempty_lebs \t\t\t%u\n", le32_to_cpu(mst->empty_lebs));
+		printf("\t\tidx_lebs \t\t\t%u\n", le32_to_cpu(mst->idx_lebs));
+		printf("\t\ttotal_free \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(mst->total_free));
+		printf("\t\ttotal_dirty \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(mst->total_dirty));
+		printf("\t\ttotal_used \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(mst->total_used));
+		printf("\t\ttotal_dead \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(mst->total_dead));
+		printf("\t\ttotal_dark \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(mst->total_dark));
+		break;
+	}
+	case UBIFS_REF_NODE:
+	{
+		const struct ubifs_ref_node *ref = node;
+
+		printf("\t\tlnum \t\t\t\t%u\n", le32_to_cpu(ref->lnum));
+		printf("\t\toffs \t\t\t\t%u\n", le32_to_cpu(ref->offs));
+		printf("\t\tjhead \t\t\t\t%u\n", le32_to_cpu(ref->jhead));
+		break;
+	}
+	case UBIFS_INO_NODE:
+	{
+		const struct ubifs_ino_node *ino = node;
+
+		key_read(c, &ino->key, &key);
+		printf("\t\tkey \t\t\t%s\n",
+		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
+		printf("\t\tcreat_sqnum \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(ino->creat_sqnum));
+		printf("\t\tsize \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(ino->size));
+		printf("\t\tnlink \t\t\t%u\n", le32_to_cpu(ino->nlink));
+		printf("\t\tatime \t\t\t%lld.%u\n",
+		       (long long)le64_to_cpu(ino->atime_sec),
+		       le32_to_cpu(ino->atime_nsec));
+		printf("\t\tmtime \t\t\t%lld.%u\n",
+		       (long long)le64_to_cpu(ino->mtime_sec),
+		       le32_to_cpu(ino->mtime_nsec));
+		printf("\t\tctime \t\t\t%lld.%u\n",
+		       (long long)le64_to_cpu(ino->ctime_sec),
+		       le32_to_cpu(ino->ctime_nsec));
+		printf("\t\tuid \t\t\t%u\n", le32_to_cpu(ino->uid));
+		printf("\t\tgid \t\t\t%u\n", le32_to_cpu(ino->gid));
+		printf("\t\tmode \t\t\t%u\n", le32_to_cpu(ino->mode));
+		printf("\t\tflags \t\t\t%#x\n", le32_to_cpu(ino->flags));
+		printf("\t\txattr_cnt \t\t\t%u\n", le32_to_cpu(ino->xattr_cnt));
+		printf("\t\txattr_size \t\t\t%u\n", le32_to_cpu(ino->xattr_size));
+		printf("\t\txattr_names \t\t\t%u\n", le32_to_cpu(ino->xattr_names));
+		printf("\t\tcompr_type \t\t\t%#x\n",
+		       (int)le16_to_cpu(ino->compr_type));
+		printf("\t\tdata len \t\t\t%u\n", le32_to_cpu(ino->data_len));
+		break;
+	}
+	case UBIFS_DENT_NODE:
+	case UBIFS_XENT_NODE:
+	{
+		const struct ubifs_dent_node *dent = node;
+		int nlen = le16_to_cpu(dent->nlen);
+
+		key_read(c, &dent->key, &key);
+		printf("\t\tkey \t\t\t%s\n",
+		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
+		printf("\t\tinum \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(dent->inum));
+		printf("\t\ttype \t\t\t%d\n", (int)dent->type);
+		printf("\t\tnlen \t\t\t%d\n", nlen);
+		printf("\t\tname           ");
+
+		if (nlen > UBIFS_MAX_NLEN)
+			printf("(bad name length, not printing, bad or corrupted node)");
+		else {
+			for (i = 0; i < nlen && dent->name[i]; i++)
+				printf("%c", dent->name[i]);
+		}
+		printf("\n");
+
+		break;
+	}
+	case UBIFS_DATA_NODE:
+	{
+		const struct ubifs_data_node *dn = node;
+		int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
+
+		key_read(c, &dn->key, &key);
+		printf("\t\tkey \t\t\t%s\n",
+		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
+		printf("\t\tsize \t\t\t%u\n", le32_to_cpu(dn->size));
+		printf("\t\tcompr_typ \t\t\t%d\n",
+		       (int)le16_to_cpu(dn->compr_type));
+		printf("\t\tdata size \t\t\t%d\n", dlen);
+		break;
+	}
+	case UBIFS_TRUN_NODE:
+	{
+		const struct ubifs_trun_node *trun = node;
+
+		printf("\t\tinum \t\t\t%u\n", le32_to_cpu(trun->inum));
+		printf("\t\told_size \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(trun->old_size));
+		printf("\t\tnew_size \t\t\t%llu\n",
+		       (unsigned long long)le64_to_cpu(trun->new_size));
+		break;
+	}
+	case UBIFS_IDX_NODE:
+	{
+		const struct ubifs_idx_node *idx = node;
+
+		n = le16_to_cpu(idx->child_cnt);
+		printf("\t\tchild_cnt \t\t%d\n", n);
+		printf("\t\tlevel \t\t\t%d\n", (int)le16_to_cpu(idx->level));
+		printf("\t\tBranches:\n");
+
+		for (i = 0; i < n && i < c->fanout - 1; i++) {
+			const struct ubifs_branch *br;
+
+			br = ubifs_idx_branch(c, idx, i);
+			key_read(c, &br->key, &key);
+			printf("\t\t%d: LEB %d:%d len %d key %s\n",
+			       i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
+			       le32_to_cpu(br->len),
+			       dbg_snprintf_key(c, &key, key_buf,
+						DBG_KEY_BUF_LEN));
+		}
+		break;
+	}
+	case UBIFS_CS_NODE:
+		break;
+	case UBIFS_ORPH_NODE:
+	{
+		const struct ubifs_orph_node *orph = node;
+
+		printf("\t\tcommit number \t\t\t%llu\n",
+		       (unsigned long long)
+				le64_to_cpu(orph->cmt_no) & LLONG_MAX);
+		printf("\t\tlast node flag \t\t\t%llu\n",
+		       (unsigned long long)(le64_to_cpu(orph->cmt_no)) >> 63);
+		n = (le32_to_cpu(ch->len) - UBIFS_ORPH_NODE_SZ) >> 3;
+		printf("\t\t%d orphan inode numbers:\n", n);
+		for (i = 0; i < n; i++)
+			printf("\t\t  ino \t\t\t%llu\n",
+			       (unsigned long long)le64_to_cpu(orph->inos[i]));
+		break;
+	}
+	default:
+		printf("node type \t\t\t%d was not recognized\n",
+		       (int)ch->node_type);
+	}
+	printf("\n");
+}
+
 static int dump()
 {
 	return 0;
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 14/27] ubifs: defs.h: introduce some compatible definition for printk class
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (12 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 13/27] ubifs: ubifs_dump: add dump_ch and dump_node functions Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 15/27] ubifs: io: introduce ubifs_read function to read ubi volume Dongsheng Yang
                   ` (13 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

There are some functions of printk class in code copied from kernel.
Then add a compatible definitions in defs.h for them.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/defs.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/ubifs-utils/include/defs.h b/ubifs-utils/include/defs.h
index 1fa3316..739af7f 100644
--- a/ubifs-utils/include/defs.h
+++ b/ubifs-utils/include/defs.h
@@ -81,6 +81,15 @@ __res = ((unsigned long) n) % (unsigned) base; \
 n = ((unsigned long) n) / (unsigned) base; \
 __res; })
 
+/*
+ * printk
+ */
+#define printk(fmt, args...) fprintf(stderr, fmt, ##args)
+#define	KERN_CRIT	""
+#define KERN_ERR	""
+#define ubifs_err(c, fmt, args...) printk(fmt, ##args)
+#define pr_err(fmt, args...) printk(fmt, ##args)
+
 #if INT_MAX != 0x7fffffff
 #error : sizeof(int) must be 4 for this program
 #endif
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 15/27] ubifs: io: introduce ubifs_read function to read ubi volume
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (13 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 14/27] ubifs: defs.h: introduce some compatible definition for printk class Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 16/27] ubifs: ubifs_dump: dump super block Dongsheng Yang
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Implement a ubifs_read function in io lib. This function
will read the data at offset in length of len from ubi volume
to buf.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/io.h |  2 ++
 ubifs-utils/lib/io.c     | 18 ++++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/ubifs-utils/include/io.h b/ubifs-utils/include/io.h
index 920645d..11f568c 100644
--- a/ubifs-utils/include/io.h
+++ b/ubifs-utils/include/io.h
@@ -16,4 +16,6 @@ int write_leb(struct ubifs_info *c, int lnum, int len, void *buf);
 int close_target(void);
 int open_target(struct ubifs_info *c, int yes);
 int open_ubi(struct ubifs_info *c, const char *node);
+
+int ubifs_read(loff_t offset, int len, void *buf);
 #endif
diff --git a/ubifs-utils/lib/io.c b/ubifs-utils/lib/io.c
index 9817d2a..d05cf86 100644
--- a/ubifs-utils/lib/io.c
+++ b/ubifs-utils/lib/io.c
@@ -132,3 +132,21 @@ int write_leb(struct ubifs_info *c, int lnum, int len, void *buf)
 
 	return 0;
 }
+
+/**
+ * ubifs_read - read data from ubi volume.
+ * @offset: offset of data in volume
+ * @len: length of data in the buffer
+ * @buf: buffer (must be at least c->leb_size bytes)
+ */
+int ubifs_read(loff_t offset, int len, void *buf)
+{
+	if (lseek(out_fd, offset, SEEK_SET) != offset)
+		return sys_err_msg("lseek failed seeking %"PRIdoff_t, offset);
+
+	if (read(out_fd, buf, len) != len)
+		return sys_err_msg("write failed writing %d bytes at pos %"PRIdoff_t,
+				   len, offset);
+
+	return 0;
+}
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 16/27] ubifs: ubifs_dump: dump super block
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (14 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 15/27] ubifs: io: introduce ubifs_read function to read ubi volume Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 17/27] ubifs: introduce scan for ubifs-utils Dongsheng Yang
                   ` (11 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Read the super block from ubi volume and dump it out.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/lpt.h           |   1 +
 ubifs-utils/lib/lpt.c               |  29 +++++++
 ubifs-utils/ubifs_dump/ubifs_dump.c | 151 ++++++++++++++++++++++++++++++++++--
 3 files changed, 173 insertions(+), 8 deletions(-)

diff --git a/ubifs-utils/include/lpt.h b/ubifs-utils/include/lpt.h
index 4cde59d..e2f7348 100644
--- a/ubifs-utils/include/lpt.h
+++ b/ubifs-utils/include/lpt.h
@@ -24,5 +24,6 @@
 
 int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt);
 int create_lpt(struct ubifs_info *c);
+int ubifs_calc_lpt_geom(struct ubifs_info *c);
 
 #endif
diff --git a/ubifs-utils/lib/lpt.c b/ubifs-utils/lib/lpt.c
index 100d747..26fb4dd 100644
--- a/ubifs-utils/lib/lpt.c
+++ b/ubifs-utils/lib/lpt.c
@@ -585,3 +585,32 @@ out:
 	free(pnode);
 	return err;
 }
+
+/**
+ * ubifs_calc_lpt_geom - calculate and check sizes for the LPT area.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_calc_lpt_geom(struct ubifs_info *c)
+{
+	int lebs_needed;
+	long long sz;
+
+	do_calc_lpt_geom(c);
+
+	/* Verify that lpt_lebs is big enough */
+	sz = c->lpt_sz * 2; /* Must have at least 2 times the size */
+	lebs_needed = (sz + c->leb_size - 1) / c->leb_size;
+	if (lebs_needed > c->lpt_lebs) {
+		ubifs_err(c, "too few LPT LEBs, %d", lebs_needed);
+		return -EINVAL;
+	}
+
+	/* Verify that ltab fits in a single LEB (since ltab is a single node */
+	if (c->ltab_sz > c->leb_size) {
+		ubifs_err(c, "LPT ltab too big");
+		return -EINVAL;
+	}
+	return 0;
+}
diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
index a510aeb..9ddb0f7 100644
--- a/ubifs-utils/ubifs_dump/ubifs_dump.c
+++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
@@ -4,6 +4,7 @@
 
 #include "io.h"
 #include "key.h"
+#include "lpt.h"
 
 #define DBG_KEY_BUF_LEN		48
 
@@ -16,6 +17,13 @@ static const struct option longopts[] = {
 struct ubifs_info info_;
 static struct ubifs_info *c = &info_;
 
+/* Global buffers */
+static void *leb_buf;
+
+/* Global nodes*/
+struct ubifs_mst_node mst;
+struct ubifs_sb_node sup;
+
 static int get_options(int argc, char**argv)
 {
 	int opt, i;
@@ -73,13 +81,6 @@ static const char *hash_type_to_str[] = {
 		"UBIFS_KEY_HASH_TEST"
 };
 
-static const char *compr_type_to_str[] = {
-		"UBIFS_COMPR_NONE",
-		"UBIFS_COMPR_LZO",
-		"UBIFS_COMPR_ZLIB",
-		"UBIFS_COMPR_TYPES_CNT",
-};
-
 static const char *key_fmt_to_str[] = {
 	"UBIFS_SIMPLE_KEY_FMT"
 };
@@ -375,11 +376,145 @@ void dump_node(const struct ubifs_info *c, const void *node)
 	printf("\n");
 }
 
-static int dump()
+/**
+ * init - initialize things.
+ */
+static int init(void)
+{
+	leb_buf = malloc(c->leb_size);
+	if (!leb_buf)
+		return err_msg("out of memory");
+
+	return 0;
+}
+
+/**
+ * deinit - deinitialize things.
+ */
+static void deinit(void)
+{
+	free(leb_buf);
+}
+
+/*
+ * init_constants_sb - initialize UBIFS constants.
+ * @c: UBIFS file-system description object
+ *
+ * This is a helper function which initializes various UBIFS constants after
+ * the superblock has been read. It also checks various UBIFS parameters and
+ * makes sure they are all right. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+static int init_constants_sb(struct ubifs_info *c)
 {
+	int tmp, err;
+
+	tmp = ubifs_idx_node_sz(c, 1);
+	c->min_idx_node_sz = ALIGN(tmp, 8);
+
+	tmp = ubifs_idx_node_sz(c, c->fanout);
+	c->max_idx_node_sz = ALIGN(tmp, 8);
+
+	c->max_znode_sz = sizeof(struct ubifs_znode) +
+			c->fanout * sizeof(struct ubifs_zbranch);
+	/* Make sure LEB size is large enough to fit full commit */
+	tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt;
+	tmp = ALIGN(tmp, c->min_io_size);
+	if (tmp > c->leb_size) {
+		printf("too small LEB size %d, at least %d needed",
+			  c->leb_size, tmp);
+		return -EINVAL;
+	}
+
+	err = ubifs_calc_lpt_geom(c);
+	if (err)
+		return err;
+
 	return 0;
 }
 
+static int dump_super(void)
+{
+	int err = 0;
+	unsigned long sup_flags;
+
+	memset(&sup, 0, UBIFS_SB_NODE_SZ);
+	err = ubifs_read(0, UBIFS_SB_NODE_SZ, &sup);
+	if (err)
+		return err;
+
+	printf("SUPER BLOCK: \n");
+	dump_node(c, &sup);
+
+        switch (sup.key_hash) {
+        case UBIFS_KEY_HASH_R5:
+                c->key_hash = key_r5_hash;
+                c->key_hash_type = UBIFS_KEY_HASH_R5;
+                break;
+
+        case UBIFS_KEY_HASH_TEST:
+                c->key_hash = key_test_hash;
+                c->key_hash_type = UBIFS_KEY_HASH_TEST;
+                break;
+        };
+
+	c->key_fmt = sup.key_fmt;
+
+	switch (c->key_fmt) {
+	case UBIFS_SIMPLE_KEY_FMT:
+		c->key_len = UBIFS_SK_LEN;
+		break;
+	default:
+		printf("unsupported key format");
+		err = -EINVAL;
+		return err;
+	}
+
+	c->leb_size	 = le32_to_cpu(sup.leb_size);
+	c->min_io_size	 = le32_to_cpu(sup.min_io_size);
+	c->leb_cnt       = le32_to_cpu(sup.leb_cnt);
+	c->max_leb_cnt   = le32_to_cpu(sup.max_leb_cnt);
+	c->max_bud_bytes = le64_to_cpu(sup.max_bud_bytes);
+	c->log_lebs      = le32_to_cpu(sup.log_lebs);
+	c->lpt_lebs      = le32_to_cpu(sup.lpt_lebs);
+	c->orph_lebs     = le32_to_cpu(sup.orph_lebs);
+	c->jhead_cnt     = le32_to_cpu(sup.jhead_cnt) + NONDATA_JHEADS_CNT;
+	c->fanout        = le32_to_cpu(sup.fanout);
+	c->lsave_cnt     = le32_to_cpu(sup.lsave_cnt);
+	c->rp_size       = le64_to_cpu(sup.rp_size);
+	sup_flags        = le32_to_cpu(sup.flags);
+	c->default_compr = le16_to_cpu(sup.default_compr);
+
+	c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
+	c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
+
+	/* Automatically increase file system size to the maximum size */
+	c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs;
+	c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
+	c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+	c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs;
+	c->main_first = c->leb_cnt - c->main_lebs;
+
+	return init_constants_sb(c);
+}
+
+static int dump()
+{
+	int err = 0;
+
+	err = init();
+	if (err)
+		goto out;
+
+	err = dump_super();
+	if (err)
+		goto out;
+
+out:
+	deinit();
+	return err;
+}
+
 int main(int argc, char *argv[])
 {
 	int err;
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 17/27] ubifs: introduce scan for ubifs-utils
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (15 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 16/27] ubifs: ubifs_dump: dump super block Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 18/27] ubifs: add some more compatible definitions in defs.h Dongsheng Yang
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

It's a lib to scan a leb.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/scan.h |   8 ++
 ubifs-utils/lib/scan.c     | 318 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 326 insertions(+)
 create mode 100644 ubifs-utils/include/scan.h
 create mode 100644 ubifs-utils/lib/scan.c

diff --git a/ubifs-utils/include/scan.h b/ubifs-utils/include/scan.h
new file mode 100644
index 0000000..8447adf
--- /dev/null
+++ b/ubifs-utils/include/scan.h
@@ -0,0 +1,8 @@
+#ifndef __UBIFS_SCAN_H__
+#define __UBIFS_SCAN_H__
+
+struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
+				  int offs, void *sbuf, int quiet);
+
+void ubifs_scan_destroy(struct ubifs_scan_leb *sleb);
+#endif
diff --git a/ubifs-utils/lib/scan.c b/ubifs-utils/lib/scan.c
new file mode 100644
index 0000000..69c84d1
--- /dev/null
+++ b/ubifs-utils/lib/scan.c
@@ -0,0 +1,318 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copied from kernel
+ *
+ * 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
+ */
+
+/*
+ * This file implements the scan which is a general-purpose function for
+ * determining what nodes are in an eraseblock. The scan is used to replay the
+ * journal, to do garbage collection. for the TNC in-the-gaps method, and by
+ * debugging functions.
+ */
+#include "ubifs_common.h"
+
+#include "ubifs.h"
+#define PROGRAM_NAME "ubifs_scan"
+#include "common.h"
+#include "key.h"
+#include "io.h"
+#include "scan.h"
+
+/**
+ * scan_padding_bytes - scan for padding bytes.
+ * @buf: buffer to scan
+ * @len: length of buffer
+ *
+ * This function returns the number of padding bytes on success and
+ * %SCANNED_GARBAGE on failure.
+ */
+static int scan_padding_bytes(void *buf, int len)
+{
+	int pad_len = 0, max_pad_len = min_t(int, UBIFS_PAD_NODE_SZ, len);
+	int *p = buf;
+
+	while (pad_len < max_pad_len && *p++ == UBIFS_PADDING_BYTE)
+		pad_len += 1;
+
+	if (!pad_len || (pad_len & 7)) {
+		return SCANNED_GARBAGE;
+	}
+
+	return pad_len;
+}
+
+/**
+ * ubifs_scan_a_node - scan for a node or padding.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to scan
+ * @len: length of buffer
+ * @lnum: logical eraseblock number
+ * @offs: offset within the logical eraseblock
+ * @quiet: print no messages
+ *
+ * This function returns a scanning code to indicate what was scanned.
+ */
+int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len,
+		      int lnum __attribute__((unused)), int offs,
+		      int quiet __attribute__((unused)))
+{
+	struct ubifs_ch *ch = buf;
+	uint32_t magic;
+
+	magic = le32_to_cpu(ch->magic);
+
+	if (magic == 0xFFFFFFFF)
+		return SCANNED_EMPTY_SPACE;
+
+	if (magic != UBIFS_NODE_MAGIC)
+		return scan_padding_bytes(buf, len);
+
+	if (len < UBIFS_CH_SZ) {
+		return SCANNED_GARBAGE;
+	}
+
+	if (ch->node_type == UBIFS_PAD_NODE) {
+		struct ubifs_pad_node *pad = buf;
+		int pad_len = le32_to_cpu(pad->pad_len);
+		int node_len = le32_to_cpu(ch->len);
+
+		/* Validate the padding node */
+		if (pad_len < 0 ||
+		    offs + node_len + pad_len > c->leb_size) {
+			return SCANNED_A_BAD_PAD_NODE;
+		}
+
+		/* Make the node pads to 8-byte boundary */
+		if ((node_len + pad_len) & 7) {
+			return SCANNED_A_BAD_PAD_NODE;
+		}
+
+		return node_len + pad_len;
+	}
+
+	return SCANNED_A_NODE;
+}
+
+/**
+ * ubifs_start_scan - create LEB scanning information at start of scan.
+ * @c: UBIFS file-system description object
+ * @lnum: logical eraseblock number
+ * @offs: offset to start at (usually zero)
+ * @sbuf: scan buffer (must be c->leb_size)
+ *
+ * This function returns the scanned information on success and a negative error
+ * code on failure.
+ */
+struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
+					int offs, void *sbuf)
+{
+	struct ubifs_scan_leb *sleb;
+	int err;
+
+	sleb = kzalloc(sizeof(struct ubifs_scan_leb), GFP_NOFS);
+	if (!sleb)
+		return ERR_PTR(-ENOMEM);
+
+	sleb->lnum = lnum;
+	INIT_LIST_HEAD(&sleb->nodes);
+	sleb->buf = sbuf;
+
+	err = ubifs_read(lnum * c->leb_size + offs, c->leb_size - offs, sbuf + offs);
+	if (err && err != -EBADMSG) {
+		kfree(sleb);
+		return ERR_PTR(err);
+	}
+
+	/*
+	 * Note, we ignore integrity errors (EBASMSG) because all the nodes are
+	 * protected by CRC checksums.
+	 */
+	return sleb;
+}
+
+/**
+ * ubifs_end_scan - update LEB scanning information at end of scan.
+ * @c: UBIFS file-system description object
+ * @sleb: scanning information
+ * @lnum: logical eraseblock number
+ * @offs: offset to start at (usually zero)
+ */
+void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+		    int lnum, int offs)
+{
+	lnum = lnum;
+	ubifs_assert(offs % c->min_io_size == 0);
+
+	sleb->endpt = ALIGN(offs, c->min_io_size);
+}
+
+/**
+ * ubifs_add_snod - add a scanned node to LEB scanning information.
+ * @c: UBIFS file-system description object
+ * @sleb: scanning information
+ * @buf: buffer containing node
+ * @offs: offset of node on flash
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+		   void *buf, int offs)
+{
+	struct ubifs_ch *ch = buf;
+	struct ubifs_ino_node *ino = buf;
+	struct ubifs_scan_node *snod;
+
+	snod = kmalloc(sizeof(struct ubifs_scan_node), GFP_NOFS);
+	if (!snod)
+		return -ENOMEM;
+
+	snod->sqnum = le64_to_cpu(ch->sqnum);
+	snod->type = ch->node_type;
+	snod->offs = offs;
+	snod->len = le32_to_cpu(ch->len);
+	snod->node = buf;
+
+	switch (ch->node_type) {
+	case UBIFS_INO_NODE:
+	case UBIFS_DENT_NODE:
+	case UBIFS_XENT_NODE:
+	case UBIFS_DATA_NODE:
+		/*
+		 * The key is in the same place in all keyed
+		 * nodes.
+		 */
+		key_read(c, &ino->key, &snod->key);
+		break;
+	default:
+		invalid_key_init(c, &snod->key);
+		break;
+	}
+	list_add_tail(&snod->list, &sleb->nodes);
+	sleb->nodes_cnt += 1;
+	return 0;
+}
+
+/**
+ * ubifs_scan - scan a logical eraseblock.
+ * @c: UBIFS file-system description object
+ * @lnum: logical eraseblock number
+ * @offs: offset to start at (usually zero)
+ * @sbuf: scan buffer (must be of @c->leb_size bytes in size)
+ * @quiet: print no messages
+ *
+ * This function scans LEB number @lnum and returns complete information about
+ * its contents. Returns the scanned information in case of success and,
+ * %-EUCLEAN if the LEB neads recovery, and other negative error codes in case
+ * of failure.
+ *
+ * If @quiet is non-zero, this function does not print large and scary
+ * error messages and flash dumps in case of errors.
+ */
+struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
+				  int offs, void *sbuf, int quiet)
+{
+	void *buf = sbuf + offs;
+	int err, len = c->leb_size - offs;
+	struct ubifs_scan_leb *sleb;
+
+	sleb = ubifs_start_scan(c, lnum, offs, sbuf);
+	if (IS_ERR(sleb))
+		return sleb;
+
+	while (len >= 8) {
+		struct ubifs_ch *ch = buf;
+		int node_len, ret;
+
+		cond_resched();
+
+		ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
+		if (ret > 0) {
+			/* Padding bytes or a valid padding node */
+			offs += ret;
+			buf += ret;
+			len -= ret;
+			continue;
+		}
+
+		if (ret == SCANNED_EMPTY_SPACE)
+			/* Empty space is checked later */
+			break;
+
+		switch (ret) {
+		case SCANNED_GARBAGE:
+			if (offs == 0)
+				break;
+			goto corrupted;
+		case SCANNED_A_NODE:
+			break;
+		case SCANNED_A_CORRUPT_NODE:
+		case SCANNED_A_BAD_PAD_NODE:
+			goto corrupted;
+		default:
+			err = -EINVAL;
+			goto error;
+		}
+
+		err = ubifs_add_snod(c, sleb, buf, offs);
+		if (err)
+			goto error;
+
+		node_len = ALIGN(le32_to_cpu(ch->len), 8);
+		offs += node_len;
+		buf += node_len;
+		len -= node_len;
+	}
+
+	if (offs % c->min_io_size) {
+		goto corrupted;
+	}
+
+	ubifs_end_scan(c, sleb, lnum, offs);
+
+	for (; len > 2; offs += 2, buf = buf + 2, len -= 2)
+		if ((*(const uint8_t *)buf) != 0xff)
+			goto corrupted;
+
+	return sleb;
+
+corrupted:
+	err = -EUCLEAN;
+	ubifs_scan_destroy(sleb);
+	return ERR_PTR(err);
+
+error:
+	ubifs_scan_destroy(sleb);
+	return ERR_PTR(err);
+}
+
+/**
+ * ubifs_scan_destroy - destroy LEB scanning information.
+ * @sleb: scanning information to free
+ */
+void ubifs_scan_destroy(struct ubifs_scan_leb *sleb)
+{
+	struct ubifs_scan_node *node;
+	struct list_head *head;
+
+	head = &sleb->nodes;
+	while (!list_empty(head)) {
+		node = list_entry(head->next, struct ubifs_scan_node, list);
+		list_del(&node->list);
+		kfree(node);
+	}
+	kfree(sleb);
+}
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 18/27] ubifs: add some more compatible definitions in defs.h
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (16 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 17/27] ubifs: introduce scan for ubifs-utils Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 19/27] ubifs: ubifs_dump: dump master node Dongsheng Yang
                   ` (9 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Add kmalloc class compatible definitions to defs.h.
Add error pointer class compatible definitions to defs.h.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/defs.h | 84 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/ubifs-utils/include/defs.h b/ubifs-utils/include/defs.h
index 739af7f..ed42ab1 100644
--- a/ubifs-utils/include/defs.h
+++ b/ubifs-utils/include/defs.h
@@ -6,6 +6,37 @@
 #ifndef __UBIFS_DEFS_H__
 #define __UBIFS_DEFS_H__
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <assert.h>
+#include <stddef.h>
+#include <linux/types.h>
+#include <stdint.h>
+
+#include <features.h>
+
+#ifndef __GLIBC__
+#define BTRFS_DISABLE_BACKTRACE
+#define __always_inline __inline __attribute__ ((__always_inline__))
+#endif
+
+#ifndef BTRFS_DISABLE_BACKTRACE
+#include <execinfo.h>
+#endif
+
+#define ptr_to_u64(x)	((u64)(uintptr_t)x)
+#define u64_to_ptr(x)	((void *)(uintptr_t)x)
+
+#ifndef READ
+#define READ 0
+#define WRITE 1
+#define READA 2
+#endif
+
 #define t16(x) ({ \
 	uint16_t __b = (x); \
 	(__LITTLE_ENDIAN==__BYTE_ORDER) ? __b : bswap_16(__b); \
@@ -82,6 +113,41 @@ n = ((unsigned long) n) / (unsigned) base; \
 __res; })
 
 /*
+ * error pointer
+ */
+#define MAX_ERRNO	4095
+#define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO)
+
+static inline void *ERR_PTR(long error)
+{
+	return (void *) error;
+}
+
+static inline long PTR_ERR(const void *ptr)
+{
+	return (long) ptr;
+}
+
+static inline long IS_ERR(const void *ptr)
+{
+	return IS_ERR_VALUE((unsigned long)ptr);
+}
+
+#define cond_resched()		do { } while (0)
+#define preempt_enable()	do { } while (0)
+#define preempt_disable()	do { } while (0)
+
+/*
+ * kmalloc/kfree
+ */
+#define kmalloc(x, y) malloc(x)
+#define kzalloc(x, y) calloc(1, x)
+#define kstrdup(x, y) strdup(x)
+#define kfree(x) free(x)
+#define vmalloc(x) malloc(x)
+#define vfree(x) free(x)
+
+/*
  * printk
  */
 #define printk(fmt, args...) fprintf(stderr, fmt, ##args)
@@ -90,6 +156,24 @@ __res; })
 #define ubifs_err(c, fmt, args...) printk(fmt, ##args)
 #define pr_err(fmt, args...) printk(fmt, ##args)
 
+#define container_of(ptr, type, member) ({                      \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+	        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define gfp_t int
+#define get_cpu_var(p) (p)
+#define __get_cpu_var(p) (p)
+#define BITS_PER_LONG (__SIZEOF_LONG__ * 8)
+#define __GFP_BITS_SHIFT 20
+#define __GFP_BITS_MASK ((int)((1 << __GFP_BITS_SHIFT) - 1))
+#define GFP_KERNEL 0
+#define GFP_NOFS 0
+#define __read_mostly
+
+#ifndef ULONG_MAX
+#define ULONG_MAX       (~0UL)
+#endif
+
 #if INT_MAX != 0x7fffffff
 #error : sizeof(int) must be 4 for this program
 #endif
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 19/27] ubifs: ubifs_dump: dump master node
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (17 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 18/27] ubifs: add some more compatible definitions in defs.h Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 20/27] ubifs: ubifs_dump: dump log area Dongsheng Yang
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Search the master lebs and found the latest master node.
Then dump it out.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 Makefile                            |   1 +
 ubifs-utils/ubifs_dump/ubifs_dump.c | 139 +++++++++++++++++++++++++++++-------
 2 files changed, 115 insertions(+), 25 deletions(-)

diff --git a/Makefile b/Makefile
index cad71dc..7abbef9 100644
--- a/Makefile
+++ b/Makefile
@@ -133,6 +133,7 @@ $(foreach v,$(UBI_BINS),$(eval $(call mkdep,ubi-utils/,$(v),libubi.a ubiutils-co
 $(foreach v,crc16.o lpt.o compr.o devtable.o io.o hashtable.o hashtable_itr.o,$(eval UBIFS_LIBS += ../lib/$(v)))
 
 obj-ubifs_dump = $(UBIFS_LIBS)
+obj-ubifs_dump += ../lib/scan.o
 LDFLAGS_ubifs_dump = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
 LDLIBS_ubifs_dump = -lz -llzo2 -lm -luuid
 $(call mkdep,ubifs-utils/ubifs_dump/,ubifs_dump,,ubi-utils/libubi.a)
diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
index 9ddb0f7..4f67621 100644
--- a/ubifs-utils/ubifs_dump/ubifs_dump.c
+++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
@@ -2,9 +2,11 @@
 #define PROGRAM_NAME "ubifs-dump"
 #include "common.h"
 
+#include "ubifs.h"
 #include "io.h"
 #include "key.h"
 #include "lpt.h"
+#include "scan.h"
 
 #define DBG_KEY_BUF_LEN		48
 
@@ -17,7 +19,6 @@ static const struct option longopts[] = {
 struct ubifs_info info_;
 static struct ubifs_info *c = &info_;
 
-/* Global buffers */
 static void *leb_buf;
 
 /* Global nodes*/
@@ -376,26 +377,6 @@ void dump_node(const struct ubifs_info *c, const void *node)
 	printf("\n");
 }
 
-/**
- * init - initialize things.
- */
-static int init(void)
-{
-	leb_buf = malloc(c->leb_size);
-	if (!leb_buf)
-		return err_msg("out of memory");
-
-	return 0;
-}
-
-/**
- * deinit - deinitialize things.
- */
-static void deinit(void)
-{
-	free(leb_buf);
-}
-
 /*
  * init_constants_sb - initialize UBIFS constants.
  * @c: UBIFS file-system description object
@@ -498,20 +479,128 @@ static int dump_super(void)
 	return init_constants_sb(c);
 }
 
-static int dump()
+/**
+ * scan_for_master - search the valid master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function scans the master node LEBs and search for the latest master
+ * node. Returns zero in case of success, %-EUCLEAN if there master area is
+ * corrupted and requires recovery, and a negative error code in case of
+ * failure.
+ */
+static int scan_for_master(struct ubifs_info *c, struct ubifs_mst_node *mst_node)
 {
+	struct ubifs_scan_leb *sleb;
+	struct ubifs_scan_node *snod;
+	int lnum, offs = 0, nodes_cnt;
 	int err = 0;
 
-	err = init();
-	if (err)
+	lnum = UBIFS_MST_LNUM;
+
+	sleb = ubifs_scan(c, lnum, 0, leb_buf, 1);
+	if (IS_ERR(sleb))
+		return PTR_ERR(sleb);
+	nodes_cnt = sleb->nodes_cnt;
+	if (nodes_cnt > 0) {
+		snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
+				  list);
+		if (snod->type != UBIFS_MST_NODE) {
+			err = -EINVAL;
+			goto out;
+		}
+		memcpy(mst_node, snod->node, snod->len);
+		offs = snod->offs;
+	}
+	ubifs_scan_destroy(sleb);
+
+	lnum += 1;
+
+	sleb = ubifs_scan(c, lnum, 0, leb_buf, 1);
+	if (IS_ERR(sleb)) {
+		return PTR_ERR(sleb);
+	}
+	err = -EUCLEAN;
+	if (sleb->nodes_cnt != nodes_cnt)
+		goto out;
+	if (!sleb->nodes_cnt)
+		goto out;
+	snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list);
+	if (snod->type != UBIFS_MST_NODE) {
+		err = -EINVAL;
+		goto out;
+	}
+	if (snod->offs != offs)
+		goto out;
+	if (memcmp((void *)mst_node + UBIFS_CH_SZ,
+		   (void *)snod->node + UBIFS_CH_SZ,
+		   UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
 		goto out;
+	err = 0;
+
+out:
+	ubifs_scan_destroy(sleb);
+	return err;
+}
+
+static int dump_master(void)
+{
+	int err = 0;
+
+	printf("MASTER: \n");
+	err = scan_for_master(c, &mst);
+	if (err)
+		return err;
+	dump_node(c, &mst);
+	mst.flags &= cpu_to_le32(~UBIFS_MST_RCVRY);
+
+	c->max_sqnum       = le64_to_cpu(mst.ch.sqnum);
+	c->highest_inum    = le64_to_cpu(mst.highest_inum);
+	c->zroot.lnum      = le32_to_cpu(mst.root_lnum);
+	c->zroot.offs      = le32_to_cpu(mst.root_offs);
+	c->zroot.len       = le32_to_cpu(mst.root_len);
+	c->gc_lnum         = le32_to_cpu(mst.gc_lnum);
+	c->ihead_lnum      = le32_to_cpu(mst.ihead_lnum);
+	c->ihead_offs      = le32_to_cpu(mst.ihead_offs);
+	c->lpt_lnum        = le32_to_cpu(mst.lpt_lnum);
+	c->lpt_offs        = le32_to_cpu(mst.lpt_offs);
+	c->nhead_lnum      = le32_to_cpu(mst.nhead_lnum);
+	c->nhead_offs      = le32_to_cpu(mst.nhead_offs);
+	c->ltab_lnum       = le32_to_cpu(mst.ltab_lnum);
+	c->ltab_offs       = le32_to_cpu(mst.ltab_offs);
+	c->lsave_lnum      = le32_to_cpu(mst.lsave_lnum);
+	c->lsave_offs      = le32_to_cpu(mst.lsave_offs);
+	c->lscan_lnum      = le32_to_cpu(mst.lscan_lnum);
+	c->lst.empty_lebs  = le32_to_cpu(mst.empty_lebs);
+	c->lst.idx_lebs    = le32_to_cpu(mst.idx_lebs);
+	c->lst.total_free  = le64_to_cpu(mst.total_free);
+	c->lst.total_dirty = le64_to_cpu(mst.total_dirty);
+	c->lst.total_used  = le64_to_cpu(mst.total_used);
+	c->lst.total_dead  = le64_to_cpu(mst.total_dead);
+	c->lst.total_dark  = le64_to_cpu(mst.total_dark);
+
+	return 0;
+}
+
+static int dump()
+{
+	int err = 0;
 
 	err = dump_super();
 	if (err)
 		goto out;
 
+	leb_buf = malloc(c->leb_size);
+	if (!leb_buf) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = dump_master();
+	if (err)
+		goto free;
+free:
+	free(leb_buf);
 out:
-	deinit();
 	return err;
 }
 
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 20/27] ubifs: ubifs_dump: dump log area
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (18 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 19/27] ubifs: ubifs_dump: dump master node Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 21/27] ubifs: introduce lprops lib Dongsheng Yang
                   ` (7 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

scan the log lebs and dump the log nodes out.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/ubifs_dump/ubifs_dump.c | 140 ++++++++++++++++++++++++++++++++++++
 1 file changed, 140 insertions(+)

diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
index 4f67621..d7a2951 100644
--- a/ubifs-utils/ubifs_dump/ubifs_dump.c
+++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
@@ -581,6 +581,142 @@ static int dump_master(void)
 	return 0;
 }
 
+static int __dump_log_leb(int leb_num)
+{
+	int err = 0;
+	struct ubifs_scan_leb *sleb;
+	struct ubifs_scan_node *snod;
+	const struct ubifs_cs_node *node;
+	static int cs_sqnum = 0;
+	int lnum = leb_num;
+	loff_t offs = 0;
+	int node_num = 0;
+
+	sleb = ubifs_scan(c, lnum, offs, leb_buf, 0);
+	if (IS_ERR(sleb)) {
+		printf("Error in scaning log leb");
+		return PTR_ERR(sleb);
+	}
+
+	if (sleb->nodes_cnt == 0) {
+		err = 1;
+		goto out;
+	}
+
+	node = sleb->buf;
+	snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list);
+	if (cs_sqnum == 0) {
+		/*
+		 * This is the first log LEB we are looking at, make sure that
+		 * the first node is a commit start node. Also record its
+		 * sequence number so that UBIFS can determine where the log
+		 * ends, because all nodes which were have higher sequence
+		 * numbers.
+		 */
+		if (snod->type != UBIFS_CS_NODE) {
+			ubifs_err(c, "first log node at LEB %d:%lu is not CS node",
+				  lnum, offs);
+			goto out_dump;
+		}
+		if (le64_to_cpu(node->cmt_no) != mst.cmt_no) {
+			ubifs_err(c, "first CS node at LEB %d:%lu has wrong commit number %llu expected %llu",
+				  lnum, offs,
+				  (unsigned long long)le64_to_cpu(node->cmt_no),
+				  mst.cmt_no);
+			goto out_dump;
+		}
+
+		cs_sqnum = le64_to_cpu(node->ch.sqnum);
+	}
+
+	if (snod->sqnum < cs_sqnum) {
+		/*
+		 * This means that we reached end of log and now
+		 * look to the older log data, which was already
+		 * committed but the eraseblock was not erased (UBIFS
+		 * only un-maps it). So this basically means we have to
+		 * exit with "end of log" code.
+		 */
+		err = 1;
+		goto out;
+	}
+
+	/* Make sure the first node sits at offset zero of the LEB */
+	if (snod->offs != 0) {
+		ubifs_err(c, "first node is not at zero offset");
+		goto out_dump;
+	}
+
+	printf("\tLOG LEB %d\n", lnum);
+	list_for_each_entry(snod, &sleb->nodes, list) {
+		if (snod->sqnum < cs_sqnum) {
+			ubifs_err(c, "bad sqnum %llu, commit sqnum %d",
+				  snod->sqnum, cs_sqnum);
+			goto out_dump;
+		}
+
+		printf("\tNODE %d", node_num++);
+		switch (snod->type) {
+		case UBIFS_CS_NODE:
+			printf(" <START COMMIT>");
+		case UBIFS_REF_NODE: {
+			printf(":\n");
+			dump_node(c, snod->node);
+			break;
+		}
+		default:
+			ubifs_err(c, "unexpected node in log");
+			goto out_dump;
+		}
+	}
+	err = !sleb->endpt;
+out:
+	ubifs_scan_destroy(sleb);
+	return err;
+
+out_dump:
+	ubifs_err(c, "log error detected while replaying the log at LEB %d:%lu",
+		  lnum, offs + snod->offs);
+	ubifs_scan_destroy(sleb);
+	return -EINVAL;
+
+}
+
+static int dump_log(void)
+{
+	int err, lnum, ltail_lnum, log_last;
+
+	lnum = ltail_lnum = mst.log_lnum;
+	log_last = UBIFS_LOG_LNUM + sup.log_lebs - 1;
+	printf("LOG AREA:\n");
+	while (lnum <= log_last) {
+		err = __dump_log_leb(lnum);
+		if (err == 1) {
+			if (lnum != mst.log_lnum)
+				/* We hit the end of the log */
+				break;
+
+			/*
+			 * The head of the log must always start with the
+			 * "commit start" node on a properly formatted UBIFS.
+			 * But we found no nodes at all, which means that
+			 * someting went wrong and we cannot proceed mounting
+			 * the file-system.
+			 */
+			ubifs_err(c, "no UBIFS nodes found at the log head LEB %d:%d, possibly corrupted",
+				  lnum, 0);
+			err = -EINVAL;
+		}
+		if (err)
+			goto out;
+		lnum++;
+	}
+
+	err = 0;
+out:
+	return err;
+}
+
 static int dump()
 {
 	int err = 0;
@@ -598,6 +734,10 @@ static int dump()
 	err = dump_master();
 	if (err)
 		goto free;
+
+	err = dump_log();
+	if (err)
+		goto free;
 free:
 	free(leb_buf);
 out:
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 21/27] ubifs: introduce lprops lib
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (19 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 20/27] ubifs: ubifs_dump: dump log area Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 22/27] ubifs: lpt: implement functions to scan lpt Dongsheng Yang
                   ` (6 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Copy lprops.c from kernel to ubifs-utils/.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/lprops.h |  6 ++++
 ubifs-utils/lib/lprops.c     | 79 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)
 create mode 100644 ubifs-utils/include/lprops.h
 create mode 100644 ubifs-utils/lib/lprops.c

diff --git a/ubifs-utils/include/lprops.h b/ubifs-utils/include/lprops.h
new file mode 100644
index 0000000..5bf3108
--- /dev/null
+++ b/ubifs-utils/include/lprops.h
@@ -0,0 +1,6 @@
+#ifndef __UBIFS_LPROPS_H__
+#define __UBIFS_LPROPS_H__
+
+int ubifs_categorize_lprops(const struct ubifs_info *c,
+			    const struct ubifs_lprops *lprops);
+#endif
diff --git a/ubifs-utils/lib/lprops.c b/ubifs-utils/lib/lprops.c
new file mode 100644
index 0000000..818d220
--- /dev/null
+++ b/ubifs-utils/lib/lprops.c
@@ -0,0 +1,79 @@
+/*
+ * 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: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file implements the functions that access LEB properties and their
+ * categories. LEBs are categorized based on the needs of UBIFS, and the
+ * categories are stored as either heaps or lists to provide a fast way of
+ * finding a LEB in a particular category. For example, UBIFS may need to find
+ * an empty LEB for the journal, or a very dirty LEB for garbage collection.
+ */
+
+#include "ubifs_common.h"
+
+/* common.h requires the PROGRAM_NAME macro */
+#define PROGRAM_NAME "ubifs-lprops"
+#include "common.h"
+
+#include "ubifs.h"
+
+/**
+ * ubifs_categorize_lprops - categorize LEB properties.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to categorize
+ *
+ * LEB properties are categorized to enable fast find operations. This function
+ * returns the LEB category to which the LEB properties belong. Note however
+ * that if the LEB category is stored as a heap and the heap is full, the
+ * LEB properties may have their category changed to %LPROPS_UNCAT.
+ */
+int ubifs_categorize_lprops(const struct ubifs_info *c,
+			    const struct ubifs_lprops *lprops)
+{
+	if (lprops->flags & LPROPS_TAKEN)
+		return LPROPS_UNCAT;
+
+	if (lprops->free == c->leb_size) {
+		ubifs_assert(!(lprops->flags & LPROPS_INDEX));
+		return LPROPS_EMPTY;
+	}
+
+	if (lprops->free + lprops->dirty == c->leb_size) {
+		if (lprops->flags & LPROPS_INDEX)
+			return LPROPS_FRDI_IDX;
+		else
+			return LPROPS_FREEABLE;
+	}
+
+	if (lprops->flags & LPROPS_INDEX) {
+		if (lprops->dirty + lprops->free >= c->min_idx_node_sz)
+			return LPROPS_DIRTY_IDX;
+	} else {
+		if (lprops->dirty >= c->dead_wm &&
+		    lprops->dirty > lprops->free)
+			return LPROPS_DIRTY;
+		if (lprops->free > 0)
+			return LPROPS_FREE;
+	}
+
+	return LPROPS_UNCAT;
+}
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 22/27] ubifs: lpt: implement functions to scan lpt
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (20 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 21/27] ubifs: introduce lprops lib Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 23/27] ubifs: ubifs_dump: dump lpt area Dongsheng Yang
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Implement ubifs_scan_lpt_nolock() in lpt to scan lpt.
And then we can use this function to scan the lpt
and dump all lprops out.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/lpt.h |   3 +
 ubifs-utils/lib/lpt.c     | 661 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 663 insertions(+), 1 deletion(-)

diff --git a/ubifs-utils/include/lpt.h b/ubifs-utils/include/lpt.h
index e2f7348..d4264c3 100644
--- a/ubifs-utils/include/lpt.h
+++ b/ubifs-utils/include/lpt.h
@@ -25,5 +25,8 @@
 int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt);
 int create_lpt(struct ubifs_info *c);
 int ubifs_calc_lpt_geom(struct ubifs_info *c);
+int unpack_ltab(const struct ubifs_info *c, void *buf);
+int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum,
+			  ubifs_lpt_scan_callback scan_cb, void *data);
 
 #endif
diff --git a/ubifs-utils/lib/lpt.c b/ubifs-utils/lib/lpt.c
index 26fb4dd..52fbcfa 100644
--- a/ubifs-utils/lib/lpt.c
+++ b/ubifs-utils/lib/lpt.c
@@ -29,6 +29,7 @@
 #include "crc16.h"
 #include "ubifs.h"
 #include "lpt.h"
+#include "lprops.h"
 #include "io.h"
 
 /**
@@ -402,7 +403,6 @@ int create_lpt(struct ubifs_info *c)
 	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
@@ -614,3 +614,662 @@ int ubifs_calc_lpt_geom(struct ubifs_info *c)
 	}
 	return 0;
 }
+
+/**
+ * struct lpt_scan_node - somewhere to put nodes while we scan LPT.
+ * @nnode: where to keep a nnode
+ * @pnode: where to keep a pnode
+ * @cnode: where to keep a cnode
+ * @in_tree: is the node in the tree in memory
+ * @ptr.nnode: pointer to the nnode (if it is an nnode) which may be here or in
+ * the tree
+ * @ptr.pnode: ditto for pnode
+ * @ptr.cnode: ditto for cnode
+ */
+struct lpt_scan_node {
+	union {
+		struct ubifs_nnode nnode;
+		struct ubifs_pnode pnode;
+		struct ubifs_cnode cnode;
+	};
+	int in_tree;
+	union {
+		struct ubifs_nnode *nnode;
+		struct ubifs_pnode *pnode;
+		struct ubifs_cnode *cnode;
+	} ptr;
+};
+
+/**
+ * ubifs_unpack_bits - unpack bit fields.
+ * @addr: address at which to unpack (passed and next address returned)
+ * @pos: bit position at which to unpack (passed and next position returned)
+ * @nrbits: number of bits of value to unpack (1-32)
+ *
+ * This functions returns the value unpacked.
+ */
+uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits)
+{
+	const int k = 32 - nrbits;
+	uint8_t *p = *addr;
+	int b = *pos;
+	uint32_t val = 0;
+	const int bytes = (nrbits + b + 7) >> 3;
+
+	ubifs_assert(nrbits > 0);
+	ubifs_assert(nrbits <= 32);
+	ubifs_assert(*pos >= 0);
+	ubifs_assert(*pos < 8);
+	if (b) {
+		switch (bytes) {
+		case 2:
+			val = p[1];
+			break;
+		case 3:
+			val = p[1] | ((uint32_t)p[2] << 8);
+			break;
+		case 4:
+			val = p[1] | ((uint32_t)p[2] << 8) |
+				     ((uint32_t)p[3] << 16);
+			break;
+		case 5:
+			val = p[1] | ((uint32_t)p[2] << 8) |
+				     ((uint32_t)p[3] << 16) |
+				     ((uint32_t)p[4] << 24);
+		}
+		val <<= (8 - b);
+		val |= *p >> b;
+		nrbits += b;
+	} else {
+		switch (bytes) {
+		case 1:
+			val = p[0];
+			break;
+		case 2:
+			val = p[0] | ((uint32_t)p[1] << 8);
+			break;
+		case 3:
+			val = p[0] | ((uint32_t)p[1] << 8) |
+				     ((uint32_t)p[2] << 16);
+			break;
+		case 4:
+			val = p[0] | ((uint32_t)p[1] << 8) |
+				     ((uint32_t)p[2] << 16) |
+				     ((uint32_t)p[3] << 24);
+			break;
+		}
+	}
+	val <<= k;
+	val >>= k;
+	b = nrbits & 7;
+	p += nrbits >> 3;
+	*addr = p;
+	*pos = b;
+	ubifs_assert((val >> nrbits) == 0 || nrbits - b == 32);
+	return val;
+}
+/**
+ * calc_nnode_num_from_parent - calculate nnode number.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * 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 based on the parent's
+ * nnode number and the index in parent.
+ */
+static int calc_nnode_num_from_parent(const struct ubifs_info *c,
+				      struct ubifs_nnode *parent, int iip)
+{
+	int num, shft;
+
+	if (!parent)
+		return 1;
+	shft = (c->lpt_hght - parent->level) * UBIFS_LPT_FANOUT_SHIFT;
+	num = parent->num ^ (1 << shft);
+	num |= (UBIFS_LPT_FANOUT + iip) << shft;
+	return num;
+}
+
+int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
+		       struct ubifs_nnode *nnode);
+/**
+ * scan_get_nnode - for the scan, get a nnode from either the tree or flash.
+ * @c: the UBIFS file-system description object
+ * @path: where to put the nnode
+ * @parent: parent of the nnode
+ * @iip: index in parent of the nnode
+ *
+ * This function returns a pointer to the nnode on success or a negative error
+ * code on failure.
+ */
+static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
+					  struct lpt_scan_node *path,
+					  struct ubifs_nnode *parent, int iip)
+{
+	struct ubifs_nbranch *branch;
+	struct ubifs_nnode *nnode;
+	int i = max_t(int, c->nnode_sz, c->pnode_sz);
+	void *buf = malloc(i);;
+	int err;
+
+	branch = &parent->nbranch[iip];
+	nnode = branch->nnode;
+	if (nnode) {
+		path->in_tree = 1;
+		path->ptr.nnode = nnode;
+		free(buf);
+		return nnode;
+	}
+	nnode = &path->nnode;
+	path->in_tree = 0;
+	path->ptr.nnode = nnode;
+	memset(nnode, 0, sizeof(struct ubifs_nnode));
+	if (branch->lnum == 0) {
+		/*
+		 * This nnode was not written which just means that the LEB
+		 * properties in the subtree below it describe empty LEBs. We
+		 * make the nnode as though we had read it, which in fact means
+		 * doing almost nothing.
+		 */
+		if (c->big_lpt)
+			nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+	} else {
+		err = ubifs_read(branch->lnum * c->leb_size + branch->offs, c->nnode_sz, buf);
+		if (err) {
+			free(buf);
+			return ERR_PTR(err);
+		}
+		err = ubifs_unpack_nnode(c, buf, nnode);
+		if (err) {
+			free(buf);
+			return ERR_PTR(err);
+		}
+	}
+	if (!c->big_lpt)
+		nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+	nnode->level = parent->level - 1;
+	nnode->parent = parent;
+	nnode->iip = iip;
+
+	free(buf);
+	return nnode;
+}
+/**
+ * calc_pnode_num_from_parent - calculate pnode number.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * The pnode number is a number that uniquely identifies a pnode and can be used
+ * easily to traverse the tree from the root to that pnode.
+ *
+ * This function calculates and returns the pnode number based on the parent's
+ * nnode number and the index in parent.
+ */
+static int calc_pnode_num_from_parent(const struct ubifs_info *c,
+				      struct ubifs_nnode *parent, int iip)
+{
+	int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0;
+
+	for (i = 0; i < n; i++) {
+		num <<= UBIFS_LPT_FANOUT_SHIFT;
+		num |= pnum & (UBIFS_LPT_FANOUT - 1);
+		pnum >>= UBIFS_LPT_FANOUT_SHIFT;
+	}
+	num <<= UBIFS_LPT_FANOUT_SHIFT;
+	num |= iip;
+	return num;
+}
+/**
+ * set_pnode_lnum - set LEB numbers on a pnode.
+ * @c: UBIFS file-system description object
+ * @pnode: pnode to update
+ *
+ * This function calculates the LEB numbers for the LEB properties it contains
+ * based on the pnode number.
+ */
+static void set_pnode_lnum(const struct ubifs_info *c,
+			   struct ubifs_pnode *pnode)
+{
+	int i, lnum;
+
+	lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + c->main_first;
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		if (lnum >= c->leb_cnt)
+			return;
+		pnode->lprops[i].lnum = lnum++;
+	}
+}
+/**
+ * check_lpt_crc - check LPT node crc is correct.
+ * @c: UBIFS file-system description object
+ * @buf: buffer containing node
+ * @len: length of node
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int check_lpt_crc(const struct ubifs_info *c __attribute__((unused)), void *buf, int len)
+{
+	int pos = 0;
+	uint8_t *addr = buf;
+	uint16_t crc, calc_crc;
+
+	crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS);
+	calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+			 len - UBIFS_LPT_CRC_BYTES);
+	if (crc != calc_crc) {
+		ubifs_err(c, "invalid crc in LPT node: crc %hx calc %hx",
+			  crc, calc_crc);
+		return -EINVAL;
+	}
+	return 0;
+}
+/**
+ * check_lpt_type - check LPT node type is correct.
+ * @c: UBIFS file-system description object
+ * @addr: address of type bit field is passed and returned updated here
+ * @pos: position of type bit field is passed and returned updated here
+ * @type: expected type
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int check_lpt_type(const struct ubifs_info *c __attribute__((unused)), uint8_t **addr,
+			  int *pos, int type)
+{
+	int node_type;
+
+	node_type = ubifs_unpack_bits(addr, pos, UBIFS_LPT_TYPE_BITS);
+	if (node_type != type) {
+		ubifs_err(c, "invalid type (%d) in LPT node type %d",
+			  node_type, type);
+		return -EINVAL;
+	}
+	return 0;
+}
+/**
+ * unpack_pnode - unpack a pnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer containing packed pnode to unpack
+ * @pnode: pnode structure to fill
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int unpack_pnode(const struct ubifs_info *c, void *buf,
+			struct ubifs_pnode *pnode)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0, err;
+
+	err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_PNODE);
+	if (err)
+		return err;
+	if (c->big_lpt)
+		pnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		struct ubifs_lprops * const lprops = &pnode->lprops[i];
+
+		lprops->free = ubifs_unpack_bits(&addr, &pos, c->space_bits);
+		lprops->free <<= 3;
+		lprops->dirty = ubifs_unpack_bits(&addr, &pos, c->space_bits);
+		lprops->dirty <<= 3;
+
+		if (ubifs_unpack_bits(&addr, &pos, 1))
+			lprops->flags = LPROPS_INDEX;
+		else
+			lprops->flags = 0;
+		lprops->flags |= ubifs_categorize_lprops(c, lprops);
+	}
+	err = check_lpt_crc(c, buf, c->pnode_sz);
+	return err;
+}
+/**
+ * ubifs_unpack_nnode - unpack a nnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer containing packed nnode to unpack
+ * @nnode: nnode structure to fill
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
+		       struct ubifs_nnode *nnode)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0, err;
+
+	err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_NNODE);
+	if (err)
+		return err;
+	if (c->big_lpt)
+		nnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		int lnum;
+
+		lnum = ubifs_unpack_bits(&addr, &pos, c->lpt_lnum_bits) +
+		       c->lpt_first;
+		if (lnum == c->lpt_last + 1)
+			lnum = 0;
+		nnode->nbranch[i].lnum = lnum;
+		nnode->nbranch[i].offs = ubifs_unpack_bits(&addr, &pos,
+						     c->lpt_offs_bits);
+	}
+	err = check_lpt_crc(c, buf, c->nnode_sz);
+	return err;
+}
+/**
+ * unpack_ltab - unpack the LPT's own lprops table.
+ * @c: UBIFS file-system description object
+ * @buf: buffer from which to unpack
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int unpack_ltab(const struct ubifs_info *c, void *buf)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0, err;
+
+	err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_LTAB);
+	if (err)
+		return err;
+	for (i = 0; i < c->lpt_lebs; i++) {
+		int free = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
+		int dirty = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
+
+		if (free < 0 || free > c->leb_size || dirty < 0 ||
+		    dirty > c->leb_size || free + dirty > c->leb_size)
+			return -EINVAL;
+
+		c->ltab[i].free = free;
+		c->ltab[i].dirty = dirty;
+		c->ltab[i].tgc = 0;
+		c->ltab[i].cmt = 0;
+	}
+	return 0;
+}
+
+/**
+ * scan_get_pnode - for the scan, get a pnode from either the tree or flash.
+ * @c: the UBIFS file-system description object
+ * @path: where to put the pnode
+ * @parent: parent of the pnode
+ * @iip: index in parent of the pnode
+ *
+ * This function returns a pointer to the pnode on success or a negative error
+ * code on failure.
+ */
+static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
+					  struct lpt_scan_node *path,
+					  struct ubifs_nnode *parent, int iip)
+{
+	struct ubifs_nbranch *branch;
+	struct ubifs_pnode *pnode;
+	int i = max_t(int, c->nnode_sz, c->pnode_sz);
+	void *buf = malloc(i);;
+	int err;
+
+	branch = &parent->nbranch[iip];
+	pnode = branch->pnode;
+	if (pnode) {
+		path->in_tree = 1;
+		path->ptr.pnode = pnode;
+		free(buf);
+		return pnode;
+	}
+	pnode = &path->pnode;
+	path->in_tree = 0;
+	path->ptr.pnode = pnode;
+	memset(pnode, 0, sizeof(struct ubifs_pnode));
+	if (branch->lnum == 0) {
+		/*
+		 * This pnode was not written which just means that the LEB
+		 * properties in it describe empty LEBs. We make the pnode as
+		 * though we had read it.
+		 */
+		int i;
+
+		if (c->big_lpt)
+			pnode->num = calc_pnode_num_from_parent(c, parent, iip);
+		for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+			struct ubifs_lprops * const lprops = &pnode->lprops[i];
+
+			lprops->free = c->leb_size;
+			lprops->flags = ubifs_categorize_lprops(c, lprops);
+		}
+	} else {
+		ubifs_assert(branch->lnum >= c->lpt_first &&
+			     branch->lnum <= c->lpt_last);
+		ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
+		err = ubifs_read(branch->lnum * c->leb_size + branch->offs, c->pnode_sz, buf);
+		if (err) {
+			free(buf);
+			return ERR_PTR(err);
+		}
+		err = unpack_pnode(c, buf, pnode);
+		if (err) {
+			free(buf);
+			return ERR_PTR(err);
+		}
+	}
+	if (!c->big_lpt)
+		pnode->num = calc_pnode_num_from_parent(c, parent, iip);
+	pnode->parent = parent;
+	pnode->iip = iip;
+	set_pnode_lnum(c, pnode);
+	free(buf);
+	return pnode;
+}
+/**
+ * ubifs_read_nnode - read a nnode from flash and link it to the tree in memory.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode (or NULL for the root)
+ * @iip: index in parent
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+{
+	struct ubifs_nbranch *branch = NULL;
+	struct ubifs_nnode *nnode = NULL;
+	void *buf = c->lpt_nod_buf;
+	int err, lnum, offs;
+
+	if (parent) {
+		branch = &parent->nbranch[iip];
+		lnum = branch->lnum;
+		offs = branch->offs;
+	} else {
+		lnum = c->lpt_lnum;
+		offs = c->lpt_offs;
+	}
+	nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
+	if (!nnode) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (lnum == 0) {
+		/*
+		 * This nnode was not written which just means that the LEB
+		 * properties in the subtree below it describe empty LEBs. We
+		 * make the nnode as though we had read it, which in fact means
+		 * doing almost nothing.
+		 */
+		if (c->big_lpt)
+			nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+	} else {
+		err = ubifs_read(lnum * c->leb_size + offs, c->nnode_sz, buf);
+		if (err)
+			goto out;
+		err = ubifs_unpack_nnode(c, buf, nnode);
+		if (err)
+			goto out;
+	}
+	if (!c->big_lpt)
+		nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+	if (parent) {
+		branch->nnode = nnode;
+		nnode->level = parent->level - 1;
+	} else {
+		c->nroot = nnode;
+		nnode->level = c->lpt_hght;
+	}
+	nnode->parent = parent;
+	nnode->iip = iip;
+	return 0;
+
+out:
+	ubifs_err(c, "error %d reading nnode at %d:%d", err, lnum, offs);
+	kfree(nnode);
+	return err;
+}
+
+/**
+ * ubifs_lpt_scan_nolock - scan the LPT.
+ * @c: the UBIFS file-system description object
+ * @start_lnum: LEB number from which to start scanning
+ * @end_lnum: LEB number at which to stop scanning
+ * @scan_cb: callback function called for each lprops
+ * @data: data to be passed to the callback function
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum,
+			  ubifs_lpt_scan_callback scan_cb, void *data)
+{
+	int err = 0, i, h, iip, shft;
+	struct ubifs_nnode *nnode;
+	struct ubifs_pnode *pnode;
+	struct lpt_scan_node *path;
+
+	if (start_lnum == -1) {
+		start_lnum = end_lnum + 1;
+		if (start_lnum >= c->leb_cnt)
+			start_lnum = c->main_first;
+	}
+
+	ubifs_assert(start_lnum >= c->main_first && start_lnum < c->leb_cnt);
+	ubifs_assert(end_lnum >= c->main_first && end_lnum < c->leb_cnt);
+
+	if (!c->nroot) {
+		err = ubifs_read_nnode(c, NULL, 0);
+		if (err)
+			return err;
+	}
+
+	path = kmalloc(sizeof(struct lpt_scan_node) * (c->lpt_hght + 1),
+		       GFP_NOFS);
+	if (!path)
+		return -ENOMEM;
+
+	path[0].ptr.nnode = c->nroot;
+	path[0].in_tree = 1;
+again:
+	/* Descend to the pnode containing start_lnum */
+	nnode = c->nroot;
+	i = start_lnum - c->main_first;
+	shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
+	for (h = 1; h < c->lpt_hght; h++) {
+		iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
+		shft -= UBIFS_LPT_FANOUT_SHIFT;
+		nnode = scan_get_nnode(c, path + h, nnode, iip);
+		if (IS_ERR(nnode)) {
+			err = PTR_ERR(nnode);
+			goto out;
+		}
+	}
+	iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
+	pnode = scan_get_pnode(c, path + h, nnode, iip);
+	if (IS_ERR(pnode)) {
+		err = PTR_ERR(pnode);
+		goto out;
+	}
+	iip = (i & (UBIFS_LPT_FANOUT - 1));
+
+	/* Loop for each lprops */
+	while (1) {
+		struct ubifs_lprops *lprops = &pnode->lprops[iip];
+		int ret, lnum = lprops->lnum;
+
+		ret = scan_cb(c, lprops, path[h].in_tree, data);
+		if (ret < 0) {
+			err = ret;
+			goto out;
+		}
+		if (ret & LPT_SCAN_ADD) {
+			/* Add all the nodes in path to the tree in memory */
+			for (h = 1; h < c->lpt_hght; h++) {
+				const size_t sz = sizeof(struct ubifs_nnode);
+				struct ubifs_nnode *parent;
+
+				if (path[h].in_tree)
+					continue;
+				nnode = malloc(sz);
+				if (!nnode) {
+					err = -ENOMEM;
+					goto out;
+				}
+				memcpy(nnode, &path[h].nnode, sz);
+				parent = nnode->parent;
+				parent->nbranch[nnode->iip].nnode = nnode;
+				path[h].ptr.nnode = nnode;
+				path[h].in_tree = 1;
+				path[h + 1].cnode.parent = nnode;
+			}
+		}
+		if (ret & LPT_SCAN_STOP) {
+			err = 0;
+			break;
+		}
+		/* Get the next lprops */
+		if (lnum == end_lnum) {
+			/*
+			 * We got to the end without finding what we were
+			 * looking for
+			 */
+			err = -ENOSPC;
+			goto out;
+		}
+		if (lnum + 1 >= c->leb_cnt) {
+			/* Wrap-around to the beginning */
+			start_lnum = c->main_first;
+			goto again;
+		}
+		if (iip + 1 < UBIFS_LPT_FANOUT) {
+			/* Next lprops is in the same pnode */
+			iip += 1;
+			continue;
+		}
+		/* We need to get the next pnode. Go up until we can go right */
+		iip = pnode->iip;
+		while (1) {
+			h -= 1;
+			ubifs_assert(h >= 0);
+			nnode = path[h].ptr.nnode;
+			if (iip + 1 < UBIFS_LPT_FANOUT)
+				break;
+			iip = nnode->iip;
+		}
+		/* Go right */
+		iip += 1;
+		/* Descend to the pnode */
+		h += 1;
+		for (; h < c->lpt_hght; h++) {
+			nnode = scan_get_nnode(c, path + h, nnode, iip);
+			if (IS_ERR(nnode)) {
+				err = PTR_ERR(nnode);
+				goto out;
+			}
+			iip = 0;
+		}
+		pnode = scan_get_pnode(c, path + h, nnode, iip);
+		if (IS_ERR(pnode)) {
+			err = PTR_ERR(pnode);
+			goto out;
+		}
+		iip = 0;
+	}
+out:
+	kfree(path);
+	return err;
+}
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 23/27] ubifs: ubifs_dump: dump lpt area
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (21 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 22/27] ubifs: lpt: implement functions to scan lpt Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 24/27] ubifs: ubifs_dump: dump index area Dongsheng Yang
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

At first dump the ltab and then scan the whole lpt,
dumping every lprops in it.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 Makefile                            |   2 +-
 ubifs-utils/ubifs_dump/ubifs_dump.c | 170 ++++++++++++++++++++++++++++++++++++
 2 files changed, 171 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 7abbef9..af17307 100644
--- a/Makefile
+++ b/Makefile
@@ -133,7 +133,7 @@ $(foreach v,$(UBI_BINS),$(eval $(call mkdep,ubi-utils/,$(v),libubi.a ubiutils-co
 $(foreach v,crc16.o lpt.o compr.o devtable.o io.o hashtable.o hashtable_itr.o,$(eval UBIFS_LIBS += ../lib/$(v)))
 
 obj-ubifs_dump = $(UBIFS_LIBS)
-obj-ubifs_dump += ../lib/scan.o
+obj-ubifs_dump += ../lib/scan.o ../lib/lprops.o
 LDFLAGS_ubifs_dump = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
 LDLIBS_ubifs_dump = -lz -llzo2 -lm -luuid
 $(call mkdep,ubifs-utils/ubifs_dump/,ubifs_dump,,ubi-utils/libubi.a)
diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
index d7a2951..4b255e3 100644
--- a/ubifs-utils/ubifs_dump/ubifs_dump.c
+++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
@@ -717,6 +717,172 @@ out:
 	return err;
 }
 
+void ubifs_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+{
+	int spc, dark = 0, dead = 0;
+
+	if ((lp->flags & LPROPS_CAT_MASK) == LPROPS_EMPTY)
+		return;
+
+	spc = lp->free + lp->dirty;
+	dead = spc;
+
+	if (lp->flags & LPROPS_INDEX)
+		printf("\tLEB %-7d free %-8d dirty %-8d used %-8d free + dirty %-8d flags %#x (",
+		       lp->lnum, lp->free, lp->dirty, c->leb_size - spc, spc,
+		       lp->flags);
+	else
+		printf("\tLEB %-7d free %-8d dirty %-8d used %-8d free + dirty %-8d dark %-4d dead %-4d nodes fit %-3d flags %#-4x (",
+		       lp->lnum, lp->free, lp->dirty, c->leb_size - spc, spc,
+		       dark, dead, (int)(spc / UBIFS_MAX_NODE_SZ), lp->flags);
+
+	if (lp->flags & LPROPS_TAKEN) {
+		if (lp->flags & LPROPS_INDEX)
+			printf("index, taken");
+		else
+			printf("taken");
+	} else {
+		const char *s;
+
+		if (lp->flags & LPROPS_INDEX) {
+			switch (lp->flags & LPROPS_CAT_MASK) {
+			case LPROPS_DIRTY_IDX:
+				s = "dirty index";
+				break;
+			case LPROPS_FRDI_IDX:
+				s = "freeable index";
+				break;
+			default:
+				s = "index";
+			}
+		} else {
+			switch (lp->flags & LPROPS_CAT_MASK) {
+			case LPROPS_UNCAT:
+				s = "not categorized";
+				break;
+			case LPROPS_DIRTY:
+				s = "dirty";
+				break;
+			case LPROPS_FREE:
+				s = "free";
+				break;
+			case LPROPS_EMPTY:
+				s = "empty";
+				break;
+			case LPROPS_FREEABLE:
+				s = "freeable";
+				break;
+			default:
+				s = NULL;
+				break;
+			}
+		}
+		printf("%s", s);
+	}
+
+	if (lp->lnum == c->gc_lnum)
+		printf(", GC LEB");
+	printf(")\n");
+}
+
+void ubifs_dump_lstats(const struct ubifs_lp_stats *lst)
+{
+	printf("\tempty_lebs %d, idx_lebs  %d\n",
+	       lst->empty_lebs, lst->idx_lebs);
+	printf("\ttaken_empty_lebs %d, total_free %lld, total_dirty %lld\n",
+	       lst->taken_empty_lebs, lst->total_free, lst->total_dirty);
+	printf("\ttotal_used %lld, total_dark %lld, total_dead %lld\n",
+	       lst->total_used, lst->total_dark, lst->total_dead);
+	printf("\n");
+}
+
+static int scan_dump_cb(struct ubifs_info *c,
+			 const struct ubifs_lprops *lp, int in_tree __attribute__((unused)),
+			 struct ubifs_lp_stats *lst __attribute__((unused)))
+{
+	ubifs_dump_lprop(c, lp);
+	return 0;
+}
+
+static int ubifs_dump_lprops(struct ubifs_info *c)
+{
+	printf("\tLPROPS statistics: \n");
+	ubifs_dump_lstats(&c->lst);
+	printf("\tLPROPS TREE: \n");
+	c->lpt_nod_buf = malloc(min(c->nnode_sz, c->pnode_sz));
+	ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
+			  (ubifs_lpt_scan_callback)scan_dump_cb, NULL);
+	printf("\n");
+
+	return 0;
+}
+
+/**
+ * read_ltab - read LPT's own lprops table.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int read_ltab(struct ubifs_info *c)
+{
+	int err;
+	void *buf;
+
+	buf = vmalloc(c->ltab_sz);
+	if (!buf)
+		return -ENOMEM;
+	err = ubifs_read(c->ltab_lnum * c->leb_size + c->ltab_offs, c->ltab_sz, buf);
+	if (err)
+		goto out;
+	err = unpack_ltab(c, buf);
+out:
+	vfree(buf);
+	return err;
+}
+
+static int ubifs_dump_lpt_info(struct ubifs_info *c)
+{
+	int i;
+	int ret = 0;
+
+	c->ltab = malloc(c->lpt_lebs * sizeof(struct ubifs_lprops));
+	if (!c->ltab)
+		return err_msg("unable to allocate LPT ltab");
+
+	ret = read_ltab(c);
+	if (ret)
+		return ret;
+	printf("\tLPT INFO: \n");
+	printf("\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
+	printf("\tLPT head is at %d:%d\n",
+	       c->nhead_lnum, c->nhead_offs);
+	printf("\tLPT ltab is at %d:%d\n", c->ltab_lnum, c->ltab_offs);
+	if (c->big_lpt)
+		printf("\tLPT lsave is at %d:%d\n",
+		       c->lsave_lnum, c->lsave_offs);
+	for (i = 0; i < c->lpt_lebs; i++)
+		printf("\tLPT LEB %d free %d dirty %d tgc %d cmt %d\n",
+		       i + c->lpt_first, c->ltab[i].free, c->ltab[i].dirty,
+		       c->ltab[i].tgc, c->ltab[i].cmt);
+	printf("\n");
+	return 0;
+}
+
+static int dump_lpt(void)
+{
+	int ret = 0;
+
+	printf("LPT AREA: \n");
+	ret = ubifs_dump_lpt_info(c);
+	if (ret)
+		return ret;
+
+	ret = ubifs_dump_lprops(c);
+	if (ret)
+		return ret;
+	return 0;
+}
+
 static int dump()
 {
 	int err = 0;
@@ -738,6 +904,10 @@ static int dump()
 	err = dump_log();
 	if (err)
 		goto free;
+
+	err = dump_lpt();
+	if (err)
+		goto free;
 free:
 	free(leb_buf);
 out:
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 24/27] ubifs: ubifs_dump: dump index area
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (22 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 23/27] ubifs: ubifs_dump: dump lpt area Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 25/27] ubifs: defs.h: introduce some compatible definitions about integer such as __u16 Dongsheng Yang
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Scan the whole index tree and dump each index node.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/ubifs_dump/ubifs_dump.c | 95 +++++++++++++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)

diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
index 4b255e3..e72b8dd 100644
--- a/ubifs-utils/ubifs_dump/ubifs_dump.c
+++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
@@ -883,6 +883,97 @@ static int dump_lpt(void)
 	return 0;
 }
 
+/**
+ * ubifs_read_node - read node.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to read to
+ * @type: node type
+ * @len: node length (not aligned)
+ * @lnum: logical eraseblock number
+ * @offs: offset within the logical eraseblock
+ *
+ * This function reads a node of known type and and length, checks it and
+ * stores in @buf. Returns zero in case of success, %-EUCLEAN if CRC mismatched
+ * and a negative error code in case of failure.
+ */
+int ubifs_read_node(const struct ubifs_info *c, void *buf, int len,
+		    int lnum, loff_t offs)
+{
+	int err;
+
+	ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
+	ubifs_assert(len >= UBIFS_CH_SZ && offs + len <= c->leb_size);
+	ubifs_assert(!(offs & 7) && offs < c->leb_size);
+	ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
+
+	err = ubifs_read((loff_t)lnum * c->leb_size + offs, len, buf);
+	if (err && err != -EBADMSG)
+		return err;
+
+	return 0;
+}
+
+static int dump_zbr(struct ubifs_info *c, struct ubifs_zbranch *zbr)
+{
+	int i = 0;
+	int err = 0;
+	struct ubifs_idx_node *idx;
+	void *buf;
+
+	buf = malloc(zbr->len);
+	if (!buf)
+		return -ENOMEM;
+
+	err = ubifs_read_node(c, buf, zbr->len, zbr->lnum, zbr->offs);
+	if (err)
+		goto out;
+
+	dump_node(c, buf);
+
+	if (((struct ubifs_ch *)buf)->node_type != UBIFS_IDX_NODE)
+		goto out;
+
+	idx = ((struct ubifs_idx_node *)buf);
+	for (i = 0; i < le16_to_cpu(idx->child_cnt); i++) {
+		struct ubifs_branch *br;
+		struct ubifs_zbranch child;
+
+		br = ubifs_idx_branch(c, idx, i);
+		child.lnum = le32_to_cpu(br->lnum);
+		child.offs = le32_to_cpu(br->offs);
+		child.len = le32_to_cpu(br->len);
+		err = dump_zbr(c, &child);
+		if (err)
+			goto out;
+	}
+
+out:
+	free(buf);
+	return err;
+}
+
+static int dump_index()
+{
+	int err = 0;
+
+	printf("\tINDEX AREA: \n");
+	err = dump_zbr(c, &c->zroot);
+	if (err)
+		return err;
+	return 0;
+}
+
+static int dump_main()
+{
+	int err = 0;
+	printf("MAIN AREA: \n");
+	err = dump_index();
+	if (err)
+		return err;
+
+	return 0;
+}
+
 static int dump()
 {
 	int err = 0;
@@ -908,6 +999,10 @@ static int dump()
 	err = dump_lpt();
 	if (err)
 		goto free;
+
+	err = dump_main();
+	if (err)
+		goto free;
 free:
 	free(leb_buf);
 out:
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 25/27] ubifs: defs.h: introduce some compatible definitions about integer such as __u16
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (23 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 24/27] ubifs: ubifs_dump: dump index area Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 26/27] ubifs: introduce hexdump lib Dongsheng Yang
                   ` (2 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Add __uXX class compatible definitions in defs.h

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/defs.h | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/ubifs-utils/include/defs.h b/ubifs-utils/include/defs.h
index ed42ab1..91ef175 100644
--- a/ubifs-utils/include/defs.h
+++ b/ubifs-utils/include/defs.h
@@ -174,6 +174,36 @@ static inline long IS_ERR(const void *ptr)
 #define ULONG_MAX       (~0UL)
 #endif
 
+#ifndef __CHECKER__
+/*
+ * Since we're using primitive definitions from kernel-space, we need to
+ * define __KERNEL__ so that system header files know which definitions
+ * to use.
+ */
+#define __KERNEL__
+#include <asm/types.h>
+typedef __u32 u32;
+typedef __u64 u64;
+typedef __u16 u16;
+typedef __u8 u8;
+typedef __s64 s64;
+typedef __s32 s32;
+
+/*
+ * Continuing to define __KERNEL__ breaks others parts of the code, so
+ * we can just undefine it now that we have the correct headers...
+ */
+#undef __KERNEL__
+#else
+typedef unsigned int u32;
+typedef unsigned int __u32;
+typedef unsigned long long u64;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef long long s64;
+typedef int s32;
+#endif
+
 #if INT_MAX != 0x7fffffff
 #error : sizeof(int) must be 4 for this program
 #endif
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 26/27] ubifs: introduce hexdump lib
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (24 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 25/27] ubifs: defs.h: introduce some compatible definitions about integer such as __u16 Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-15  4:04 ` [PATCH v2 27/27] ubifs: ubifs_dump: dump data in hex format Dongsheng Yang
  2015-10-31  3:13 ` [PATCH] gitignore: add ubifs_dump to gitignore Dongsheng Yang
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Introduce a hexdump lib to allow us to dump data in hex format

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ubifs-utils/include/hexdump.h |  21 +++++
 ubifs-utils/lib/hexdump.c     | 200 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 221 insertions(+)
 create mode 100644 ubifs-utils/include/hexdump.h
 create mode 100644 ubifs-utils/lib/hexdump.c

diff --git a/ubifs-utils/include/hexdump.h b/ubifs-utils/include/hexdump.h
new file mode 100644
index 0000000..f5f2800
--- /dev/null
+++ b/ubifs-utils/include/hexdump.h
@@ -0,0 +1,21 @@
+#ifndef __UBIFS_HEXDUMP_H__
+#define __UBIFS_HEXDUMP_H__
+
+#include "ubifs_common.h"
+
+static const char hex_asc[] = "0123456789abcdef";
+static const char hex_asc_upper[] = "0123456789ABCDEF";
+
+#define hex_asc_lo(x)	hex_asc[((x) & 0x0f)]
+#define hex_asc_hi(x)	hex_asc[((x) & 0xf0) >> 4]
+
+enum {
+	DUMP_PREFIX_NONE,
+	DUMP_PREFIX_ADDRESS,
+	DUMP_PREFIX_OFFSET
+};
+
+void print_hex_dump(const char *prefix_str, int prefix_type,
+		    int rowsize, int groupsize,
+		    const void *buf, size_t len, int ascii);
+#endif
diff --git a/ubifs-utils/lib/hexdump.c b/ubifs-utils/lib/hexdump.c
new file mode 100644
index 0000000..c58f7cc
--- /dev/null
+++ b/ubifs-utils/lib/hexdump.c
@@ -0,0 +1,200 @@
+/*
+ * lib/hexdump.c
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+#include "hexdump.h"
+#define PROGRAM_NAME "hexdump"
+#include "common.h"
+/**
+ * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ * @rowsize: number of bytes to print per line; must be 16 or 32
+ * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
+ * @linebuf: where to put the converted data
+ * @linebuflen: total size of @linebuf, including space for terminating NUL
+ * @ascii: include ASCII after the hex output
+ *
+ * hex_dump_to_buffer() works on one "line" of output at a time, i.e.,
+ * 16 or 32 bytes of input data converted to hex + ASCII output.
+ *
+ * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data
+ * to a hex + ASCII dump at the supplied memory location.
+ * The converted output is always NUL-terminated.
+ *
+ * E.g.:
+ *   hex_dump_to_buffer(frame->data, frame->len, 16, 1,
+ *			linebuf, sizeof(linebuf), true);
+ *
+ * example output buffer:
+ * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
+ *
+ * Return:
+ * The amount of bytes placed in the buffer without terminating NUL. If the
+ * output was truncated, then the return value is the number of bytes
+ * (excluding the terminating NUL) which would have been written to the final
+ * string if enough space had been available.
+ */
+int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
+		       char *linebuf, size_t linebuflen, int ascii)
+{
+	const u8 *ptr = buf;
+	int ngroups;
+	u8 ch;
+	int j, lx = 0;
+	int ascii_column;
+	int ret;
+
+	if (rowsize != 16 && rowsize != 32)
+		rowsize = 16;
+
+	if (len > rowsize)		/* limit to one line at a time */
+		len = rowsize;
+	if (!is_power_of_2(groupsize) || groupsize > 8)
+		groupsize = 1;
+	if ((len % groupsize) != 0)	/* no mixed size output */
+		groupsize = 1;
+
+	ngroups = len / groupsize;
+	ascii_column = rowsize * 2 + rowsize / groupsize + 1;
+
+	if (!linebuflen)
+		goto overflow1;
+
+	if (!len)
+		goto nil;
+
+	if (groupsize == 8) {
+		const u64 *ptr8 = buf;
+
+		for (j = 0; j < ngroups; j++) {
+			ret = snprintf(linebuf + lx, linebuflen - lx,
+				       "%s%16.16llx", j ? " " : "",
+				       (unsigned long long)*(ptr8 + j));
+			if (ret >= linebuflen - lx)
+				goto overflow1;
+			lx += ret;
+		}
+	} else if (groupsize == 4) {
+		const u32 *ptr4 = buf;
+
+		for (j = 0; j < ngroups; j++) {
+			ret = snprintf(linebuf + lx, linebuflen - lx,
+				       "%s%8.8x", j ? " " : "",
+				       *(ptr4 + j));
+			if (ret >= linebuflen - lx)
+				goto overflow1;
+			lx += ret;
+		}
+	} else if (groupsize == 2) {
+		const u16 *ptr2 = buf;
+
+		for (j = 0; j < ngroups; j++) {
+			ret = snprintf(linebuf + lx, linebuflen - lx,
+				       "%s%4.4x", j ? " " : "",
+				       *(ptr2 + j));
+			if (ret >= linebuflen - lx)
+				goto overflow1;
+			lx += ret;
+		}
+	} else {
+		for (j = 0; j < len; j++) {
+			if (linebuflen < lx + 3)
+				goto overflow2;
+			ch = ptr[j];
+			linebuf[lx++] = hex_asc_hi(ch);
+			linebuf[lx++] = hex_asc_lo(ch);
+			linebuf[lx++] = ' ';
+		}
+		if (j)
+			lx--;
+	}
+	if (!ascii)
+		goto nil;
+
+	while (lx < ascii_column) {
+		if (linebuflen < lx + 2)
+			goto overflow2;
+		linebuf[lx++] = ' ';
+	}
+	for (j = 0; j < len; j++) {
+		if (linebuflen < lx + 2)
+			goto overflow2;
+		ch = ptr[j];
+		linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
+	}
+nil:
+	linebuf[lx] = '\0';
+	return lx;
+overflow2:
+	linebuf[lx++] = '\0';
+overflow1:
+	return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
+}
+
+/**
+ * print_hex_dump - print a text hex dump to syslog for a binary blob of data
+ * @prefix_str: string to prefix each line with;
+ *  caller supplies trailing spaces for alignment if desired
+ * @prefix_type: controls whether prefix of an offset, address, or none
+ *  is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
+ * @rowsize: number of bytes to print per line; must be 16 or 32
+ * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ * @ascii: include ASCII after the hex output
+ *
+ * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump
+ * to the kernel log at the specified kernel log level, with an optional
+ * leading prefix.
+ *
+ * print_hex_dump() works on one "line" of output at a time, i.e.,
+ * 16 or 32 bytes of input data converted to hex + ASCII output.
+ * print_hex_dump() iterates over the entire input @buf, breaking it into
+ * "line size" chunks to format and print.
+ *
+ * E.g.:
+ *   print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS,
+ *		    16, 1, frame->data, frame->len, true);
+ *
+ * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode:
+ * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
+ * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode:
+ * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c  pqrstuvwxyz{|}~.
+ */
+void print_hex_dump(const char *prefix_str, int prefix_type,
+		    int rowsize, int groupsize,
+		    const void *buf, size_t len, int ascii)
+{
+	const u8 *ptr = buf;
+	int i, linelen, remaining = len;
+	char linebuf[32 * 3 + 2 + 32 + 1];
+
+	if (rowsize != 16 && rowsize != 32)
+		rowsize = 16;
+
+	for (i = 0; i < len; i += rowsize) {
+		linelen = min(remaining, rowsize);
+		remaining -= rowsize;
+
+		hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
+				   linebuf, sizeof(linebuf), ascii);
+
+		switch (prefix_type) {
+		case DUMP_PREFIX_ADDRESS:
+			printf("%s%p: %s\n",
+			       prefix_str, ptr + i, linebuf);
+			break;
+		case DUMP_PREFIX_OFFSET:
+			printf("%s%.8x: %s\n", prefix_str, i, linebuf);
+			break;
+		default:
+			printf("%s%s\n", prefix_str, linebuf);
+			break;
+		}
+	}
+}
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 27/27] ubifs: ubifs_dump: dump data in hex format
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (25 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 26/27] ubifs: introduce hexdump lib Dongsheng Yang
@ 2015-10-15  4:04 ` Dongsheng Yang
  2015-10-31  3:13 ` [PATCH] gitignore: add ubifs_dump to gitignore Dongsheng Yang
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:04 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

When we dump data node, we can dump the data in it
in hex format.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 Makefile                            |  2 +-
 ubifs-utils/ubifs_dump/ubifs_dump.c | 42 ++++++++++++++++++++-----------------
 2 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/Makefile b/Makefile
index af17307..e3b670d 100644
--- a/Makefile
+++ b/Makefile
@@ -133,7 +133,7 @@ $(foreach v,$(UBI_BINS),$(eval $(call mkdep,ubi-utils/,$(v),libubi.a ubiutils-co
 $(foreach v,crc16.o lpt.o compr.o devtable.o io.o hashtable.o hashtable_itr.o,$(eval UBIFS_LIBS += ../lib/$(v)))
 
 obj-ubifs_dump = $(UBIFS_LIBS)
-obj-ubifs_dump += ../lib/scan.o ../lib/lprops.o
+obj-ubifs_dump += ../lib/scan.o ../lib/lprops.o ../lib/hexdump.o
 LDFLAGS_ubifs_dump = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
 LDLIBS_ubifs_dump = -lz -llzo2 -lm -luuid
 $(call mkdep,ubifs-utils/ubifs_dump/,ubifs_dump,,ubi-utils/libubi.a)
diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
index e72b8dd..47b0c89 100644
--- a/ubifs-utils/ubifs_dump/ubifs_dump.c
+++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
@@ -7,6 +7,7 @@
 #include "key.h"
 #include "lpt.h"
 #include "scan.h"
+#include "hexdump.h"
 
 #define DBG_KEY_BUF_LEN		48
 
@@ -252,26 +253,26 @@ void dump_node(const struct ubifs_info *c, const void *node)
 		const struct ubifs_ino_node *ino = node;
 
 		key_read(c, &ino->key, &key);
-		printf("\t\tkey \t\t\t%s\n",
+		printf("\t\tkey \t\t\t\t%s\n",
 		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
 		printf("\t\tcreat_sqnum \t\t\t%llu\n",
 		       (unsigned long long)le64_to_cpu(ino->creat_sqnum));
-		printf("\t\tsize \t\t\t%llu\n",
+		printf("\t\tsize \t\t\t\t%llu\n",
 		       (unsigned long long)le64_to_cpu(ino->size));
-		printf("\t\tnlink \t\t\t%u\n", le32_to_cpu(ino->nlink));
-		printf("\t\tatime \t\t\t%lld.%u\n",
+		printf("\t\tnlink \t\t\t\t%u\n", le32_to_cpu(ino->nlink));
+		printf("\t\tatime \t\t\t\t%lld.%u\n",
 		       (long long)le64_to_cpu(ino->atime_sec),
 		       le32_to_cpu(ino->atime_nsec));
-		printf("\t\tmtime \t\t\t%lld.%u\n",
+		printf("\t\tmtime \t\t\t\t%lld.%u\n",
 		       (long long)le64_to_cpu(ino->mtime_sec),
 		       le32_to_cpu(ino->mtime_nsec));
-		printf("\t\tctime \t\t\t%lld.%u\n",
+		printf("\t\tctime \t\t\t\t%lld.%u\n",
 		       (long long)le64_to_cpu(ino->ctime_sec),
 		       le32_to_cpu(ino->ctime_nsec));
-		printf("\t\tuid \t\t\t%u\n", le32_to_cpu(ino->uid));
-		printf("\t\tgid \t\t\t%u\n", le32_to_cpu(ino->gid));
-		printf("\t\tmode \t\t\t%u\n", le32_to_cpu(ino->mode));
-		printf("\t\tflags \t\t\t%#x\n", le32_to_cpu(ino->flags));
+		printf("\t\tuid \t\t\t\t%u\n", le32_to_cpu(ino->uid));
+		printf("\t\tgid \t\t\t\t%u\n", le32_to_cpu(ino->gid));
+		printf("\t\tmode \t\t\t\t%u\n", le32_to_cpu(ino->mode));
+		printf("\t\tflags \t\t\t\t%#x\n", le32_to_cpu(ino->flags));
 		printf("\t\txattr_cnt \t\t\t%u\n", le32_to_cpu(ino->xattr_cnt));
 		printf("\t\txattr_size \t\t\t%u\n", le32_to_cpu(ino->xattr_size));
 		printf("\t\txattr_names \t\t\t%u\n", le32_to_cpu(ino->xattr_names));
@@ -287,13 +288,13 @@ void dump_node(const struct ubifs_info *c, const void *node)
 		int nlen = le16_to_cpu(dent->nlen);
 
 		key_read(c, &dent->key, &key);
-		printf("\t\tkey \t\t\t%s\n",
+		printf("\t\tkey \t\t\t\t%s\n",
 		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
-		printf("\t\tinum \t\t\t%llu\n",
+		printf("\t\tinum \t\t\t\t%llu\n",
 		       (unsigned long long)le64_to_cpu(dent->inum));
-		printf("\t\ttype \t\t\t%d\n", (int)dent->type);
-		printf("\t\tnlen \t\t\t%d\n", nlen);
-		printf("\t\tname           ");
+		printf("\t\ttype \t\t\t\t%d\n", (int)dent->type);
+		printf("\t\tnlen \t\t\t\t%d\n", nlen);
+		printf("\t\tname \t\t\t\t");
 
 		if (nlen > UBIFS_MAX_NLEN)
 			printf("(bad name length, not printing, bad or corrupted node)");
@@ -311,12 +312,15 @@ void dump_node(const struct ubifs_info *c, const void *node)
 		int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
 
 		key_read(c, &dn->key, &key);
-		printf("\t\tkey \t\t\t%s\n",
+		printf("\t\tkey \t\t\t\t%s\n",
 		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
-		printf("\t\tsize \t\t\t%u\n", le32_to_cpu(dn->size));
+		printf("\t\tsize \t\t\t\t%u\n", le32_to_cpu(dn->size));
 		printf("\t\tcompr_typ \t\t\t%d\n",
 		       (int)le16_to_cpu(dn->compr_type));
 		printf("\t\tdata size \t\t\t%d\n", dlen);
+		printf("\t\tdata:\n");
+		print_hex_dump("\t\t", DUMP_PREFIX_OFFSET, 32, 1,
+			       (void *)&dn->data, dlen, 0);
 		break;
 	}
 	case UBIFS_TRUN_NODE:
@@ -335,8 +339,8 @@ void dump_node(const struct ubifs_info *c, const void *node)
 		const struct ubifs_idx_node *idx = node;
 
 		n = le16_to_cpu(idx->child_cnt);
-		printf("\t\tchild_cnt \t\t%d\n", n);
-		printf("\t\tlevel \t\t\t%d\n", (int)le16_to_cpu(idx->level));
+		printf("\t\tchild_cnt \t\t\t%d\n", n);
+		printf("\t\tlevel \t\t\t\t%d\n", (int)le16_to_cpu(idx->level));
 		printf("\t\tBranches:\n");
 
 		for (i = 0; i < n && i < c->fanout - 1; i++) {
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source.
  2015-10-15  4:04 ` [PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source Dongsheng Yang
@ 2015-10-15  4:06   ` Dongsheng Yang
  2015-10-15  4:10   ` [RESEND PATCH " Dongsheng Yang
  1 sibling, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:06 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd

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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@lineo.com>
> + *           2002 Axis Communications AB
> + *           2001, 2002 Erik Andersen <andersen@codepoet.org>
> + *           2004 University of Szeged, Hungary
> + *           2006 KaiGai Kohei <kaigai@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@schleef.org>.
> + *
> + * Major architectural rewrite by Erik Andersen <andersen@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@suse.de>
> +  (C) 2002  David Woodhouse <dwmw2@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@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@inf.u-szeged.hu>,
> + *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
> + *                     Patrik Kluba <pajko@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@inf.u-szeged.hu>,
> + *                     Ferenc Havasi <havasi@inf.u-szeged.hu>
> + *                     University of Szeged, Hungary
> + *                2006 KaiGai Kohei <kaigai@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@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@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@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 = &part;
> +
> +	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@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@lineo.com>
> - *           2002 Axis Communications AB
> - *           2001, 2002 Erik Andersen <andersen@codepoet.org>
> - *           2004 University of Szeged, Hungary
> - *           2006 KaiGai Kohei <kaigai@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@schleef.org>.
> - *
> - * Major architectural rewrite by Erik Andersen <andersen@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.
> -\f
> -		    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.)
> -\f
> -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.
> -\f
> -  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.
> -\f
> -  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
> -\f
> -	    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@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@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@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@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@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@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@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@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 = &part;
> -
> -	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@infradead.org)
> + *                     Steven J. Hill (sjhill@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@realitydiluted.com)
> + *		  2003 Thomas Gleixner (tglx@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@infradead.org)
> - *                     Steven J. Hill (sjhill@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@realitydiluted.com)
> - *		  2003 Thomas Gleixner (tglx@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@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@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@suse.de>
> -  (C) 2002  David Woodhouse <dwmw2@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@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@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@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@inf.u-szeged.hu>,
> - *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
> - *                     Patrik Kluba <pajko@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@inf.u-szeged.hu>,
> - *                     Ferenc Havasi <havasi@inf.u-szeged.hu>
> - *                     University of Szeged, Hungary
> - *                2006 KaiGai Kohei <kaigai@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.
> +\f
> +		    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.)
> +\f
> +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.
> +\f
> +  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.
> +\f
> +  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
> +\f
> +	    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@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@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@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@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@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@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@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__ */
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [RESEND PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source.
  2015-10-15  4:04 ` [PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source Dongsheng Yang
  2015-10-15  4:06   ` Dongsheng Yang
@ 2015-10-15  4:10   ` Dongsheng Yang
  2015-10-27 23:00     ` Brian Norris
  2015-10-31  3:12     ` [PATCH V3 " Dongsheng Yang
  1 sibling, 2 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-15  4:10 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

* 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@cn.fujitsu.com>
---
 Makefile                                           | 66 +++++++++++++---------
 flash_erase.c => flash-utils/flash_erase.c         |  0
 flash_eraseall => flash-utils/flash_eraseall       |  0
 flash_lock.c => flash-utils/flash_lock.c           |  0
 flash_otp_dump.c => flash-utils/flash_otp_dump.c   |  0
 flash_otp_info.c => flash-utils/flash_otp_info.c   |  0
 flash_otp_lock.c => flash-utils/flash_otp_lock.c   |  0
 flash_otp_write.c => flash-utils/flash_otp_write.c |  0
 flash_unlock.c => flash-utils/flash_unlock.c       |  0
 flashcp.c => flash-utils/flashcp.c                 |  0
 compr.c => jffsX-utils/compr.c                     |  0
 compr.h => jffsX-utils/compr.h                     |  0
 compr_lzo.c => jffsX-utils/compr_lzo.c             |  0
 compr_rtime.c => jffsX-utils/compr_rtime.c         |  0
 compr_zlib.c => jffsX-utils/compr_zlib.c           |  0
 device_table.txt => jffsX-utils/device_table.txt   |  0
 jffs-dump.c => jffsX-utils/jffs-dump.c             |  0
 jffs2dump.c => jffsX-utils/jffs2dump.c             |  0
 jffs2reader.c => jffsX-utils/jffs2reader.c         |  0
 mkfs.jffs2.1 => jffsX-utils/mkfs.jffs2.1           |  0
 mkfs.jffs2.c => jffsX-utils/mkfs.jffs2.c           |  0
 rbtree.c => jffsX-utils/rbtree.c                   |  0
 rbtree.h => jffsX-utils/rbtree.h                   |  0
 summary.h => jffsX-utils/summary.h                 |  0
 sumtool.c => jffsX-utils/sumtool.c                 |  0
 MAKEDEV => misc-utils/MAKEDEV                      |  0
 doc_loadbios.c => misc-utils/doc_loadbios.c        |  0
 docfdisk.c => misc-utils/docfdisk.c                |  0
 fectest.c => misc-utils/fectest.c                  |  0
 ftl_check.c => misc-utils/ftl_check.c              |  0
 ftl_format.c => misc-utils/ftl_format.c            |  0
 mcast_image.h => misc-utils/mcast_image.h          |  0
 mtd_debug.c => misc-utils/mtd_debug.c              |  0
 mtdpart.c => misc-utils/mtdpart.c                  |  0
 recv_image.c => misc-utils/recv_image.c            |  0
 serve_image.c => misc-utils/serve_image.c          |  0
 load_nandsim.sh => nand-utils/load_nandsim.sh      |  0
 nanddump.c => nand-utils/nanddump.c                |  0
 nandtest.c => nand-utils/nandtest.c                |  0
 nandwrite.c => nand-utils/nandwrite.c              |  0
 nftl_format.c => nand-utils/nftl_format.c          |  0
 nftldump.c => nand-utils/nftldump.c                |  0
 rfddump.c => nor-utils/rfddump.c                   |  0
 rfdformat.c => nor-utils/rfdformat.c               |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/.gitignore  |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/COPYING     |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/README      |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/compr.c     |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/compr.h     |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/crc16.c     |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/crc16.h     |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/defs.h      |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/devtable.c  |  0
 .../mkfs.ubifs}/hashtable/hashtable.c              |  0
 .../mkfs.ubifs}/hashtable/hashtable.h              |  0
 .../mkfs.ubifs}/hashtable/hashtable_itr.c          |  0
 .../mkfs.ubifs}/hashtable/hashtable_itr.h          |  0
 .../mkfs.ubifs}/hashtable/hashtable_private.h      |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/key.h       |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/lpt.c       |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/lpt.h       |  0
 .../mkfs.ubifs}/mkfs.ubifs.c                       |  0
 .../mkfs.ubifs}/mkfs.ubifs.h                       |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/ubifs.h     |  0
 64 files changed, 39 insertions(+), 27 deletions(-)
 rename flash_erase.c => flash-utils/flash_erase.c (100%)
 rename flash_eraseall => flash-utils/flash_eraseall (100%)
 rename flash_lock.c => flash-utils/flash_lock.c (100%)
 rename flash_otp_dump.c => flash-utils/flash_otp_dump.c (100%)
 rename flash_otp_info.c => flash-utils/flash_otp_info.c (100%)
 rename flash_otp_lock.c => flash-utils/flash_otp_lock.c (100%)
 rename flash_otp_write.c => flash-utils/flash_otp_write.c (100%)
 rename flash_unlock.c => flash-utils/flash_unlock.c (100%)
 rename flashcp.c => flash-utils/flashcp.c (100%)
 rename compr.c => jffsX-utils/compr.c (100%)
 rename compr.h => jffsX-utils/compr.h (100%)
 rename compr_lzo.c => jffsX-utils/compr_lzo.c (100%)
 rename compr_rtime.c => jffsX-utils/compr_rtime.c (100%)
 rename compr_zlib.c => jffsX-utils/compr_zlib.c (100%)
 rename device_table.txt => jffsX-utils/device_table.txt (100%)
 rename jffs-dump.c => jffsX-utils/jffs-dump.c (100%)
 rename jffs2dump.c => jffsX-utils/jffs2dump.c (100%)
 rename jffs2reader.c => jffsX-utils/jffs2reader.c (100%)
 rename mkfs.jffs2.1 => jffsX-utils/mkfs.jffs2.1 (100%)
 rename mkfs.jffs2.c => jffsX-utils/mkfs.jffs2.c (100%)
 rename rbtree.c => jffsX-utils/rbtree.c (100%)
 rename rbtree.h => jffsX-utils/rbtree.h (100%)
 rename summary.h => jffsX-utils/summary.h (100%)
 rename sumtool.c => jffsX-utils/sumtool.c (100%)
 rename MAKEDEV => misc-utils/MAKEDEV (100%)
 rename doc_loadbios.c => misc-utils/doc_loadbios.c (100%)
 rename docfdisk.c => misc-utils/docfdisk.c (100%)
 rename fectest.c => misc-utils/fectest.c (100%)
 rename ftl_check.c => misc-utils/ftl_check.c (100%)
 rename ftl_format.c => misc-utils/ftl_format.c (100%)
 rename mcast_image.h => misc-utils/mcast_image.h (100%)
 rename mtd_debug.c => misc-utils/mtd_debug.c (100%)
 rename mtdpart.c => misc-utils/mtdpart.c (100%)
 rename recv_image.c => misc-utils/recv_image.c (100%)
 rename serve_image.c => misc-utils/serve_image.c (100%)
 rename load_nandsim.sh => nand-utils/load_nandsim.sh (100%)
 rename nanddump.c => nand-utils/nanddump.c (100%)
 rename nandtest.c => nand-utils/nandtest.c (100%)
 rename nandwrite.c => nand-utils/nandwrite.c (100%)
 rename nftl_format.c => nand-utils/nftl_format.c (100%)
 rename nftldump.c => nand-utils/nftldump.c (100%)
 rename rfddump.c => nor-utils/rfddump.c (100%)
 rename rfdformat.c => nor-utils/rfdformat.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/.gitignore (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/COPYING (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/README (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/compr.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/compr.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/crc16.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/crc16.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/defs.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/devtable.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/hashtable/hashtable.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/hashtable/hashtable.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/hashtable/hashtable_itr.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/hashtable/hashtable_itr.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/hashtable/hashtable_private.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/key.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/lpt.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/lpt.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/mkfs.ubifs.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/mkfs.ubifs.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/ubifs.h (100%)

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/flash_erase.c b/flash-utils/flash_erase.c
similarity index 100%
rename from flash_erase.c
rename to flash-utils/flash_erase.c
diff --git a/flash_eraseall b/flash-utils/flash_eraseall
similarity index 100%
rename from flash_eraseall
rename to flash-utils/flash_eraseall
diff --git a/flash_lock.c b/flash-utils/flash_lock.c
similarity index 100%
rename from flash_lock.c
rename to flash-utils/flash_lock.c
diff --git a/flash_otp_dump.c b/flash-utils/flash_otp_dump.c
similarity index 100%
rename from flash_otp_dump.c
rename to flash-utils/flash_otp_dump.c
diff --git a/flash_otp_info.c b/flash-utils/flash_otp_info.c
similarity index 100%
rename from flash_otp_info.c
rename to flash-utils/flash_otp_info.c
diff --git a/flash_otp_lock.c b/flash-utils/flash_otp_lock.c
similarity index 100%
rename from flash_otp_lock.c
rename to flash-utils/flash_otp_lock.c
diff --git a/flash_otp_write.c b/flash-utils/flash_otp_write.c
similarity index 100%
rename from flash_otp_write.c
rename to flash-utils/flash_otp_write.c
diff --git a/flash_unlock.c b/flash-utils/flash_unlock.c
similarity index 100%
rename from flash_unlock.c
rename to flash-utils/flash_unlock.c
diff --git a/flashcp.c b/flash-utils/flashcp.c
similarity index 100%
rename from flashcp.c
rename to flash-utils/flashcp.c
diff --git a/compr.c b/jffsX-utils/compr.c
similarity index 100%
rename from compr.c
rename to jffsX-utils/compr.c
diff --git a/compr.h b/jffsX-utils/compr.h
similarity index 100%
rename from compr.h
rename to jffsX-utils/compr.h
diff --git a/compr_lzo.c b/jffsX-utils/compr_lzo.c
similarity index 100%
rename from compr_lzo.c
rename to jffsX-utils/compr_lzo.c
diff --git a/compr_rtime.c b/jffsX-utils/compr_rtime.c
similarity index 100%
rename from compr_rtime.c
rename to jffsX-utils/compr_rtime.c
diff --git a/compr_zlib.c b/jffsX-utils/compr_zlib.c
similarity index 100%
rename from compr_zlib.c
rename to jffsX-utils/compr_zlib.c
diff --git a/device_table.txt b/jffsX-utils/device_table.txt
similarity index 100%
rename from device_table.txt
rename to jffsX-utils/device_table.txt
diff --git a/jffs-dump.c b/jffsX-utils/jffs-dump.c
similarity index 100%
rename from jffs-dump.c
rename to jffsX-utils/jffs-dump.c
diff --git a/jffs2dump.c b/jffsX-utils/jffs2dump.c
similarity index 100%
rename from jffs2dump.c
rename to jffsX-utils/jffs2dump.c
diff --git a/jffs2reader.c b/jffsX-utils/jffs2reader.c
similarity index 100%
rename from jffs2reader.c
rename to jffsX-utils/jffs2reader.c
diff --git a/mkfs.jffs2.1 b/jffsX-utils/mkfs.jffs2.1
similarity index 100%
rename from mkfs.jffs2.1
rename to jffsX-utils/mkfs.jffs2.1
diff --git a/mkfs.jffs2.c b/jffsX-utils/mkfs.jffs2.c
similarity index 100%
rename from mkfs.jffs2.c
rename to jffsX-utils/mkfs.jffs2.c
diff --git a/rbtree.c b/jffsX-utils/rbtree.c
similarity index 100%
rename from rbtree.c
rename to jffsX-utils/rbtree.c
diff --git a/rbtree.h b/jffsX-utils/rbtree.h
similarity index 100%
rename from rbtree.h
rename to jffsX-utils/rbtree.h
diff --git a/summary.h b/jffsX-utils/summary.h
similarity index 100%
rename from summary.h
rename to jffsX-utils/summary.h
diff --git a/sumtool.c b/jffsX-utils/sumtool.c
similarity index 100%
rename from sumtool.c
rename to jffsX-utils/sumtool.c
diff --git a/MAKEDEV b/misc-utils/MAKEDEV
similarity index 100%
rename from MAKEDEV
rename to misc-utils/MAKEDEV
diff --git a/doc_loadbios.c b/misc-utils/doc_loadbios.c
similarity index 100%
rename from doc_loadbios.c
rename to misc-utils/doc_loadbios.c
diff --git a/docfdisk.c b/misc-utils/docfdisk.c
similarity index 100%
rename from docfdisk.c
rename to misc-utils/docfdisk.c
diff --git a/fectest.c b/misc-utils/fectest.c
similarity index 100%
rename from fectest.c
rename to misc-utils/fectest.c
diff --git a/ftl_check.c b/misc-utils/ftl_check.c
similarity index 100%
rename from ftl_check.c
rename to misc-utils/ftl_check.c
diff --git a/ftl_format.c b/misc-utils/ftl_format.c
similarity index 100%
rename from ftl_format.c
rename to misc-utils/ftl_format.c
diff --git a/mcast_image.h b/misc-utils/mcast_image.h
similarity index 100%
rename from mcast_image.h
rename to misc-utils/mcast_image.h
diff --git a/mtd_debug.c b/misc-utils/mtd_debug.c
similarity index 100%
rename from mtd_debug.c
rename to misc-utils/mtd_debug.c
diff --git a/mtdpart.c b/misc-utils/mtdpart.c
similarity index 100%
rename from mtdpart.c
rename to misc-utils/mtdpart.c
diff --git a/recv_image.c b/misc-utils/recv_image.c
similarity index 100%
rename from recv_image.c
rename to misc-utils/recv_image.c
diff --git a/serve_image.c b/misc-utils/serve_image.c
similarity index 100%
rename from serve_image.c
rename to misc-utils/serve_image.c
diff --git a/load_nandsim.sh b/nand-utils/load_nandsim.sh
similarity index 100%
rename from load_nandsim.sh
rename to nand-utils/load_nandsim.sh
diff --git a/nanddump.c b/nand-utils/nanddump.c
similarity index 100%
rename from nanddump.c
rename to nand-utils/nanddump.c
diff --git a/nandtest.c b/nand-utils/nandtest.c
similarity index 100%
rename from nandtest.c
rename to nand-utils/nandtest.c
diff --git a/nandwrite.c b/nand-utils/nandwrite.c
similarity index 100%
rename from nandwrite.c
rename to nand-utils/nandwrite.c
diff --git a/nftl_format.c b/nand-utils/nftl_format.c
similarity index 100%
rename from nftl_format.c
rename to nand-utils/nftl_format.c
diff --git a/nftldump.c b/nand-utils/nftldump.c
similarity index 100%
rename from nftldump.c
rename to nand-utils/nftldump.c
diff --git a/rfddump.c b/nor-utils/rfddump.c
similarity index 100%
rename from rfddump.c
rename to nor-utils/rfddump.c
diff --git a/rfdformat.c b/nor-utils/rfdformat.c
similarity index 100%
rename from rfdformat.c
rename to nor-utils/rfdformat.c
diff --git a/mkfs.ubifs/.gitignore b/ubifs-utils/mkfs.ubifs/.gitignore
similarity index 100%
rename from mkfs.ubifs/.gitignore
rename to ubifs-utils/mkfs.ubifs/.gitignore
diff --git a/mkfs.ubifs/COPYING b/ubifs-utils/mkfs.ubifs/COPYING
similarity index 100%
rename from mkfs.ubifs/COPYING
rename to ubifs-utils/mkfs.ubifs/COPYING
diff --git a/mkfs.ubifs/README b/ubifs-utils/mkfs.ubifs/README
similarity index 100%
rename from mkfs.ubifs/README
rename to ubifs-utils/mkfs.ubifs/README
diff --git a/mkfs.ubifs/compr.c b/ubifs-utils/mkfs.ubifs/compr.c
similarity index 100%
rename from mkfs.ubifs/compr.c
rename to ubifs-utils/mkfs.ubifs/compr.c
diff --git a/mkfs.ubifs/compr.h b/ubifs-utils/mkfs.ubifs/compr.h
similarity index 100%
rename from mkfs.ubifs/compr.h
rename to ubifs-utils/mkfs.ubifs/compr.h
diff --git a/mkfs.ubifs/crc16.c b/ubifs-utils/mkfs.ubifs/crc16.c
similarity index 100%
rename from mkfs.ubifs/crc16.c
rename to ubifs-utils/mkfs.ubifs/crc16.c
diff --git a/mkfs.ubifs/crc16.h b/ubifs-utils/mkfs.ubifs/crc16.h
similarity index 100%
rename from mkfs.ubifs/crc16.h
rename to ubifs-utils/mkfs.ubifs/crc16.h
diff --git a/mkfs.ubifs/defs.h b/ubifs-utils/mkfs.ubifs/defs.h
similarity index 100%
rename from mkfs.ubifs/defs.h
rename to ubifs-utils/mkfs.ubifs/defs.h
diff --git a/mkfs.ubifs/devtable.c b/ubifs-utils/mkfs.ubifs/devtable.c
similarity index 100%
rename from mkfs.ubifs/devtable.c
rename to ubifs-utils/mkfs.ubifs/devtable.c
diff --git a/mkfs.ubifs/hashtable/hashtable.c b/ubifs-utils/mkfs.ubifs/hashtable/hashtable.c
similarity index 100%
rename from mkfs.ubifs/hashtable/hashtable.c
rename to ubifs-utils/mkfs.ubifs/hashtable/hashtable.c
diff --git a/mkfs.ubifs/hashtable/hashtable.h b/ubifs-utils/mkfs.ubifs/hashtable/hashtable.h
similarity index 100%
rename from mkfs.ubifs/hashtable/hashtable.h
rename to ubifs-utils/mkfs.ubifs/hashtable/hashtable.h
diff --git a/mkfs.ubifs/hashtable/hashtable_itr.c b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.c
similarity index 100%
rename from mkfs.ubifs/hashtable/hashtable_itr.c
rename to ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.c
diff --git a/mkfs.ubifs/hashtable/hashtable_itr.h b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.h
similarity index 100%
rename from mkfs.ubifs/hashtable/hashtable_itr.h
rename to ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.h
diff --git a/mkfs.ubifs/hashtable/hashtable_private.h b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_private.h
similarity index 100%
rename from mkfs.ubifs/hashtable/hashtable_private.h
rename to ubifs-utils/mkfs.ubifs/hashtable/hashtable_private.h
diff --git a/mkfs.ubifs/key.h b/ubifs-utils/mkfs.ubifs/key.h
similarity index 100%
rename from mkfs.ubifs/key.h
rename to ubifs-utils/mkfs.ubifs/key.h
diff --git a/mkfs.ubifs/lpt.c b/ubifs-utils/mkfs.ubifs/lpt.c
similarity index 100%
rename from mkfs.ubifs/lpt.c
rename to ubifs-utils/mkfs.ubifs/lpt.c
diff --git a/mkfs.ubifs/lpt.h b/ubifs-utils/mkfs.ubifs/lpt.h
similarity index 100%
rename from mkfs.ubifs/lpt.h
rename to ubifs-utils/mkfs.ubifs/lpt.h
diff --git a/mkfs.ubifs/mkfs.ubifs.c b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
similarity index 100%
rename from mkfs.ubifs/mkfs.ubifs.c
rename to ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
diff --git a/mkfs.ubifs/mkfs.ubifs.h b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
similarity index 100%
rename from mkfs.ubifs/mkfs.ubifs.h
rename to ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
diff --git a/mkfs.ubifs/ubifs.h b/ubifs-utils/mkfs.ubifs/ubifs.h
similarity index 100%
rename from mkfs.ubifs/ubifs.h
rename to ubifs-utils/mkfs.ubifs/ubifs.h
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [RESEND PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source.
  2015-10-15  4:10   ` [RESEND PATCH " Dongsheng Yang
@ 2015-10-27 23:00     ` Brian Norris
  2015-10-31  2:38       ` Dongsheng Yang
  2015-10-31  3:12     ` [PATCH V3 " Dongsheng Yang
  1 sibling, 1 reply; 37+ messages in thread
From: Brian Norris @ 2015-10-27 23:00 UTC (permalink / raw)
  To: Dongsheng Yang; +Cc: david, dedekind1, richard, linux-mtd

On Thu, Oct 15, 2015 at 12:10:08PM +0800, 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

What's the difference between flash-utils and misc-utils? And don't just
tell me it's because they were named starting with "flash" :)

Particularly, I think things like "mtdpart" and "flash_erase" are pretty
similar levels of generic.

(Also, why is mtdinfo in ubi-utils still? It should be moved, IMO.)

> 	|-- jffsX-utils

What makes more sense: jffsX or just jffs?

> 	|-- nand-utils
> 	|-- nor-utils

What are specific to NOR flash? I don't even know what "rfddump" and
"rfdformat" are. Do they really deserve their own directory?

> 	|-- ubi-utils
> 	|-- ubifs-utils
> 	`-- tests

You need to update .gitignore too.

Brian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RESEND PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source.
  2015-10-27 23:00     ` Brian Norris
@ 2015-10-31  2:38       ` Dongsheng Yang
  0 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-31  2:38 UTC (permalink / raw)
  To: Brian Norris; +Cc: david, dedekind1, richard, linux-mtd

On 10/28/2015 07:00 AM, Brian Norris wrote:
> On Thu, Oct 15, 2015 at 12:10:08PM +0800, 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
>
> What's the difference between flash-utils and misc-utils? And don't just
> tell me it's because they were named starting with "flash" :)

Haha, I am afraid yes.
>
> Particularly, I think things like "mtdpart" and "flash_erase" are pretty
> similar levels of generic.

Agreed, I thought the flash_xxx is working in lower level than mtd_xxx.
But I found I was wrong. The are in a similar level. I will move
flash_xxx to misc-utils then.
>
> (Also, why is mtdinfo in ubi-utils still? It should be moved, IMO.)

This would be done after this restructure, then we have to move some
header files from ubi-utils to the top level and then move mtdinfo to 
misc-utils.
>
>> 	|-- jffsX-utils
>
> What makes more sense: jffsX or just jffs?

Hmmmm, I prefer jffsX for jffs and jffs2.
>
>> 	|-- nand-utils
>> 	|-- nor-utils
>
> What are specific to NOR flash? I don't even know what "rfddump" and
> "rfdformat" are. Do they really deserve their own directory?

I just read the helper of them "Formats NOR flash for resident flash
disk". Then I think there should be a nor-utils at the same time
with nand-utils.
>
>> 	|-- ubi-utils
>> 	|-- ubifs-utils
>> 	`-- tests
>
> You need to update .gitignore too.

Oh, yes, will update it.

TBH, I am not familiar with the *all* tools in our mtd-utils, so
I sent a RFC out to get more information for what I am not sure
about. But unfortunately, no response except yours.

I will send a V2 soon.

Thanx
Yang
>
> Brian
> .
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH V3 01/27] mtd-utils: Restructure the mtd-utils source.
  2015-10-15  4:10   ` [RESEND PATCH " Dongsheng Yang
  2015-10-27 23:00     ` Brian Norris
@ 2015-10-31  3:12     ` Dongsheng Yang
  2015-11-11 22:30       ` Brian Norris
  1 sibling, 1 reply; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-31  3:12 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

* 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
	|-- jffsX-utils
	|-- nand-utils
	|-- nor-utils
	|-- ubi-utils
	|-- ubifs-utils
	`-- tests

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
changelog:
	v1:
		- move tools in flash-utils to misc-utils
		- change dir in gitignore
		- remove flash_info in gitignore
		- add mtdpart in gitignore
 .gitignore                                         | 54 +++++++++----------
 Makefile                                           | 63 ++++++++++++----------
 compr.c => jffsX-utils/compr.c                     |  0
 compr.h => jffsX-utils/compr.h                     |  0
 compr_lzo.c => jffsX-utils/compr_lzo.c             |  0
 compr_rtime.c => jffsX-utils/compr_rtime.c         |  0
 compr_zlib.c => jffsX-utils/compr_zlib.c           |  0
 device_table.txt => jffsX-utils/device_table.txt   |  0
 jffs-dump.c => jffsX-utils/jffs-dump.c             |  0
 jffs2dump.c => jffsX-utils/jffs2dump.c             |  0
 jffs2reader.c => jffsX-utils/jffs2reader.c         |  0
 mkfs.jffs2.1 => jffsX-utils/mkfs.jffs2.1           |  0
 mkfs.jffs2.c => jffsX-utils/mkfs.jffs2.c           |  0
 rbtree.c => jffsX-utils/rbtree.c                   |  0
 rbtree.h => jffsX-utils/rbtree.h                   |  0
 summary.h => jffsX-utils/summary.h                 |  0
 sumtool.c => jffsX-utils/sumtool.c                 |  0
 MAKEDEV => misc-utils/MAKEDEV                      |  0
 doc_loadbios.c => misc-utils/doc_loadbios.c        |  0
 docfdisk.c => misc-utils/docfdisk.c                |  0
 fectest.c => misc-utils/fectest.c                  |  0
 flash_erase.c => misc-utils/flash_erase.c          |  0
 flash_eraseall => misc-utils/flash_eraseall        |  0
 flash_lock.c => misc-utils/flash_lock.c            |  0
 flash_otp_dump.c => misc-utils/flash_otp_dump.c    |  0
 flash_otp_info.c => misc-utils/flash_otp_info.c    |  0
 flash_otp_lock.c => misc-utils/flash_otp_lock.c    |  0
 flash_otp_write.c => misc-utils/flash_otp_write.c  |  0
 flash_unlock.c => misc-utils/flash_unlock.c        |  0
 flashcp.c => misc-utils/flashcp.c                  |  0
 ftl_check.c => misc-utils/ftl_check.c              |  0
 ftl_format.c => misc-utils/ftl_format.c            |  0
 mcast_image.h => misc-utils/mcast_image.h          |  0
 mtd_debug.c => misc-utils/mtd_debug.c              |  0
 mtdpart.c => misc-utils/mtdpart.c                  |  0
 recv_image.c => misc-utils/recv_image.c            |  0
 serve_image.c => misc-utils/serve_image.c          |  0
 load_nandsim.sh => nand-utils/load_nandsim.sh      |  0
 nanddump.c => nand-utils/nanddump.c                |  0
 nandtest.c => nand-utils/nandtest.c                |  0
 nandwrite.c => nand-utils/nandwrite.c              |  0
 nftl_format.c => nand-utils/nftl_format.c          |  0
 nftldump.c => nand-utils/nftldump.c                |  0
 rfddump.c => nor-utils/rfddump.c                   |  0
 rfdformat.c => nor-utils/rfdformat.c               |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/.gitignore  |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/COPYING     |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/README      |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/compr.c     |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/compr.h     |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/crc16.c     |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/crc16.h     |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/defs.h      |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/devtable.c  |  0
 .../mkfs.ubifs}/hashtable/hashtable.c              |  0
 .../mkfs.ubifs}/hashtable/hashtable.h              |  0
 .../mkfs.ubifs}/hashtable/hashtable_itr.c          |  0
 .../mkfs.ubifs}/hashtable/hashtable_itr.h          |  0
 .../mkfs.ubifs}/hashtable/hashtable_private.h      |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/key.h       |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/lpt.c       |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/lpt.h       |  0
 .../mkfs.ubifs}/mkfs.ubifs.c                       |  0
 .../mkfs.ubifs}/mkfs.ubifs.h                       |  0
 {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/ubifs.h     |  0
 65 files changed, 63 insertions(+), 54 deletions(-)
 rename compr.c => jffsX-utils/compr.c (100%)
 rename compr.h => jffsX-utils/compr.h (100%)
 rename compr_lzo.c => jffsX-utils/compr_lzo.c (100%)
 rename compr_rtime.c => jffsX-utils/compr_rtime.c (100%)
 rename compr_zlib.c => jffsX-utils/compr_zlib.c (100%)
 rename device_table.txt => jffsX-utils/device_table.txt (100%)
 rename jffs-dump.c => jffsX-utils/jffs-dump.c (100%)
 rename jffs2dump.c => jffsX-utils/jffs2dump.c (100%)
 rename jffs2reader.c => jffsX-utils/jffs2reader.c (100%)
 rename mkfs.jffs2.1 => jffsX-utils/mkfs.jffs2.1 (100%)
 rename mkfs.jffs2.c => jffsX-utils/mkfs.jffs2.c (100%)
 rename rbtree.c => jffsX-utils/rbtree.c (100%)
 rename rbtree.h => jffsX-utils/rbtree.h (100%)
 rename summary.h => jffsX-utils/summary.h (100%)
 rename sumtool.c => jffsX-utils/sumtool.c (100%)
 rename MAKEDEV => misc-utils/MAKEDEV (100%)
 rename doc_loadbios.c => misc-utils/doc_loadbios.c (100%)
 rename docfdisk.c => misc-utils/docfdisk.c (100%)
 rename fectest.c => misc-utils/fectest.c (100%)
 rename flash_erase.c => misc-utils/flash_erase.c (100%)
 rename flash_eraseall => misc-utils/flash_eraseall (100%)
 rename flash_lock.c => misc-utils/flash_lock.c (100%)
 rename flash_otp_dump.c => misc-utils/flash_otp_dump.c (100%)
 rename flash_otp_info.c => misc-utils/flash_otp_info.c (100%)
 rename flash_otp_lock.c => misc-utils/flash_otp_lock.c (100%)
 rename flash_otp_write.c => misc-utils/flash_otp_write.c (100%)
 rename flash_unlock.c => misc-utils/flash_unlock.c (100%)
 rename flashcp.c => misc-utils/flashcp.c (100%)
 rename ftl_check.c => misc-utils/ftl_check.c (100%)
 rename ftl_format.c => misc-utils/ftl_format.c (100%)
 rename mcast_image.h => misc-utils/mcast_image.h (100%)
 rename mtd_debug.c => misc-utils/mtd_debug.c (100%)
 rename mtdpart.c => misc-utils/mtdpart.c (100%)
 rename recv_image.c => misc-utils/recv_image.c (100%)
 rename serve_image.c => misc-utils/serve_image.c (100%)
 rename load_nandsim.sh => nand-utils/load_nandsim.sh (100%)
 rename nanddump.c => nand-utils/nanddump.c (100%)
 rename nandtest.c => nand-utils/nandtest.c (100%)
 rename nandwrite.c => nand-utils/nandwrite.c (100%)
 rename nftl_format.c => nand-utils/nftl_format.c (100%)
 rename nftldump.c => nand-utils/nftldump.c (100%)
 rename rfddump.c => nor-utils/rfddump.c (100%)
 rename rfdformat.c => nor-utils/rfdformat.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/.gitignore (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/COPYING (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/README (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/compr.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/compr.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/crc16.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/crc16.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/defs.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/devtable.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/hashtable/hashtable.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/hashtable/hashtable.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/hashtable/hashtable_itr.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/hashtable/hashtable_itr.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/hashtable/hashtable_private.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/key.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/lpt.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/lpt.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/mkfs.ubifs.c (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/mkfs.ubifs.h (100%)
 rename {mkfs.ubifs => ubifs-utils/mkfs.ubifs}/ubifs.h (100%)

diff --git a/.gitignore b/.gitignore
index 83ca938..e1d23cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,33 +18,33 @@
 #
 # Our programs
 #
-/doc_loadbios
-/docfdisk
-/flash_erase
-/flash_info
-/flash_lock
-/flash_otp_dump
-/flash_otp_info
-/flash_otp_lock
-/flash_otp_write
-/flash_unlock
-/flashcp
-/ftl_check
-/ftl_format
-/jffs2dump
-/jffs2reader
-/mkfs.jffs2
-/mtd_debug
-/nanddump
-/nandtest
-/nandwrite
-/nftl_format
-/nftldump
-/recv_image
-/rfddump
-/rfdformat
-/serve_image
-/sumtool
+/misc-utils/mtdpart
+/misc-utils/doc_loadbios
+/misc-utils/docfdisk
+/misc-utils/flash_erase
+/misc-utils/flash_lock
+/misc-utils/flash_otp_dump
+/misc-utils/flash_otp_info
+/misc-utils/flash_otp_lock
+/misc-utils/flash_otp_write
+/misc-utils/flash_unlock
+/misc-utils/flashcp
+/misc-utils/ftl_check
+/misc-utils/ftl_format
+/jffsX-utils/jffs2dump
+/jffsX-utils/jffs2reader
+/jffsX-utils/mkfs.jffs2
+/misc-utils/mtd_debug
+/nand-utils/nanddump
+/nand-utils/nandtest
+/nand-utils/nandwrite
+/nand-utils/nftl_format
+/nand-utils/nftldump
+/misc-utils/recv_image
+/nor-utils/rfddump
+/nor-utils/rfdformat
+/misc-utils/serve_image
+/jffsX-utils/sumtool
 
 #
 # Top-level generic files
diff --git a/Makefile b/Makefile
index f4ce313..68f7df3 100644
--- a/Makefile
+++ b/Makefile
@@ -16,24 +16,30 @@ 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 flash_erase flash_lock \
+	flash_unlock flash_otp_info flash_otp_dump flash_otp_lock \
+	flash_otp_write flashcp
 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
+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 nand-utils/,$(NAND_BINS))
+BINS += $(addprefix nor-utils/,$(NOR_BINS))
+SCRIPTS = $(addprefix misc-utils/,flash_eraseall)
 
 TARGETS = $(BINS)
 TARGETS += lib/libmtd.a
@@ -61,11 +67,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 +91,16 @@ $(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,$(NAND_BINS),$(eval $(call mkdep,nand-utils/,$(v))))
+$(foreach v,$(NOR_BINS),$(eval $(call mkdep,nor-utils/,$(v))))
 
 #
 # Common libmtd
@@ -100,15 +109,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 +122,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/jffsX-utils/compr.c
similarity index 100%
rename from compr.c
rename to jffsX-utils/compr.c
diff --git a/compr.h b/jffsX-utils/compr.h
similarity index 100%
rename from compr.h
rename to jffsX-utils/compr.h
diff --git a/compr_lzo.c b/jffsX-utils/compr_lzo.c
similarity index 100%
rename from compr_lzo.c
rename to jffsX-utils/compr_lzo.c
diff --git a/compr_rtime.c b/jffsX-utils/compr_rtime.c
similarity index 100%
rename from compr_rtime.c
rename to jffsX-utils/compr_rtime.c
diff --git a/compr_zlib.c b/jffsX-utils/compr_zlib.c
similarity index 100%
rename from compr_zlib.c
rename to jffsX-utils/compr_zlib.c
diff --git a/device_table.txt b/jffsX-utils/device_table.txt
similarity index 100%
rename from device_table.txt
rename to jffsX-utils/device_table.txt
diff --git a/jffs-dump.c b/jffsX-utils/jffs-dump.c
similarity index 100%
rename from jffs-dump.c
rename to jffsX-utils/jffs-dump.c
diff --git a/jffs2dump.c b/jffsX-utils/jffs2dump.c
similarity index 100%
rename from jffs2dump.c
rename to jffsX-utils/jffs2dump.c
diff --git a/jffs2reader.c b/jffsX-utils/jffs2reader.c
similarity index 100%
rename from jffs2reader.c
rename to jffsX-utils/jffs2reader.c
diff --git a/mkfs.jffs2.1 b/jffsX-utils/mkfs.jffs2.1
similarity index 100%
rename from mkfs.jffs2.1
rename to jffsX-utils/mkfs.jffs2.1
diff --git a/mkfs.jffs2.c b/jffsX-utils/mkfs.jffs2.c
similarity index 100%
rename from mkfs.jffs2.c
rename to jffsX-utils/mkfs.jffs2.c
diff --git a/rbtree.c b/jffsX-utils/rbtree.c
similarity index 100%
rename from rbtree.c
rename to jffsX-utils/rbtree.c
diff --git a/rbtree.h b/jffsX-utils/rbtree.h
similarity index 100%
rename from rbtree.h
rename to jffsX-utils/rbtree.h
diff --git a/summary.h b/jffsX-utils/summary.h
similarity index 100%
rename from summary.h
rename to jffsX-utils/summary.h
diff --git a/sumtool.c b/jffsX-utils/sumtool.c
similarity index 100%
rename from sumtool.c
rename to jffsX-utils/sumtool.c
diff --git a/MAKEDEV b/misc-utils/MAKEDEV
similarity index 100%
rename from MAKEDEV
rename to misc-utils/MAKEDEV
diff --git a/doc_loadbios.c b/misc-utils/doc_loadbios.c
similarity index 100%
rename from doc_loadbios.c
rename to misc-utils/doc_loadbios.c
diff --git a/docfdisk.c b/misc-utils/docfdisk.c
similarity index 100%
rename from docfdisk.c
rename to misc-utils/docfdisk.c
diff --git a/fectest.c b/misc-utils/fectest.c
similarity index 100%
rename from fectest.c
rename to misc-utils/fectest.c
diff --git a/flash_erase.c b/misc-utils/flash_erase.c
similarity index 100%
rename from flash_erase.c
rename to misc-utils/flash_erase.c
diff --git a/flash_eraseall b/misc-utils/flash_eraseall
similarity index 100%
rename from flash_eraseall
rename to misc-utils/flash_eraseall
diff --git a/flash_lock.c b/misc-utils/flash_lock.c
similarity index 100%
rename from flash_lock.c
rename to misc-utils/flash_lock.c
diff --git a/flash_otp_dump.c b/misc-utils/flash_otp_dump.c
similarity index 100%
rename from flash_otp_dump.c
rename to misc-utils/flash_otp_dump.c
diff --git a/flash_otp_info.c b/misc-utils/flash_otp_info.c
similarity index 100%
rename from flash_otp_info.c
rename to misc-utils/flash_otp_info.c
diff --git a/flash_otp_lock.c b/misc-utils/flash_otp_lock.c
similarity index 100%
rename from flash_otp_lock.c
rename to misc-utils/flash_otp_lock.c
diff --git a/flash_otp_write.c b/misc-utils/flash_otp_write.c
similarity index 100%
rename from flash_otp_write.c
rename to misc-utils/flash_otp_write.c
diff --git a/flash_unlock.c b/misc-utils/flash_unlock.c
similarity index 100%
rename from flash_unlock.c
rename to misc-utils/flash_unlock.c
diff --git a/flashcp.c b/misc-utils/flashcp.c
similarity index 100%
rename from flashcp.c
rename to misc-utils/flashcp.c
diff --git a/ftl_check.c b/misc-utils/ftl_check.c
similarity index 100%
rename from ftl_check.c
rename to misc-utils/ftl_check.c
diff --git a/ftl_format.c b/misc-utils/ftl_format.c
similarity index 100%
rename from ftl_format.c
rename to misc-utils/ftl_format.c
diff --git a/mcast_image.h b/misc-utils/mcast_image.h
similarity index 100%
rename from mcast_image.h
rename to misc-utils/mcast_image.h
diff --git a/mtd_debug.c b/misc-utils/mtd_debug.c
similarity index 100%
rename from mtd_debug.c
rename to misc-utils/mtd_debug.c
diff --git a/mtdpart.c b/misc-utils/mtdpart.c
similarity index 100%
rename from mtdpart.c
rename to misc-utils/mtdpart.c
diff --git a/recv_image.c b/misc-utils/recv_image.c
similarity index 100%
rename from recv_image.c
rename to misc-utils/recv_image.c
diff --git a/serve_image.c b/misc-utils/serve_image.c
similarity index 100%
rename from serve_image.c
rename to misc-utils/serve_image.c
diff --git a/load_nandsim.sh b/nand-utils/load_nandsim.sh
similarity index 100%
rename from load_nandsim.sh
rename to nand-utils/load_nandsim.sh
diff --git a/nanddump.c b/nand-utils/nanddump.c
similarity index 100%
rename from nanddump.c
rename to nand-utils/nanddump.c
diff --git a/nandtest.c b/nand-utils/nandtest.c
similarity index 100%
rename from nandtest.c
rename to nand-utils/nandtest.c
diff --git a/nandwrite.c b/nand-utils/nandwrite.c
similarity index 100%
rename from nandwrite.c
rename to nand-utils/nandwrite.c
diff --git a/nftl_format.c b/nand-utils/nftl_format.c
similarity index 100%
rename from nftl_format.c
rename to nand-utils/nftl_format.c
diff --git a/nftldump.c b/nand-utils/nftldump.c
similarity index 100%
rename from nftldump.c
rename to nand-utils/nftldump.c
diff --git a/rfddump.c b/nor-utils/rfddump.c
similarity index 100%
rename from rfddump.c
rename to nor-utils/rfddump.c
diff --git a/rfdformat.c b/nor-utils/rfdformat.c
similarity index 100%
rename from rfdformat.c
rename to nor-utils/rfdformat.c
diff --git a/mkfs.ubifs/.gitignore b/ubifs-utils/mkfs.ubifs/.gitignore
similarity index 100%
rename from mkfs.ubifs/.gitignore
rename to ubifs-utils/mkfs.ubifs/.gitignore
diff --git a/mkfs.ubifs/COPYING b/ubifs-utils/mkfs.ubifs/COPYING
similarity index 100%
rename from mkfs.ubifs/COPYING
rename to ubifs-utils/mkfs.ubifs/COPYING
diff --git a/mkfs.ubifs/README b/ubifs-utils/mkfs.ubifs/README
similarity index 100%
rename from mkfs.ubifs/README
rename to ubifs-utils/mkfs.ubifs/README
diff --git a/mkfs.ubifs/compr.c b/ubifs-utils/mkfs.ubifs/compr.c
similarity index 100%
rename from mkfs.ubifs/compr.c
rename to ubifs-utils/mkfs.ubifs/compr.c
diff --git a/mkfs.ubifs/compr.h b/ubifs-utils/mkfs.ubifs/compr.h
similarity index 100%
rename from mkfs.ubifs/compr.h
rename to ubifs-utils/mkfs.ubifs/compr.h
diff --git a/mkfs.ubifs/crc16.c b/ubifs-utils/mkfs.ubifs/crc16.c
similarity index 100%
rename from mkfs.ubifs/crc16.c
rename to ubifs-utils/mkfs.ubifs/crc16.c
diff --git a/mkfs.ubifs/crc16.h b/ubifs-utils/mkfs.ubifs/crc16.h
similarity index 100%
rename from mkfs.ubifs/crc16.h
rename to ubifs-utils/mkfs.ubifs/crc16.h
diff --git a/mkfs.ubifs/defs.h b/ubifs-utils/mkfs.ubifs/defs.h
similarity index 100%
rename from mkfs.ubifs/defs.h
rename to ubifs-utils/mkfs.ubifs/defs.h
diff --git a/mkfs.ubifs/devtable.c b/ubifs-utils/mkfs.ubifs/devtable.c
similarity index 100%
rename from mkfs.ubifs/devtable.c
rename to ubifs-utils/mkfs.ubifs/devtable.c
diff --git a/mkfs.ubifs/hashtable/hashtable.c b/ubifs-utils/mkfs.ubifs/hashtable/hashtable.c
similarity index 100%
rename from mkfs.ubifs/hashtable/hashtable.c
rename to ubifs-utils/mkfs.ubifs/hashtable/hashtable.c
diff --git a/mkfs.ubifs/hashtable/hashtable.h b/ubifs-utils/mkfs.ubifs/hashtable/hashtable.h
similarity index 100%
rename from mkfs.ubifs/hashtable/hashtable.h
rename to ubifs-utils/mkfs.ubifs/hashtable/hashtable.h
diff --git a/mkfs.ubifs/hashtable/hashtable_itr.c b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.c
similarity index 100%
rename from mkfs.ubifs/hashtable/hashtable_itr.c
rename to ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.c
diff --git a/mkfs.ubifs/hashtable/hashtable_itr.h b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.h
similarity index 100%
rename from mkfs.ubifs/hashtable/hashtable_itr.h
rename to ubifs-utils/mkfs.ubifs/hashtable/hashtable_itr.h
diff --git a/mkfs.ubifs/hashtable/hashtable_private.h b/ubifs-utils/mkfs.ubifs/hashtable/hashtable_private.h
similarity index 100%
rename from mkfs.ubifs/hashtable/hashtable_private.h
rename to ubifs-utils/mkfs.ubifs/hashtable/hashtable_private.h
diff --git a/mkfs.ubifs/key.h b/ubifs-utils/mkfs.ubifs/key.h
similarity index 100%
rename from mkfs.ubifs/key.h
rename to ubifs-utils/mkfs.ubifs/key.h
diff --git a/mkfs.ubifs/lpt.c b/ubifs-utils/mkfs.ubifs/lpt.c
similarity index 100%
rename from mkfs.ubifs/lpt.c
rename to ubifs-utils/mkfs.ubifs/lpt.c
diff --git a/mkfs.ubifs/lpt.h b/ubifs-utils/mkfs.ubifs/lpt.h
similarity index 100%
rename from mkfs.ubifs/lpt.h
rename to ubifs-utils/mkfs.ubifs/lpt.h
diff --git a/mkfs.ubifs/mkfs.ubifs.c b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
similarity index 100%
rename from mkfs.ubifs/mkfs.ubifs.c
rename to ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
diff --git a/mkfs.ubifs/mkfs.ubifs.h b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
similarity index 100%
rename from mkfs.ubifs/mkfs.ubifs.h
rename to ubifs-utils/mkfs.ubifs/mkfs.ubifs.h
diff --git a/mkfs.ubifs/ubifs.h b/ubifs-utils/mkfs.ubifs/ubifs.h
similarity index 100%
rename from mkfs.ubifs/ubifs.h
rename to ubifs-utils/mkfs.ubifs/ubifs.h
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH] gitignore: add ubifs_dump to gitignore.
  2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
                   ` (26 preceding siblings ...)
  2015-10-15  4:04 ` [PATCH v2 27/27] ubifs: ubifs_dump: dump data in hex format Dongsheng Yang
@ 2015-10-31  3:13 ` Dongsheng Yang
  27 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-10-31  3:13 UTC (permalink / raw)
  To: david, dedekind1, richard, computersforpeace, linux-mtd; +Cc: Dongsheng Yang

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index e1d23cd..04d9251 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,6 +45,7 @@
 /nor-utils/rfdformat
 /misc-utils/serve_image
 /jffsX-utils/sumtool
+/ubifs-utils/ubifs_dump/ubifs_dump
 
 #
 # Top-level generic files
-- 
1.8.4.2

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH V3 01/27] mtd-utils: Restructure the mtd-utils source.
  2015-10-31  3:12     ` [PATCH V3 " Dongsheng Yang
@ 2015-11-11 22:30       ` Brian Norris
  2015-11-11 22:40         ` Brian Norris
  0 siblings, 1 reply; 37+ messages in thread
From: Brian Norris @ 2015-11-11 22:30 UTC (permalink / raw)
  To: Dongsheng Yang; +Cc: david, dedekind1, richard, linux-mtd

On Sat, Oct 31, 2015 at 11:12:01AM +0800, 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
> 	|-- jffsX-utils
> 	|-- nand-utils
> 	|-- nor-utils
> 	|-- ubi-utils
> 	|-- ubifs-utils
> 	`-- tests
> 
> Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
> ---
> changelog:
> 	v1:
> 		- move tools in flash-utils to misc-utils
> 		- change dir in gitignore
> 		- remove flash_info in gitignore
> 		- add mtdpart in gitignore
>  .gitignore                                         | 54 +++++++++----------

This patch doesn't apply, due to .gitignore. I don't know what repo
you're patching of, but it's not the tip of mtd-utils.git...

...

> diff --git a/.gitignore b/.gitignore
> index 83ca938..e1d23cd 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -18,33 +18,33 @@
>  #
>  # Our programs
>  #
> -/doc_loadbios
> -/docfdisk
> -/flash_erase
> -/flash_info
> -/flash_lock
> -/flash_otp_dump
> -/flash_otp_info
> -/flash_otp_lock
> -/flash_otp_write
> -/flash_unlock
> -/flashcp
> -/ftl_check
> -/ftl_format
> -/jffs2dump
> -/jffs2reader
> -/mkfs.jffs2
> -/mtd_debug

You're missing mtdpart?

> -/nanddump
> -/nandtest
> -/nandwrite
> -/nftl_format
> -/nftldump
> -/recv_image
> -/rfddump
> -/rfdformat
> -/serve_image
> -/sumtool
> +/misc-utils/mtdpart

But it shows up here?

> +/misc-utils/doc_loadbios
> +/misc-utils/docfdisk
> +/misc-utils/flash_erase
> +/misc-utils/flash_lock
> +/misc-utils/flash_otp_dump
> +/misc-utils/flash_otp_info
> +/misc-utils/flash_otp_lock
> +/misc-utils/flash_otp_write
> +/misc-utils/flash_unlock
> +/misc-utils/flashcp
> +/misc-utils/ftl_check
> +/misc-utils/ftl_format
> +/jffsX-utils/jffs2dump
> +/jffsX-utils/jffs2reader
> +/jffsX-utils/mkfs.jffs2
> +/misc-utils/mtd_debug
> +/nand-utils/nanddump
> +/nand-utils/nandtest
> +/nand-utils/nandwrite
> +/nand-utils/nftl_format
> +/nand-utils/nftldump
> +/misc-utils/recv_image
> +/nor-utils/rfddump
> +/nor-utils/rfdformat
> +/misc-utils/serve_image
> +/jffsX-utils/sumtool
>  
>  #
>  # Top-level generic files

Brian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH V3 01/27] mtd-utils: Restructure the mtd-utils source.
  2015-11-11 22:30       ` Brian Norris
@ 2015-11-11 22:40         ` Brian Norris
  2015-11-12  7:20           ` Dongsheng Yang
  0 siblings, 1 reply; 37+ messages in thread
From: Brian Norris @ 2015-11-11 22:40 UTC (permalink / raw)
  To: Dongsheng Yang; +Cc: david, dedekind1, richard, linux-mtd

On Wed, Nov 11, 2015 at 02:30:07PM -0800, Brian Norris wrote:
> On Sat, Oct 31, 2015 at 11:12:01AM +0800, 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
> > 	|-- jffsX-utils
> > 	|-- nand-utils
> > 	|-- nor-utils
> > 	|-- ubi-utils
> > 	|-- ubifs-utils
> > 	`-- tests
> > 
> > Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
> > ---
> > changelog:
> > 	v1:
> > 		- move tools in flash-utils to misc-utils
> > 		- change dir in gitignore
> > 		- remove flash_info in gitignore
> > 		- add mtdpart in gitignore
> >  .gitignore                                         | 54 +++++++++----------
> 
> This patch doesn't apply, due to .gitignore. I don't know what repo
> you're patching of, but it's not the tip of mtd-utils.git...

Anyway, I fixed the conflicts and pushed this patch to mtd-utils.git.
Please let me know if you see any problems.

I'm probably not the one to review/apply the rest of this series, so
I'll leave that to Richard and others.

Brian

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH V3 01/27] mtd-utils: Restructure the mtd-utils source.
  2015-11-11 22:40         ` Brian Norris
@ 2015-11-12  7:20           ` Dongsheng Yang
  0 siblings, 0 replies; 37+ messages in thread
From: Dongsheng Yang @ 2015-11-12  7:20 UTC (permalink / raw)
  To: Brian Norris; +Cc: david, dedekind1, richard, linux-mtd

On 11/12/2015 06:40 AM, Brian Norris wrote:
> On Wed, Nov 11, 2015 at 02:30:07PM -0800, Brian Norris wrote:
[...]

 >>>		- add mtdpart in gitignore
>>>   .gitignore                                         | 54 +++++++++----------
>>
>> This patch doesn't apply, due to .gitignore. I don't know what repo
>> you're patching of, but it's not the tip of mtd-utils.git...
>
> Anyway, I fixed the conflicts and pushed this patch to mtd-utils.git.
> Please let me know if you see any problems.

Oh, my bad. Thanx for the fixing.

  I will rebase my rest patches. :)

Yang
>
> I'm probably not the one to review/apply the rest of this series, so
> I'll leave that to Richard and others.
>
> Brian
> .
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2015-11-12  7:27 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-15  4:04 [PATCH v2 00/27] Introduce ubifs_dump in ubifs-utils Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 01/27] mtd-utils: Restructure the mtd-utils source Dongsheng Yang
2015-10-15  4:06   ` Dongsheng Yang
2015-10-15  4:10   ` [RESEND PATCH " Dongsheng Yang
2015-10-27 23:00     ` Brian Norris
2015-10-31  2:38       ` Dongsheng Yang
2015-10-31  3:12     ` [PATCH V3 " Dongsheng Yang
2015-11-11 22:30       ` Brian Norris
2015-11-11 22:40         ` Brian Norris
2015-11-12  7:20           ` Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 02/27] ubifs: pick some common definitions into ubifs_common.h Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 03/27] ubifs: move the all io related code into io.[h|c] Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 04/27] ubifs: remove the including of mkfs.ubifs.h in lpt.c Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 05/27] ubifs: cut off the dependence from compr.o to mkfs.ubifs Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 06/27] ubifs: cut off the dependence from devtable to mkfs.ubifs.h Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 07/27] ubifs: introduce ubifs-utils/include and ubifs-utils/lib Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 08/27] ubifs: move more functions into io lib Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 09/27] ubifs: introduce a new tool ubifs_dump Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 10/27] ubifs: introduce list.h Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 11/27] ubifs: copy some important data in ubifs.h from kernel to ubifs-utils Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 12/27] ubifs: copy some important functions in key.h " Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 13/27] ubifs: ubifs_dump: add dump_ch and dump_node functions Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 14/27] ubifs: defs.h: introduce some compatible definition for printk class Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 15/27] ubifs: io: introduce ubifs_read function to read ubi volume Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 16/27] ubifs: ubifs_dump: dump super block Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 17/27] ubifs: introduce scan for ubifs-utils Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 18/27] ubifs: add some more compatible definitions in defs.h Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 19/27] ubifs: ubifs_dump: dump master node Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 20/27] ubifs: ubifs_dump: dump log area Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 21/27] ubifs: introduce lprops lib Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 22/27] ubifs: lpt: implement functions to scan lpt Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 23/27] ubifs: ubifs_dump: dump lpt area Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 24/27] ubifs: ubifs_dump: dump index area Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 25/27] ubifs: defs.h: introduce some compatible definitions about integer such as __u16 Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 26/27] ubifs: introduce hexdump lib Dongsheng Yang
2015-10-15  4:04 ` [PATCH v2 27/27] ubifs: ubifs_dump: dump data in hex format Dongsheng Yang
2015-10-31  3:13 ` [PATCH] gitignore: add ubifs_dump to gitignore Dongsheng Yang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.