Project import
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..3fb6713
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,117 @@
+#
+# Copyright (c) 2010-2011 Nest, Inc.
+# All rights reserved.
+#
+# This document is the property of Nest. It is considered
+# confidential and proprietary information.
+#
+# This document may not be reproduced or transmitted in any form,
+# in whole or in part, without the express written permission of
+# Nest.
+#
+# Description:
+# This file is the makefile for the Memory Technology Devices
+# (MTD) utilities.
+#
+
+BuildConfigSpecialized := No
+BuildProductSpecialized := No
+
+include pre.mak
+
+PackageName := mtd-utils
+
+PackageExtension := tar.bz2
+PackageSeparator := -
+
+PackagePatchArgs := -p1
+
+PackageArchive := $(PackageName).$(PackageExtension)
+PackageSourceDir := $(PackageName)$(PackageSeparator)$(PackageVersion)
+
+PackageBuildMakefile = $(call GenerateBuildPaths,Makefile)
+
+CleanPaths += $(PackageLicenseFile)
+
+LzoDir := sw/tps/lzo
+LzoIncDir = $(call GenerateResultPaths,$(LzoDir),usr/include)
+LzoLibDir = $(call GenerateResultPaths,$(LzoDir),usr/lib)
+
+UUIDDir := sw/tps/e2fsprogs
+UUIDIncDir = $(call GenerateResultPaths,$(UUIDDir),usr/include)
+UUIDLibDir = $(call GenerateResultPaths,$(UUIDDir),usr/lib)
+
+ZlibDir := sw/tps/zlib
+ZlibIncDir = $(call GenerateResultPaths,$(ZlibDir),usr/include)
+ZlibLibDir = $(call GenerateResultPaths,$(ZlibDir),usr/lib)
+
+all: $(PackageDefaultGoal)
+
+# Generate the package license contents.
+
+$(PackageSourceDir)/COPYING: source
+
+$(PackageLicenseFile): $(PackageSourceDir)/COPYING
+ $(copy-result)
+
+# Extract the source from the archive and apply patches, if any.
+
+$(PackageSourceDir): $(PackageArchive) $(PackagePatchPaths)
+ $(expand-and-patch-package)
+
+# Prepare the sources.
+
+.PHONY: source
+source: | $(PackageSourceDir)
+
+# Patch the sources, if necessary.
+
+.PHONY: patch
+patch: source
+
+# Configure the source for building.
+
+.PHONY: configure
+configure: source
+
+# Build the source.
+
+.PHONY: build
+build: configure
+ $(Verbose)cd $(PackageSourceDir) && \
+ $(MAKE) \
+ WITHOUT_XATTR=1 CC="$(CC)" \
+ LZOCPPFLAGS=-I$(LzoIncDir) \
+ LZOLDFLAGS=-L$(LzoLibDir) \
+ UUIDCPPFLAGS=-I$(UUIDIncDir) \
+ UUIDLDFLAGS=-L$(UUIDLibDir) \
+ ZLIBCPPFLAGS=-I$(ZlibIncDir) \
+ ZLIBLDFLAGS=-L$(ZlibLibDir) \
+ BUILDDIR=$(CURDIR)/$(BuildDirectory) \
+ INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+ all
+
+# Stage the build to a temporary installation area.
+
+.PHONY: stage
+stage: build | $(ResultDirectory)
+ $(Verbose)cd $(PackageSourceDir) && \
+ $(MAKE) \
+ WITHOUT_XATTR=1 CC="$(CC)" \
+ LZOCFLAGS=-I$(LzoIncDir) \
+ LZOLDFLAGS=-L$(LzoLibDir) \
+ UUIDCPPFLAGS=-I$(UUIDIncDir) \
+ UUIDLDFLAGS=-L$(UUIDLibDir) \
+ ZLIBCFLAGS=-I$(ZlibIncDir) \
+ ZLIBLDFLAGS=-L$(ZlibLibDir) \
+ BUILDDIR=$(CURDIR)/$(BuildDirectory) \
+ INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+ DESTDIR=$(ResultDirectory) \
+ install
+
+clean:
+ $(Verbose)$(RM) $(RMFLAGS) -r $(PackageSourceDir)
+ $(Verbose)$(RM) $(RMFLAGS) -r $(BuildDirectory)
+ $(Verbose)$(RM) $(RMFLAGS) -r $(ResultDirectory)
+
+include post.mak
diff --git a/mtd-utils-1.3.1/COPYING b/mtd-utils-1.3.1/COPYING
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/mtd-utils-1.3.1/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/mtd-utils-1.3.1/MAKEDEV b/mtd-utils-1.3.1/MAKEDEV
new file mode 100755
index 0000000..b31e61f
--- /dev/null
+++ b/mtd-utils-1.3.1/MAKEDEV
@@ -0,0 +1,42 @@
+#!/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/mtd-utils-1.3.1/Makefile b/mtd-utils-1.3.1/Makefile
new file mode 100644
index 0000000..666537b
--- /dev/null
+++ b/mtd-utils-1.3.1/Makefile
@@ -0,0 +1,72 @@
+
+# -*- sh -*-
+
+PREFIX=/usr
+EXEC_PREFIX=$(PREFIX)
+SBINDIR=$(EXEC_PREFIX)/sbin
+MANDIR=$(PREFIX)/man
+INCLUDEDIR=$(PREFIX)/include
+
+CPPFLAGS += -I./include $(ZLIBCPPFLAGS) $(LZOCPPFLAGS)
+
+ifeq ($(WITHOUT_XATTR), 1)
+ CPPFLAGS += -DWITHOUT_XATTR
+endif
+
+SUBDIRS = ubi-utils mkfs.ubifs
+
+TARGETS = ftl_format flash_erase flash_eraseall nanddump doc_loadbios \
+ ftl_check mkfs.jffs2 flash_lock flash_unlock flash_info \
+ flash_otp_info flash_otp_dump mtd_debug flashcp nandwrite nandtest \
+ jffs2dump \
+ nftldump nftl_format docfdisk \
+ rfddump rfdformat \
+ serve_image recv_image \
+ sumtool #jffs2reader
+
+SYMLINKS =
+
+include common.mk
+
+clean::
+ -rm -f $(SYMLINKS)
+ifneq ($(BUILDDIR)/.git,)
+ifneq ($(BUILDDIR),.)
+ifneq ($(BUILDDIR),$(PWD))
+ rm -rf $(BUILDDIR)
+endif
+endif
+endif
+
+$(SYMLINKS):
+ ln -sf ../fs/jffs2/$@ $@
+
+$(BUILDDIR)/mkfs.jffs2: $(addprefix $(BUILDDIR)/,\
+ crc32.o compr_rtime.o mkfs.jffs2.o compr_zlib.o compr_lzo.o \
+ compr.o rbtree.o)
+LDFLAGS_mkfs.jffs2 = $(ZLIBLDFLAGS) $(LZOLDFLAGS)
+LDLIBS_mkfs.jffs2 = -lz -llzo2
+
+$(BUILDDIR)/flash_eraseall: $(BUILDDIR)/crc32.o $(BUILDDIR)/flash_eraseall.o
+
+$(BUILDDIR)/jffs2reader: $(BUILDDIR)/jffs2reader.o
+LDFLAGS_jffs2reader = $(ZLIBLDFLAGS) $(LZOLDFLAGS)
+LDLIBS_jffs2reader = -lz -llzo2
+
+$(BUILDDIR)/jffs2dump: $(BUILDDIR)/jffs2dump.o $(BUILDDIR)/crc32.o
+
+$(BUILDDIR)/sumtool: $(BUILDDIR)/sumtool.o $(BUILDDIR)/crc32.o
+
+$(BUILDDIR)/serve_image: $(BUILDDIR)/serve_image.o $(BUILDDIR)/crc32.o $(BUILDDIR)/fec.o
+
+$(BUILDDIR)/recv_image: $(BUILDDIR)/recv_image.o $(BUILDDIR)/crc32.o $(BUILDDIR)/fec.o
+
+$(BUILDDIR)/fectest: $(BUILDDIR)/fectest.o $(BUILDDIR)/crc32.o $(BUILDDIR)/fec.o
+
+
+
+install:: ${TARGETS}
+ mkdir -p ${DESTDIR}/${SBINDIR}
+ install -m 0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/
+ mkdir -p ${DESTDIR}/${MANDIR}/man1
+ gzip -9c mkfs.jffs2.1 > ${DESTDIR}/${MANDIR}/man1/mkfs.jffs2.1.gz
diff --git a/mtd-utils-1.3.1/common.mk b/mtd-utils-1.3.1/common.mk
new file mode 100644
index 0000000..9893704
--- /dev/null
+++ b/mtd-utils-1.3.1/common.mk
@@ -0,0 +1,73 @@
+.NOTPARALLEL:
+
+CC := $(CROSS)gcc
+AR := $(CROSS)ar
+RANLIB := $(CROSS)ranlib
+
+# Stolen from Linux build system
+try-run = $(shell set -e; ($(1)) >/dev/null 2>&1 && echo "$(2)" || echo "$(3)")
+cc-option = $(call try-run, $(CC) $(1) -c -xc /dev/null -o /dev/null,$(1),$(2))
+
+CFLAGS ?= -O2 -g
+WFLAGS := -Wall \
+ $(call cc-option,-Wextra) \
+ $(call cc-option,-Wwrite-strings) \
+ $(call cc-option,-Wno-sign-compare)
+CFLAGS += $(WFLAGS)
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+
+DESTDIR ?= /usr/local
+PREFIX=/usr
+EXEC_PREFIX=$(PREFIX)
+SBINDIR=$(EXEC_PREFIX)/sbin
+MANDIR=$(PREFIX)/share/man
+INCLUDEDIR=$(PREFIX)/include
+
+ifndef BUILDDIR
+ifeq ($(origin CROSS),undefined)
+ BUILDDIR := $(PWD)
+else
+# Remove the trailing slash to make the directory name
+ BUILDDIR := $(PWD)/$(CROSS:-=)
+endif
+endif
+override BUILDDIR := $(patsubst %/,%,$(BUILDDIR))
+
+override TARGETS := $(addprefix $(BUILDDIR)/,$(TARGETS))
+
+SUBDIRS_ALL = $(patsubst %,subdirs_%_all,$(SUBDIRS))
+SUBDIRS_CLEAN = $(patsubst %,subdirs_%_clean,$(SUBDIRS))
+SUBDIRS_INSTALL = $(patsubst %,subdirs_%_install,$(SUBDIRS))
+
+all:: $(TARGETS) $(SUBDIRS_ALL)
+
+clean:: $(SUBDIRS_CLEAN)
+ rm -f $(BUILDDIR)/*.o $(TARGETS) $(BUILDDIR)/.*.c.dep
+
+install:: $(TARGETS) $(SUBDIRS_INSTALL)
+
+%: %.o
+ $(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_$(notdir $@)) -g -o $@ $^ $(LDLIBS) $(LDLIBS_$(notdir $@))
+
+$(BUILDDIR)/%.a:
+ $(AR) crv $@ $^
+ $(RANLIB) $@
+
+$(BUILDDIR)/%.o: %.c
+ifneq ($(BUILDDIR),$(CURDIR))
+ mkdir -p $(dir $@)
+endif
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< -g -Wp,-MD,$(BUILDDIR)/.$(<F).dep
+
+subdirs_%:
+ d=$(patsubst subdirs_%,%,$@); \
+ t=`echo $$d | sed s:.*_::` d=`echo $$d | sed s:_.*::`; \
+ $(MAKE) BUILDDIR=$(BUILDDIR)/$$d -C $$d $$t
+
+.SUFFIXES:
+
+IGNORE=${wildcard $(BUILDDIR)/.*.c.dep}
+-include ${IGNORE}
+
+PHONY += all clean install
+.PHONY: $(PHONY)
diff --git a/mtd-utils-1.3.1/compr.c b/mtd-utils-1.3.1/compr.c
new file mode 100644
index 0000000..7028c93
--- /dev/null
+++ b/mtd-utils-1.3.1/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,NULL)) {
+ 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, NULL);
+ 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, NULL);
+ 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: unknow 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,"unkown");
+ 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/mtd-utils-1.3.1/compr.h b/mtd-utils-1.3.1/compr.h
new file mode 100644
index 0000000..51bf0dd
--- /dev/null
+++ b/mtd-utils-1.3.1/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 */
+ char *name;
+ char compr; /* JFFS2_COMPR_XXX */
+ int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t *srclen, uint32_t *destlen, void *model);
+ int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
+ uint32_t cdatalen, uint32_t datalen, void *model);
+ 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/mtd-utils-1.3.1/compr_lzo.c b/mtd-utils-1.3.1/compr_lzo.c
new file mode 100644
index 0000000..3d7dad7
--- /dev/null
+++ b/mtd-utils-1.3.1/compr_lzo.c
@@ -0,0 +1,120 @@
+/*
+ * 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>
+#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, void *model)
+{
+ 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, void *model)
+{
+ 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);
+}
diff --git a/mtd-utils-1.3.1/compr_rtime.c b/mtd-utils-1.3.1/compr_rtime.c
new file mode 100644
index 0000000..131536c
--- /dev/null
+++ b/mtd-utils-1.3.1/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, void *model)
+{
+ short positions[256];
+ int outpos = 0;
+ int pos=0;
+
+ memset(positions,0,sizeof(positions));
+
+ while (pos < (*sourcelen) && outpos <= (*dstlen)-2) {
+ 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,
+ uint32_t srclen, uint32_t destlen, void *model)
+{
+ 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/mtd-utils-1.3.1/compr_zlib.c b/mtd-utils-1.3.1/compr_zlib.c
new file mode 100644
index 0000000..400b18a
--- /dev/null
+++ b/mtd-utils-1.3.1/compr_zlib.c
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <zlib.h>
+#include <stdio.h>
+#include <asm/types.h>
+#include <linux/jffs2.h>
+#include "compr.h"
+
+#define min(x,y) ((x)<(y)?(x):(y))
+
+/* 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
+
+int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
+{
+ 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;
+}
+
+int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t srclen, uint32_t destlen, void *model)
+{
+ 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/mtd-utils-1.3.1/crc32.c b/mtd-utils-1.3.1/crc32.c
new file mode 100644
index 0000000..6b1e50c
--- /dev/null
+++ b/mtd-utils-1.3.1/crc32.c
@@ -0,0 +1,95 @@
+/*
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ *
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ */
+
+#include <stdint.h>
+
+const uint32_t crc32_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
diff --git a/mtd-utils-1.3.1/crc32.h b/mtd-utils-1.3.1/crc32.h
new file mode 100644
index 0000000..ee3145b
--- /dev/null
+++ b/mtd-utils-1.3.1/crc32.h
@@ -0,0 +1,19 @@
+#ifndef CRC32_H
+#define CRC32_H
+
+#include <stdint.h>
+
+extern const uint32_t crc32_table[256];
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+ static inline uint32_t
+crc32(uint32_t val, const void *ss, int len)
+{
+ const unsigned char *s = ss;
+ while (--len >= 0)
+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+ return val;
+}
+
+#endif
diff --git a/mtd-utils-1.3.1/device_table.txt b/mtd-utils-1.3.1/device_table.txt
new file mode 100644
index 0000000..74fdc56
--- /dev/null
+++ b/mtd-utils-1.3.1/device_table.txt
@@ -0,0 +1,129 @@
+# 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/mtd-utils-1.3.1/doc_loadbios.c b/mtd-utils-1.3.1/doc_loadbios.c
new file mode 100644
index 0000000..0a11fd2
--- /dev/null
+++ b/mtd-utils-1.3.1/doc_loadbios.c
@@ -0,0 +1,148 @@
+#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/mtd-utils-1.3.1/docfdisk.c b/mtd-utils-1.3.1/docfdisk.c
new file mode 100644
index 0000000..56fffc4
--- /dev/null
+++ b/mtd-utils-1.3.1/docfdisk.c
@@ -0,0 +1,317 @@
+/*
+ * 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 _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",
+ argv[0]);
+ 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/mtd-utils-1.3.1/feature-removal-schedule.txt b/mtd-utils-1.3.1/feature-removal-schedule.txt
new file mode 100644
index 0000000..d0116f8
--- /dev/null
+++ b/mtd-utils-1.3.1/feature-removal-schedule.txt
@@ -0,0 +1,9 @@
+The following is a list of files and features that are going to be
+removed in the mtd-utils source tree. Every entry should contain what
+exactly is going away, why it is happening, and who is going to be doing
+the work. When the feature is removed from the utils, it should also
+be removed from this file.
+
+---------------------------
+
+---------------------------
diff --git a/mtd-utils-1.3.1/fec.c b/mtd-utils-1.3.1/fec.c
new file mode 100644
index 0000000..6d9020f
--- /dev/null
+++ b/mtd-utils-1.3.1/fec.c
@@ -0,0 +1,904 @@
+/*
+ * fec.c -- forward error correction based on Vandermonde matrices
+ * 980624
+ * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
+ *
+ * Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
+ * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
+ * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS
+ * 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.
+ */
+
+/*
+ * The following parameter defines how many bits are used for
+ * field elements. The code supports any value from 2 to 16
+ * but fastest operation is achieved with 8 bit elements
+ * This is the only parameter you may want to change.
+ */
+#ifndef GF_BITS
+#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * stuff used for testing purposes only
+ */
+
+#ifdef TEST
+#define DEB(x)
+#define DDB(x) x
+#define DEBUG 0 /* minimal debugging */
+#ifdef MSDOS
+#include <time.h>
+struct timeval {
+ unsigned long ticks;
+};
+#define gettimeofday(x, dummy) { (x)->ticks = clock() ; }
+#define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC )
+typedef unsigned long u_long ;
+typedef unsigned short u_short ;
+#else /* typically, unix systems */
+#include <sys/time.h>
+#define DIFF_T(a,b) \
+ (1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) )
+#endif
+
+#define TICK(t) \
+ {struct timeval x ; \
+ gettimeofday(&x, NULL) ; \
+ t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \
+ }
+#define TOCK(t) \
+ { u_long t1 ; TICK(t1) ; \
+ if (t1 < t) t = 256000000 + t1 - t ; \
+ else t = t1 - t ; \
+ if (t == 0) t = 1 ;}
+
+u_long ticks[10]; /* vars for timekeeping */
+#else
+#define DEB(x)
+#define DDB(x)
+#define TICK(x)
+#define TOCK(x)
+#endif /* TEST */
+
+/*
+ * You should not need to change anything beyond this point.
+ * The first part of the file implements linear algebra in GF.
+ *
+ * gf is the type used to store an element of the Galois Field.
+ * Must constain at least GF_BITS bits.
+ *
+ * Note: unsigned char will work up to GF(256) but int seems to run
+ * faster on the Pentium. We use int whenever have to deal with an
+ * index, since they are generally faster.
+ */
+#if (GF_BITS < 2 && GF_BITS >16)
+#error "GF_BITS must be 2 .. 16"
+#endif
+#if (GF_BITS <= 8)
+typedef unsigned char gf;
+#else
+typedef unsigned short gf;
+#endif
+
+#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
+
+/*
+ * Primitive polynomials - see Lin & Costello, Appendix A,
+ * and Lee & Messerschmitt, p. 453.
+ */
+static char *allPp[] = { /* GF_BITS polynomial */
+ NULL, /* 0 no code */
+ NULL, /* 1 no code */
+ "111", /* 2 1+x+x^2 */
+ "1101", /* 3 1+x+x^3 */
+ "11001", /* 4 1+x+x^4 */
+ "101001", /* 5 1+x^2+x^5 */
+ "1100001", /* 6 1+x+x^6 */
+ "10010001", /* 7 1 + x^3 + x^7 */
+ "101110001", /* 8 1+x^2+x^3+x^4+x^8 */
+ "1000100001", /* 9 1+x^4+x^9 */
+ "10010000001", /* 10 1+x^3+x^10 */
+ "101000000001", /* 11 1+x^2+x^11 */
+ "1100101000001", /* 12 1+x+x^4+x^6+x^12 */
+ "11011000000001", /* 13 1+x+x^3+x^4+x^13 */
+ "110000100010001", /* 14 1+x+x^6+x^10+x^14 */
+ "1100000000000001", /* 15 1+x+x^15 */
+ "11010000000010001" /* 16 1+x+x^3+x^12+x^16 */
+};
+
+
+/*
+ * To speed up computations, we have tables for logarithm, exponent
+ * and inverse of a number. If GF_BITS <= 8, we use a table for
+ * multiplication as well (it takes 64K, no big deal even on a PDA,
+ * especially because it can be pre-initialized an put into a ROM!),
+ * otherwhise we use a table of logarithms.
+ * In any case the macro gf_mul(x,y) takes care of multiplications.
+ */
+
+static gf gf_exp[2*GF_SIZE]; /* index->poly form conversion table */
+static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */
+static gf inverse[GF_SIZE+1]; /* inverse of field elem. */
+ /* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */
+
+/*
+ * modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1,
+ * without a slow divide.
+ */
+static inline gf
+modnn(int x)
+{
+ while (x >= GF_SIZE) {
+ x -= GF_SIZE;
+ x = (x >> GF_BITS) + (x & GF_SIZE);
+ }
+ return x;
+}
+
+#define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;}
+
+/*
+ * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much
+ * faster to use a multiplication table.
+ *
+ * USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying
+ * many numbers by the same constant. In this case the first
+ * call sets the constant, and others perform the multiplications.
+ * A value related to the multiplication is held in a local variable
+ * declared with USE_GF_MULC . See usage in addmul1().
+ */
+#if (GF_BITS <= 8)
+static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];
+
+#define gf_mul(x,y) gf_mul_table[x][y]
+
+#define USE_GF_MULC register gf * __gf_mulc_
+#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c]
+#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x]
+
+static void
+init_mul_table()
+{
+ int i, j;
+ for (i=0; i< GF_SIZE+1; i++)
+ for (j=0; j< GF_SIZE+1; j++)
+ gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j]) ] ;
+
+ for (j=0; j< GF_SIZE+1; j++)
+ gf_mul_table[0][j] = gf_mul_table[j][0] = 0;
+}
+#else /* GF_BITS > 8 */
+static inline gf
+gf_mul(x,y)
+{
+ if ( (x) == 0 || (y)==0 ) return 0;
+
+ return gf_exp[gf_log[x] + gf_log[y] ] ;
+}
+#define init_mul_table()
+
+#define USE_GF_MULC register gf * __gf_mulc_
+#define GF_MULC0(c) __gf_mulc_ = &gf_exp[ gf_log[c] ]
+#define GF_ADDMULC(dst, x) { if (x) dst ^= __gf_mulc_[ gf_log[x] ] ; }
+#endif
+
+/*
+ * Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
+ * Lookup tables:
+ * index->polynomial form gf_exp[] contains j= \alpha^i;
+ * polynomial form -> index form gf_log[ j = \alpha^i ] = i
+ * \alpha=x is the primitive element of GF(2^m)
+ *
+ * For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple
+ * multiplication of two numbers can be resolved without calling modnn
+ */
+
+/*
+ * i use malloc so many times, it is easier to put checks all in
+ * one place.
+ */
+static void *
+my_malloc(int sz, char *err_string)
+{
+ void *p = malloc( sz );
+ if (p == NULL) {
+ fprintf(stderr, "-- malloc failure allocating %s\n", err_string);
+ exit(1) ;
+ }
+ return p ;
+}
+
+#define NEW_GF_MATRIX(rows, cols) \
+ (gf *)my_malloc(rows * cols * sizeof(gf), " ## __LINE__ ## " )
+
+/*
+ * initialize the data structures used for computations in GF.
+ */
+static void
+generate_gf(void)
+{
+ int i;
+ gf mask;
+ char *Pp = allPp[GF_BITS] ;
+
+ mask = 1; /* x ** 0 = 1 */
+ gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */
+ /*
+ * first, generate the (polynomial representation of) powers of \alpha,
+ * which are stored in gf_exp[i] = \alpha ** i .
+ * At the same time build gf_log[gf_exp[i]] = i .
+ * The first GF_BITS powers are simply bits shifted to the left.
+ */
+ for (i = 0; i < GF_BITS; i++, mask <<= 1 ) {
+ gf_exp[i] = mask;
+ gf_log[gf_exp[i]] = i;
+ /*
+ * If Pp[i] == 1 then \alpha ** i occurs in poly-repr
+ * gf_exp[GF_BITS] = \alpha ** GF_BITS
+ */
+ if ( Pp[i] == '1' )
+ gf_exp[GF_BITS] ^= mask;
+ }
+ /*
+ * now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als
+ * compute its inverse.
+ */
+ gf_log[gf_exp[GF_BITS]] = GF_BITS;
+ /*
+ * Poly-repr of \alpha ** (i+1) is given by poly-repr of
+ * \alpha ** i shifted left one-bit and accounting for any
+ * \alpha ** GF_BITS term that may occur when poly-repr of
+ * \alpha ** i is shifted.
+ */
+ mask = 1 << (GF_BITS - 1 ) ;
+ for (i = GF_BITS + 1; i < GF_SIZE; i++) {
+ if (gf_exp[i - 1] >= mask)
+ gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1);
+ else
+ gf_exp[i] = gf_exp[i - 1] << 1;
+ gf_log[gf_exp[i]] = i;
+ }
+ /*
+ * log(0) is not defined, so use a special value
+ */
+ gf_log[0] = GF_SIZE ;
+ /* set the extended gf_exp values for fast multiply */
+ for (i = 0 ; i < GF_SIZE ; i++)
+ gf_exp[i + GF_SIZE] = gf_exp[i] ;
+
+ /*
+ * again special cases. 0 has no inverse. This used to
+ * be initialized to GF_SIZE, but it should make no difference
+ * since noone is supposed to read from here.
+ */
+ inverse[0] = 0 ;
+ inverse[1] = 1;
+ for (i=2; i<=GF_SIZE; i++)
+ inverse[i] = gf_exp[GF_SIZE-gf_log[i]];
+}
+
+/*
+ * Various linear algebra operations that i use often.
+ */
+
+/*
+ * addmul() computes dst[] = dst[] + c * src[]
+ * This is used often, so better optimize it! Currently the loop is
+ * unrolled 16 times, a good value for 486 and pentium-class machines.
+ * The case c=0 is also optimized, whereas c=1 is not. These
+ * calls are unfrequent in my typical apps so I did not bother.
+ *
+ * Note that gcc on
+ */
+#define addmul(dst, src, c, sz) \
+ if (c != 0) addmul1(dst, src, c, sz)
+
+#define UNROLL 16 /* 1, 4, 8, 16 */
+static void
+addmul1(gf *dst1, gf *src1, gf c, int sz)
+{
+ USE_GF_MULC ;
+ register gf *dst = dst1, *src = src1 ;
+ gf *lim = &dst[sz - UNROLL + 1] ;
+
+ GF_MULC0(c) ;
+
+#if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */
+ for (; dst < lim ; dst += UNROLL, src += UNROLL ) {
+ GF_ADDMULC( dst[0] , src[0] );
+ GF_ADDMULC( dst[1] , src[1] );
+ GF_ADDMULC( dst[2] , src[2] );
+ GF_ADDMULC( dst[3] , src[3] );
+#if (UNROLL > 4)
+ GF_ADDMULC( dst[4] , src[4] );
+ GF_ADDMULC( dst[5] , src[5] );
+ GF_ADDMULC( dst[6] , src[6] );
+ GF_ADDMULC( dst[7] , src[7] );
+#endif
+#if (UNROLL > 8)
+ GF_ADDMULC( dst[8] , src[8] );
+ GF_ADDMULC( dst[9] , src[9] );
+ GF_ADDMULC( dst[10] , src[10] );
+ GF_ADDMULC( dst[11] , src[11] );
+ GF_ADDMULC( dst[12] , src[12] );
+ GF_ADDMULC( dst[13] , src[13] );
+ GF_ADDMULC( dst[14] , src[14] );
+ GF_ADDMULC( dst[15] , src[15] );
+#endif
+ }
+#endif
+ lim += UNROLL - 1 ;
+ for (; dst < lim; dst++, src++ ) /* final components */
+ GF_ADDMULC( *dst , *src );
+}
+
+/*
+ * computes C = AB where A is n*k, B is k*m, C is n*m
+ */
+static void
+matmul(gf *a, gf *b, gf *c, int n, int k, int m)
+{
+ int row, col, i ;
+
+ for (row = 0; row < n ; row++) {
+ for (col = 0; col < m ; col++) {
+ gf *pa = &a[ row * k ];
+ gf *pb = &b[ col ];
+ gf acc = 0 ;
+ for (i = 0; i < k ; i++, pa++, pb += m )
+ acc ^= gf_mul( *pa, *pb ) ;
+ c[ row * m + col ] = acc ;
+ }
+ }
+}
+
+#ifdef DEBUG
+/*
+ * returns 1 if the square matrix is identiy
+ * (only for test)
+ */
+static int
+is_identity(gf *m, int k)
+{
+ int row, col ;
+ for (row=0; row<k; row++)
+ for (col=0; col<k; col++)
+ if ( (row==col && *m != 1) ||
+ (row!=col && *m != 0) )
+ return 0 ;
+ else
+ m++ ;
+ return 1 ;
+}
+#endif /* debug */
+
+/*
+ * invert_mat() takes a matrix and produces its inverse
+ * k is the size of the matrix.
+ * (Gauss-Jordan, adapted from Numerical Recipes in C)
+ * Return non-zero if singular.
+ */
+DEB( int pivloops=0; int pivswaps=0 ; /* diagnostic */)
+static int
+invert_mat(gf *src, int k)
+{
+ gf c, *p ;
+ int irow, icol, row, col, i, ix ;
+
+ int error = 1 ;
+ int *indxc = my_malloc(k*sizeof(int), "indxc");
+ int *indxr = my_malloc(k*sizeof(int), "indxr");
+ int *ipiv = my_malloc(k*sizeof(int), "ipiv");
+ gf *id_row = NEW_GF_MATRIX(1, k);
+ gf *temp_row = NEW_GF_MATRIX(1, k);
+
+ memset(id_row, '\0', k*sizeof(gf));
+ DEB( pivloops=0; pivswaps=0 ; /* diagnostic */ )
+ /*
+ * ipiv marks elements already used as pivots.
+ */
+ for (i = 0; i < k ; i++)
+ ipiv[i] = 0 ;
+
+ for (col = 0; col < k ; col++) {
+ gf *pivot_row ;
+ /*
+ * Zeroing column 'col', look for a non-zero element.
+ * First try on the diagonal, if it fails, look elsewhere.
+ */
+ irow = icol = -1 ;
+ if (ipiv[col] != 1 && src[col*k + col] != 0) {
+ irow = col ;
+ icol = col ;
+ goto found_piv ;
+ }
+ for (row = 0 ; row < k ; row++) {
+ if (ipiv[row] != 1) {
+ for (ix = 0 ; ix < k ; ix++) {
+ DEB( pivloops++ ; )
+ if (ipiv[ix] == 0) {
+ if (src[row*k + ix] != 0) {
+ irow = row ;
+ icol = ix ;
+ goto found_piv ;
+ }
+ } else if (ipiv[ix] > 1) {
+ fprintf(stderr, "singular matrix\n");
+ goto fail ;
+ }
+ }
+ }
+ }
+ if (icol == -1) {
+ fprintf(stderr, "XXX pivot not found!\n");
+ goto fail ;
+ }
+found_piv:
+ ++(ipiv[icol]) ;
+ /*
+ * swap rows irow and icol, so afterwards the diagonal
+ * element will be correct. Rarely done, not worth
+ * optimizing.
+ */
+ if (irow != icol) {
+ for (ix = 0 ; ix < k ; ix++ ) {
+ SWAP( src[irow*k + ix], src[icol*k + ix], gf) ;
+ }
+ }
+ indxr[col] = irow ;
+ indxc[col] = icol ;
+ pivot_row = &src[icol*k] ;
+ c = pivot_row[icol] ;
+ if (c == 0) {
+ fprintf(stderr, "singular matrix 2\n");
+ goto fail ;
+ }
+ if (c != 1 ) { /* otherwhise this is a NOP */
+ /*
+ * this is done often , but optimizing is not so
+ * fruitful, at least in the obvious ways (unrolling)
+ */
+ DEB( pivswaps++ ; )
+ c = inverse[ c ] ;
+ pivot_row[icol] = 1 ;
+ for (ix = 0 ; ix < k ; ix++ )
+ pivot_row[ix] = gf_mul(c, pivot_row[ix] );
+ }
+ /*
+ * from all rows, remove multiples of the selected row
+ * to zero the relevant entry (in fact, the entry is not zero
+ * because we know it must be zero).
+ * (Here, if we know that the pivot_row is the identity,
+ * we can optimize the addmul).
+ */
+ id_row[icol] = 1;
+ if (memcmp(pivot_row, id_row, k*sizeof(gf)) != 0) {
+ for (p = src, ix = 0 ; ix < k ; ix++, p += k ) {
+ if (ix != icol) {
+ c = p[icol] ;
+ p[icol] = 0 ;
+ addmul(p, pivot_row, c, k );
+ }
+ }
+ }
+ id_row[icol] = 0;
+ } /* done all columns */
+ for (col = k-1 ; col >= 0 ; col-- ) {
+ if (indxr[col] <0 || indxr[col] >= k)
+ fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]);
+ else if (indxc[col] <0 || indxc[col] >= k)
+ fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]);
+ else
+ if (indxr[col] != indxc[col] ) {
+ for (row = 0 ; row < k ; row++ ) {
+ SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ;
+ }
+ }
+ }
+ error = 0 ;
+fail:
+ free(indxc);
+ free(indxr);
+ free(ipiv);
+ free(id_row);
+ free(temp_row);
+ return error ;
+}
+
+/*
+ * fast code for inverting a vandermonde matrix.
+ * XXX NOTE: It assumes that the matrix
+ * is not singular and _IS_ a vandermonde matrix. Only uses
+ * the second column of the matrix, containing the p_i's.
+ *
+ * Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but
+ * largely revised for my purposes.
+ * p = coefficients of the matrix (p_i)
+ * q = values of the polynomial (known)
+ */
+
+int
+invert_vdm(gf *src, int k)
+{
+ int i, j, row, col ;
+ gf *b, *c, *p;
+ gf t, xx ;
+
+ if (k == 1) /* degenerate case, matrix must be p^0 = 1 */
+ return 0 ;
+ /*
+ * c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1
+ * b holds the coefficient for the matrix inversion
+ */
+ c = NEW_GF_MATRIX(1, k);
+ b = NEW_GF_MATRIX(1, k);
+
+ p = NEW_GF_MATRIX(1, k);
+
+ for ( j=1, i = 0 ; i < k ; i++, j+=k ) {
+ c[i] = 0 ;
+ p[i] = src[j] ; /* p[i] */
+ }
+ /*
+ * construct coeffs. recursively. We know c[k] = 1 (implicit)
+ * and start P_0 = x - p_0, then at each stage multiply by
+ * x - p_i generating P_i = x P_{i-1} - p_i P_{i-1}
+ * After k steps we are done.
+ */
+ c[k-1] = p[0] ; /* really -p(0), but x = -x in GF(2^m) */
+ for (i = 1 ; i < k ; i++ ) {
+ gf p_i = p[i] ; /* see above comment */
+ for (j = k-1 - ( i - 1 ) ; j < k-1 ; j++ )
+ c[j] ^= gf_mul( p_i, c[j+1] ) ;
+ c[k-1] ^= p_i ;
+ }
+
+ for (row = 0 ; row < k ; row++ ) {
+ /*
+ * synthetic division etc.
+ */
+ xx = p[row] ;
+ t = 1 ;
+ b[k-1] = 1 ; /* this is in fact c[k] */
+ for (i = k-2 ; i >= 0 ; i-- ) {
+ b[i] = c[i+1] ^ gf_mul(xx, b[i+1]) ;
+ t = gf_mul(xx, t) ^ b[i] ;
+ }
+ for (col = 0 ; col < k ; col++ )
+ src[col*k + row] = gf_mul(inverse[t], b[col] );
+ }
+ free(c) ;
+ free(b) ;
+ free(p) ;
+ return 0 ;
+}
+
+static int fec_initialized = 0 ;
+static void
+init_fec()
+{
+ TICK(ticks[0]);
+ generate_gf();
+ TOCK(ticks[0]);
+ DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);)
+ TICK(ticks[0]);
+ init_mul_table();
+ TOCK(ticks[0]);
+ DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);)
+ fec_initialized = 1 ;
+}
+
+/*
+ * This section contains the proper FEC encoding/decoding routines.
+ * The encoding matrix is computed starting with a Vandermonde matrix,
+ * and then transforming it into a systematic matrix.
+ */
+
+#define FEC_MAGIC 0xFECC0DEC
+
+struct fec_parms {
+ u_long magic ;
+ int k, n ; /* parameters of the code */
+ gf *enc_matrix ;
+} ;
+
+void
+fec_free(struct fec_parms *p)
+{
+ if (p==NULL ||
+ p->magic != ( ( (FEC_MAGIC ^ p->k) ^ p->n) ^ (int)(p->enc_matrix)) ) {
+ fprintf(stderr, "bad parameters to fec_free\n");
+ return ;
+ }
+ free(p->enc_matrix);
+ free(p);
+}
+
+/*
+ * create a new encoder, returning a descriptor. This contains k,n and
+ * the encoding matrix.
+ */
+struct fec_parms *
+fec_new(int k, int n)
+{
+ int row, col ;
+ gf *p, *tmp_m ;
+
+ struct fec_parms *retval ;
+
+ if (fec_initialized == 0)
+ init_fec();
+
+ if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n ) {
+ fprintf(stderr, "Invalid parameters k %d n %d GF_SIZE %d\n",
+ k, n, GF_SIZE );
+ return NULL ;
+ }
+ retval = my_malloc(sizeof(struct fec_parms), "new_code");
+ retval->k = k ;
+ retval->n = n ;
+ retval->enc_matrix = NEW_GF_MATRIX(n, k);
+ retval->magic = ( ( FEC_MAGIC ^ k) ^ n) ^ (int)(retval->enc_matrix) ;
+ tmp_m = NEW_GF_MATRIX(n, k);
+ /*
+ * fill the matrix with powers of field elements, starting from 0.
+ * The first row is special, cannot be computed with exp. table.
+ */
+ tmp_m[0] = 1 ;
+ for (col = 1; col < k ; col++)
+ tmp_m[col] = 0 ;
+ for (p = tmp_m + k, row = 0; row < n-1 ; row++, p += k) {
+ for ( col = 0 ; col < k ; col ++ )
+ p[col] = gf_exp[modnn(row*col)];
+ }
+
+ /*
+ * quick code to build systematic matrix: invert the top
+ * k*k vandermonde matrix, multiply right the bottom n-k rows
+ * by the inverse, and construct the identity matrix at the top.
+ */
+ TICK(ticks[3]);
+ invert_vdm(tmp_m, k); /* much faster than invert_mat */
+ matmul(tmp_m + k*k, tmp_m, retval->enc_matrix + k*k, n - k, k, k);
+ /*
+ * the upper matrix is I so do not bother with a slow multiply
+ */
+ memset(retval->enc_matrix, '\0', k*k*sizeof(gf) );
+ for (p = retval->enc_matrix, col = 0 ; col < k ; col++, p += k+1 )
+ *p = 1 ;
+ free(tmp_m);
+ TOCK(ticks[3]);
+
+ DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n",
+ ticks[3]);)
+ DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");)
+ return retval ;
+}
+
+/*
+ * fec_encode accepts as input pointers to n data packets of size sz,
+ * and produces as output a packet pointed to by fec, computed
+ * with index "index".
+ */
+void
+fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz)
+{
+ int i, k = code->k ;
+ gf *p ;
+
+ if (GF_BITS > 8)
+ sz /= 2 ;
+
+ if (index < k)
+ memcpy(fec, src[index], sz*sizeof(gf) ) ;
+ else if (index < code->n) {
+ p = &(code->enc_matrix[index*k] );
+ memset(fec, '\0', sz*sizeof(gf));
+ for (i = 0; i < k ; i++)
+ addmul(fec, src[i], p[i], sz ) ;
+ } else
+ fprintf(stderr, "Invalid index %d (max %d)\n",
+ index, code->n - 1 );
+}
+
+void fec_encode_linear(struct fec_parms *code, gf *src, gf *fec, int index, int sz)
+{
+ int i, k = code->k ;
+ gf *p ;
+
+ if (GF_BITS > 8)
+ sz /= 2 ;
+
+ if (index < k)
+ memcpy(fec, src + (index * sz), sz*sizeof(gf) ) ;
+ else if (index < code->n) {
+ p = &(code->enc_matrix[index*k] );
+ memset(fec, '\0', sz*sizeof(gf));
+ for (i = 0; i < k ; i++)
+ addmul(fec, src + (i * sz), p[i], sz ) ;
+ } else
+ fprintf(stderr, "Invalid index %d (max %d)\n",
+ index, code->n - 1 );
+}
+/*
+ * shuffle move src packets in their position
+ */
+static int
+shuffle(gf *pkt[], int index[], int k)
+{
+ int i;
+
+ for ( i = 0 ; i < k ; ) {
+ if (index[i] >= k || index[i] == i)
+ i++ ;
+ else {
+ /*
+ * put pkt in the right position (first check for conflicts).
+ */
+ int c = index[i] ;
+
+ if (index[c] == c) {
+ DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);)
+ return 1 ;
+ }
+ SWAP(index[i], index[c], int) ;
+ SWAP(pkt[i], pkt[c], gf *) ;
+ }
+ }
+ DEB( /* just test that it works... */
+ for ( i = 0 ; i < k ; i++ ) {
+ if (index[i] < k && index[i] != i) {
+ fprintf(stderr, "shuffle: after\n");
+ for (i=0; i<k ; i++) fprintf(stderr, "%3d ", index[i]);
+ fprintf(stderr, "\n");
+ return 1 ;
+ }
+ }
+ )
+ return 0 ;
+}
+
+/*
+ * build_decode_matrix constructs the encoding matrix given the
+ * indexes. The matrix must be already allocated as
+ * a vector of k*k elements, in row-major order
+ */
+static gf *
+build_decode_matrix(struct fec_parms *code, gf *pkt[], int index[])
+{
+ int i , k = code->k ;
+ gf *p, *matrix = NEW_GF_MATRIX(k, k);
+
+ TICK(ticks[9]);
+ for (i = 0, p = matrix ; i < k ; i++, p += k ) {
+#if 1 /* this is simply an optimization, not very useful indeed */
+ if (index[i] < k) {
+ memset(p, '\0', k*sizeof(gf) );
+ p[i] = 1 ;
+ } else
+#endif
+ if (index[i] < code->n )
+ memcpy(p, &(code->enc_matrix[index[i]*k]), k*sizeof(gf) );
+ else {
+ fprintf(stderr, "decode: invalid index %d (max %d)\n",
+ index[i], code->n - 1 );
+ free(matrix) ;
+ return NULL ;
+ }
+ }
+ TICK(ticks[9]);
+ if (invert_mat(matrix, k)) {
+ free(matrix);
+ matrix = NULL ;
+ }
+ TOCK(ticks[9]);
+ return matrix ;
+}
+
+/*
+ * fec_decode receives as input a vector of packets, the indexes of
+ * packets, and produces the correct vector as output.
+ *
+ * Input:
+ * code: pointer to code descriptor
+ * pkt: pointers to received packets. They are modified
+ * to store the output packets (in place)
+ * index: pointer to packet indexes (modified)
+ * sz: size of each packet
+ */
+int
+fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz)
+{
+ gf *m_dec ;
+ gf **new_pkt ;
+ int row, col , k = code->k ;
+
+ if (GF_BITS > 8)
+ sz /= 2 ;
+
+ if (shuffle(pkt, index, k)) /* error if true */
+ return 1 ;
+ m_dec = build_decode_matrix(code, pkt, index);
+
+ if (m_dec == NULL)
+ return 1 ; /* error */
+ /*
+ * do the actual decoding
+ */
+ new_pkt = my_malloc (k * sizeof (gf * ), "new pkt pointers" );
+ for (row = 0 ; row < k ; row++ ) {
+ if (index[row] >= k) {
+ new_pkt[row] = my_malloc (sz * sizeof (gf), "new pkt buffer" );
+ memset(new_pkt[row], '\0', sz * sizeof(gf) ) ;
+ for (col = 0 ; col < k ; col++ )
+ addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz) ;
+ }
+ }
+ /*
+ * move pkts to their final destination
+ */
+ for (row = 0 ; row < k ; row++ ) {
+ if (index[row] >= k) {
+ memcpy(pkt[row], new_pkt[row], sz*sizeof(gf));
+ free(new_pkt[row]);
+ }
+ }
+ free(new_pkt);
+ free(m_dec);
+
+ return 0;
+}
+
+/*********** end of FEC code -- beginning of test code ************/
+
+#if (TEST || DEBUG)
+void
+test_gf()
+{
+ int i ;
+ /*
+ * test gf tables. Sufficiently tested...
+ */
+ for (i=0; i<= GF_SIZE; i++) {
+ if (gf_exp[gf_log[i]] != i)
+ fprintf(stderr, "bad exp/log i %d log %d exp(log) %d\n",
+ i, gf_log[i], gf_exp[gf_log[i]]);
+
+ if (i != 0 && gf_mul(i, inverse[i]) != 1)
+ fprintf(stderr, "bad mul/inv i %d inv %d i*inv(i) %d\n",
+ i, inverse[i], gf_mul(i, inverse[i]) );
+ if (gf_mul(0,i) != 0)
+ fprintf(stderr, "bad mul table 0,%d\n",i);
+ if (gf_mul(i,0) != 0)
+ fprintf(stderr, "bad mul table %d,0\n",i);
+ }
+}
+#endif /* TEST */
diff --git a/mtd-utils-1.3.1/fectest.c b/mtd-utils-1.3.1/fectest.c
new file mode 100644
index 0000000..d5893b9
--- /dev/null
+++ b/mtd-utils-1.3.1/fectest.c
@@ -0,0 +1,92 @@
+#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 PKT_SIZE 1400
+#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/mtd-utils-1.3.1/flash_erase.c b/mtd-utils-1.3.1/flash_erase.c
new file mode 100644
index 0000000..fdf9918
--- /dev/null
+++ b/mtd-utils-1.3.1/flash_erase.c
@@ -0,0 +1,189 @@
+/*
+ * flash_erase.c -- erase parts of a MTD device
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <mtd/mtd-user.h>
+
+int region_erase(int Fd, int start, int count, int unlock, int regcount)
+{
+ int i, j;
+ region_info_t * reginfo;
+
+ reginfo = calloc(regcount, sizeof(region_info_t));
+
+ for(i = 0; i < regcount; i++)
+ {
+ reginfo[i].regionindex = i;
+ if(ioctl(Fd,MEMGETREGIONINFO,&(reginfo[i])) != 0)
+ return 8;
+ else
+ printf("Region %d is at %d of %d sector and with sector "
+ "size %x\n", i, reginfo[i].offset, reginfo[i].numblocks,
+ reginfo[i].erasesize);
+ }
+
+ // We have all the information about the chip we need.
+
+ for(i = 0; i < regcount; i++)
+ { //Loop through the regions
+ region_info_t * r = &(reginfo[i]);
+
+ if((start >= reginfo[i].offset) &&
+ (start < (r->offset + r->numblocks*r->erasesize)))
+ break;
+ }
+
+ if(i >= regcount)
+ {
+ printf("Starting offset %x not within chip.\n", start);
+ return 8;
+ }
+
+ //We are now positioned within region i of the chip, so start erasing
+ //count sectors from there.
+
+ for(j = 0; (j < count)&&(i < regcount); j++)
+ {
+ erase_info_t erase;
+ region_info_t * r = &(reginfo[i]);
+
+ erase.start = start;
+ erase.length = r->erasesize;
+
+ if(unlock != 0)
+ { //Unlock the sector first.
+ if(ioctl(Fd, MEMUNLOCK, &erase) != 0)
+ {
+ perror("\nMTD Unlock failure");
+ close(Fd);
+ return 8;
+ }
+ }
+ printf("\rPerforming Flash Erase of length %u at offset 0x%x",
+ erase.length, erase.start);
+ fflush(stdout);
+ if(ioctl(Fd, MEMERASE, &erase) != 0)
+ {
+ perror("\nMTD Erase failure");
+ close(Fd);
+ return 8;
+ }
+
+
+ start += erase.length;
+ if(start >= (r->offset + r->numblocks*r->erasesize))
+ { //We finished region i so move to region i+1
+ printf("\nMoving to region %d\n", i+1);
+ i++;
+ }
+ }
+
+ printf(" done\n");
+
+ return 0;
+}
+
+int non_region_erase(int Fd, int start, int count, int unlock)
+{
+ mtd_info_t meminfo;
+
+ if (ioctl(Fd,MEMGETINFO,&meminfo) == 0)
+ {
+ erase_info_t erase;
+
+ erase.start = start;
+
+ erase.length = meminfo.erasesize;
+
+ for (; count > 0; count--) {
+ printf("\rPerforming Flash Erase of length %u at offset 0x%x",
+ erase.length, erase.start);
+ fflush(stdout);
+
+ if(unlock != 0)
+ {
+ //Unlock the sector first.
+ printf("\rPerforming Flash unlock at offset 0x%x",erase.start);
+ if(ioctl(Fd, MEMUNLOCK, &erase) != 0)
+ {
+ perror("\nMTD Unlock failure");
+ close(Fd);
+ return 8;
+ }
+ }
+
+ if (ioctl(Fd,MEMERASE,&erase) != 0)
+ {
+ perror("\nMTD Erase failure");
+ close(Fd);
+ return 8;
+ }
+ erase.start += meminfo.erasesize;
+ }
+ printf(" done\n");
+ }
+ return 0;
+}
+
+int main(int argc,char *argv[])
+{
+ int regcount;
+ int Fd;
+ int start;
+ int count;
+ int unlock;
+ int res = 0;
+
+ if (1 >= argc || !strcmp(argv[1], "-h") || !strcmp (argv[1], "--help") ) {
+ printf("Usage: flash_erase MTD-device [start] [cnt (# erase blocks)] [lock]\n"
+ " flash_erase -h | --help\n") ;
+ return 16 ;
+ }
+
+ if (argc > 2)
+ start = strtol(argv[2], NULL, 0);
+ else
+ start = 0;
+
+ if (argc > 3)
+ count = strtol(argv[3], NULL, 0);
+ else
+ count = 1;
+
+ if(argc > 4)
+ unlock = strtol(argv[4], NULL, 0);
+ else
+ unlock = 0;
+
+
+ // Open and size the device
+ if ((Fd = open(argv[1],O_RDWR)) < 0)
+ {
+ fprintf(stderr,"File open error\n");
+ return 8;
+ }
+
+ printf("Erase Total %d Units\n", count);
+
+ if (ioctl(Fd,MEMGETREGIONCOUNT,®count) == 0)
+ {
+ if(regcount == 0)
+ {
+ res = non_region_erase(Fd, start, count, unlock);
+ }
+ else
+ {
+ res = region_erase(Fd, start, count, unlock, regcount);
+ }
+ }
+
+ return res;
+}
diff --git a/mtd-utils-1.3.1/flash_eraseall.c b/mtd-utils-1.3.1/flash_eraseall.c
new file mode 100644
index 0000000..a22fc49
--- /dev/null
+++ b/mtd-utils-1.3.1/flash_eraseall.c
@@ -0,0 +1,289 @@
+/* eraseall.c -- erase the whole of a MTD device
+
+ Copyright (C) 2000 Arcom Control System Ltd
+
+ Renamed to flash_eraseall.c
+
+ 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
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.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>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include "crc32.h"
+
+#include <mtd/mtd-user.h>
+#include <mtd/jffs2-user.h>
+
+#define PROGRAM "flash_eraseall"
+#define VERSION "$Revision: 1.22 $"
+
+static const char *exe_name;
+static const char *mtd_device;
+static int quiet; /* true -- don't output progress */
+static int jffs2; // format for jffs2 usage
+
+static void process_options (int argc, char *argv[]);
+void show_progress (mtd_info_t *meminfo, erase_info_t *erase);
+static void display_help (void);
+static void display_version (void);
+static struct jffs2_unknown_node cleanmarker;
+int target_endian = __BYTE_ORDER;
+
+int main (int argc, char *argv[])
+{
+ mtd_info_t meminfo;
+ int fd, clmpos = 0, clmlen = 8;
+ erase_info_t erase;
+ int isNAND, bbtest = 1;
+
+ process_options(argc, argv);
+
+ if ((fd = open(mtd_device, O_RDWR)) < 0) {
+ fprintf(stderr, "%s: %s: %s\n", exe_name, mtd_device, strerror(errno));
+ return 1;
+ }
+
+
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ fprintf(stderr, "%s: %s: unable to get MTD device info\n", exe_name, mtd_device);
+ return 1;
+ }
+
+ erase.length = meminfo.erasesize;
+ isNAND = meminfo.type == MTD_NANDFLASH ? 1 : 0;
+
+ 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 (struct jffs2_unknown_node));
+ else {
+ struct nand_oobinfo oobinfo;
+
+ if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0) {
+ fprintf(stderr, "%s: %s: unable to get NAND oobinfo\n", exe_name, mtd_device);
+ return 1;
+ }
+
+ /* Check for autoplacement */
+ if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
+ /* Get the position of the free bytes */
+ if (!oobinfo.oobfree[0][1]) {
+ fprintf (stderr, " Eeep. Autoplacement selected and no empty space in oob\n");
+ return 1;
+ }
+ clmpos = oobinfo.oobfree[0][0];
+ clmlen = oobinfo.oobfree[0][1];
+ if (clmlen > 8)
+ clmlen = 8;
+ } else {
+ /* Legacy mode */
+ switch (meminfo.oobsize) {
+ 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 (crc32 (0, &cleanmarker, sizeof (struct jffs2_unknown_node) - 4));
+ }
+
+ for (erase.start = 0; erase.start < meminfo.size; erase.start += meminfo.erasesize) {
+ if (bbtest) {
+ loff_t offset = erase.start;
+ int ret = ioctl(fd, MEMGETBADBLOCK, &offset);
+ if (ret > 0) {
+ if (!quiet)
+ printf ("\nSkipping bad block at 0x%08x\n", erase.start);
+ continue;
+ } else if (ret < 0) {
+ if (errno == EOPNOTSUPP) {
+ bbtest = 0;
+ if (isNAND) {
+ fprintf(stderr, "%s: %s: Bad block check not available\n", exe_name, mtd_device);
+ return 1;
+ }
+ } else {
+ fprintf(stderr, "\n%s: %s: MTD get bad block failed: %s\n", exe_name, mtd_device, strerror(errno));
+ return 1;
+ }
+ }
+ }
+
+ if (!quiet)
+ show_progress(&meminfo, &erase);
+
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ fprintf(stderr, "\n%s: %s: MTD Erase failure: %s\n", exe_name, mtd_device, strerror(errno));
+ continue;
+ }
+
+ /* format for JFFS2 ? */
+ if (!jffs2)
+ continue;
+
+ /* write cleanmarker */
+ if (isNAND) {
+ struct mtd_oob_buf oob;
+ oob.ptr = (unsigned char *) &cleanmarker;
+ oob.start = erase.start + clmpos;
+ oob.length = clmlen;
+ if (ioctl (fd, MEMWRITEOOB, &oob) != 0) {
+ fprintf(stderr, "\n%s: %s: MTD writeoob failure: %s\n", exe_name, mtd_device, strerror(errno));
+ continue;
+ }
+ } else {
+ if (lseek (fd, erase.start, SEEK_SET) < 0) {
+ fprintf(stderr, "\n%s: %s: MTD lseek failure: %s\n", exe_name, mtd_device, strerror(errno));
+ continue;
+ }
+ if (write (fd , &cleanmarker, sizeof (cleanmarker)) != sizeof (cleanmarker)) {
+ fprintf(stderr, "\n%s: %s: MTD write failure: %s\n", exe_name, mtd_device, strerror(errno));
+ continue;
+ }
+ }
+ if (!quiet)
+ printf (" Cleanmarker written at %x.", erase.start);
+ }
+ if (!quiet) {
+ show_progress(&meminfo, &erase);
+ printf("\n");
+ }
+
+ return 0;
+}
+
+
+void process_options (int argc, char *argv[])
+{
+ int error = 0;
+
+ exe_name = argv[0];
+
+ for (;;) {
+ int option_index = 0;
+ static const char *short_options = "jq";
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 0},
+ {"version", no_argument, 0, 0},
+ {"jffs2", no_argument, 0, 'j'},
+ {"quiet", no_argument, 0, 'q'},
+ {"silent", 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_help();
+ break;
+ case 1:
+ display_version();
+ break;
+ }
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'j':
+ jffs2 = 1;
+ break;
+ case '?':
+ error = 1;
+ break;
+ }
+ }
+ if (optind == argc) {
+ fprintf(stderr, "%s: no MTD device specified\n", exe_name);
+ error = 1;
+ }
+ if (error) {
+ fprintf(stderr, "Try `%s --help' for more information.\n",
+ exe_name);
+ exit(1);
+ }
+
+ mtd_device = argv[optind];
+}
+
+void show_progress (mtd_info_t *meminfo, erase_info_t *erase)
+{
+ printf("\rErasing %d Kibyte @ %x -- %2llu %% complete.",
+ meminfo->erasesize / 1024, erase->start,
+ (unsigned long long) erase->start * 100 / meminfo->size);
+ fflush(stdout);
+}
+
+void display_help (void)
+{
+ printf("Usage: %s [OPTION] MTD_DEVICE\n"
+ "Erases all of the specified MTD device.\n"
+ "\n"
+ " -j, --jffs2 format the device for jffs2\n"
+ " -q, --quiet don't display progress messages\n"
+ " --silent same as --quiet\n"
+ " --help display this help and exit\n"
+ " --version output version information and exit\n",
+ exe_name);
+ exit(0);
+}
+
+
+void display_version (void)
+{
+ printf(PROGRAM " " VERSION "\n"
+ "\n"
+ "Copyright (C) 2000 Arcom Control Systems Ltd\n"
+ "\n"
+ PROGRAM " comes with NO WARRANTY\n"
+ "to the extent permitted by law.\n"
+ "\n"
+ "You may redistribute copies of " PROGRAM "\n"
+ "under the terms of the GNU General Public Licence.\n"
+ "See the file `COPYING' for more information.\n");
+ exit(0);
+}
diff --git a/mtd-utils-1.3.1/flash_info.c b/mtd-utils-1.3.1/flash_info.c
new file mode 100644
index 0000000..f5ed1c6
--- /dev/null
+++ b/mtd-utils-1.3.1/flash_info.c
@@ -0,0 +1,55 @@
+/*
+ * flash_info.c -- print info about a MTD device
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc,char *argv[])
+{
+ int regcount;
+ int Fd;
+
+ if (1 >= argc)
+ {
+ fprintf(stderr,"Usage: flash_info device\n");
+ return 16;
+ }
+
+ // Open and size the device
+ if ((Fd = open(argv[1],O_RDONLY)) < 0)
+ {
+ fprintf(stderr,"File open error\n");
+ return 8;
+ }
+
+ if (ioctl(Fd,MEMGETREGIONCOUNT,®count) == 0)
+ {
+ int i;
+ region_info_t reginfo;
+ printf("Device %s has %d erase regions\n", argv[1], regcount);
+ for (i = 0; i < regcount; i++)
+ {
+ reginfo.regionindex = i;
+ if(ioctl(Fd, MEMGETREGIONINFO, ®info) == 0)
+ {
+ printf("Region %d is at 0x%x with size 0x%x and "
+ "has 0x%x blocks\n", i, reginfo.offset,
+ reginfo.erasesize, reginfo.numblocks);
+ }
+ else
+ {
+ printf("Strange can not read region %d from a %d region device\n",
+ i, regcount);
+ }
+ }
+ }
+ return 0;
+}
diff --git a/mtd-utils-1.3.1/flash_lock.c b/mtd-utils-1.3.1/flash_lock.c
new file mode 100644
index 0000000..37f2ad3
--- /dev/null
+++ b/mtd-utils-1.3.1/flash_lock.c
@@ -0,0 +1,83 @@
+/*
+ * FILE flash_lock.c
+ *
+ * This utility locks one or more sectors of flash device.
+ *
+ */
+
+#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 <mtd/mtd-user.h>
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ struct mtd_info_user mtdInfo;
+ struct erase_info_user mtdLockInfo;
+ int num_sectors;
+ int ofs;
+
+ /*
+ * Parse command line options
+ */
+ if(argc != 4)
+ {
+ fprintf(stderr, "USAGE: %s <mtd device> <ofs in hex> <num of sectors in decimal or -1 for all sectors>\n", argv[0]);
+ exit(1);
+ }
+ else if(strncmp(argv[1], "/dev/mtd", 8) != 0)
+ {
+ fprintf(stderr, "'%s' is not a MTD device. Must specify mtd device: /dev/mtd?\n", argv[1]);
+ exit(1);
+ }
+
+ fd = open(argv[1], O_RDWR);
+ if(fd < 0)
+ {
+ fprintf(stderr, "Could not open mtd device: %s\n", argv[1]);
+ exit(1);
+ }
+
+ if(ioctl(fd, MEMGETINFO, &mtdInfo))
+ {
+ fprintf(stderr, "Could not get MTD device info from %s\n", argv[1]);
+ close(fd);
+ exit(1);
+ }
+ sscanf(argv[2], "%x",&ofs);
+ sscanf(argv[3], "%d",&num_sectors);
+ if(ofs > mtdInfo.size - mtdInfo.erasesize)
+ {
+ fprintf(stderr, "%x is beyond device size %x\n",ofs,(unsigned int)(mtdInfo.size - mtdInfo.erasesize));
+ exit(1);
+ }
+
+ if (num_sectors == -1) {
+ num_sectors = mtdInfo.size/mtdInfo.erasesize;
+ }
+ else {
+ if(num_sectors > mtdInfo.size/mtdInfo.erasesize)
+ {
+ fprintf(stderr, "%d are too many sectors, device only has %d\n",num_sectors,(int)(mtdInfo.size/mtdInfo.erasesize));
+ exit(1);
+ }
+ }
+
+ mtdLockInfo.start = ofs;
+ mtdLockInfo.length = (num_sectors - 1) * mtdInfo.erasesize;
+ if(ioctl(fd, MEMLOCK, &mtdLockInfo))
+ {
+ fprintf(stderr, "Could not lock MTD device: %s\n", argv[1]);
+ close(fd);
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/mtd-utils-1.3.1/flash_otp_dump.c b/mtd-utils-1.3.1/flash_otp_dump.c
new file mode 100644
index 0000000..a18130d
--- /dev/null
+++ b/mtd-utils-1.3.1/flash_otp_dump.c
@@ -0,0 +1,54 @@
+/*
+ * flash_otp_dump.c -- display One-Time-Programm data
+ */
+
+#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", argv[0]);
+ 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/mtd-utils-1.3.1/flash_otp_info.c b/mtd-utils-1.3.1/flash_otp_info.c
new file mode 100644
index 0000000..c9486ee
--- /dev/null
+++ b/mtd-utils-1.3.1/flash_otp_info.c
@@ -0,0 +1,63 @@
+/*
+ * flash_otp_info.c -- print info about One-Time-Programm data
+ */
+
+#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", argv[0]);
+ 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/mtd-utils-1.3.1/flash_otp_lock.c b/mtd-utils-1.3.1/flash_otp_lock.c
new file mode 100644
index 0000000..d0e06cd
--- /dev/null
+++ b/mtd-utils-1.3.1/flash_otp_lock.c
@@ -0,0 +1,70 @@
+/*
+ * flash_otp_lock.c -- lock area of One-Time-Program data
+ */
+
+#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>
+
+int main(int argc,char *argv[])
+{
+ int fd, val, ret, offset, size;
+ char *p, buf[8];
+
+ if (argc != 5 || strcmp(argv[1], "-u")) {
+ fprintf(stderr, "Usage: %s -u <device> <offset> <size>\n", argv[0]);
+ 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", argv[0]);
+ return ERANGE;
+ }
+
+ size = strtoul(argv[4], &p, 0);
+ if (argv[4][0] == 0 || *p != 0) {
+ fprintf(stderr, "%s: bad size value\n", argv[0]);
+ return ERANGE;
+ }
+
+ printf("About to lock OTP user data on %s from 0x%x to 0x%x\n",
+ argv[2], offset, offset + size);
+ printf("Are you sure (yes|no)? ");
+ if (fgets(buf, sizeof(buf), stdin) && strcmp(buf, "yes\n") == 0) {
+ 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/mtd-utils-1.3.1/flash_otp_write.c b/mtd-utils-1.3.1/flash_otp_write.c
new file mode 100644
index 0000000..f01df51
--- /dev/null
+++ b/mtd-utils-1.3.1/flash_otp_write.c
@@ -0,0 +1,96 @@
+/*
+ * flash_otp_write.c -- write One-Time-Program data
+ */
+
+#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 <mtd/mtd-user.h>
+
+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", argv[0]);
+ 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 = strtoul(argv[3], &p, 0);
+ if (argv[3][0] == 0 || *p != 0) {
+ fprintf(stderr, "%s: bad offset value\n", argv[0]);
+ 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%lx\n", argv[2], offset);
+
+ if (mtdInfo.type == MTD_NANDFLASH)
+ len = mtdInfo.writesize;
+ else
+ len = 256;
+
+ wrote = 0;
+ while ((size = read(0, buf, len))) {
+ if (size < 0) {
+ perror("read()");
+ return errno;
+ }
+ p = buf;
+ while (size > 0) {
+ if (mtdInfo.type == MTD_NANDFLASH) {
+ /* 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/mtd-utils-1.3.1/flash_unlock.c b/mtd-utils-1.3.1/flash_unlock.c
new file mode 100644
index 0000000..3969453
--- /dev/null
+++ b/mtd-utils-1.3.1/flash_unlock.c
@@ -0,0 +1,74 @@
+/*
+ * FILE flash_unlock.c
+ *
+ * This utility unlock all sectors of flash device.
+ *
+ */
+
+#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 <mtd/mtd-user.h>
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ struct mtd_info_user mtdInfo;
+ struct erase_info_user mtdLockInfo;
+ int count;
+
+ /*
+ * Parse command line options
+ */
+ if(argc < 2)
+ {
+ fprintf(stderr, "USAGE: %s <mtd device> <offset in hex> <block count in decimal number>\n", argv[0]);
+ exit(1);
+ }
+ else if(strncmp(argv[1], "/dev/mtd", 8) != 0)
+ {
+ fprintf(stderr, "'%s' is not a MTD device. Must specify mtd device: /dev/mtd?\n", argv[1]);
+ exit(1);
+ }
+
+ fd = open(argv[1], O_RDWR);
+ if(fd < 0)
+ {
+ fprintf(stderr, "Could not open mtd device: %s\n", argv[1]);
+ exit(1);
+ }
+
+ if(ioctl(fd, MEMGETINFO, &mtdInfo))
+ {
+ fprintf(stderr, "Could not get MTD device info from %s\n", argv[1]);
+ close(fd);
+ exit(1);
+ }
+
+ if (argc > 2)
+ mtdLockInfo.start = strtol(argv[2], NULL, 0);
+ else
+ mtdLockInfo.start = 0;
+
+ if (argc > 3) {
+ count = strtol(argv[3], NULL, 0);
+ mtdLockInfo.length = mtdInfo.erasesize * count;
+ } else {
+ mtdLockInfo.length = mtdInfo.size - mtdInfo.erasesize;
+ }
+
+ if(ioctl(fd, MEMUNLOCK, &mtdLockInfo))
+ {
+ fprintf(stderr, "Could not unlock MTD device: %s\n", argv[1]);
+ close(fd);
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/mtd-utils-1.3.1/flashcp.c b/mtd-utils-1.3.1/flashcp.c
new file mode 100644
index 0000000..8775022
--- /dev/null
+++ b/mtd-utils-1.3.1/flashcp.c
@@ -0,0 +1,390 @@
+/*
+ * 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.
+ */
+
+#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 (const char *progname,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: %s [ -v | --verbose ] <filename> <device>\n"
+ " %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",
+ progname,progname);
+
+ 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 *progname,*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];
+
+ (progname = strrchr (argv[0],'/')) ? progname++ : (progname = argv[0]);
+
+ /*********************
+ * 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 (progname,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 || progname == NULL || device == NULL)
+ showusage (progname,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/mtd-utils-1.3.1/ftl_check.c b/mtd-utils-1.3.1/ftl_check.c
new file mode 100644
index 0000000..f41e79a
--- /dev/null
+++ b/mtd-utils-1.3.1/ftl_check.c
@@ -0,0 +1,232 @@
+/* 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.
+
+ ======================================================================*/
+
+#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 <byteswap.h>
+#include <endian.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define TO_LE32(x) (x)
+# define TO_LE16(x) (x)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+# define TO_LE32(x) (bswap_32(x))
+# define TO_LE16(x) (bswap_16(x))
+#else
+# error cannot detect endianess
+#endif
+
+#define FROM_LE32(x) TO_LE32(x)
+#define FROM_LE16(x) TO_LE16(x)
+
+/*====================================================================*/
+
+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, int verbose)
+{
+ mtd_info_t mtd;
+ erase_unit_header_t hdr, hdr2;
+ u_int i, 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 ((FROM_LE32(hdr.FormattedSize) > 0) &&
+ (FROM_LE32(hdr.FormattedSize) <= mtd.size) &&
+ (FROM_LE16(hdr.NumEraseUnits) > 0) &&
+ (FROM_LE16(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(FROM_LE32(hdr.FormattedSize));
+ printf(", erase units = %d, transfer units = %d\n",
+ FROM_LE16(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 < FROM_LE16(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 %d:\n", i);
+ if ((hdr2.FormattedSize != hdr.FormattedSize) ||
+ (hdr2.NumEraseUnits != hdr.NumEraseUnits) ||
+ (hdr2.SerialNumber != hdr.SerialNumber))
+ printf(" Erase unit header is corrupt.\n");
+ else if (FROM_LE16(hdr2.LogicalEUN) == 0xffff)
+ printf(" Transfer unit, erase count = %d\n", FROM_LE32(hdr2.EraseCount));
+ else {
+ printf(" Logical unit %d, erase count = %d\n",
+ FROM_LE16(hdr2.LogicalEUN), FROM_LE32(hdr2.EraseCount));
+ if (lseek(fd, (i << hdr.EraseUnitSize)+FROM_LE32(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(FROM_LE32(bam[j])))
+ free++;
+ else if (BLOCK_DELETED(FROM_LE32(bam[j])))
+ deleted++;
+ else switch (BLOCK_TYPE(FROM_LE32(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(char *pname)
+{
+ fprintf(stderr, "usage: %s [-v] device\n", pname);
+ fprintf(stderr, "-v verbose messages\n");
+}
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+ int verbose;
+ int optch, errflg, fd;
+ struct stat buf;
+
+ errflg = 0;
+ verbose = 0;
+ while ((optch = getopt(argc, argv, "vh")) != -1) {
+ switch (optch) {
+ case 'h':
+ errflg = 1; break;
+ case 'v':
+ verbose = 1; break;
+ default:
+ errflg = -1; break;
+ }
+ }
+ if (errflg || (optind != argc-1)) {
+ showusage(argv[0]);
+ 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, verbose);
+ close(fd);
+
+ exit(EXIT_SUCCESS);
+ return 0;
+}
diff --git a/mtd-utils-1.3.1/ftl_format.c b/mtd-utils-1.3.1/ftl_format.c
new file mode 100644
index 0000000..ae00c99
--- /dev/null
+++ b/mtd-utils-1.3.1/ftl_format.c
@@ -0,0 +1,342 @@
+/* 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.
+
+ ======================================================================*/
+
+#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 <byteswap.h>
+#include <endian.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define TO_LE32(x) (x)
+# define TO_LE16(x) (x)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+# define TO_LE32(x) (bswap_32(x))
+# define TO_LE16(x) (bswap_16(x))
+#else
+# error cannot detect endianess
+#endif
+
+#define FROM_LE32(x) TO_LE32(x)
+#define FROM_LE16(x) TO_LE16(x)
+
+/*====================================================================*/
+
+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 = TO_LE32(0);
+ hdr->FirstPhysicalEUN = TO_LE16(BootUnits);
+ hdr->NumEraseUnits = 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 = TO_LE32(0x80);
+ /* Adjust size to account for BAM space */
+ nbam = ((1 << (hdr->EraseUnitSize - hdr->BlockSize)) * sizeof(u_int)
+ + FROM_LE32(hdr->BAMOffset) + (1 << hdr->BlockSize) - 1) >> hdr->BlockSize;
+
+ __FormattedSize -=
+ (FROM_LE16(hdr->NumEraseUnits) - Spare) * (nbam << hdr->BlockSize);
+ __FormattedSize -= ((__FormattedSize * Reserve / 100) & ~0xfff);
+
+ hdr->FormattedSize = TO_LE32(__FormattedSize);
+
+ /* hdr->FirstVMAddress defaults to erased state */
+ hdr->NumVMPages = TO_LE16(0);
+ hdr->Flags = 0;
+ /* hdr->Code defaults to erased state */
+ hdr->SerialNumber = 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(FROM_LE16(hdr.FirstPhysicalEUN) << hdr.EraseUnitSize);
+ printf(" allocated for boot image\n");
+ }
+ printf("Reserved %d%%, formatted size = ", reserve);
+ print_size(FROM_LE32(hdr.FormattedSize));
+ printf("\n");
+ fflush(stdout);
+ }
+
+ if (interrogate) {
+ char str[3];
+ printf("This will destroy all data on the target device. "
+ "Confirm (y/n): ");
+ if (fgets(str, 3, stdin) == NULL)
+ return -1;
+ if ((strcmp(str, "y\n") != 0) && (strcmp(str, "Y\n") != 0))
+ return -1;
+ }
+
+ /* Create basic block allocation table for control blocks */
+ nbam = ((mtd.erasesize >> hdr.BlockSize) * sizeof(u_int)
+ + FROM_LE32(hdr.BAMOffset) + (1 << hdr.BlockSize) - 1) >> hdr.BlockSize;
+ bam = malloc(nbam * sizeof(u_int));
+ for (i = 0; i < nbam; i++)
+ bam[i] = TO_LE32(BLOCK_CONTROL);
+
+ /* Erase partition */
+ if (!quiet) {
+ printf("Erasing all blocks...\n");
+ fflush(stdout);
+ }
+ erase.length = mtd.erasesize;
+ erase.start = mtd.erasesize * FROM_LE16(hdr.FirstPhysicalEUN);
+ for (i = 0; i < FROM_LE16(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) ? (FROM_LE16(hdr.NumEraseUnits)/spare) : (FROM_LE16(hdr.NumEraseUnits)+1);
+ for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) {
+ u_int ofs = (i + FROM_LE16(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 = TO_LE16(0xffff);
+ else {
+ hdr.LogicalEUN = TO_LE16(lun);
+ lun++;
+ }
+ if (write(fd, &hdr, sizeof(hdr)) == -1) {
+ perror("write failed");
+ break;
+ }
+ if (lseek(fd, ofs + FROM_LE32(hdr.BAMOffset), SEEK_SET) == -1) {
+ perror("seek failed");
+ break;
+ }
+ if (write(fd, bam, nbam * sizeof(u_int)) == -1) {
+ perror("write failed");
+ break;
+ }
+ }
+ if (i < FROM_LE16(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", argv[0]);
+ 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/mtd-utils-1.3.1/include/linux/jffs2.h b/mtd-utils-1.3.1/include/linux/jffs2.h
new file mode 100644
index 0000000..c2f684a
--- /dev/null
+++ b/mtd-utils-1.3.1/include/linux/jffs2.h
@@ -0,0 +1,218 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ *
+ * For licensing information, see the file 'LICENCE' in the
+ * jffs2 directory.
+ *
+ * $Id: jffs2.h,v 1.38 2005/09/26 11:37:23 havasi Exp $
+ *
+ */
+
+#ifndef __LINUX_JFFS2_H__
+#define __LINUX_JFFS2_H__
+
+/* You must include something which defines the C99 uintXX_t types.
+ We don't do it from here because this file is used in too many
+ different environments. */
+
+#define JFFS2_SUPER_MAGIC 0x72b6
+
+/* Values we may expect to find in the 'magic' field */
+#define JFFS2_OLD_MAGIC_BITMASK 0x1984
+#define JFFS2_MAGIC_BITMASK 0x1985
+#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
+#define JFFS2_EMPTY_BITMASK 0xffff
+#define JFFS2_DIRTY_BITMASK 0x0000
+
+/* Summary node MAGIC marker */
+#define JFFS2_SUM_MAGIC 0x02851885
+
+/* We only allow a single char for length, and 0xFF is empty flash so
+ we don't want it confused with a real length. Hence max 254.
+*/
+#define JFFS2_MAX_NAME_LEN 254
+
+/* How small can we sensibly write nodes? */
+#define JFFS2_MIN_DATA_LEN 128
+
+#define JFFS2_COMPR_NONE 0x00
+#define JFFS2_COMPR_ZERO 0x01
+#define JFFS2_COMPR_RTIME 0x02
+#define JFFS2_COMPR_RUBINMIPS 0x03
+#define JFFS2_COMPR_COPY 0x04
+#define JFFS2_COMPR_DYNRUBIN 0x05
+#define JFFS2_COMPR_ZLIB 0x06
+#define JFFS2_COMPR_LZO 0x07
+/* Compatibility flags. */
+#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
+#define JFFS2_NODE_ACCURATE 0x2000
+/* INCOMPAT: Fail to mount the filesystem */
+#define JFFS2_FEATURE_INCOMPAT 0xc000
+/* ROCOMPAT: Mount read-only */
+#define JFFS2_FEATURE_ROCOMPAT 0x8000
+/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
+#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
+/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
+#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
+
+#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
+#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
+#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
+#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
+
+#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
+
+#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
+#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
+
+/* XATTR Related */
+#define JFFS2_XPREFIX_USER 1 /* for "user." */
+#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */
+#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */
+#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */
+#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */
+
+#define JFFS2_ACL_VERSION 0x0001
+
+// Maybe later...
+//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
+//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
+
+
+#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at
+ mount time, don't wait for it to
+ happen later */
+#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific
+ compression type */
+
+
+/* These can go once we've made sure we've caught all uses without
+ byteswapping */
+
+typedef struct {
+ uint32_t v32;
+} __attribute__((packed)) jint32_t;
+
+typedef struct {
+ uint32_t m;
+} __attribute__((packed)) jmode_t;
+
+typedef struct {
+ uint16_t v16;
+} __attribute__((packed)) jint16_t;
+
+struct jffs2_unknown_node
+{
+ /* All start like this */
+ jint16_t magic;
+ jint16_t nodetype;
+ jint32_t totlen; /* So we can skip over nodes we don't grok */
+ jint32_t hdr_crc;
+} __attribute__((packed));
+
+struct jffs2_raw_dirent
+{
+ jint16_t magic;
+ jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t pino;
+ jint32_t version;
+ jint32_t ino; /* == zero for unlink */
+ jint32_t mctime;
+ uint8_t nsize;
+ uint8_t type;
+ uint8_t unused[2];
+ jint32_t node_crc;
+ jint32_t name_crc;
+ uint8_t name[0];
+} __attribute__((packed));
+
+/* The JFFS2 raw inode structure: Used for storage on physical media. */
+/* The uid, gid, atime, mtime and ctime members could be longer, but
+ are left like this for space efficiency. If and when people decide
+ they really need them extended, it's simple enough to add support for
+ a new type of raw node.
+*/
+struct jffs2_raw_inode
+{
+ jint16_t magic; /* A constant magic number. */
+ jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */
+ jint32_t totlen; /* Total length of this node (inc data, etc.) */
+ jint32_t hdr_crc;
+ jint32_t ino; /* Inode number. */
+ jint32_t version; /* Version number. */
+ jmode_t mode; /* The file's type or mode. */
+ jint16_t uid; /* The file's owner. */
+ jint16_t gid; /* The file's group. */
+ jint32_t isize; /* Total resultant size of this inode (used for truncations) */
+ jint32_t atime; /* Last access time. */
+ jint32_t mtime; /* Last modification time. */
+ jint32_t ctime; /* Change time. */
+ jint32_t offset; /* Where to begin to write. */
+ jint32_t csize; /* (Compressed) data size */
+ jint32_t dsize; /* Size of the node's data. (after decompression) */
+ uint8_t compr; /* Compression algorithm used */
+ uint8_t usercompr; /* Compression algorithm requested by the user */
+ jint16_t flags; /* See JFFS2_INO_FLAG_* */
+ jint32_t data_crc; /* CRC for the (compressed) data. */
+ jint32_t node_crc; /* CRC for the raw inode (excluding data) */
+ uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xattr {
+ jint16_t magic;
+ jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t xid; /* XATTR identifier number */
+ jint32_t version;
+ uint8_t xprefix;
+ uint8_t name_len;
+ jint16_t value_len;
+ jint32_t data_crc;
+ jint32_t node_crc;
+ uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xref
+{
+ jint16_t magic;
+ jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t ino; /* inode number */
+ jint32_t xid; /* XATTR identifier number */
+ jint32_t xseqno; /* xref sequencial number */
+ jint32_t node_crc;
+} __attribute__((packed));
+
+struct jffs2_raw_summary
+{
+ jint16_t magic;
+ jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t sum_num; /* number of sum entries*/
+ jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */
+ jint32_t padded; /* sum of the size of padding nodes */
+ jint32_t sum_crc; /* summary information crc */
+ jint32_t node_crc; /* node crc */
+ jint32_t sum[0]; /* inode summary info */
+} __attribute__((packed));
+
+union jffs2_node_union
+{
+ struct jffs2_raw_inode i;
+ struct jffs2_raw_dirent d;
+ struct jffs2_raw_xattr x;
+ struct jffs2_raw_xref r;
+ struct jffs2_raw_summary s;
+ struct jffs2_unknown_node u;
+};
+
+#endif /* __LINUX_JFFS2_H__ */
diff --git a/mtd-utils-1.3.1/include/mtd/ftl-user.h b/mtd-utils-1.3.1/include/mtd/ftl-user.h
new file mode 100644
index 0000000..53e94c2
--- /dev/null
+++ b/mtd-utils-1.3.1/include/mtd/ftl-user.h
@@ -0,0 +1,76 @@
+/*
+ * $Id: ftl.h,v 1.7 2005/11/07 11:14:54 gleixner Exp $
+ *
+ * Derived from (and probably identical to):
+ * ftl.h 1.7 1999/10/25 20:23:17
+ *
+ * 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
+ * <dahinds@users.sourceforge.net>. 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 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 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.
+ */
+
+#ifndef __MTD_FTL_USER_H__
+#define __MTD_FTL_USER_H__
+
+typedef struct erase_unit_header_t {
+ u_int8_t LinkTargetTuple[5];
+ u_int8_t DataOrgTuple[10];
+ u_int8_t NumTransferUnits;
+ u_int32_t EraseCount;
+ u_int16_t LogicalEUN;
+ u_int8_t BlockSize;
+ u_int8_t EraseUnitSize;
+ u_int16_t FirstPhysicalEUN;
+ u_int16_t NumEraseUnits;
+ u_int32_t FormattedSize;
+ u_int32_t FirstVMAddress;
+ u_int16_t NumVMPages;
+ u_int8_t Flags;
+ u_int8_t Code;
+ u_int32_t SerialNumber;
+ u_int32_t AltEUHOffset;
+ u_int32_t BAMOffset;
+ u_int8_t Reserved[12];
+ u_int8_t EndTuple[2];
+} erase_unit_header_t;
+
+/* Flags in erase_unit_header_t */
+#define HIDDEN_AREA 0x01
+#define REVERSE_POLARITY 0x02
+#define DOUBLE_BAI 0x04
+
+/* Definitions for block allocation information */
+
+#define BLOCK_FREE(b) ((b) == 0xffffffff)
+#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe))
+
+#define BLOCK_TYPE(b) ((b) & 0x7f)
+#define BLOCK_ADDRESS(b) ((b) & ~0x7f)
+#define BLOCK_NUMBER(b) ((b) >> 9)
+#define BLOCK_CONTROL 0x30
+#define BLOCK_DATA 0x40
+#define BLOCK_REPLACEMENT 0x60
+#define BLOCK_BAD 0x70
+
+#endif /* __MTD_FTL_USER_H__ */
diff --git a/mtd-utils-1.3.1/include/mtd/inftl-user.h b/mtd-utils-1.3.1/include/mtd/inftl-user.h
new file mode 100644
index 0000000..9b1e252
--- /dev/null
+++ b/mtd-utils-1.3.1/include/mtd/inftl-user.h
@@ -0,0 +1,91 @@
+/*
+ * $Id: inftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
+ *
+ * Parts of INFTL headers shared with userspace
+ *
+ */
+
+#ifndef __MTD_INFTL_USER_H__
+#define __MTD_INFTL_USER_H__
+
+#define OSAK_VERSION 0x5120
+#define PERCENTUSED 98
+
+#define SECTORSIZE 512
+
+/* Block Control Information */
+
+struct inftl_bci {
+ uint8_t ECCsig[6];
+ uint8_t Status;
+ uint8_t Status1;
+} __attribute__((packed));
+
+struct inftl_unithead1 {
+ uint16_t virtualUnitNo;
+ uint16_t prevUnitNo;
+ uint8_t ANAC;
+ uint8_t NACs;
+ uint8_t parityPerField;
+ uint8_t discarded;
+} __attribute__((packed));
+
+struct inftl_unithead2 {
+ uint8_t parityPerField;
+ uint8_t ANAC;
+ uint16_t prevUnitNo;
+ uint16_t virtualUnitNo;
+ uint8_t NACs;
+ uint8_t discarded;
+} __attribute__((packed));
+
+struct inftl_unittail {
+ uint8_t Reserved[4];
+ uint16_t EraseMark;
+ uint16_t EraseMark1;
+} __attribute__((packed));
+
+union inftl_uci {
+ struct inftl_unithead1 a;
+ struct inftl_unithead2 b;
+ struct inftl_unittail c;
+};
+
+struct inftl_oob {
+ struct inftl_bci b;
+ union inftl_uci u;
+};
+
+
+/* INFTL Media Header */
+
+struct INFTLPartition {
+ __u32 virtualUnits;
+ __u32 firstUnit;
+ __u32 lastUnit;
+ __u32 flags;
+ __u32 spareUnits;
+ __u32 Reserved0;
+ __u32 Reserved1;
+} __attribute__((packed));
+
+struct INFTLMediaHeader {
+ char bootRecordID[8];
+ __u32 NoOfBootImageBlocks;
+ __u32 NoOfBinaryPartitions;
+ __u32 NoOfBDTLPartitions;
+ __u32 BlockMultiplierBits;
+ __u32 FormatFlags;
+ __u32 OsakVersion;
+ __u32 PercentUsed;
+ struct INFTLPartition Partitions[4];
+} __attribute__((packed));
+
+/* Partition flag types */
+#define INFTL_BINARY 0x20000000
+#define INFTL_BDTL 0x40000000
+#define INFTL_LAST 0x80000000
+
+#endif /* __MTD_INFTL_USER_H__ */
+
+
diff --git a/mtd-utils-1.3.1/include/mtd/jffs2-user.h b/mtd-utils-1.3.1/include/mtd/jffs2-user.h
new file mode 100644
index 0000000..bc5d99a
--- /dev/null
+++ b/mtd-utils-1.3.1/include/mtd/jffs2-user.h
@@ -0,0 +1,82 @@
+/*
+ * $Id: jffs2-user.h,v 1.1 2004/05/05 11:57:54 dwmw2 Exp $
+ *
+ * JFFS2 definitions for use in user space only
+ */
+
+#ifndef __JFFS2_USER_H__
+#define __JFFS2_USER_H__
+
+/* This file is blessed for inclusion by userspace */
+#include <linux/jffs2.h>
+#include <endian.h>
+#include <byteswap.h>
+
+#undef cpu_to_je16
+#undef cpu_to_je32
+#undef cpu_to_jemode
+#undef je16_to_cpu
+#undef je32_to_cpu
+#undef jemode_to_cpu
+
+extern int target_endian;
+
+#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
+#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
+
+#define cpu_to_je16(x) ((jint16_t){t16(x)})
+#define cpu_to_je32(x) ((jint32_t){t32(x)})
+#define cpu_to_jemode(x) ((jmode_t){t32(x)})
+
+#define je16_to_cpu(x) (t16((x).v16))
+#define je32_to_cpu(x) (t32((x).v32))
+#define jemode_to_cpu(x) (t32((x).m))
+
+#define le16_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
+#define le32_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
+#define cpu_to_le16(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
+#define cpu_to_le32(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
+
+/* XATTR/POSIX-ACL related definition */
+/* Namespaces copied from xattr.h and posix_acl_xattr.h */
+#define XATTR_USER_PREFIX "user."
+#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
+#define XATTR_SECURITY_PREFIX "security."
+#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1)
+#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access"
+#define POSIX_ACL_XATTR_ACCESS_LEN (sizeof (POSIX_ACL_XATTR_ACCESS) - 1)
+#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default"
+#define POSIX_ACL_XATTR_DEFAULT_LEN (sizeof (POSIX_ACL_XATTR_DEFAULT) - 1)
+#define XATTR_TRUSTED_PREFIX "trusted."
+#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1)
+
+struct jffs2_acl_entry {
+ jint16_t e_tag;
+ jint16_t e_perm;
+ jint32_t e_id;
+};
+
+struct jffs2_acl_entry_short {
+ jint16_t e_tag;
+ jint16_t e_perm;
+};
+
+struct jffs2_acl_header {
+ jint32_t a_version;
+};
+
+/* copied from include/linux/posix_acl_xattr.h */
+#define POSIX_ACL_XATTR_VERSION 0x0002
+
+struct posix_acl_xattr_entry {
+ uint16_t e_tag;
+ uint16_t e_perm;
+ uint32_t e_id;
+};
+
+struct posix_acl_xattr_header {
+ uint32_t a_version;
+ struct posix_acl_xattr_entry a_entries[0];
+};
+
+#endif /* __JFFS2_USER_H__ */
diff --git a/mtd-utils-1.3.1/include/mtd/mtd-abi.h b/mtd-utils-1.3.1/include/mtd/mtd-abi.h
new file mode 100644
index 0000000..86defe1
--- /dev/null
+++ b/mtd-utils-1.3.1/include/mtd/mtd-abi.h
@@ -0,0 +1,152 @@
+/*
+ * $Id: mtd-abi.h,v 1.13 2005/11/07 11:14:56 gleixner Exp $
+ *
+ * Portions of MTD ABI definition which are shared by kernel and user space
+ */
+
+#ifndef __MTD_ABI_H__
+#define __MTD_ABI_H__
+
+struct erase_info_user {
+ uint32_t start;
+ uint32_t length;
+};
+
+struct mtd_oob_buf {
+ uint32_t start;
+ uint32_t length;
+ unsigned char *ptr;
+};
+
+#define MTD_ABSENT 0
+#define MTD_RAM 1
+#define MTD_ROM 2
+#define MTD_NORFLASH 3
+#define MTD_NANDFLASH 4
+#define MTD_DATAFLASH 6
+#define MTD_UBIVOLUME 7
+
+#define MTD_WRITEABLE 0x400 /* Device is writeable */
+#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
+#define MTD_NO_ERASE 0x1000 /* No erase necessary */
+#define MTD_STUPID_LOCK 0x2000 /* Always locked after reset */
+
+// Some common devices / combinations of capabilities
+#define MTD_CAP_ROM 0
+#define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
+#define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE)
+#define MTD_CAP_NANDFLASH (MTD_WRITEABLE)
+
+/* ECC byte placement */
+#define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended)
+#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode)
+#define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme
+#define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read)
+#define MTD_NANDECC_AUTOPL_USR 4 // Use the given autoplacement scheme rather than using the default
+
+/* OTP mode selection */
+#define MTD_OTP_OFF 0
+#define MTD_OTP_FACTORY 1
+#define MTD_OTP_USER 2
+
+struct mtd_info_user {
+ uint8_t type;
+ uint32_t flags;
+ uint32_t size; // Total size of the MTD
+ uint32_t erasesize;
+ uint32_t writesize;
+ uint32_t oobsize; // Amount of OOB data per block (e.g. 16)
+ /* The below two fields are obsolete and broken, do not use them
+ * (TODO: remove at some point) */
+ uint32_t ecctype;
+ uint32_t eccsize;
+};
+
+struct region_info_user {
+ uint32_t offset; /* At which this region starts,
+ * from the beginning of the MTD */
+ uint32_t erasesize; /* For this region */
+ uint32_t numblocks; /* Number of blocks in this region */
+ uint32_t regionindex;
+};
+
+struct otp_info {
+ uint32_t start;
+ uint32_t length;
+ uint32_t locked;
+};
+
+#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
+#define MEMERASE _IOW('M', 2, struct erase_info_user)
+#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
+#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
+#define MEMLOCK _IOW('M', 5, struct erase_info_user)
+#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
+#define MEMGETREGIONCOUNT _IOR('M', 7, int)
+#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
+#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
+#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
+#define MEMGETBADBLOCK _IOW('M', 11, loff_t)
+#define MEMSETBADBLOCK _IOW('M', 12, loff_t)
+#define OTPSELECT _IOR('M', 13, int)
+#define OTPGETREGIONCOUNT _IOW('M', 14, int)
+#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
+#define OTPLOCK _IOR('M', 16, struct otp_info)
+#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
+#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
+#define MTDFILEMODE _IO('M', 19)
+
+/*
+ * Obsolete legacy interface. Keep it in order not to break userspace
+ * interfaces
+ */
+struct nand_oobinfo {
+ uint32_t useecc;
+ uint32_t eccbytes;
+ uint32_t oobfree[8][2];
+ uint32_t eccpos[32];
+};
+
+struct nand_oobfree {
+ uint32_t offset;
+ uint32_t length;
+};
+
+#define MTD_MAX_OOBFREE_ENTRIES 8
+/*
+ * ECC layout control structure. Exported to userspace for
+ * diagnosis and to allow creation of raw images
+ */
+struct nand_ecclayout {
+ uint32_t eccbytes;
+ uint32_t eccpos[64];
+ uint32_t oobavail;
+ struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
+};
+
+/**
+ * struct mtd_ecc_stats - error correction stats
+ *
+ * @corrected: number of corrected bits
+ * @failed: number of uncorrectable errors
+ * @badblocks: number of bad blocks in this partition
+ * @bbtblocks: number of blocks reserved for bad block tables
+ */
+struct mtd_ecc_stats {
+ uint32_t corrected;
+ uint32_t failed;
+ uint32_t badblocks;
+ uint32_t bbtblocks;
+};
+
+/*
+ * Read/write file modes for access to MTD
+ */
+enum mtd_file_modes {
+ MTD_MODE_NORMAL = MTD_OTP_OFF,
+ MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY,
+ MTD_MODE_OTP_USER = MTD_OTP_USER,
+ MTD_MODE_RAW,
+};
+
+#endif /* __MTD_ABI_H__ */
diff --git a/mtd-utils-1.3.1/include/mtd/mtd-user.h b/mtd-utils-1.3.1/include/mtd/mtd-user.h
new file mode 100644
index 0000000..713f34d
--- /dev/null
+++ b/mtd-utils-1.3.1/include/mtd/mtd-user.h
@@ -0,0 +1,21 @@
+/*
+ * $Id: mtd-user.h,v 1.2 2004/05/05 14:44:57 dwmw2 Exp $
+ *
+ * MTD ABI header for use by user space only.
+ */
+
+#ifndef __MTD_USER_H__
+#define __MTD_USER_H__
+
+#include <stdint.h>
+
+/* This file is blessed for inclusion by userspace */
+#include <mtd/mtd-abi.h>
+
+typedef struct mtd_info_user mtd_info_t;
+typedef struct erase_info_user erase_info_t;
+typedef struct region_info_user region_info_t;
+typedef struct nand_oobinfo nand_oobinfo_t;
+typedef struct nand_ecclayout nand_ecclayout_t;
+
+#endif /* __MTD_USER_H__ */
diff --git a/mtd-utils-1.3.1/include/mtd/nftl-user.h b/mtd-utils-1.3.1/include/mtd/nftl-user.h
new file mode 100644
index 0000000..b2bca18
--- /dev/null
+++ b/mtd-utils-1.3.1/include/mtd/nftl-user.h
@@ -0,0 +1,76 @@
+/*
+ * $Id: nftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
+ *
+ * Parts of NFTL headers shared with userspace
+ *
+ */
+
+#ifndef __MTD_NFTL_USER_H__
+#define __MTD_NFTL_USER_H__
+
+/* Block Control Information */
+
+struct nftl_bci {
+ unsigned char ECCSig[6];
+ uint8_t Status;
+ uint8_t Status1;
+}__attribute__((packed));
+
+/* Unit Control Information */
+
+struct nftl_uci0 {
+ uint16_t VirtUnitNum;
+ uint16_t ReplUnitNum;
+ uint16_t SpareVirtUnitNum;
+ uint16_t SpareReplUnitNum;
+} __attribute__((packed));
+
+struct nftl_uci1 {
+ uint32_t WearInfo;
+ uint16_t EraseMark;
+ uint16_t EraseMark1;
+} __attribute__((packed));
+
+struct nftl_uci2 {
+ uint16_t FoldMark;
+ uint16_t FoldMark1;
+ uint32_t unused;
+} __attribute__((packed));
+
+union nftl_uci {
+ struct nftl_uci0 a;
+ struct nftl_uci1 b;
+ struct nftl_uci2 c;
+};
+
+struct nftl_oob {
+ struct nftl_bci b;
+ union nftl_uci u;
+};
+
+/* NFTL Media Header */
+
+struct NFTLMediaHeader {
+ char DataOrgID[6];
+ uint16_t NumEraseUnits;
+ uint16_t FirstPhysicalEUN;
+ uint32_t FormattedSize;
+ unsigned char UnitSizeFactor;
+} __attribute__((packed));
+
+#define MAX_ERASE_ZONES (8192 - 512)
+
+#define ERASE_MARK 0x3c69
+#define SECTOR_FREE 0xff
+#define SECTOR_USED 0x55
+#define SECTOR_IGNORE 0x11
+#define SECTOR_DELETED 0x00
+
+#define FOLD_MARK_IN_PROGRESS 0x5555
+
+#define ZONE_GOOD 0xff
+#define ZONE_BAD_ORIGINAL 0
+#define ZONE_BAD_MARKED 7
+
+
+#endif /* __MTD_NFTL_USER_H__ */
diff --git a/mtd-utils-1.3.1/include/mtd/ubi-media.h b/mtd-utils-1.3.1/include/mtd/ubi-media.h
new file mode 100644
index 0000000..08bec3e
--- /dev/null
+++ b/mtd-utils-1.3.1/include/mtd/ubi-media.h
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ * Thomas Gleixner
+ * Frank Haverkamp
+ * Oliver Lohmann
+ * Andreas Arnez
+ */
+
+/*
+ * This file defines the layout of UBI headers and all the other UBI on-flash
+ * data structures.
+ */
+
+#ifndef __UBI_MEDIA_H__
+#define __UBI_MEDIA_H__
+
+#include <asm/byteorder.h>
+
+/* The version of UBI images supported by this implementation */
+#define UBI_VERSION 1
+
+/* The highest erase counter value supported by this implementation */
+#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF
+
+/* The initial CRC32 value used when calculating CRC checksums */
+#define UBI_CRC32_INIT 0xFFFFFFFFU
+
+/* Erase counter header magic number (ASCII "UBI#") */
+#define UBI_EC_HDR_MAGIC 0x55424923
+/* Volume identifier header magic number (ASCII "UBI!") */
+#define UBI_VID_HDR_MAGIC 0x55424921
+
+/*
+ * Volume type constants used in the volume identifier header.
+ *
+ * @UBI_VID_DYNAMIC: dynamic volume
+ * @UBI_VID_STATIC: static volume
+ */
+enum {
+ UBI_VID_DYNAMIC = 1,
+ UBI_VID_STATIC = 2
+};
+
+/*
+ * Volume flags used in the volume table record.
+ *
+ * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume
+ *
+ * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume
+ * table. UBI automatically re-sizes the volume which has this flag and makes
+ * the volume to be of largest possible size. This means that if after the
+ * initialization UBI finds out that there are available physical eraseblocks
+ * present on the device, it automatically appends all of them to the volume
+ * (the physical eraseblocks reserved for bad eraseblocks handling and other
+ * reserved physical eraseblocks are not taken). So, if there is a volume with
+ * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical
+ * eraseblocks will be zero after UBI is loaded, because all of them will be
+ * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared
+ * after the volume had been initialized.
+ *
+ * The auto-resize feature is useful for device production purposes. For
+ * example, different NAND flash chips may have different amount of initial bad
+ * eraseblocks, depending of particular chip instance. Manufacturers of NAND
+ * chips usually guarantee that the amount of initial bad eraseblocks does not
+ * exceed certain percent, e.g. 2%. When one creates an UBI image which will be
+ * flashed to the end devices in production, he does not know the exact amount
+ * of good physical eraseblocks the NAND chip on the device will have, but this
+ * number is required to calculate the volume sized and put them to the volume
+ * table of the UBI image. In this case, one of the volumes (e.g., the one
+ * which will store the root file system) is marked as "auto-resizable", and
+ * UBI will adjust its size on the first boot if needed.
+ *
+ * Note, first UBI reserves some amount of physical eraseblocks for bad
+ * eraseblock handling, and then re-sizes the volume, not vice-versa. This
+ * means that the pool of reserved physical eraseblocks will always be present.
+ */
+enum {
+ UBI_VTBL_AUTORESIZE_FLG = 0x01,
+};
+
+/*
+ * Compatibility constants used by internal volumes.
+ *
+ * @UBI_COMPAT_DELETE: delete this internal volume before anything is written
+ * to the flash
+ * @UBI_COMPAT_RO: attach this device in read-only mode
+ * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
+ * physical eraseblocks, don't allow the wear-leveling
+ * sub-system to move them
+ * @UBI_COMPAT_REJECT: reject this UBI image
+ */
+enum {
+ UBI_COMPAT_DELETE = 1,
+ UBI_COMPAT_RO = 2,
+ UBI_COMPAT_PRESERVE = 4,
+ UBI_COMPAT_REJECT = 5
+};
+
+/* Sizes of UBI headers */
+#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr)
+#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
+
+/* Sizes of UBI headers without the ending CRC */
+#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32))
+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
+
+/**
+ * struct ubi_ec_hdr - UBI erase counter header.
+ * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
+ * @version: version of UBI implementation which is supposed to accept this
+ * UBI image
+ * @padding1: reserved for future, zeroes
+ * @ec: the erase counter
+ * @vid_hdr_offset: where the VID header starts
+ * @data_offset: where the user data start
+ * @image_seq: image sequence number
+ * @padding2: reserved for future, zeroes
+ * @hdr_crc: erase counter header CRC checksum
+ *
+ * The erase counter header takes 64 bytes and has a plenty of unused space for
+ * future usage. The unused fields are zeroed. The @version field is used to
+ * indicate the version of UBI implementation which is supposed to be able to
+ * work with this UBI image. If @version is greater than the current UBI
+ * version, the image is rejected. This may be useful in future if something
+ * is changed radically. This field is duplicated in the volume identifier
+ * header.
+ *
+ * The @vid_hdr_offset and @data_offset fields contain the offset of the the
+ * volume identifier header and user data, relative to the beginning of the
+ * physical eraseblock. These values have to be the same for all physical
+ * eraseblocks.
+ *
+ * The @image_seq field is used to validate a UBI image that has been prepared
+ * for a UBI device. The @image_seq value can be any value, but it must be the
+ * same on all eraseblocks. UBI will ensure that all new erase counter headers
+ * also contain this value, and will check the value when scanning at start-up.
+ * One way to make use of @image_seq is to increase its value by one every time
+ * an image is flashed over an existing image, then, if the flashing does not
+ * complete, UBI will detect the error when scanning.
+ */
+struct ubi_ec_hdr {
+ __be32 magic;
+ __u8 version;
+ __u8 padding1[3];
+ __be64 ec; /* Warning: the current limit is 31-bit anyway! */
+ __be32 vid_hdr_offset;
+ __be32 data_offset;
+ __be32 image_seq;
+ __u8 padding2[32];
+ __be32 hdr_crc;
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_vid_hdr - on-flash UBI volume identifier header.
+ * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
+ * @version: UBI implementation version which is supposed to accept this UBI
+ * image (%UBI_VERSION)
+ * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
+ * @copy_flag: if this logical eraseblock was copied from another physical
+ * eraseblock (for wear-leveling reasons)
+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
+ * @vol_id: ID of this volume
+ * @lnum: logical eraseblock number
+ * @padding1: reserved for future, zeroes
+ * @data_size: how many bytes of data this logical eraseblock contains
+ * @used_ebs: total number of used logical eraseblocks in this volume
+ * @data_pad: how many bytes at the end of this physical eraseblock are not
+ * used
+ * @data_crc: CRC checksum of the data stored in this logical eraseblock
+ * @padding2: reserved for future, zeroes
+ * @sqnum: sequence number
+ * @padding3: reserved for future, zeroes
+ * @hdr_crc: volume identifier header CRC checksum
+ *
+ * The @sqnum is the value of the global sequence counter at the time when this
+ * VID header was created. The global sequence counter is incremented each time
+ * UBI writes a new VID header to the flash, i.e. when it maps a logical
+ * eraseblock to a new physical eraseblock. The global sequence counter is an
+ * unsigned 64-bit integer and we assume it never overflows. The @sqnum
+ * (sequence number) is used to distinguish between older and newer versions of
+ * logical eraseblocks.
+ *
+ * There are 2 situations when there may be more than one physical eraseblock
+ * corresponding to the same logical eraseblock, i.e., having the same @vol_id
+ * and @lnum values in the volume identifier header. Suppose we have a logical
+ * eraseblock L and it is mapped to the physical eraseblock P.
+ *
+ * 1. Because UBI may erase physical eraseblocks asynchronously, the following
+ * situation is possible: L is asynchronously erased, so P is scheduled for
+ * erasure, then L is written to,i.e. mapped to another physical eraseblock P1,
+ * so P1 is written to, then an unclean reboot happens. Result - there are 2
+ * physical eraseblocks P and P1 corresponding to the same logical eraseblock
+ * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the
+ * flash.
+ *
+ * 2. From time to time UBI moves logical eraseblocks to other physical
+ * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P
+ * to P1, and an unclean reboot happens before P is physically erased, there
+ * are two physical eraseblocks P and P1 corresponding to L and UBI has to
+ * select one of them when the flash is attached. The @sqnum field says which
+ * PEB is the original (obviously P will have lower @sqnum) and the copy. But
+ * it is not enough to select the physical eraseblock with the higher sequence
+ * number, because the unclean reboot could have happen in the middle of the
+ * copying process, so the data in P is corrupted. It is also not enough to
+ * just select the physical eraseblock with lower sequence number, because the
+ * data there may be old (consider a case if more data was added to P1 after
+ * the copying). Moreover, the unclean reboot may happen when the erasure of P
+ * was just started, so it result in unstable P, which is "mostly" OK, but
+ * still has unstable bits.
+ *
+ * UBI uses the @copy_flag field to indicate that this logical eraseblock is a
+ * copy. UBI also calculates data CRC when the data is moved and stores it at
+ * the @data_crc field of the copy (P1). So when UBI needs to pick one physical
+ * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is
+ * examined. If it is cleared, the situation* is simple and the newer one is
+ * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC
+ * checksum is correct, this physical eraseblock is selected (P1). Otherwise
+ * the older one (P) is selected.
+ *
+ * There are 2 sorts of volumes in UBI: user volumes and internal volumes.
+ * Internal volumes are not seen from outside and are used for various internal
+ * UBI purposes. In this implementation there is only one internal volume - the
+ * layout volume. Internal volumes are the main mechanism of UBI extensions.
+ * For example, in future one may introduce a journal internal volume. Internal
+ * volumes have their own reserved range of IDs.
+ *
+ * The @compat field is only used for internal volumes and contains the "degree
+ * of their compatibility". It is always zero for user volumes. This field
+ * provides a mechanism to introduce UBI extensions and to be still compatible
+ * with older UBI binaries. For example, if someone introduced a journal in
+ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the
+ * journal volume. And in this case, older UBI binaries, which know nothing
+ * about the journal volume, would just delete this volume and work perfectly
+ * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image
+ * - it just ignores the Ext3fs journal.
+ *
+ * The @data_crc field contains the CRC checksum of the contents of the logical
+ * eraseblock if this is a static volume. In case of dynamic volumes, it does
+ * not contain the CRC checksum as a rule. The only exception is when the
+ * data of the physical eraseblock was moved by the wear-leveling sub-system,
+ * then the wear-leveling sub-system calculates the data CRC and stores it in
+ * the @data_crc field. And of course, the @copy_flag is %in this case.
+ *
+ * The @data_size field is used only for static volumes because UBI has to know
+ * how many bytes of data are stored in this eraseblock. For dynamic volumes,
+ * this field usually contains zero. The only exception is when the data of the
+ * physical eraseblock was moved to another physical eraseblock for
+ * wear-leveling reasons. In this case, UBI calculates CRC checksum of the
+ * contents and uses both @data_crc and @data_size fields. In this case, the
+ * @data_size field contains data size.
+ *
+ * The @used_ebs field is used only for static volumes and indicates how many
+ * eraseblocks the data of the volume takes. For dynamic volumes this field is
+ * not used and always contains zero.
+ *
+ * The @data_pad is calculated when volumes are created using the alignment
+ * parameter. So, effectively, the @data_pad field reduces the size of logical
+ * eraseblocks of this volume. This is very handy when one uses block-oriented
+ * software (say, cramfs) on top of the UBI volume.
+ */
+struct ubi_vid_hdr {
+ __be32 magic;
+ __u8 version;
+ __u8 vol_type;
+ __u8 copy_flag;
+ __u8 compat;
+ __be32 vol_id;
+ __be32 lnum;
+ __be32 leb_ver;
+ __be32 data_size;
+ __be32 used_ebs;
+ __be32 data_pad;
+ __be32 data_crc;
+ __u8 padding2[4];
+ __be64 sqnum;
+ __u8 padding3[12];
+ __be32 hdr_crc;
+} __attribute__ ((packed));
+
+/* Internal UBI volumes count */
+#define UBI_INT_VOL_COUNT 1
+
+/*
+ * Starting ID of internal volumes. There is reserved room for 4096 internal
+ * volumes.
+ */
+#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
+
+/* The layout volume contains the volume table */
+
+#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START
+#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC
+#define UBI_LAYOUT_VOLUME_ALIGN 1
+#define UBI_LAYOUT_VOLUME_EBS 2
+#define UBI_LAYOUT_VOLUME_NAME "layout volume"
+#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
+
+/* The maximum number of volumes per one UBI device */
+#define UBI_MAX_VOLUMES 128
+
+/* The maximum volume name length */
+#define UBI_VOL_NAME_MAX 127
+
+/* Size of the volume table record */
+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
+
+/* Size of the volume table record without the ending CRC */
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
+
+/**
+ * struct ubi_vtbl_record - a record in the volume table.
+ * @reserved_pebs: how many physical eraseblocks are reserved for this volume
+ * @alignment: volume alignment
+ * @data_pad: how many bytes are unused at the end of the each physical
+ * eraseblock to satisfy the requested alignment
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @upd_marker: if volume update was started but not finished
+ * @name_len: volume name length
+ * @name: the volume name
+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
+ * @padding: reserved, zeroes
+ * @crc: a CRC32 checksum of the record
+ *
+ * The volume table records are stored in the volume table, which is stored in
+ * the layout volume. The layout volume consists of 2 logical eraseblock, each
+ * of which contains a copy of the volume table (i.e., the volume table is
+ * duplicated). The volume table is an array of &struct ubi_vtbl_record
+ * objects indexed by the volume ID.
+ *
+ * If the size of the logical eraseblock is large enough to fit
+ * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES
+ * records. Otherwise, it contains as many records as it can fit (i.e., size of
+ * logical eraseblock divided by sizeof(struct ubi_vtbl_record)).
+ *
+ * The @upd_marker flag is used to implement volume update. It is set to %1
+ * before update and set to %0 after the update. So if the update operation was
+ * interrupted, UBI knows that the volume is corrupted.
+ *
+ * The @alignment field is specified when the volume is created and cannot be
+ * later changed. It may be useful, for example, when a block-oriented file
+ * system works on top of UBI. The @data_pad field is calculated using the
+ * logical eraseblock size and @alignment. The alignment must be multiple to the
+ * minimal flash I/O unit. If @alignment is 1, all the available space of
+ * the physical eraseblocks is used.
+ *
+ * Empty records contain all zeroes and the CRC checksum of those zeroes.
+ */
+struct ubi_vtbl_record {
+ __be32 reserved_pebs;
+ __be32 alignment;
+ __be32 data_pad;
+ __u8 vol_type;
+ __u8 upd_marker;
+ __be16 name_len;
+ __u8 name[UBI_VOL_NAME_MAX+1];
+ __u8 flags;
+ __u8 padding[23];
+ __be32 crc;
+} __attribute__ ((packed));
+
+#endif /* !__UBI_MEDIA_H__ */
diff --git a/mtd-utils-1.3.1/include/mtd/ubi-user.h b/mtd-utils-1.3.1/include/mtd/ubi-user.h
new file mode 100644
index 0000000..296efae
--- /dev/null
+++ b/mtd-utils-1.3.1/include/mtd/ubi-user.h
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+#ifndef __UBI_USER_H__
+#define __UBI_USER_H__
+
+/*
+ * UBI device creation (the same as MTD device attachment)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI
+ * control device. The caller has to properly fill and pass
+ * &struct ubi_attach_req object - UBI will attach the MTD device specified in
+ * the request and return the newly created UBI device number as the ioctl
+ * return value.
+ *
+ * UBI device deletion (the same as MTD device detachment)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI
+ * control device.
+ *
+ * UBI volume creation
+ * ~~~~~~~~~~~~~~~~~~~
+ *
+ * UBI volumes are created via the %UBI_IOCMKVOL ioctl command of UBI character
+ * device. A &struct ubi_mkvol_req object has to be properly filled and a
+ * pointer to it has to be passed to the ioctl.
+ *
+ * UBI volume deletion
+ * ~~~~~~~~~~~~~~~~~~~
+ *
+ * To delete a volume, the %UBI_IOCRMVOL ioctl command of the UBI character
+ * device should be used. A pointer to the 32-bit volume ID hast to be passed
+ * to the ioctl.
+ *
+ * UBI volume re-size
+ * ~~~~~~~~~~~~~~~~~~
+ *
+ * To re-size a volume, the %UBI_IOCRSVOL ioctl command of the UBI character
+ * device should be used. A &struct ubi_rsvol_req object has to be properly
+ * filled and a pointer to it has to be passed to the ioctl.
+ *
+ * UBI volumes re-name
+ * ~~~~~~~~~~~~~~~~~~~
+ *
+ * To re-name several volumes atomically at one go, the %UBI_IOCRNVOL command
+ * of the UBI character device should be used. A &struct ubi_rnvol_req object
+ * has to be properly filled and a pointer to it has to be passed to the ioctl.
+ *
+ * UBI volume update
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * Volume update should be done via the %UBI_IOCVOLUP ioctl command of the
+ * corresponding UBI volume character device. A pointer to a 64-bit update
+ * size should be passed to the ioctl. After this, UBI expects user to write
+ * this number of bytes to the volume character device. The update is finished
+ * when the claimed number of bytes is passed. So, the volume update sequence
+ * is something like:
+ *
+ * fd = open("/dev/my_volume");
+ * ioctl(fd, UBI_IOCVOLUP, &image_size);
+ * write(fd, buf, image_size);
+ * close(fd);
+ *
+ * Logical eraseblock erase
+ * ~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To erase a logical eraseblock, the %UBI_IOCEBER ioctl command of the
+ * corresponding UBI volume character device should be used. This command
+ * unmaps the requested logical eraseblock, makes sure the corresponding
+ * physical eraseblock is successfully erased, and returns.
+ *
+ * Atomic logical eraseblock change
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Atomic logical eraseblock change operation is called using the %UBI_IOCEBCH
+ * ioctl command of the corresponding UBI volume character device. A pointer to
+ * a &struct ubi_leb_change_req object has to be passed to the ioctl. Then the
+ * user is expected to write the requested amount of bytes (similarly to what
+ * should be done in case of the "volume update" ioctl).
+ *
+ * Logical eraseblock map
+ * ~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To map a logical eraseblock to a physical eraseblock, the %UBI_IOCEBMAP
+ * ioctl command should be used. A pointer to a &struct ubi_map_req object is
+ * expected to be passed. The ioctl maps the requested logical eraseblock to
+ * a physical eraseblock and returns. Only non-mapped logical eraseblocks can
+ * be mapped. If the logical eraseblock specified in the request is already
+ * mapped to a physical eraseblock, the ioctl fails and returns error.
+ *
+ * Logical eraseblock unmap
+ * ~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To unmap a logical eraseblock to a physical eraseblock, the %UBI_IOCEBUNMAP
+ * ioctl command should be used. The ioctl unmaps the logical eraseblocks,
+ * schedules corresponding physical eraseblock for erasure, and returns. Unlike
+ * the "LEB erase" command, it does not wait for the physical eraseblock being
+ * erased. Note, the side effect of this is that if an unclean reboot happens
+ * after the unmap ioctl returns, you may find the LEB mapped again to the same
+ * physical eraseblock after the UBI is run again.
+ *
+ * Check if logical eraseblock is mapped
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To check if a logical eraseblock is mapped to a physical eraseblock, the
+ * %UBI_IOCEBISMAP ioctl command should be used. It returns %0 if the LEB is
+ * not mapped, and %1 if it is mapped.
+ *
+ * Set an UBI volume property
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To set an UBI volume property the %UBI_IOCSETPROP ioctl command should be
+ * used. A pointer to a &struct ubi_set_prop_req object is expected to be
+ * passed. The object describes which property should be set, and to which value
+ * it should be set.
+ */
+
+/*
+ * When a new UBI volume or UBI device is created, users may either specify the
+ * volume/device number they want to create or to let UBI automatically assign
+ * the number using these constants.
+ */
+#define UBI_VOL_NUM_AUTO (-1)
+#define UBI_DEV_NUM_AUTO (-1)
+
+/* Maximum volume name length */
+#define UBI_MAX_VOLUME_NAME 127
+
+/* ioctl commands of UBI character devices */
+
+#define UBI_IOC_MAGIC 'o'
+
+/* Create an UBI volume */
+#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req)
+/* Remove an UBI volume */
+#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t)
+/* Re-size an UBI volume */
+#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req)
+/* Re-name volumes */
+#define UBI_IOCRNVOL _IOW(UBI_IOC_MAGIC, 3, struct ubi_rnvol_req)
+
+/* ioctl commands of the UBI control character device */
+
+#define UBI_CTRL_IOC_MAGIC 'o'
+
+/* Attach an MTD device */
+#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req)
+/* Detach an MTD device */
+#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t)
+
+/* ioctl commands of UBI volume character devices */
+
+#define UBI_VOL_IOC_MAGIC 'O'
+
+/* Start UBI volume update */
+#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)
+/* LEB erasure command, used for debugging, disabled by default */
+#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
+/* Atomic LEB change command */
+#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t)
+/* Map LEB command */
+#define UBI_IOCEBMAP _IOW(UBI_VOL_IOC_MAGIC, 3, struct ubi_map_req)
+/* Unmap LEB command */
+#define UBI_IOCEBUNMAP _IOW(UBI_VOL_IOC_MAGIC, 4, int32_t)
+/* Check if LEB is mapped command */
+#define UBI_IOCEBISMAP _IOR(UBI_VOL_IOC_MAGIC, 5, int32_t)
+/* Set an UBI volume property */
+#define UBI_IOCSETPROP _IOW(UBI_VOL_IOC_MAGIC, 6, struct ubi_set_prop_req)
+
+/* Maximum MTD device name length supported by UBI */
+#define MAX_UBI_MTD_NAME_LEN 127
+
+/* Maximum amount of UBI volumes that can be re-named at one go */
+#define UBI_MAX_RNVOL 32
+
+/*
+ * UBI data type hint constants.
+ *
+ * UBI_LONGTERM: long-term data
+ * UBI_SHORTTERM: short-term data
+ * UBI_UNKNOWN: data persistence is unknown
+ *
+ * These constants are used when data is written to UBI volumes in order to
+ * help the UBI wear-leveling unit to find more appropriate physical
+ * eraseblocks.
+ */
+enum {
+ UBI_LONGTERM = 1,
+ UBI_SHORTTERM = 2,
+ UBI_UNKNOWN = 3,
+};
+
+/*
+ * UBI volume type constants.
+ *
+ * @UBI_DYNAMIC_VOLUME: dynamic volume
+ * @UBI_STATIC_VOLUME: static volume
+ */
+enum {
+ UBI_DYNAMIC_VOLUME = 3,
+ UBI_STATIC_VOLUME = 4,
+};
+
+/*
+ * UBI set property ioctl constants
+ *
+ * @UBI_PROP_DIRECT_WRITE: allow / disallow user to directly write and
+ * erase individual eraseblocks on dynamic volumes
+ */
+enum {
+ UBI_PROP_DIRECT_WRITE = 1,
+};
+
+/**
+ * struct ubi_attach_req - attach MTD device request.
+ * @ubi_num: UBI device number to create
+ * @mtd_num: MTD device number to attach
+ * @vid_hdr_offset: VID header offset (use defaults if %0)
+ * @padding: reserved for future, not used, has to be zeroed
+ *
+ * This data structure is used to specify MTD device UBI has to attach and the
+ * parameters it has to use. The number which should be assigned to the new UBI
+ * device is passed in @ubi_num. UBI may automatically assign the number if
+ * @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in
+ * @ubi_num.
+ *
+ * Most applications should pass %0 in @vid_hdr_offset to make UBI use default
+ * offset of the VID header within physical eraseblocks. The default offset is
+ * the next min. I/O unit after the EC header. For example, it will be offset
+ * 512 in case of a 512 bytes page NAND flash with no sub-page support. Or
+ * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages.
+ *
+ * But in rare cases, if this optimizes things, the VID header may be placed to
+ * a different offset. For example, the boot-loader might do things faster if
+ * the VID header sits at the end of the first 2KiB NAND page with 4 sub-pages.
+ * As the boot-loader would not normally need to read EC headers (unless it
+ * needs UBI in RW mode), it might be faster to calculate ECC. This is weird
+ * example, but it real-life example. So, in this example, @vid_hdr_offer would
+ * be 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes
+ * aligned, which is OK, as UBI is clever enough to realize this is 4th
+ * sub-page of the first page and add needed padding.
+ */
+struct ubi_attach_req {
+ int32_t ubi_num;
+ int32_t mtd_num;
+ int32_t vid_hdr_offset;
+ int8_t padding[12];
+};
+
+/**
+ * struct ubi_mkvol_req - volume description data structure used in
+ * volume creation requests.
+ * @vol_id: volume number
+ * @alignment: volume alignment
+ * @bytes: volume size in bytes
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @padding1: reserved for future, not used, has to be zeroed
+ * @name_len: volume name length
+ * @padding2: reserved for future, not used, has to be zeroed
+ * @name: volume name
+ *
+ * This structure is used by user-space programs when creating new volumes. The
+ * @used_bytes field is only necessary when creating static volumes.
+ *
+ * The @alignment field specifies the required alignment of the volume logical
+ * eraseblock. This means, that the size of logical eraseblocks will be aligned
+ * to this number, i.e.,
+ * (UBI device logical eraseblock size) mod (@alignment) = 0.
+ *
+ * To put it differently, the logical eraseblock of this volume may be slightly
+ * shortened in order to make it properly aligned. The alignment has to be
+ * multiple of the flash minimal input/output unit, or %1 to utilize the entire
+ * available space of logical eraseblocks.
+ *
+ * The @alignment field may be useful, for example, when one wants to maintain
+ * a block device on top of an UBI volume. In this case, it is desirable to fit
+ * an integer number of blocks in logical eraseblocks of this UBI volume. With
+ * alignment it is possible to update this volume using plane UBI volume image
+ * BLOBs, without caring about how to properly align them.
+ */
+struct ubi_mkvol_req {
+ int32_t vol_id;
+ int32_t alignment;
+ int64_t bytes;
+ int8_t vol_type;
+ int8_t padding1;
+ int16_t name_len;
+ int8_t padding2[4];
+ char name[UBI_MAX_VOLUME_NAME + 1];
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_rsvol_req - a data structure used in volume re-size requests.
+ * @vol_id: ID of the volume to re-size
+ * @bytes: new size of the volume in bytes
+ *
+ * Re-sizing is possible for both dynamic and static volumes. But while dynamic
+ * volumes may be re-sized arbitrarily, static volumes cannot be made to be
+ * smaller than the number of bytes they bear. To arbitrarily shrink a static
+ * volume, it must be wiped out first (by means of volume update operation with
+ * zero number of bytes).
+ */
+struct ubi_rsvol_req {
+ int64_t bytes;
+ int32_t vol_id;
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_rnvol_req - volumes re-name request.
+ * @count: count of volumes to re-name
+ * @padding1: reserved for future, not used, has to be zeroed
+ * @vol_id: ID of the volume to re-name
+ * @name_len: name length
+ * @padding2: reserved for future, not used, has to be zeroed
+ * @name: new volume name
+ *
+ * UBI allows to re-name up to %32 volumes at one go. The count of volumes to
+ * re-name is specified in the @count field. The ID of the volumes to re-name
+ * and the new names are specified in the @vol_id and @name fields.
+ *
+ * The UBI volume re-name operation is atomic, which means that should power cut
+ * happen, the volumes will have either old name or new name. So the possible
+ * use-cases of this command is atomic upgrade. Indeed, to upgrade, say, volumes
+ * A and B one may create temporary volumes %A1 and %B1 with the new contents,
+ * then atomically re-name A1->A and B1->B, in which case old %A and %B will
+ * be removed.
+ *
+ * If it is not desirable to remove old A and B, the re-name request has to
+ * contain 4 entries: A1->A, A->A1, B1->B, B->B1, in which case old A1 and B1
+ * become A and B, and old A and B will become A1 and B1.
+ *
+ * It is also OK to request: A1->A, A1->X, B1->B, B->Y, in which case old A1
+ * and B1 become A and B, and old A and B become X and Y.
+ *
+ * In other words, in case of re-naming into an existing volume name, the
+ * existing volume is removed, unless it is re-named as well at the same
+ * re-name request.
+ */
+struct ubi_rnvol_req {
+ int32_t count;
+ int8_t padding1[12];
+ struct {
+ int32_t vol_id;
+ int16_t name_len;
+ int8_t padding2[2];
+ char name[UBI_MAX_VOLUME_NAME + 1];
+ } ents[UBI_MAX_RNVOL];
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_leb_change_req - a data structure used in atomic LEB change
+ * requests.
+ * @lnum: logical eraseblock number to change
+ * @bytes: how many bytes will be written to the logical eraseblock
+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
+ * @padding: reserved for future, not used, has to be zeroed
+ */
+struct ubi_leb_change_req {
+ int32_t lnum;
+ int32_t bytes;
+ int8_t dtype;
+ int8_t padding[7];
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_map_req - a data structure used in map LEB requests.
+ * @lnum: logical eraseblock number to unmap
+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
+ * @padding: reserved for future, not used, has to be zeroed
+ */
+struct ubi_map_req {
+ int32_t lnum;
+ int8_t dtype;
+ int8_t padding[3];
+} __attribute__ ((packed));
+
+
+/**
+ * struct ubi_set_prop_req - a data structure used to set an ubi volume
+ * property.
+ * @property: property to set (%UBI_PROP_DIRECT_WRITE)
+ * @padding: reserved for future, not used, has to be zeroed
+ * @value: value to set
+ */
+struct ubi_set_prop_req {
+ uint8_t property;
+ uint8_t padding[7];
+ uint64_t value;
+} __attribute__ ((packed));
+
+#endif /* __UBI_USER_H__ */
diff --git a/mtd-utils-1.3.1/include/mtd_swab.h b/mtd-utils-1.3.1/include/mtd_swab.h
new file mode 100644
index 0000000..c3340a6
--- /dev/null
+++ b/mtd-utils-1.3.1/include/mtd_swab.h
@@ -0,0 +1,51 @@
+#ifndef MTD_SWAB_H
+#define MTD_SWAB_H
+
+#include <endian.h>
+
+#define swab16(x) \
+ ((uint16_t)( \
+ (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
+ (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
+#define swab32(x) \
+ ((uint32_t)( \
+ (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
+ (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
+ (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
+ (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#define swab64(x) \
+ ((uint64_t)( \
+ (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \
+ (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
+ (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
+ (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
+ (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
+ (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
+ (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
+ (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) ))
+
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le16(x) ({ uint16_t _x = x; swab16(_x); })
+#define cpu_to_le32(x) ({ uint32_t _x = x; swab32(_x); })
+#define cpu_to_le64(x) ({ uint64_t _x = x; swab64(_x); })
+#define cpu_to_be16(x) (x)
+#define cpu_to_be32(x) (x)
+#define cpu_to_be64(x) (x)
+#else
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le64(x) (x)
+#define cpu_to_be16(x) ({ uint16_t _x = x; swab16(_x); })
+#define cpu_to_be32(x) ({ uint32_t _x = x; swab32(_x); })
+#define cpu_to_be64(x) ({ uint64_t _x = x; swab64(_x); })
+#endif
+#define le16_to_cpu(x) cpu_to_le16(x)
+#define be16_to_cpu(x) cpu_to_be16(x)
+#define le32_to_cpu(x) cpu_to_le32(x)
+#define be32_to_cpu(x) cpu_to_be32(x)
+#define le64_to_cpu(x) cpu_to_le64(x)
+#define be64_to_cpu(x) cpu_to_be64(x)
+
+#endif
diff --git a/mtd-utils-1.3.1/jffs-dump.c b/mtd-utils-1.3.1/jffs-dump.c
new file mode 100644
index 0000000..31cdad2
--- /dev/null
+++ b/mtd-utils-1.3.1/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>
+
+#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
+
+#define min(x,y) (x) > (y) ? (y) : (x)
+
+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/mtd-utils-1.3.1/jffs2dump.c b/mtd-utils-1.3.1/jffs2dump.c
new file mode 100644
index 0000000..2802682
--- /dev/null
+++ b/mtd-utils-1.3.1/jffs2dump.c
@@ -0,0 +1,689 @@
+/*
+ * 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:
+ */
+
+#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"
+
+#define PROGRAM "jffs2dump"
+#define VERSION "$Revision: 1.10 $"
+
+#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: " PROGRAM " [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");
+ exit(0);
+}
+
+void display_version (void)
+{
+ printf(PROGRAM " " VERSION "\n"
+ "\n"
+ "Copyright (C) 2003 Thomas Gleixner \n"
+ "\n"
+ PROGRAM " comes with NO WARRANTY\n"
+ "to the extent permitted by law.\n"
+ "\n"
+ "You may redistribute copies of " PROGRAM "\n"
+ "under the terms of the GNU General Public Licence.\n"
+ "See the file `COPYING' for more information.\n");
+ 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%08x to 0x%08x\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%08x, 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 = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+ if (crc != je32_to_cpu (node->u.hdr_crc)) {
+ printf ("Wrong hdr_crc at 0x%08x, 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%08x, 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 = crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
+ if (crc != je32_to_cpu (node->i.node_crc)) {
+ printf ("Wrong node_crc at 0x%08x, 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 = 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%08x, 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%08x, 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 = crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
+ if (crc != je32_to_cpu (node->d.node_crc)) {
+ printf ("Wrong node_crc at 0x%08x, 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 = 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%08x, 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_SUMMARY: {
+
+ int i;
+ struct jffs2_sum_marker * sm;
+
+ printf("%8s Inode Sum node at 0x%08x, 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 = crc32 (0, node, sizeof (struct jffs2_raw_summary) - 8);
+ if (crc != je32_to_cpu (node->s.node_crc)) {
+ printf ("Wrong node_crc at 0x%08x, 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 = 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%08x, 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;
+ }
+
+ 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%08x, 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%08x, 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%08x, 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%08x, 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 = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+ if (crc != je32_to_cpu (node->u.hdr_crc)) {
+ printf ("Wrong hdr_crc at 0x%08x, 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 (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 ( 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 (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 (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 (crc32 (0, &newnode, sizeof (struct jffs2_raw_dirent) - 8));
+ if (recalccrc)
+ newnode.d.name_crc = cpu_to_e32 ( 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_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 (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 (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 (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;
+
+ 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 ( 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%08x, 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/mtd-utils-1.3.1/jffs2reader.c b/mtd-utils-1.3.1/jffs2reader.c
new file mode 100644
index 0000000..cde1d06
--- /dev/null
+++ b/mtd-utils-1.3.1/jffs2reader.c
@@ -0,0 +1,939 @@
+/* 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.
+ */
+
+
+#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 <dirent.h>
+#include <zlib.h>
+#include <linux/jffs2.h>
+
+#define SCRATCH_SIZE (5*1024*1024)
+
+#ifndef MAJOR
+/* FIXME: I am using illicit insider knowledge of
+ * kernel major/minor representation... */
+#define MAJOR(dev) (((dev)>>8)&0xff)
+#define MINOR(dev) ((dev)&0xff)
+#endif
+
+
+#define DIRENT_INO(dirent) ((dirent)!=NULL?(dirent)->ino:0)
+#define DIRENT_PINO(dirent) ((dirent)!=NULL?(dirent)->pino:0)
+
+struct dir {
+ struct dir *next;
+ uint8_t type;
+ uint8_t nsize;
+ uint32_t ino;
+ char name[256];
+};
+
+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, char *path,
+ int recurse);
+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, char *,
+ uint32_t *, int);
+struct jffs2_raw_dirent *resolvepath(char *, size_t, uint32_t, char *,
+ uint32_t *);
+
+void lsdir(char *, size_t, char *, 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 = n->dsize;
+
+ if (n->isize > bsize || (n->offset + dlen) > bsize) {
+ fprintf(stderr, "File does not fit into buffer!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (*rsize < n->isize)
+ bzero(b + *rsize, n->isize - *rsize);
+
+ switch (n->compr) {
+ case JFFS2_COMPR_ZLIB:
+ uncompress((Bytef *) b + n->offset, &dlen,
+ (Bytef *) ((char *) n) + sizeof(struct jffs2_raw_inode),
+ (uLongf) n->csize);
+ break;
+
+ case JFFS2_COMPR_NONE:
+ memcpy(b + n->offset,
+ ((char *) n) + sizeof(struct jffs2_raw_inode), dlen);
+ break;
+
+ case JFFS2_COMPR_ZERO:
+ bzero(b + n->offset, dlen);
+ break;
+
+ /* [DYN]RUBIN support required! */
+
+ default:
+ fprintf(stderr, "Unsupported compression method!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ *rsize = 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 (n->ino) {
+ if (dd == NULL) {
+ d = malloc(sizeof(struct dir));
+ d->type = n->type;
+ memcpy(d->name, n->name, n->nsize);
+ d->nsize = n->nsize;
+ d->ino = 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 = n->ino;
+
+ return o;
+ }
+
+ if (dd->next == NULL) {
+ dd->next = malloc(sizeof(struct dir));
+ dd->next->type = n->type;
+ memcpy(dd->next->name, n->name, n->nsize);
+ dd->next->nsize = n->nsize;
+ dd->next->ino = 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, char *path, int recurse)
+{
+ char m;
+ char *filetime;
+ time_t age;
+ struct jffs2_raw_inode *ri;
+
+ 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) {
+ fprintf(stderr, "bug: raw_inode missing!\n");
+ d = d->next;
+ continue;
+ }
+
+ filetime = ctime((const time_t *) &(ri->ctime));
+ age = time(NULL) - ri->ctime;
+ printf("%s %-4d %-8d %-8d ", mode_string(ri->mode),
+ 1, ri->uid, 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 ", (int)MAJOR(rdev), (int)MINOR(rdev));
+ } else {
+ printf("%9ld ", (long)ri->dsize);
+ }
+ d->name[d->nsize]='\0';
+ if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
+ /* hh:mm if less than 6 months old */
+ printf("%6.6s %5.5s %s/%s%c", filetime + 4, filetime + 11, path, d->name, m);
+ } else {
+ printf("%6.6s %4.4s %s/%s%c", filetime + 4, filetime + 20, 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 = malloc(BUFSIZ);
+ if (!tmp) {
+ fprintf(stderr, "memory exhausted\n");
+ exit(EXIT_FAILURE);
+ }
+ sprintf(tmp, "%s/%s", path, d->name);
+ lsdir(o, size, tmp, recurse); /* 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 && n->u.magic != JFFS2_MAGIC_BITMASK)
+ ((char *) n) += 4;
+
+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) {
+ if (n->u.nodetype == JFFS2_NODETYPE_INODE &&
+ n->i.ino == ino && (v = 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));
+ }
+
+ ((char *) n) += ((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 && n->u.magic != JFFS2_MAGIC_BITMASK)
+ ((char *) n) += 4;
+
+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) {
+ if (n->u.nodetype == JFFS2_NODETYPE_DIRENT &&
+ n->d.pino == ino && (v = 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);
+ }
+ }
+
+ ((char *) n) += ((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) +
+ ((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 && n->u.magic != JFFS2_MAGIC_BITMASK)
+ ((char *) n) += 4;
+
+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) {
+ if (n->u.nodetype == JFFS2_NODETYPE_DIRENT &&
+ (!ino || n->d.ino == ino) &&
+ (v = n->d.version) > vmax &&
+ (!pino || (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);
+ }
+ }
+
+ ((char *) n) += ((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,
+ 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 = strdup(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,
+ 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, char *path, int recurse)
+{
+ 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)) {
+ fprintf(stderr, "jffs2reader: %s: No such file or directory\n",
+ path);
+ exit(EXIT_FAILURE);
+ }
+
+ d = collectdir(o, size, ino, d);
+ printdir(o, size, d, path, recurse);
+ 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) {
+ fprintf(stderr, "%s: No such file or directory\n", path);
+ exit(EXIT_FAILURE);
+ }
+
+ if (dd == NULL || dd->type != DT_REG) {
+ fprintf(stderr, "%s: Not a regular file\n", path);
+ exit(EXIT_FAILURE);
+ }
+
+ 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;
+ struct stat st;
+
+ char *scratch, *dir = NULL, *file = NULL;
+ size_t ssize = 0;
+
+ char *buf;
+
+ while ((opt = getopt(argc, argv, "rd:f:")) > 0) {
+ switch (opt) {
+ case 'd':
+ dir = optarg;
+ break;
+ case 'f':
+ file = optarg;
+ break;
+ case 'r':
+ recurse++;
+ break;
+ default:
+ fprintf(stderr,
+ "Usage: jffs2reader <image> [-d|-f] < path > \n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ fd = open(argv[optind], O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno));
+ exit(2);
+ }
+
+ if (fstat(fd, &st)) {
+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno));
+ exit(3);
+ }
+
+ buf = malloc((size_t) st.st_size);
+ if (buf == NULL) {
+ fprintf(stderr, "%s: memory exhausted\n", argv[optind]);
+ exit(4);
+ }
+
+ if (read(fd, buf, st.st_size) != (ssize_t) st.st_size) {
+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno));
+ exit(5);
+ }
+
+ if (dir)
+ lsdir(buf, st.st_size, dir, recurse);
+
+ if (file) {
+ scratch = malloc(SCRATCH_SIZE);
+ if (scratch == NULL) {
+ fprintf(stderr, "%s: memory exhausted\n", argv[optind]);
+ exit(6);
+ }
+
+ catfile(buf, st.st_size, file, scratch, SCRATCH_SIZE, &ssize);
+ free(scratch);
+ }
+
+ if (!dir && !file)
+ lsdir(buf, st.st_size, "/", 1);
+
+
+ free(buf);
+ exit(EXIT_SUCCESS);
+}
diff --git a/mtd-utils-1.3.1/load_nandsim.sh b/mtd-utils-1.3.1/load_nandsim.sh
new file mode 100755
index 0000000..bda3c79
--- /dev/null
+++ b/mtd-utils-1.3.1/load_nandsim.sh
@@ -0,0 +1,123 @@
+#!/bin/bash
+
+#
+# This script inserts NAND simulator module to emulate NAND flash of specified
+# size.
+#
+# Author: Artem Bityutskiy
+#
+
+# Check if nandsim module is loaded
+function nandsim_loaded()
+{
+ local NANDSIM=`lsmod | grep nandsim`
+ if [ -n "$NANDSIM" ]; then
+ return 1
+ fi
+ return 0
+}
+
+nandsim_loaded
+if (( $? != 0 )); then
+ echo "Error: nandsim is already loaded"
+ exit 1
+fi
+
+if (( $# < 1 )); then
+ echo "Load NAND simulator to simulate flash of a specified size."
+ echo ""
+ echo "Usage: ./load_nandsim.sh <size in MiB> <eraseblock size in KiB>"
+ echo " <page size (512 or 2048)>"
+ echo ""
+ echo "Only the first parameter is mandatory. Default eraseblock size"
+ echo "is 16KiB, default NAND page size is 512 bytes."
+ echo ""
+ echo "Only the following combinations are supported:"
+ echo "--------------------------------------------------"
+ echo "| size (MiB) | EB size (KiB) | Page size (bytes) |"
+ echo "--------------------------------------------------"
+ echo "| 16 | 16 | 512 |"
+ echo "| 32 | 16 | 512 |"
+ echo "| 64 | 16 | 512 |"
+ echo "| 128 | 16 | 512 |"
+ echo "| 256 | 16 | 512 |"
+ echo "| 64 | 64 | 2048 |"
+ echo "| 64 | 128 | 2048 |"
+ echo "| 64 | 256 | 2048 |"
+ echo "| 64 | 512 | 2048 |"
+ echo "| 128 | 64 | 2048 |"
+ echo "| 128 | 128 | 2048 |"
+ echo "| 128 | 256 | 2048 |"
+ echo "| 128 | 512 | 2048 |"
+ echo "| 256 | 64 | 2048 |"
+ echo "| 256 | 128 | 2048 |"
+ echo "| 256 | 256 | 2048 |"
+ echo "| 256 | 512 | 2048 |"
+ echo "| 512 | 64 | 2048 |"
+ echo "| 512 | 128 | 2048 |"
+ echo "| 512 | 256 | 2048 |"
+ echo "| 512 | 512 | 2048 |"
+ echo "| 1024 | 64 | 2048 |"
+ echo "| 1024 | 128 | 2048 |"
+ echo "| 1024 | 256 | 2048 |"
+ echo "| 1024 | 512 | 2048 |"
+ echo "--------------------------------------------------"
+ exit 1
+fi
+
+SZ=$1
+EBSZ=$2
+PGSZ=$3
+if [[ $# == '1' ]]; then
+ EBSZ=16
+ PGSZ=512
+elif [[ $# == '2' ]]; then
+ PGSZ=512
+fi
+
+if (( $PGSZ == 512 && $EBSZ != 16 )); then
+ echo "Error: only 16KiB eraseblocks are possible in case of 512 bytes page"
+ exit 1
+fi
+
+if (( $PGSZ == 512 )); then
+ case $SZ in
+ 16) modprobe nandsim first_id_byte=0x20 second_id_byte=0x33 ;;
+ 32) modprobe nandsim first_id_byte=0x20 second_id_byte=0x35 ;;
+ 64) modprobe nandsim first_id_byte=0x20 second_id_byte=0x36 ;;
+ 128) modprobe nandsim first_id_byte=0x20 second_id_byte=0x78 ;;
+ 256) modprobe nandsim first_id_byte=0x20 second_id_byte=0x71 ;;
+ *) echo "Flash size ${SZ}MiB is not supported, try 16, 32, 64 or 256"
+ exit 1 ;;
+ esac
+elif (( $PGSZ == 2048 )); then
+ case $EBSZ in
+ 64) FOURTH=0x05 ;;
+ 128) FOURTH=0x15 ;;
+ 256) FOURTH=0x25 ;;
+ 512) FOURTH=0x35 ;;
+ *) echo "Eraseblock ${EBSZ}KiB is not supported"
+ exit 1
+ esac
+
+ case $SZ in
+ 64) modprobe nandsim first_id_byte=0x20 second_id_byte=0xa2 third_id_byte=0x00 fourth_id_byte=$FOURTH ;;
+ 128) modprobe nandsim first_id_byte=0xec second_id_byte=0xa1 third_id_byte=0x00 fourth_id_byte=$FOURTH ;;
+ 256) modprobe nandsim first_id_byte=0x20 second_id_byte=0xaa third_id_byte=0x00 fourth_id_byte=$FOURTH ;;
+ 512) modprobe nandsim first_id_byte=0x20 second_id_byte=0xac third_id_byte=0x00 fourth_id_byte=$FOURTH ;;
+ 1024) modprobe nandsim first_id_byte=0xec second_id_byte=0xd3 third_id_byte=0x51 fourth_id_byte=$FOURTH ;;
+ *) echo "Unable to emulate ${SZ}MiB flash with ${EBSZ}KiB eraseblock"
+ exit 1
+ esac
+else
+ echo "Error: bad NAND page size ${PGSZ}KiB, it has to be either 512 or 2048"
+ exit 1
+fi
+
+if (( $? != 0 )); then
+ echo "Error: cannot load nandsim"
+ exit 1
+fi
+
+echo "Loaded NAND simulator (${SZ}MiB, ${EBSZ}KiB eraseblock, $PGSZ bytes NAND page)"
+exit 0
diff --git a/mtd-utils-1.3.1/mcast_image.h b/mtd-utils-1.3.1/mcast_image.h
new file mode 100644
index 0000000..07b6e31
--- /dev/null
+++ b/mtd-utils-1.3.1/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/mtd-utils-1.3.1/mkfs.jffs2.1 b/mtd-utils-1.3.1/mkfs.jffs2.1
new file mode 100644
index 0000000..1eefeda
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.jffs2.1
@@ -0,0 +1,267 @@
+.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 avaiable 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.
+.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 avaiable compressors and their default states.
+.TP
+.B -X, --enable-compressor=NAME
+Enable a compressor. Use
+.B -L
+to see the list of the avaiable 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 avaiable compressors and their default priority.
+Priorities are used by priority compression mode.
+.TP
+.B -L, --list-compressors
+Show the list of the avaiable 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/mtd-utils-1.3.1/mkfs.jffs2.c b/mtd-utils-1.3.1/mkfs.jffs2.c
new file mode 100644
index 0000000..23a8cf8
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.jffs2.c
@@ -0,0 +1,1907 @@
+/* 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 _GNU_SOURCE
+#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>
+#define crc32 __complete_crap
+#include <zlib.h>
+#undef crc32
+#include "crc32.h"
+#include "rbtree.h"
+
+/* Do not use the weird XPG version of basename */
+#undef basename
+
+//#define DMALLOC
+//#define mkfs_debug_msg error_msg
+#define mkfs_debug_msg(a...) { }
+#define min(x,y) ({ typeof((x)) _x = (x); typeof((y)) _y = (y); (_x>_y)?_y:_x; })
+
+#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;
+static const char *const app_name = "mkfs.jffs2";
+static const char *const memory_exhausted = "memory exhausted";
+
+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;
+}
+
+static void verror_msg(const char *s, va_list p)
+{
+ fflush(stdout);
+ fprintf(stderr, "%s: ", app_name);
+ vfprintf(stderr, s, p);
+}
+static void error_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ verror_msg(s, p);
+ va_end(p);
+ putc('\n', stderr);
+}
+
+static void error_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ verror_msg(s, p);
+ va_end(p);
+ putc('\n', stderr);
+ exit(EXIT_FAILURE);
+}
+
+static void vperror_msg(const char *s, va_list p)
+{
+ int err = errno;
+
+ if (s == 0)
+ s = "";
+ verror_msg(s, p);
+ if (*s)
+ s = ": ";
+ fprintf(stderr, "%s%s\n", s, strerror(err));
+}
+
+static void perror_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vperror_msg(s, p);
+ va_end(p);
+}
+
+static void perror_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vperror_msg(s, p);
+ va_end(p);
+ exit(EXIT_FAILURE);
+}
+
+#ifndef DMALLOC
+extern void *xmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+
+ if (ptr == NULL && size != 0)
+ error_msg_and_die(memory_exhausted);
+ return ptr;
+}
+
+extern void *xcalloc(size_t nmemb, size_t size)
+{
+ void *ptr = calloc(nmemb, size);
+
+ if (ptr == NULL && nmemb != 0 && size != 0)
+ error_msg_and_die(memory_exhausted);
+ return ptr;
+}
+
+extern void *xrealloc(void *ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (ptr == NULL && size != 0)
+ error_msg_and_die(memory_exhausted);
+ return ptr;
+}
+
+extern char *xstrdup(const char *s)
+{
+ char *t;
+
+ if (s == NULL)
+ return NULL;
+ t = strdup(s);
+ if (t == NULL)
+ error_msg_and_die(memory_exhausted);
+ return t;
+}
+#endif
+
+extern char *xreadlink(const char *path)
+{
+ static const int GROWBY = 80; /* how large we will grow strings by */
+
+ char *buf = NULL;
+ int bufsize = 0, readsize = 0;
+
+ do {
+ buf = xrealloc(buf, bufsize += GROWBY);
+ readsize = readlink(path, buf, bufsize); /* 1st try */
+ if (readsize == -1) {
+ perror_msg("%s:%s", app_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)
+ perror_msg_and_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(
+ char *name, 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)) {
+ error_msg_and_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) {
+ error_msg_and_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, char *targetpath, char *hostpath)
+{
+ int i, n;
+ struct stat sb;
+ char *hpath, *tpath;
+ struct dirent *dp, **namelist;
+ struct filesystem_entry *entry;
+
+
+ if (lstat(hostpath, &sb)) {
+ perror_msg_and_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) {
+ perror_msg_and_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;
+ }
+
+ asprintf(&hpath, "%s/%s", hostpath, dp->d_name);
+ if (lstat(hpath, &sb)) {
+ perror_msg_and_die("%s", hpath);
+ }
+ if (strcmp(targetpath, "/") == 0) {
+ asprintf(&tpath, "%s%s", targetpath, dp->d_name);
+ } else {
+ asprintf(&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:
+ error_msg("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 = malloc(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, "/")) {
+ error_msg_and_die("Device table entries require absolute paths");
+ }
+
+ asprintf(&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:
+ error_msg_and_die("Unsupported file type '%c'", type);
+ }
+ entry = find_filesystem_entry(root, name, mode);
+ if (entry) {
+ /* 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 = strdup(name);
+ dir = dirname(tmp);
+ parent = find_filesystem_entry(root, dir, S_IFDIR);
+ free(tmp);
+ if (parent == NULL) {
+ error_msg ("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 < count; i++) {
+ asprintf(&dname, "%s%lu", name, i);
+ asprintf(&hpath, "%s/%s%lu", rootdir, name, i);
+ rdev = makedev(major, minor + (i * increment - start));
+ 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:
+ error_msg_and_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)
+ perror_msg_and_die("write");
+
+ if (ret == 0)
+ perror_msg_and_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(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(crc32(0, &rd, sizeof(rd) - 8));
+ rd.name_crc = cpu_to_je32(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) {
+ error_msg("Skipping file \"%s\" too large.", e->path);
+ return -1;
+ }
+ fd = open(e->hostname, O_RDONLY);
+ if (fd == -1) {
+ perror_msg_and_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) {
+ perror_msg_and_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(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(crc32(0, &ri, sizeof(ri) - 8));
+ ri.data_crc = cpu_to_je32(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(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(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) {
+ error_msg("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(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(crc32(0, &ri, sizeof(ri) - 8));
+ ri.data_crc = cpu_to_je32(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(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(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(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(crc32(0, &ri, sizeof(ri) - 8));
+ ri.data_crc = cpu_to_je32(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;
+ 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(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(crc32(0, xe->xname, xe->name_len + 1 + xe->value_len));
+ rx.node_crc = cpu_to_je32(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 = (crc32(0, xname, name_len) ^ 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, *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(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(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 %9lu %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 %9lu %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 %9lu %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 %9lu %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 %9lu (%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:
+ error_msg("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(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'},
+ {"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 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 (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: priortiry)\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 avaiable 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 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%08x, 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%08x, 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%08x, 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%08x, 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%08x, 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%08x, 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 = malloc(erase_block_size);
+
+ if (!file_buffer) {
+ perror("out of memory");
+ close (in_fd);
+ close (out_fd);
+ exit(1);
+ }
+
+ 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)
+ perror_msg_and_die(optarg);
+ if (sb.st_size < 10)
+ error_msg_and_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) {
+ error_msg_and_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) {
+ error_msg_and_die("output filename specified more than once");
+ }
+ out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
+ if (out_fd == -1) {
+ perror_msg_and_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 '?':
+ error_msg_and_die(helptext);
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ case 'V':
+ error_msg_and_die("revision %s\n", revtext);
+
+ case 'e': {
+ char *next;
+ unsigned units = 0;
+ erase_block_size = strtol(optarg, &next, 0);
+ if (!erase_block_size)
+ error_msg_and_die("Unrecognisable erase size\n");
+
+ if (*next) {
+ if (!strcmp(next, "KiB")) {
+ units = 1024;
+ } else if (!strcmp(next, "MiB")) {
+ units = 1024 * 1024;
+ } else {
+ error_msg_and_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)) {
+ error_msg_and_die("cleanmarker size must be >= 12");
+ }
+ if (cleanmarker_size >= erase_block_size) {
+ error_msg_and_die("cleanmarker size must be < eraseblock size");
+ }
+ break;
+ case 'm':
+ if (jffs2_set_compression_mode_name(optarg)) {
+ error_msg_and_die("Unknown compression mode %s", optarg);
+ }
+ break;
+ case 'x':
+ if (jffs2_disable_compressor_name(optarg)) {
+ error_msg_and_die("Unknown compressor name %s",optarg);
+ }
+ break;
+ case 'X':
+ if (jffs2_enable_compressor_name(optarg)) {
+ error_msg_and_die("Unknown compressor name %s",optarg);
+ }
+ break;
+ case 'L':
+ error_msg_and_die("\n%s",jffs2_list_compressors());
+ break;
+ case 't':
+ jffs2_compression_check_set(1);
+ break;
+ case 'y':
+ compr_name = malloc(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 {
+ error_msg_and_die("Cannot parse %s",optarg);
+ }
+ free(compr_name);
+ break;
+ case 'i':
+ if (in_fd != -1) {
+ error_msg_and_die("(incremental) filename specified more than once");
+ }
+ in_fd = open(optarg, O_RDONLY);
+ if (in_fd == -1) {
+ perror_msg_and_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) {
+ error_msg("Page size for this system is by default %d", page_size);
+ error_msg("Use the --pagesize=SIZE option if this is not what you want");
+ }
+ if (out_fd == -1) {
+ if (isatty(1)) {
+ error_msg_and_die(helptext);
+ }
+ out_fd = 1;
+ }
+ if (lstat(rootdir, &sb)) {
+ perror_msg_and_die("%s", rootdir);
+ }
+ if (chdir(rootdir))
+ perror_msg_and_die("%s", rootdir);
+
+ if (!(cwd = getcwd(0, GETCWD_SIZE)))
+ perror_msg_and_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/mtd-utils-1.3.1/mkfs.ubifs/COPYING b/mtd-utils-1.3.1/mkfs.ubifs/COPYING
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.ubifs/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/mtd-utils-1.3.1/mkfs.ubifs/Makefile b/mtd-utils-1.3.1/mkfs.ubifs/Makefile
new file mode 100644
index 0000000..2b069ce
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.ubifs/Makefile
@@ -0,0 +1,28 @@
+
+CPPFLAGS += -I../include -I../ubi-utils/include
+CPPFLAGS += $(ZLIBCPPFLAGS) $(LZOCPPFLAGS) $(UUIDCPPFLAGS)
+
+ALL_SOURCES=*.[ch] hashtable/*.[ch]
+
+TARGETS = mkfs.ubifs
+
+LDLIBS_mkfs.ubifs = -lz -llzo2 -lm -luuid -L$(BUILDDIR)/../ubi-utils/ -lubi
+LDLIBS_mkfs.ubifs += $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
+
+include ../common.mk
+
+$(BUILDDIR)/mkfs.ubifs: $(addprefix $(BUILDDIR)/,\
+ crc16.o crc32.o lpt.o compr.o devtable.o \
+ hashtable/hashtable.o hashtable/hashtable_itr.o)
+
+clean::
+ rm -f $(BUILDDIR)/hashtable/*.o cscope.*
+
+cscope:
+ @echo $(ALL_SOURCES) > cscope.files
+ @cscope -bR
+ @rm cscope.files
+
+install:: ${TARGETS}
+ mkdir -p ${DESTDIR}/${SBINDIR}
+ install -m 0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/
diff --git a/mtd-utils-1.3.1/mkfs.ubifs/README b/mtd-utils-1.3.1/mkfs.ubifs/README
new file mode 100644
index 0000000..4fbaa7d
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.ubifs/README
@@ -0,0 +1,10 @@
+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-media.h is fs/ubifs/ubifs-media.h from the linux kernel
+* 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/mtd-utils-1.3.1/mkfs.ubifs/compr.c b/mtd-utils-1.3.1/mkfs.ubifs/compr.c
new file mode 100644
index 0000000..e378c5d
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.ubifs/compr.c
@@ -0,0 +1,217 @@
+/*
+ * 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 <zlib.h>
+#include <lzo/lzo1x.h>
+#include <linux/types.h>
+
+#include "compr.h"
+#include "ubifs-media.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/mtd-utils-1.3.1/mkfs.ubifs/compr.h b/mtd-utils-1.3.1/mkfs.ubifs/compr.h
new file mode 100644
index 0000000..e3dd95c
--- /dev/null
+++ b/mtd-utils-1.3.1/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/mtd-utils-1.3.1/mkfs.ubifs/crc16.c b/mtd-utils-1.3.1/mkfs.ubifs/crc16.c
new file mode 100644
index 0000000..a19512e
--- /dev/null
+++ b/mtd-utils-1.3.1/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/mtd-utils-1.3.1/mkfs.ubifs/crc16.h b/mtd-utils-1.3.1/mkfs.ubifs/crc16.h
new file mode 100644
index 0000000..539d21a
--- /dev/null
+++ b/mtd-utils-1.3.1/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/mtd-utils-1.3.1/mkfs.ubifs/crc32.c b/mtd-utils-1.3.1/mkfs.ubifs/crc32.c
new file mode 100644
index 0000000..6b1e50c
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.ubifs/crc32.c
@@ -0,0 +1,95 @@
+/*
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ *
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ */
+
+#include <stdint.h>
+
+const uint32_t crc32_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
diff --git a/mtd-utils-1.3.1/mkfs.ubifs/crc32.h b/mtd-utils-1.3.1/mkfs.ubifs/crc32.h
new file mode 100644
index 0000000..86fc841
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.ubifs/crc32.h
@@ -0,0 +1,22 @@
+/*
+ * This code was taken from the linux kernel. The license is GPL Version 2.
+ */
+
+#ifndef __CRC32_H__
+#define __CRC32_H__
+
+#include <stdint.h>
+
+extern const uint32_t crc32_table[256];
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+static inline uint32_t ubifs_crc32(uint32_t val, const void *ss, int len)
+{
+ const unsigned char *s = ss;
+
+ while (--len >= 0)
+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+ return val;
+}
+
+#endif /* __CRC32_H__ */
diff --git a/mtd-utils-1.3.1/mkfs.ubifs/defs.h b/mtd-utils-1.3.1/mkfs.ubifs/defs.h
new file mode 100644
index 0000000..06cf9e5
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.ubifs/defs.h
@@ -0,0 +1,107 @@
+/*
+ * 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 ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
+#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
+
+#define min_t(t,x,y) ({ \
+ typeof((x)) _x = (x); \
+ typeof((y)) _y = (y); \
+ (_x < _y) ? _x : _y; \
+})
+
+#define max_t(t,x,y) ({ \
+ typeof((x)) _x = (x); \
+ typeof((y)) _y = (y); \
+ (_x > _y) ? _x : _y; \
+})
+
+#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/mtd-utils-1.3.1/mkfs.ubifs/devtable.c b/mtd-utils-1.3.1/mkfs.ubifs/devtable.c
new file mode 100644
index 0000000..dee035d
--- /dev/null
+++ b/mtd-utils-1.3.1/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/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable.c b/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable.c
new file mode 100644
index 0000000..763357e
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable.c
@@ -0,0 +1,274 @@
+/* Copyright (C) 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#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 = sizeof(primes)/sizeof(primes[0]);
+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/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable.h b/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable.h
new file mode 100644
index 0000000..b90781a
--- /dev/null
+++ b/mtd-utils-1.3.1/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/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable_itr.c b/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable_itr.c
new file mode 100644
index 0000000..5dced84
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable_itr.c
@@ -0,0 +1,188 @@
+/* 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;
+}
+
+/*****************************************************************************/
+/* key - return the key of the (key,value) pair at the current position */
+/* value - return the value of the (key,value) pair at the current position */
+
+void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{ return i->e->k; }
+
+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)
+{
+ 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/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable_itr.h b/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable_itr.h
new file mode 100644
index 0000000..eea699a
--- /dev/null
+++ b/mtd-utils-1.3.1/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 */
+
+extern 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 */
+
+extern 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/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable_private.h b/mtd-utils-1.3.1/mkfs.ubifs/hashtable/hashtable_private.h
new file mode 100644
index 0000000..3e95f60
--- /dev/null
+++ b/mtd-utils-1.3.1/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/mtd-utils-1.3.1/mkfs.ubifs/key.h b/mtd-utils-1.3.1/mkfs.ubifs/key.h
new file mode 100644
index 0000000..d3a02d4
--- /dev/null
+++ b/mtd-utils-1.3.1/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/mtd-utils-1.3.1/mkfs.ubifs/lpt.c b/mtd-utils-1.3.1/mkfs.ubifs/lpt.c
new file mode 100644
index 0000000..60002ff
--- /dev/null
+++ b/mtd-utils-1.3.1/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_pnode));
+
+ 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, UBI_SHORTTERM);
+ 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, UBI_SHORTTERM);
+ 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, UBI_SHORTTERM);
+ 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, UBI_SHORTTERM);
+ 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, UBI_SHORTTERM);
+ 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/mtd-utils-1.3.1/mkfs.ubifs/lpt.h b/mtd-utils-1.3.1/mkfs.ubifs/lpt.h
new file mode 100644
index 0000000..4cde59d
--- /dev/null
+++ b/mtd-utils-1.3.1/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/mtd-utils-1.3.1/mkfs.ubifs/mkfs.ubifs.c b/mtd-utils-1.3.1/mkfs.ubifs/mkfs.ubifs.c
new file mode 100644
index 0000000..e4b4e3c
--- /dev/null
+++ b/mtd-utils-1.3.1/mkfs.ubifs/mkfs.ubifs.c
@@ -0,0 +1,2343 @@
+/*
+ * 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
+ */
+
+#include "mkfs.ubifs.h"
+
+#define PROGRAM_VERSION "1.3"
+
+/* 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;
+
+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:h?vVe:c:g:f:P:k:x:X:j:R:l:j:U";
+
+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'},
+ {"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'},
+ {"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"
+"-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"
+"-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 -R parameter specifies amount of bytes reserved for the super-user.\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;
+}
+
+/**
+ * same_dir - determine if two file descriptors refer to the same directory.
+ * @fd1: file descriptor 1
+ * @fd2: file descriptor 2
+ */
+static int same_dir(int fd1, int fd2)
+{
+ struct stat stat1, stat2;
+
+ if (fstat(fd1, &stat1) == -1)
+ return -1;
+ if (fstat(fd2, &stat2) == -1)
+ return -1;
+ return stat1.st_dev == stat2.st_dev && stat1.st_ino == stat2.st_ino;
+}
+
+/**
+ * do_openat - open a file in a directory.
+ * @fd: file descriptor of open directory
+ * @path: path relative to directory
+ * @flags: open flags
+ *
+ * This function is provided because the library function openat is sometimes
+ * not available.
+ */
+static int do_openat(int fd, const char *path, int flags)
+{
+ int ret;
+ char *cwd;
+
+ cwd = getcwd(NULL, 0);
+ if (!cwd)
+ return -1;
+ ret = fchdir(fd);
+ if (ret != -1)
+ ret = open(path, flags);
+ if (chdir(cwd) && !ret)
+ ret = -1;
+ free(cwd);
+ return ret;
+}
+
+/**
+ * in_path - determine if a file is beneath a directory.
+ * @dir_name: directory path name
+ * @file_name: file path name
+ */
+static int in_path(const char *dir_name, const char *file_name)
+{
+ char *fn = strdup(file_name);
+ char *dn;
+ int fd1, fd2, fd3, ret = -1, top_fd;
+
+ if (!fn)
+ return -1;
+ top_fd = open("/", O_RDONLY);
+ if (top_fd != -1) {
+ dn = dirname(fn);
+ fd1 = open(dir_name, O_RDONLY);
+ if (fd1 != -1) {
+ fd2 = open(dn, O_RDONLY);
+ if (fd2 != -1) {
+ while (1) {
+ int same;
+
+ same = same_dir(fd1, fd2);
+ if (same) {
+ ret = same;
+ break;
+ }
+ if (same_dir(fd2, top_fd)) {
+ ret = 0;
+ break;
+ }
+ fd3 = do_openat(fd2, "..", O_RDONLY);
+ if (fd3 == -1)
+ break;
+ close(fd2);
+ fd2 = fd3;
+ }
+ close(fd2);
+ }
+ close(fd1);
+ }
+ close(top_fd);
+ }
+ free(fn);
+ 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 inline int is_power_of_2(unsigned long long n)
+{
+ return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+static int validate_options(void)
+{
+ int tmp;
+
+ if (!output)
+ return err_msg("no output file or UBI volume specified");
+ if (root && in_path(root, output))
+ 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->min_io_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 > 1024*1024)
+ return err_msg("too large LEB size %d", c->leb_size);
+ 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 = strdup(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 'h':
+ case '?':
+ printf("%s", helptext);
+ exit(0);
+ case 'v':
+ verbose = 1;
+ break;
+ case 'V':
+ printf("Version " PROGRAM_VERSION "\n");
+ 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 '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 = strdup(argv[optind]);
+ if (output)
+ out_ubi = !open_ubi(output);
+
+ if (out_ubi) {
+ c->min_io_size = c->di.min_io_size;
+ c->leb_size = c->vi.leb_size;
+ c->max_leb_cnt = c->vi.rsvd_lebs;
+ }
+
+ if (!output)
+ return err_msg("not output device or file specified");
+
+ 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);
+ }
+
+ 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 = ubifs_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)
+ * @dtype: expected data type
+ */
+int write_leb(int lnum, int len, void *buf, int dtype)
+{
+ off64_t pos = (off64_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, dtype))
+ return sys_err_msg("ubi_leb_change_start failed");
+
+ if (lseek64(out_fd, pos, SEEK_SET) != pos)
+ return sys_err_msg("lseek64 failed seeking %lld",
+ (long long)pos);
+
+ if (write(out_fd, buf, c->leb_size) != c->leb_size)
+ return sys_err_msg("write failed writing %d bytes at pos %lld",
+ c->leb_size, (long long)pos);
+
+ return 0;
+}
+
+/**
+ * write_empty_leb - copy the image of an empty LEB to the output target.
+ * @lnum: LEB number
+ * @dtype: expected data type
+ */
+static int write_empty_leb(int lnum, int dtype)
+{
+ return write_leb(lnum, 0, leb_buf, dtype);
+}
+
+/**
+ * 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 = ubifs_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
+ * @dtype: expected data type
+ */
+static int write_node(void *node, int len, int lnum, int dtype)
+{
+ prepare_node(node, len);
+
+ memcpy(leb_buf, node, len);
+
+ len = do_pad(leb_buf, len);
+
+ return write_leb(lnum, len, leb_buf, dtype);
+}
+
+/**
+ * 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);
+ 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, UBI_UNKNOWN);
+ 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, inum,
+ (unsigned)type, 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);