1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2025-03-17 12:18:54 +02:00

purge out mtd-utils

This commit is contained in:
Mirko Vogt 2009-08-18 17:40:05 +02:00 committed by Xiangfu Liu
parent 0fd039053c
commit c16fafb1df
219 changed files with 0 additions and 54498 deletions

View File

@ -1,340 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -1,42 +0,0 @@
#!/bin/bash
function mkftl () {
mknod /dev/ftl$1 b 44 $2
for a in `seq 1 15`; do
mknod /dev/ftl$1$a b 44 `expr $2 + $a`
done
}
function mknftl () {
mknod /dev/nftl$1 b 93 $2
for a in `seq 1 15`; do
mknod /dev/nftl$1$a b 93 `expr $2 + $a`
done
}
function mkrfd () {
mknod /dev/rfd$1 b 256 $2
for a in `seq 1 15`; do
mknod /dev/rfd$1$a b 256 `expr $2 + $a`
done
}
function mkinftl () {
mknod /dev/inftl$1 b 96 $2
for a in `seq 1 15`; do
mknod /dev/inftl$1$a b 96 `expr $2 + $a`
done
}
M=0
for C in a b c d e f g h i j k l m n o p; do
mkftl $C $M
mknftl $C $M
mkrfd $C $M
mkinftl $C $M
let M=M+16
done
for a in `seq 0 16` ; do
mknod /dev/mtd$a c 90 `expr $a + $a`
mknod /dev/mtdr$a c 90 `expr $a + $a + 1`
mknod /dev/mtdblock$a b 31 $a
done

View File

@ -1,102 +0,0 @@
# -*- sh -*-
OPTFLAGS := -O2 -Wall
SBINDIR=/usr/sbin
MANDIR=/usr/share/man
INCLUDEDIR=/usr/include
CROSS=mipsel-linux-
CC := $(CROSS)gcc
CFLAGS := -I./include $(OPTFLAGS)
ifeq ($(origin CROSS),undefined)
BUILDDIR := .
else
# Remove the trailing slash to make the directory name
BUILDDIR := .#$(CROSS:-=)
endif
ifeq ($(WITHOUT_XATTR), 1)
CFLAGS += -DWITHOUT_XATTR
endif
#RAWTARGETS = 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
RAWTARGETS = flash_erase flash_eraseall nanddump nanddump_vfat \
flash_info \
flash_otp_info flash_otp_dump nandwrite nandwrite_mlc \
nandtest \
sumtool #jffs2reader
TARGETS = $(foreach target,$(RAWTARGETS),$(BUILDDIR)/$(target))
SYMLINKS =
%: %.o
$(CC) $(CFLAGS) $(LDFLAGS) -g -o $@ $^
$(BUILDDIR)/%.o: %.c
mkdir -p $(BUILDDIR)
$(CC) $(CFLAGS) -g -c -o $@ $< -g -Wp,-MD,$(BUILDDIR)/.$(<F).dep
.SUFFIXES:
all: $(TARGETS)
make -C $(BUILDDIR)/ubi-utils
IGNORE=${wildcard $(BUILDDIR)/.*.c.dep}
-include ${IGNORE}
clean:
rm -f $(BUILDDIR)/*.o $(TARGETS) $(BUILDDIR)/.*.c.dep $(SYMLINKS)
if [ "$(BUILDDIR)x" != ".x" ]; then rm -rf $(BUILDDIR); fi
make -C $(BUILDDIR)/ubi-utils clean
$(SYMLINKS):
ln -sf ../fs/jffs2/$@ $@
$(BUILDDIR)/mkfs.jffs2: $(BUILDDIR)/crc32.o \
$(BUILDDIR)/compr_rtime.o \
$(BUILDDIR)/mkfs.jffs2.o \
$(BUILDDIR)/compr_zlib.o \
$(BUILDDIR)/compr_lzo.o \
$(BUILDDIR)/compr.o \
$(BUILDDIR)/rbtree.o
$(CC) $(LDFLAGS) -o $@ $^ -lz -llzo2
$(BUILDDIR)/flash_eraseall: $(BUILDDIR)/crc32.o $(BUILDDIR)/flash_eraseall.o
$(CC) $(LDFLAGS) -o $@ $^
$(BUILDDIR)/jffs2reader: $(BUILDDIR)/jffs2reader.o
$(CC) $(LDFLAGS) -o $@ $^ -lz
$(BUILDDIR)/jffs2dump: $(BUILDDIR)/jffs2dump.o $(BUILDDIR)/crc32.o
$(CC) $(LDFLAGS) -o $@ $^
$(BUILDDIR)/sumtool: $(BUILDDIR)/sumtool.o $(BUILDDIR)/crc32.o
$(CC) $(LDFLAGS) -o $@ $^
$(BUILDDIR)/serve_image: $(BUILDDIR)/serve_image.o $(BUILDDIR)/crc32.o $(BUILDDIR)/fec.o
$(CC) $(LDFLAGS) -o $@ $^
$(BUILDDIR)/recv_image: $(BUILDDIR)/recv_image.o $(BUILDDIR)/crc32.o $(BUILDDIR)/fec.o
$(CC) $(LDFLAGS) -o $@ $^
$(BUILDDIR)/fectest: $(BUILDDIR)/fectest.o $(BUILDDIR)/crc32.o $(BUILDDIR)/fec.o
$(CC) $(LDFLAGS) -o $@ $^
install: ${TARGETS}
mkdir -p ${DESTDIR}/${SBINDIR}
install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/
mkdir -p ${DESTDIR}/${MANDIR}/man1
gzip -9c mkfs.jffs2.1 > ${DESTDIR}/${MANDIR}/man1/mkfs.jffs2.1.gz
make -C $(BUILDDIR)/ubi-utils install

View File

@ -1,538 +0,0 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
* University of Szeged, Hungary
*
* For licensing information, see the file 'LICENCE' in this directory
* in the jffs2 directory.
*/
#include "compr.h"
#include <string.h>
#include <stdlib.h>
#include <linux/jffs2.h>
#define FAVOUR_LZO_PERCENT 80
extern int page_size;
/* LIST IMPLEMENTATION (from linux/list.h) */
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = (void *) 0;
entry->prev = (void *) 0;
}
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/* Available compressors are on this list */
static LIST_HEAD(jffs2_compressor_list);
/* Actual compression mode */
static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
void jffs2_set_compression_mode(int mode)
{
jffs2_compression_mode = mode;
}
int jffs2_get_compression_mode(void)
{
return jffs2_compression_mode;
}
/* Statistics for blocks stored without compression */
static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
/* Compression test stuffs */
static int jffs2_compression_check = 0;
static unsigned char *jffs2_compression_check_buf = NULL;
void jffs2_compression_check_set(int yesno)
{
jffs2_compression_check = yesno;
}
int jffs2_compression_check_get(void)
{
return jffs2_compression_check;
}
static int jffs2_error_cnt = 0;
int jffs2_compression_check_errorcnt_get(void)
{
return jffs2_error_cnt;
}
#define JFFS2_BUFFER_FILL 0x55
/* Called before compression (if compression_check is setted) to prepare
the buffer for buffer overflow test */
static void jffs2_decompression_test_prepare(unsigned char *buf, int size)
{
memset(buf,JFFS2_BUFFER_FILL,size+1);
}
/* Called after compression (if compression_check is setted) to test the result */
static void jffs2_decompression_test(struct jffs2_compressor *compr,
unsigned char *data_in, unsigned char *output_buf,
uint32_t cdatalen, uint32_t datalen, uint32_t buf_size)
{
uint32_t i;
/* buffer overflow test */
for (i=buf_size;i>cdatalen;i--) {
if (output_buf[i]!=JFFS2_BUFFER_FILL) {
fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. "
"(bs=%d csize=%d b[%d]=%d)\n", compr->name,
buf_size, cdatalen, i, (int)(output_buf[i]));
jffs2_error_cnt++;
return;
}
}
/* allocing temporary buffer for decompression */
if (!jffs2_compression_check_buf) {
jffs2_compression_check_buf = malloc(page_size);
if (!jffs2_compression_check_buf) {
fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n");
jffs2_compression_check = 0;
return;
}
}
/* decompressing */
if (!compr->decompress) {
fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name);
jffs2_error_cnt++;
return;
}
if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen,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;
}

View File

@ -1,119 +0,0 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
* University of Szeged, Hungary
*
* For licensing information, see the file 'LICENCE' in the
* jffs2 directory.
*/
#ifndef __JFFS2_COMPR_H__
#define __JFFS2_COMPR_H__
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "linux/jffs2.h"
#define CONFIG_JFFS2_ZLIB
#define CONFIG_JFFS2_RTIME
#define CONFIG_JFFS2_LZO
#define JFFS2_RUBINMIPS_PRIORITY 10
#define JFFS2_DYNRUBIN_PRIORITY 20
#define JFFS2_RTIME_PRIORITY 50
#define JFFS2_ZLIB_PRIORITY 60
#define JFFS2_LZO_PRIORITY 80
#define JFFS2_COMPR_MODE_NONE 0
#define JFFS2_COMPR_MODE_PRIORITY 1
#define JFFS2_COMPR_MODE_SIZE 2
#define JFFS2_COMPR_MODE_FAVOURLZO 3
#define kmalloc(a,b) malloc(a)
#define kfree(a) free(a)
#ifndef GFP_KERNEL
#define GFP_KERNEL 0
#endif
#define vmalloc(a) malloc(a)
#define vfree(a) free(a)
#define printk(...) fprintf(stderr,__VA_ARGS__)
#define KERN_EMERG
#define KERN_ALERT
#define KERN_CRIT
#define KERN_ERR
#define KERN_WARNING
#define KERN_NOTICE
#define KERN_INFO
#define KERN_DEBUG
struct list_head {
struct list_head *next, *prev;
};
void jffs2_set_compression_mode(int mode);
int jffs2_get_compression_mode(void);
int jffs2_set_compression_mode_name(const char *mode_name);
int jffs2_enable_compressor_name(const char *name);
int jffs2_disable_compressor_name(const char *name);
int jffs2_set_compressor_priority(const char *name, int priority);
struct jffs2_compressor {
struct list_head list;
int priority; /* used by prirority comr. mode */
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__ */

View File

@ -1,120 +0,0 @@
/*
* JFFS2 LZO Compression Interface.
*
* Copyright (C) 2007 Nokia Corporation. All rights reserved.
*
* Author: Richard Purdie <rpurdie@openedhand.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#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)
{
uint32_t 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;
uint32_t 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);
}

View File

@ -1,119 +0,0 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by Arjan van de Ven <arjanv@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* Very simple lz77-ish encoder.
*
* Theory of operation: Both encoder and decoder have a list of "last
* occurrences" for every possible source-value; after sending the
* first source-byte, the second byte indicated the "run" length of
* matches
*
* The algorithm is intended to only send "whole bytes", no bit-messing.
*
*/
#include <stdint.h>
#include <string.h>
#include "compr.h"
/* _compress returns the compressed size, -1 if bigger */
static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t *sourcelen, uint32_t *dstlen, 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);
}

View File

@ -1,145 +0,0 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
* The original JFFS, from which the design for JFFS2 was derived,
* was designed and implemented by Axis Communications AB.
*
* The contents of this file are subject to the Red Hat eCos Public
* License Version 1.1 (the "Licence"); you may not use this file
* except in compliance with the Licence. You may obtain a copy of
* the Licence at http://www.redhat.com/
*
* Software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the Licence for the specific language governing rights and
* limitations under the Licence.
*
* The Original Code is JFFS2 - Journalling Flash File System, version 2
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License version 2 (the "GPL"), in
* which case the provisions of the GPL are applicable instead of the
* above. If you wish to allow the use of your version of this file
* only under the terms of the GPL and not to allow others to use your
* version of this file under the RHEPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the GPL. If you do not delete the
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*/
#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);
}

View File

@ -1,95 +0,0 @@
/*
* 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
};

View File

@ -1,19 +0,0 @@
#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

View File

@ -1,129 +0,0 @@
# This is a sample device table file for use with mkfs.jffs2. You can
# do all sorts of interesting things with a device table file. For
# example, if you want to adjust the permissions on a particular file
# you can just add an entry like:
# /sbin/foobar f 2755 0 0 - - - - -
# and (assuming the file /sbin/foobar exists) it will be made setuid
# root (regardless of what its permissions are on the host filesystem.
#
# Device table entries take the form of:
# <name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
# where name is the file name, type can be one of:
# f A regular file
# d Directory
# c Character special device file
# b Block special device file
# p Fifo (named pipe)
# uid is the user id for the target file, gid is the group id for the
# target file. The rest of the entried apply only to device special
# file.
# When building a target filesystem, it is desirable to not have to
# become root and then run 'mknod' a thousand times. Using a device
# table you can create device nodes and directories "on the fly".
# Furthermore, you can use a single table entry to create a many device
# minors. For example, if I wanted to create /dev/hda and /dev/hda[0-15]
# I could just use the following two table entries:
# /dev/hda b 640 0 0 3 0 0 0 -
# /dev/hda b 640 0 0 3 1 1 1 15
#
# Have fun
# -Erik Andersen <andersen@codepoet.org>
#
#<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
/dev d 755 0 0 - - - - -
/dev/mem c 640 0 0 1 1 0 0 -
/dev/kmem c 640 0 0 1 2 0 0 -
/dev/null c 640 0 0 1 3 0 0 -
/dev/zero c 640 0 0 1 5 0 0 -
/dev/random c 640 0 0 1 8 0 0 -
/dev/urandom c 640 0 0 1 9 0 0 -
/dev/tty c 666 0 0 5 0 0 0 -
/dev/tty c 666 0 0 4 0 0 1 6
/dev/console c 640 0 0 5 1 0 0 -
/dev/ram b 640 0 0 1 1 0 0 -
/dev/ram b 640 0 0 1 0 0 1 4
/dev/loop b 640 0 0 7 0 0 1 2
/dev/ptmx c 666 0 0 5 2 0 0 -
#/dev/ttyS c 640 0 0 4 64 0 1 4
#/dev/psaux c 640 0 0 10 1 0 0 -
#/dev/rtc c 640 0 0 10 135 0 0 -
# Adjust permissions on some normal files
#/etc/shadow f 600 0 0 - - - - -
#/bin/tinylogin f 4755 0 0 - - - - -
# User-mode Linux stuff
/dev/ubda b 640 0 0 98 0 0 0 -
/dev/ubda b 640 0 0 98 1 1 1 15
# IDE Devices
/dev/hda b 640 0 0 3 0 0 0 -
/dev/hda b 640 0 0 3 1 1 1 15
/dev/hdb b 640 0 0 3 64 0 0 -
/dev/hdb b 640 0 0 3 65 1 1 15
#/dev/hdc b 640 0 0 22 0 0 0 -
#/dev/hdc b 640 0 0 22 1 1 1 15
#/dev/hdd b 640 0 0 22 64 0 0 -
#/dev/hdd b 640 0 0 22 65 1 1 15
#/dev/hde b 640 0 0 33 0 0 0 -
#/dev/hde b 640 0 0 33 1 1 1 15
#/dev/hdf b 640 0 0 33 64 0 0 -
#/dev/hdf b 640 0 0 33 65 1 1 15
#/dev/hdg b 640 0 0 34 0 0 0 -
#/dev/hdg b 640 0 0 34 1 1 1 15
#/dev/hdh b 640 0 0 34 64 0 0 -
#/dev/hdh b 640 0 0 34 65 1 1 15
# SCSI Devices
#/dev/sda b 640 0 0 8 0 0 0 -
#/dev/sda b 640 0 0 8 1 1 1 15
#/dev/sdb b 640 0 0 8 16 0 0 -
#/dev/sdb b 640 0 0 8 17 1 1 15
#/dev/sdc b 640 0 0 8 32 0 0 -
#/dev/sdc b 640 0 0 8 33 1 1 15
#/dev/sdd b 640 0 0 8 48 0 0 -
#/dev/sdd b 640 0 0 8 49 1 1 15
#/dev/sde b 640 0 0 8 64 0 0 -
#/dev/sde b 640 0 0 8 65 1 1 15
#/dev/sdf b 640 0 0 8 80 0 0 -
#/dev/sdf b 640 0 0 8 81 1 1 15
#/dev/sdg b 640 0 0 8 96 0 0 -
#/dev/sdg b 640 0 0 8 97 1 1 15
#/dev/sdh b 640 0 0 8 112 0 0 -
#/dev/sdh b 640 0 0 8 113 1 1 15
#/dev/sg c 640 0 0 21 0 0 1 15
#/dev/scd b 640 0 0 11 0 0 1 15
#/dev/st c 640 0 0 9 0 0 1 8
#/dev/nst c 640 0 0 9 128 0 1 8
#/dev/st c 640 0 0 9 32 1 1 4
#/dev/st c 640 0 0 9 64 1 1 4
#/dev/st c 640 0 0 9 96 1 1 4
# Floppy disk devices
#/dev/fd b 640 0 0 2 0 0 1 2
#/dev/fd0d360 b 640 0 0 2 4 0 0 -
#/dev/fd1d360 b 640 0 0 2 5 0 0 -
#/dev/fd0h1200 b 640 0 0 2 8 0 0 -
#/dev/fd1h1200 b 640 0 0 2 9 0 0 -
#/dev/fd0u1440 b 640 0 0 2 28 0 0 -
#/dev/fd1u1440 b 640 0 0 2 29 0 0 -
#/dev/fd0u2880 b 640 0 0 2 32 0 0 -
#/dev/fd1u2880 b 640 0 0 2 33 0 0 -
# All the proprietary cdrom devices in the world
#/dev/aztcd b 640 0 0 29 0 0 0 -
#/dev/bpcd b 640 0 0 41 0 0 0 -
#/dev/capi20 c 640 0 0 68 0 0 1 2
#/dev/cdu31a b 640 0 0 15 0 0 0 -
#/dev/cdu535 b 640 0 0 24 0 0 0 -
#/dev/cm206cd b 640 0 0 32 0 0 0 -
#/dev/sjcd b 640 0 0 18 0 0 0 -
#/dev/sonycd b 640 0 0 15 0 0 0 -
#/dev/gscd b 640 0 0 16 0 0 0 -
#/dev/sbpcd b 640 0 0 25 0 0 0 -
#/dev/sbpcd b 640 0 0 25 0 0 1 4
#/dev/mcd b 640 0 0 23 0 0 0 -
#/dev/optcd b 640 0 0 17 0 0 0 -

View File

@ -1,148 +0,0 @@
#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;
}

View File

@ -1,317 +0,0 @@
/*
* docfdisk.c: Modify INFTL partition tables
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define _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;
}

View File

@ -1,9 +0,0 @@
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.
---------------------------
---------------------------

View File

@ -1,917 +0,0 @@
/*
* 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>
/*
* compatibility stuff
*/
#ifdef MSDOS /* but also for others, e.g. sun... */
#define NEED_BCOPY
#define bcmp(a,b,n) memcmp(a,b,n)
#endif
#ifdef NEED_BCOPY
#define bcopy(s, d, siz) memcpy((d), (s), (siz))
#define bzero(d, siz) memset((d), '\0', (siz))
#endif
/*
* 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);
bzero(id_row, 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 (bcmp(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
*/
bzero(retval->enc_matrix, 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)
bcopy(src[index], fec, sz*sizeof(gf) ) ;
else if (index < code->n) {
p = &(code->enc_matrix[index*k] );
bzero(fec, 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)
bcopy(src + (index * sz), fec, sz*sizeof(gf) ) ;
else if (index < code->n) {
p = &(code->enc_matrix[index*k] );
bzero(fec, 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) {
bzero(p, k*sizeof(gf) );
p[i] = 1 ;
} else
#endif
if (index[i] < code->n )
bcopy( &(code->enc_matrix[index[i]*k]), p, 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" );
bzero(new_pkt[row], 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) {
bcopy(new_pkt[row], 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 */

View File

@ -1,92 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "mcast_image.h"
#include "crc32.h"
#define ERASE_SIZE 131072
//#define 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;
}

View File

@ -1,189 +0,0 @@
/*
* 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 0x%llx at offset 0x%llx",
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 0x%llx at offset 0x%llx",
erase.length, erase.start);
fflush(stdout);
if(unlock != 0)
{
//Unlock the sector first.
printf("\rPerforming Flash unlock at offset 0x%llx",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,&regcount) == 0)
{
if(regcount == 0)
{
res = non_region_erase(Fd, start, count, unlock);
}
else
{
res = region_erase(Fd, start, count, unlock, regcount);
}
}
return res;
}

View File

@ -1,286 +0,0 @@
/* 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.1.1.1 $"
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[]);
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));
exit(1);
}
if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
fprintf(stderr, "%s: %s: unable to get MTD device info\n", exe_name, mtd_device);
exit(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);
exit(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");
exit(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) {
unsigned long long offset = erase.start;
int ret = ioctl(fd, MEMGETBADBLOCK, &offset);
if (ret > 0) {
if (!quiet)
printf ("\nSkipping bad block at 0x%09llx\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);
exit(1);
}
} else {
fprintf(stderr, "\n%s: %s: MTD get bad block failed: %s\n", exe_name, mtd_device, strerror(errno));
exit(1);
}
}
}
if (!quiet) {
printf
("\rErasing %d Kibyte @ %llx -- %2u %% complete.",
meminfo.erasesize / 1024, erase.start,
(unsigned long long)
erase.start * 100 / meminfo.size);
}
fflush(stdout);
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)
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 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);
}

View File

@ -1,55 +0,0 @@
/*
* 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,&regcount) == 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, &reginfo) == 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;
}

View File

@ -1,84 +0,0 @@
/*
* 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 * mtdInfo.erasesize;
if(ioctl(fd, MEMLOCK, &mtdLockInfo))
{
fprintf(stderr, "Could not lock MTD device: %s\n", argv[1]);
close(fd);
exit(1);
}
return 0;
}

View File

@ -1,54 +0,0 @@
/*
* 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;
}

View File

@ -1,63 +0,0 @@
/*
* 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;
}

View File

@ -1,70 +0,0 @@
/*
* 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;
}

View File

@ -1,96 +0,0 @@
/*
* 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;
}

View File

@ -1,64 +0,0 @@
/*
* 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;
/*
* Parse command line options
*/
if(argc != 2)
{
fprintf(stderr, "USAGE: %s <mtd device>\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);
}
mtdLockInfo.start = 0;
mtdLockInfo.length = mtdInfo.size;
if(ioctl(fd, MEMUNLOCK, &mtdLockInfo))
{
fprintf(stderr, "Could not unlock MTD device: %s\n", argv[1]);
close(fd);
exit(1);
}
return 0;
}

View File

@ -1,389 +0,0 @@
/*
* Copyright (c) 2d3D, Inc.
* Written by Abraham vd Merwe <abraham@2d3d.co.za>
* All rights reserved.
*
* Renamed to flashcp.c to avoid conflicts with fcp from fsh package
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of other contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#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);
if (filestat.st_size % 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);
}

View File

@ -1,232 +0,0 @@
/* Ported to MTD system.
* Based on:
*/
/*======================================================================
Utility to create an FTL partition in a memory region
ftl_check.c 1.10 1999/10/25 20:01:35
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The initial developer of the original code is David A. Hinds
<dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
Alternatively, the contents of this file may be used under the
terms of the GNU Public License version 2 (the "GPL"), in which
case the provisions of the GPL are applicable instead of the
above. If you wish to allow the use of your version of this file
only under the terms of the GPL and not to allow others to use
your version of this file under the MPL, indicate your decision
by deleting the provisions above and replace them with the notice
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
======================================================================*/
#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;
}

View File

@ -1,342 +0,0 @@
/* Ported to MTD system.
* Based on:
*/
/*======================================================================
Utility to create an FTL partition in a memory region
ftl_format.c 1.13 1999/10/25 20:01:35
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The initial developer of the original code is David A. Hinds
<dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
Alternatively, the contents of this file may be used under the
terms of the GNU Public License version 2 (the "GPL"), in which
case the provisions of the GPL are applicable instead of the
above. If you wish to allow the use of your version of this file
only under the terms of the GPL and not to allow others to use
your version of this file under the MPL, indicate your decision
by deleting the provisions above and replace them with the notice
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
======================================================================*/
#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;
}

View File

@ -1,218 +0,0 @@
/*
* 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.1.1.1 2008-05-13 07:15:32 yrtan 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__ */

View File

@ -1,76 +0,0 @@
/*
* $Id: ftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan 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__ */

View File

@ -1,91 +0,0 @@
/*
* $Id: inftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan 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__ */

View File

@ -1,82 +0,0 @@
/*
* $Id: jffs2-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan 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__ */

View File

@ -1,170 +0,0 @@
/*
* $Id: mtd-abi.h,v 1.1.1.1 2008-10-30 14:29:21 lhhuang Exp $
*
* Portions of MTD ABI definition which are shared by kernel and user space
*/
#ifndef __MTD_ABI_H__
#define __MTD_ABI_H__
#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into
separate files was to avoid #ifdef __KERNEL__ */
#define __user
#endif
typedef unsigned long long size_mtd_t;
typedef unsigned long long loff_mtd_t;
struct erase_info_user {
uint64_t start;
uint64_t length;
};
struct mtd_oob_buf {
uint32_t start;
uint32_t length;
unsigned char __user *ptr;
};
struct mtd_page_buf {
uint32_t start; //page start address
uint32_t ooblength;
uint32_t datlength;
unsigned char __user *oobptr;
unsigned char __user *datptr;
};
#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;
uint64_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 {
uint64_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_mtd_t)
#define MEMSETBADBLOCK _IOW('M', 12, loff_mtd_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)
#define MEMWRITEPAGE _IOWR('M', 20, struct mtd_page_buf)
/*
* 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[104]; /* more fields(13*8) are required for
* 8-bit BCH ECC and 4KB pagesize nand, by Regen */
};
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[128];
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__ */

View File

@ -1,21 +0,0 @@
/*
* $Id: mtd-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan 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__ */

View File

@ -1,76 +0,0 @@
/*
* $Id: nftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan 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__ */

View File

@ -1,372 +0,0 @@
/*
* 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. May be included by user-space.
*/
#ifndef __UBI_HEADER_H__
#define __UBI_HEADER_H__
#include <stdint.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 unit 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(uint32_t))
#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(uint32_t))
/**
* 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
* @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 then 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.
*/
struct ubi_ec_hdr {
uint32_t magic;
uint8_t version;
uint8_t padding1[3];
uint64_t ec; /* Warning: the current limit is 31-bit anyway! */
uint32_t vid_hdr_offset;
uint32_t data_offset;
uint8_t padding2[36];
uint32_t 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
* @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be
* removed, kept only for not breaking older UBI users)
* @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
* @padding1: reserved for future, zeroes
* @sqnum: sequence number
* @padding2: 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 then 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.
*
* Note, there is an obsolete @leb_ver field which was used instead of @sqnum
* in the past. But it is not used anymore and we keep it in order to be able
* to deal with old UBI images. It will be removed at some point.
*
* 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 unit, then
* the wear-leveling unit 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 {
uint32_t magic;
uint8_t version;
uint8_t vol_type;
uint8_t copy_flag;
uint8_t compat;
uint32_t vol_id;
uint32_t lnum;
uint32_t leb_ver; /* obsolete, to be removed, don't use */
uint32_t data_size;
uint32_t used_ebs;
uint32_t data_pad;
uint32_t data_crc;
uint8_t padding1[4];
uint64_t sqnum;
uint8_t padding2[12];
uint32_t 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(uint32_t))
/**
* 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 {
uint32_t reserved_pebs;
uint32_t alignment;
uint32_t data_pad;
uint8_t vol_type;
uint8_t upd_marker;
uint16_t name_len;
uint8_t name[UBI_VOL_NAME_MAX+1];
uint8_t flags;
uint8_t padding[23];
uint32_t crc;
} __attribute__ ((packed));
#endif /* !__UBI_HEADER_H__ */

View File

@ -1,284 +0,0 @@
/*
* 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__
#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into
separate files was to avoid #ifdef __KERNEL__ */
#define __user
#endif
/*
* 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 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);
*
* Atomic eraseblock change
* ~~~~~~~~~~~~~~~~~~~~~~~~
*
* Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL
* command of the corresponding UBI volume character device. A pointer to
* &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is
* expected to write the requested amount of bytes. This is similar to the
* "volume update" IOCTL.
*/
/*
* 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)
/* 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)
/* An eraseblock erasure command, used for debugging, disabled by default */
#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
/* An atomic eraseblock change command */
#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t)
/* Start UBI leb read */
#define UBI_IOCLEBREAD _IOWR(UBI_VOL_IOC_MAGIC, 3, struct ubi_leb)
/* Maximum MTD device name length supported by UBI */
#define MAX_UBI_MTD_NAME_LEN 127
/*
* 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,
};
/**
* 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;
uint8_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 then 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_leb_change_req - a data structure used in atomic logical
* eraseblock 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;
uint8_t dtype;
uint8_t padding[7];
} __attribute__ ((packed));
/**
* struct ubi_leb - a data structure describe LEB.
* @lnum: logical eraseblock number to dump
* @lebbuf: LEB data buffer
*/
struct ubi_leb{
unsigned int lnum;
char __user *buf;
};
#endif /* __UBI_USER_H__ */

View File

@ -1,51 +0,0 @@
#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

View File

@ -1,359 +0,0 @@
/*
* Dump JFFS filesystem.
* Useful when it buggers up.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <linux/types.h>
#include <asm/byteorder.h>
#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;
}
}
}

View File

@ -1,690 +0,0 @@
/*
* dumpjffs2.c
*
* Copyright (C) 2003 Thomas Gleixner (tglx@linutronix.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Overview:
* This utility dumps the contents of a binary JFFS2 image
*
*
* Bug/ToDo:
*/
#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.1.1.1 $"
#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: dumpjffs2 [OPTION] INPUTFILE\n"
"Dumps the contents of a binary JFFS2 image.\n"
"\n"
" --help display this help and exit\n"
" --version output 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 fname --endianconvert=fname convert image endianness, output to file fname\n"
"-r --recalccrc recalc name and data crc on endian conversion\n"
"-d len --datsize=len size of data chunks, when oob data in binary image (NAND only)\n"
"-o len --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);
}

View File

@ -1,939 +0,0 @@
/* vi: set sw=4 ts=4: */
/*
* jffs2reader v0.0.18 A jffs2 image reader
*
* Copyright (c) 2001 Jari Kirma <Jari.Kirma@hut.fi>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the author be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must
* not claim that you wrote the original software. If you use this
* software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must
* not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
*
*********
* This code was altered September 2001
* Changes are Copyright (c) Erik Andersen <andersen@codepoet.org>
*
* In compliance with (2) above, this is hereby marked as an altered
* version of this software. It has been altered as follows:
* *) Listing a directory now mimics the behavior of 'ls -l'
* *) Support for recursive listing has been added
* *) Without options, does a recursive 'ls' on the whole filesystem
* *) option parsing now uses getopt()
* *) Now uses printf, and error messages go to stderr.
* *) The copyright notice has been cleaned up and reformatted
* *) The code has been reformatted
* *) Several twisty code paths have been fixed so I can understand them.
* -Erik, 1 September 2001
*
* *) Made it show major/minor numbers for device nodes
* *) Made it show symlink targets
* -Erik, 13 September 2001
*/
/*
TODO:
- Add CRC checking code to places marked with XXX.
- Add support for other node compression types.
- Test with real life images.
- Maybe port into bootloader.
*/
/*
BUGS:
- Doesn't check CRC checksums.
*/
#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);
}

View File

@ -1,123 +0,0 @@
#!/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

View File

@ -1,54 +0,0 @@
#include <stdint.h>
#define PKT_SIZE 2820
struct image_pkt_hdr {
uint32_t resend;
uint32_t totcrc;
uint32_t nr_blocks;
uint32_t blocksize;
uint32_t block_crc;
uint32_t block_nr;
uint32_t pkt_sequence;
uint16_t pkt_nr;
uint16_t nr_pkts;
uint32_t thislen;
uint32_t thiscrc;
};
struct image_pkt {
struct image_pkt_hdr hdr;
unsigned char data[PKT_SIZE];
};
struct fec_parms;
/* k - number of actual data packets
* n - total number of packets including data and redundant packets
* (actual packet size isn't relevant here) */
struct fec_parms *fec_new(int k, int n);
void fec_free(struct fec_parms *p);
/* src - array of (n) pointers to data packets
* fec - buffer for packet to be generated
* index - index of packet to be generated (0 <= index < n)
* sz - data packet size
*
* _linear version just takes a pointer to the raw data; no
* mucking about with packet pointers.
*/
void fec_encode(struct fec_parms *code, unsigned char *src[],
unsigned char *fec, int index, int sz);
void fec_encode_linear(struct fec_parms *code, unsigned char *src,
unsigned char *fec, int index, int sz);
/* data - array of (k) pointers to data packets, in arbitrary order (see i)
* i - indices of (data) packets
* sz - data packet size
*
* Will never fail as long as you give it (k) individual data packets.
* Will re-order the (data) pointers but not the indices -- data packets
* are ordered on return.
*/
int fec_decode(struct fec_parms *code, unsigned char *data[],
int i[], int sz);

View File

@ -1,259 +0,0 @@
.TH MKFS.JFFS2 1
.SH NAME
mkfs.jffs2 \- Create a JFFS2 file system image from directory
.SH SYNOPSIS
.B mkfs.jffs2
[
.B -p,--pad[=SIZE]
]
[
.B -r,-d,--root
.I directory
]
[
.B -s,--pagesize=SIZE
]
[
.B -e,--eraseblock=SIZE
]
[
.B -c,--cleanmarker=SIZE
]
[
.B -n,--no-cleanmarkers
]
[
.B -o,--output
.I image.jffs2
]
[
.B -l,--little-endian
]
[
.B -b,--big-endian
]
[
.B -D,--devtable=FILE
]
[
.B -f,--faketime
]
[
.B -q,--squash
]
[
.B -U,--squash-uids
]
[
.B -P,--squash-perms
]
[
.B --with-xattr
]
[
.B --with-selinux
]
[
.B --with-posix-acl
]
[
.B -m,--compression-mode=MODE
]
[
.B -x,--disable-compressor=NAME
]
[
.B -X,--enable-compressor=NAME
]
[
.B -y,--compressor-priority=PRIORITY:NAME
]
[
.B -L,--list-compressors
]
[
.B -t,--test-compression
]
[
.B -h,--help
]
[
.B -v,--verbose
]
[
.B -V,--version
]
[
.B -i,--incremental
.I image.jffs2
]
.SH DESCRIPTION
The program
.B mkfs.jffs2
creates a JFFS2 (Second Journalling Flash File System) file system
image and writes the resulting image to the file specified by the
.B -o
option or by default to the standard output, unless the standard
output is a terminal device in which case mkfs.jffs2 will abort.
The file system image is created using the files and directories
contained in the directory specified by the option
.B -r
or the present directory, if the
.B -r
option is not specified.
Each block of the files to be placed into the file system image
are compressed using one of the 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 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)

View File

@ -1,40 +0,0 @@
Summary: Tools for maintaining Memory Technology Devices
Name: mtd-utils
Version: 1.0
Release: 1
License: GPL
Group: Applications/System
URL: http://www.linux-mtd.infradead.org/
Source0: %{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
%description
This package contains tools for erasing and formatting flash devices,
including JFFS2, M-Systems DiskOnChip devices, etc.
%prep
%setup -q
%build
make -C util
%install
rm -rf $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT -C util install
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root,-)
/usr/sbin
/usr/man/man1/mkfs.jffs2.1.gz
/usr/include/mtd
%doc
%changelog
* Wed May 5 2004 <dwmw2@infradead.org> - 1.0
- Initial build.

View File

@ -1,418 +0,0 @@
/*
* Copyright (c) 2d3D, Inc.
* Written by Abraham vd Merwe <abraham@2d3d.co.za>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of other contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mtd/mtd-user.h>
/*
* MEMGETINFO
*/
static int getmeminfo (int fd,struct mtd_info_user *mtd)
{
return (ioctl (fd,MEMGETINFO,mtd));
}
/*
* MEMERASE
*/
static int memerase (int fd,struct erase_info_user *erase)
{
return (ioctl (fd,MEMERASE,erase));
}
/*
* MEMGETREGIONCOUNT
* MEMGETREGIONINFO
*/
static int getregions (int fd,struct region_info_user *regions,int *n)
{
int i,err;
err = ioctl (fd,MEMGETREGIONCOUNT,n);
if (err) return (err);
for (i = 0; i < *n; i++)
{
regions[i].regionindex = i;
err = ioctl (fd,MEMGETREGIONINFO,&regions[i]);
if (err) return (err);
}
return (0);
}
int erase_flash (int fd,u_int32_t offset,u_int32_t bytes)
{
int err;
struct erase_info_user erase;
erase.start = offset;
erase.length = bytes;
err = memerase (fd,&erase);
if (err < 0)
{
perror ("MEMERASE");
return (1);
}
fprintf (stderr,"Erased %d bytes from address 0x%.8x in flash\n",bytes,offset);
return (0);
}
void printsize (u_int32_t x)
{
int i;
static const char *flags = "KMGT";
printf ("%u ",x);
for (i = 0; x >= 1024 && flags[i] != '\0'; i++) x /= 1024;
i--;
if (i >= 0) printf ("(%u%c)",x,flags[i]);
}
int flash_to_file (int fd,u_int32_t offset,size_t len,const char *filename)
{
u_int8_t *buf = NULL;
int outfd,err;
int size = len * sizeof (u_int8_t);
int n = len;
if (offset != lseek (fd,offset,SEEK_SET))
{
perror ("lseek()");
goto err0;
}
outfd = creat (filename,O_WRONLY);
if (outfd < 0)
{
perror ("creat()");
goto err1;
}
retry:
if ((buf = (u_int8_t *) malloc (size)) == NULL)
{
#define BUF_SIZE (64 * 1024 * sizeof (u_int8_t))
fprintf (stderr, "%s: malloc(%#x)\n", __FUNCTION__, size);
if (size != BUF_SIZE) {
size = BUF_SIZE;
fprintf (stderr, "%s: trying buffer size %#x\n", __FUNCTION__, size);
goto retry;
}
perror ("malloc()");
goto err0;
}
do {
if (n <= size)
size = n;
err = read (fd,buf,size);
if (err < 0)
{
fprintf (stderr, "%s: read, size %#x, n %#x\n", __FUNCTION__, size, n);
perror ("read()");
goto err2;
}
err = write (outfd,buf,size);
if (err < 0)
{
fprintf (stderr, "%s: write, size %#x, n %#x\n", __FUNCTION__, size, n);
perror ("write()");
goto err2;
}
if (err != size)
{
fprintf (stderr,"Couldn't copy entire buffer to %s. (%d/%d bytes copied)\n",filename,err,size);
goto err2;
}
n -= size;
} while (n > 0);
if (buf != NULL)
free (buf);
close (outfd);
printf ("Copied %d bytes from address 0x%.8x in flash to %s\n",len,offset,filename);
return (0);
err2:
close (outfd);
err1:
if (buf != NULL)
free (buf);
err0:
return (1);
}
int file_to_flash (int fd,u_int32_t offset,u_int32_t len,const char *filename)
{
u_int8_t *buf = NULL;
FILE *fp;
int err;
int size = len * sizeof (u_int8_t);
int n = len;
if (offset != lseek (fd,offset,SEEK_SET))
{
perror ("lseek()");
return (1);
}
if ((fp = fopen (filename,"r")) == NULL)
{
perror ("fopen()");
return (1);
}
retry:
if ((buf = (u_int8_t *) malloc (size)) == NULL)
{
fprintf (stderr, "%s: malloc(%#x) failed\n", __FUNCTION__, size);
if (size != BUF_SIZE) {
size = BUF_SIZE;
fprintf (stderr, "%s: trying buffer size %#x\n", __FUNCTION__, size);
goto retry;
}
perror ("malloc()");
fclose (fp);
return (1);
}
do {
if (n <= size)
size = n;
if (fread (buf,size,1,fp) != 1 || ferror (fp))
{
fprintf (stderr, "%s: fread, size %#x, n %#x\n", __FUNCTION__, size, n);
perror ("fread()");
free (buf);
fclose (fp);
return (1);
}
err = write (fd,buf,size);
if (err < 0)
{
fprintf (stderr, "%s: write, size %#x, n %#x\n", __FUNCTION__, size, n);
perror ("write()");
free (buf);
fclose (fp);
return (1);
}
n -= size;
} while (n > 0);
if (buf != NULL)
free (buf);
fclose (fp);
printf ("Copied %d bytes from %s to address 0x%.8x in flash\n",len,filename,offset);
return (0);
}
int showinfo (int fd)
{
int i,err,n;
struct mtd_info_user mtd;
static struct region_info_user region[1024];
err = getmeminfo (fd,&mtd);
if (err < 0)
{
perror ("MEMGETINFO");
return (1);
}
err = getregions (fd,region,&n);
if (err < 0)
{
perror ("MEMGETREGIONCOUNT");
return (1);
}
printf ("mtd.type = ");
switch (mtd.type)
{
case MTD_ABSENT:
printf ("MTD_ABSENT");
break;
case MTD_RAM:
printf ("MTD_RAM");
break;
case MTD_ROM:
printf ("MTD_ROM");
break;
case MTD_NORFLASH:
printf ("MTD_NORFLASH");
break;
case MTD_NANDFLASH:
printf ("MTD_NANDFLASH");
break;
case MTD_DATAFLASH:
printf ("MTD_DATAFLASH");
break;
case MTD_UBIVOLUME:
printf ("MTD_UBIVOLUME");
default:
printf ("(unknown type - new MTD API maybe?)");
}
printf ("\nmtd.flags = ");
if (mtd.flags == MTD_CAP_ROM)
printf ("MTD_CAP_ROM");
else if (mtd.flags == MTD_CAP_RAM)
printf ("MTD_CAP_RAM");
else if (mtd.flags == MTD_CAP_NORFLASH)
printf ("MTD_CAP_NORFLASH");
else if (mtd.flags == MTD_CAP_NANDFLASH)
printf ("MTD_CAP_NANDFLASH");
else if (mtd.flags == MTD_WRITEABLE)
printf ("MTD_WRITEABLE");
else
{
int first = 1;
static struct
{
const char *name;
int value;
} flags[] =
{
{ "MTD_WRITEABLE", MTD_WRITEABLE },
{ "MTD_BIT_WRITEABLE", MTD_BIT_WRITEABLE },
{ "MTD_NO_ERASE", MTD_NO_ERASE },
{ "MTD_STUPID_LOCK", MTD_STUPID_LOCK },
{ NULL, -1 }
};
for (i = 0; flags[i].name != NULL; i++)
if (mtd.flags & flags[i].value)
{
if (first)
{
printf (flags[i].name);
first = 0;
}
else printf (" | %s",flags[i].name);
}
}
printf ("\nmtd.size = ");
printsize (mtd.size);
printf ("\nmtd.erasesize = ");
printsize (mtd.erasesize);
printf ("\nmtd.writesize = ");
printsize (mtd.writesize);
printf ("\nmtd.oobsize = ");
printsize (mtd.oobsize);
printf ("\n"
"regions = %d\n"
"\n",
n);
for (i = 0; i < n; i++)
{
printf ("region[%d].offset = 0x%.8x\n"
"region[%d].erasesize = ",
i,region[i].offset,i);
printsize (region[i].erasesize);
printf ("\nregion[%d].numblocks = %d\n"
"region[%d].regionindex = %d\n",
i,region[i].numblocks,
i,region[i].regionindex);
}
return (0);
}
void showusage (const char *progname)
{
fprintf (stderr,
"usage: %s info <device>\n"
" %s read <device> <offset> <len> <dest-filename>\n"
" %s write <device> <offset> <len> <source-filename>\n"
" %s erase <device> <offset> <len>\n",
progname,
progname,
progname,
progname);
exit (1);
}
#define OPT_INFO 1
#define OPT_READ 2
#define OPT_WRITE 3
#define OPT_ERASE 4
int main (int argc,char *argv[])
{
const char *progname;
int err = 0,fd,option = OPT_INFO;
int open_flag;
(progname = strrchr (argv[0],'/')) ? progname++ : (progname = argv[0]);
/* parse command-line options */
if (argc == 3 && !strcmp (argv[1],"info"))
option = OPT_INFO;
else if (argc == 6 && !strcmp (argv[1],"read"))
option = OPT_READ;
else if (argc == 6 && !strcmp (argv[1],"write"))
option = OPT_WRITE;
else if (argc == 5 && !strcmp (argv[1],"erase"))
option = OPT_ERASE;
else
showusage (progname);
/* open device */
open_flag = (option==OPT_INFO || option==OPT_READ) ? O_RDONLY : O_RDWR;
if ((fd = open (argv[2],O_SYNC | open_flag)) < 0)
{
perror ("open()");
exit (1);
}
switch (option)
{
case OPT_INFO:
showinfo (fd);
break;
case OPT_READ:
err = flash_to_file (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0),argv[5]);
break;
case OPT_WRITE:
err = file_to_flash (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0),argv[5]);
break;
case OPT_ERASE:
err = erase_flash (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0));
break;
}
/* close device */
if (close (fd) < 0)
perror ("close()");
exit (err);
}

View File

@ -1,403 +0,0 @@
/*
* nanddump.c
*
* Copyright (C) 2000 David Woodhouse (dwmw2@infradead.org)
* Steven J. Hill (sjhill@realitydiluted.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Overview:
* This utility dumps the contents of raw NAND chips or NAND
* chips contained in DoC devices.
*/
#define _GNU_SOURCE
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <asm/types.h>
#include <mtd/mtd-user.h>
#define PROGRAM "nanddump"
#define VERSION "$Revision: 1.1.1.1 $"
struct nand_oobinfo none_oobinfo = {
.useecc = MTD_NANDECC_OFF,
};
void display_help (void)
{
printf("Usage: nanddump [OPTIONS] MTD-device\n"
"Dumps the contents of a nand mtd partition.\n"
"\n"
" --help display this help and exit\n"
" --version output version information and exit\n"
"-f file --file=file dump to file\n"
"-i --ignoreerrors ignore errors\n"
"-l length --length=length length\n"
"-n --noecc read without error correction\n"
"-o --omitoob omit oob data\n"
"-b --omitbad omit bad blocks from the dump\n"
"-p --prettyprint print nice (hexdump)\n"
"-s addr --startaddress=addr start address\n");
exit(0);
}
void display_version (void)
{
printf(PROGRAM " " VERSION "\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 ignoreerrors; // ignore errors
int pretty_print; // print nice in ascii
int noecc; // don't error correct
int omitoob; // omit oob data
unsigned long start_addr; // start address
unsigned long length; // dump length
char *mtddev; // mtd device name
char *dumpfile; // dump file name
int omitbad;
void process_options (int argc, char *argv[])
{
int error = 0;
for (;;) {
int option_index = 0;
static const char *short_options = "bs:f:il:opn";
static const struct option long_options[] = {
{"help", no_argument, 0, 0},
{"version", no_argument, 0, 0},
{"file", required_argument, 0, 'f'},
{"ignoreerrors", no_argument, 0, 'i'},
{"prettyprint", no_argument, 0, 'p'},
{"omitoob", no_argument, 0, 'o'},
{"omitbad", no_argument, 0, 'b'},
{"startaddress", required_argument, 0, 's'},
{"length", required_argument, 0, 'l'},
{"noecc", no_argument, 0, 'n'},
{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 'b':
omitbad = 1;
break;
case 's':
start_addr = strtol(optarg, NULL, 0);
break;
case 'f':
if (!(dumpfile = strdup(optarg))) {
perror("stddup");
exit(1);
}
break;
case 'i':
ignoreerrors = 1;
break;
case 'l':
length = strtol(optarg, NULL, 0);
break;
case 'o':
omitoob = 1;
break;
case 'p':
pretty_print = 1;
break;
case 'n':
noecc = 1;
break;
case '?':
error = 1;
break;
}
}
if ((argc - optind) != 1 || error)
display_help ();
mtddev = argv[optind];
}
/*
* Buffers for reading data from flash
*/
unsigned char readbuf[8192];
unsigned char oobbuf[256];
/*
* Main program
*/
int main(int argc, char **argv)
{
unsigned long ofs, end_addr = 0;
unsigned long long blockstart = 1;
int ret, i, fd, ofd, bs, badblock = 0;
struct mtd_oob_buf oob = {0, 16, oobbuf};
mtd_info_t meminfo;
char pretty_buf[80];
int oobinfochanged = 0 ;
struct nand_oobinfo old_oobinfo;
struct mtd_ecc_stats stat1, stat2;
int eccstats = 0;
process_options(argc, argv);
/* Open MTD device */
if ((fd = open(mtddev, O_RDONLY)) == -1) {
perror("open flash");
exit (1);
}
/* Fill in MTD device capability structure */
if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
perror("MEMGETINFO");
close(fd);
exit (1);
}
/* Make sure device page sizes are valid */
if (!(meminfo.oobsize == 256 && meminfo.writesize == 8192) &&
!(meminfo.oobsize == 128 && meminfo.writesize == 4096) &&
!(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
!(meminfo.oobsize == 32 && meminfo.writesize == 1024) &&
!(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
!(meminfo.oobsize == 8 && meminfo.writesize == 256)) {
fprintf(stderr, "Unknown flash (not normal NAND)\n");
close(fd);
exit(1);
}
/* Read the real oob length */
oob.length = meminfo.oobsize;
if (noecc) {
ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW);
if (ret == 0) {
oobinfochanged = 2;
} else {
switch (errno) {
case ENOTTY:
if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMGETOOBSEL");
close (fd);
exit (1);
}
if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close (fd);
exit (1);
}
oobinfochanged = 1;
break;
default:
perror ("MTDFILEMODE");
close (fd);
exit (1);
}
}
} else {
/* check if we can read ecc stats */
if (!ioctl(fd, ECCGETSTATS, &stat1)) {
eccstats = 1;
fprintf(stderr, "ECC failed: %d\n", stat1.failed);
fprintf(stderr, "ECC corrected: %d\n", stat1.corrected);
fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks);
fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks);
} else
perror("No ECC status information available");
}
/* Open output file for writing. If file name is "-", write to standard
* output. */
if (!dumpfile) {
ofd = STDOUT_FILENO;
} else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) {
perror ("open outfile");
close(fd);
exit(1);
}
/* Initialize start/end addresses and block size */
if (length)
end_addr = start_addr + length;
if (!length || end_addr > meminfo.size)
end_addr = meminfo.size;
bs = meminfo.writesize;
/* Print informative message */
fprintf(stderr, "Block size %u, page size %u, OOB size %u\n",
meminfo.erasesize, meminfo.writesize, meminfo.oobsize);
fprintf(stderr,
"Dumping data starting at 0x%08x and ending at 0x%08x...\n",
(unsigned int) start_addr, (unsigned int) end_addr);
/* Dump the flash contents */
for (ofs = start_addr; ofs < end_addr ; ofs+=bs) {
// new eraseblock , check for bad block
if (blockstart != (ofs & (~meminfo.erasesize + 1))) {
blockstart = ofs & (~meminfo.erasesize + 1);
if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) {
perror("ioctl(MEMGETBADBLOCK)");
goto closeall;
}
}
if (badblock) {
if (omitbad)
continue;
memset (readbuf, 0xff, bs);
} else {
/* Read page data and exit on failure */
if (pread(fd, readbuf, bs, ofs) != bs) {
perror("pread");
goto closeall;
}
}
/* ECC stats available ? */
if (eccstats) {
if (ioctl(fd, ECCGETSTATS, &stat2)) {
perror("ioctl(ECCGETSTATS)");
goto closeall;
}
if (stat1.failed != stat2.failed)
fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
" at offset 0x%08lx\n",
stat2.failed - stat1.failed, ofs);
if (stat1.corrected != stat2.corrected)
fprintf(stderr, "ECC: %d corrected bitflip(s) at"
" offset 0x%08lx\n",
stat2.corrected - stat1.corrected, ofs);
stat1 = stat2;
}
/* Write out page data */
if (pretty_print) {
for (i = 0; i < bs; i += 16) {
sprintf(pretty_buf,
"0x%08x: %02x %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
(unsigned int) (ofs + i), readbuf[i],
readbuf[i+1], readbuf[i+2],
readbuf[i+3], readbuf[i+4],
readbuf[i+5], readbuf[i+6],
readbuf[i+7], readbuf[i+8],
readbuf[i+9], readbuf[i+10],
readbuf[i+11], readbuf[i+12],
readbuf[i+13], readbuf[i+14],
readbuf[i+15]);
write(ofd, pretty_buf, 60);
}
} else
write(ofd, readbuf, bs);
if (omitoob)
continue;
if (badblock) {
memset (readbuf, 0xff, meminfo.oobsize);
} else {
/* Read OOB data and exit on failure */
oob.start = ofs;
if (ioctl(fd, MEMREADOOB, &oob) != 0) {
perror("ioctl(MEMREADOOB)");
goto closeall;
}
}
/* Write out OOB data */
if (pretty_print) {
if (meminfo.oobsize < 16) {
sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x "
"%02x %02x\n",
oobbuf[0], oobbuf[1], oobbuf[2],
oobbuf[3], oobbuf[4], oobbuf[5],
oobbuf[6], oobbuf[7]);
write(ofd, pretty_buf, 48);
continue;
}
for (i = 0; i < meminfo.oobsize; i += 16) {
sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
oobbuf[i], oobbuf[i+1], oobbuf[i+2],
oobbuf[i+3], oobbuf[i+4], oobbuf[i+5],
oobbuf[i+6], oobbuf[i+7], oobbuf[i+8],
oobbuf[i+9], oobbuf[i+10], oobbuf[i+11],
oobbuf[i+12], oobbuf[i+13], oobbuf[i+14],
oobbuf[i+15]);
write(ofd, pretty_buf, 60);
}
} else
write(ofd, oobbuf, meminfo.oobsize);
}
/* reset oobinfo */
if (oobinfochanged == 1) {
if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close(fd);
close(ofd);
return 1;
}
}
/* Close the output file and MTD device */
close(fd);
close(ofd);
/* Exit happy */
return 0;
closeall:
/* The new mode change is per file descriptor ! */
if (oobinfochanged == 1) {
if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
}
}
close(fd);
close(ofd);
exit(1);
}

View File

@ -1,365 +0,0 @@
/*
* nanddump.c
*
* Copyright (C) 2000 David Woodhouse (dwmw2@infradead.org)
* Steven J. Hill (sjhill@realitydiluted.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Overview:
* This utility dumps the contents of raw NAND chips or NAND
* chips contained in DoC devices.
*/
#define _GNU_SOURCE
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <asm/types.h>
#include <mtd/mtd-user.h>
#define PROGRAM "nanddump"
#define VERSION "$Revision: 1.1.1.1 $"
struct nand_oobinfo none_oobinfo = {
.useecc = MTD_NANDECC_OFF,
};
void display_help (void)
{
printf("Usage: nanddump [OPTIONS] MTD-device\n"
"Dumps the contents of a nand mtd partition.\n"
"\n"
" --help display this help and exit\n"
" --version output version information and exit\n"
"-f file --file=file dump to file\n"
"-i --ignoreerrors ignore errors\n"
"-l length --length=length length\n"
"-n --noecc read without error correction\n"
"-o --omitoob omit oob data\n"
"-b --omitbad omit bad blocks from the dump\n"
"-p --prettyprint print nice (hexdump)\n"
"-s addr --startaddress=addr start address\n");
exit(0);
}
void display_version (void)
{
printf(PROGRAM " " VERSION "\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 ignoreerrors; // ignore errors
int pretty_print; // print nice in ascii
int noecc; // don't error correct
int omitoob; // omit oob data
unsigned long start_addr; // start address
unsigned long length; // dump length
char *mtddev; // mtd device name
char *dumpfile; // dump file name
int omitbad;
void process_options (int argc, char *argv[])
{
int error = 0;
for (;;) {
int option_index = 0;
static const char *short_options = "bs:f:il:opn";
static const struct option long_options[] = {
{"help", no_argument, 0, 0},
{"version", no_argument, 0, 0},
{"file", required_argument, 0, 'f'},
{"ignoreerrors", no_argument, 0, 'i'},
{"prettyprint", no_argument, 0, 'p'},
{"omitoob", no_argument, 0, 'o'},
{"omitbad", no_argument, 0, 'b'},
{"startaddress", required_argument, 0, 's'},
{"length", required_argument, 0, 'l'},
{"noecc", no_argument, 0, 'n'},
{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 'b':
omitbad = 1;
break;
case 's':
start_addr = strtol(optarg, NULL, 0);
break;
case 'f':
if (!(dumpfile = strdup(optarg))) {
perror("stddup");
exit(1);
}
break;
case 'i':
ignoreerrors = 1;
break;
case 'l':
length = strtol(optarg, NULL, 0);
break;
case 'o':
omitoob = 1;
break;
case 'p':
pretty_print = 1;
break;
case 'n':
noecc = 1;
break;
case '?':
error = 1;
break;
}
}
if ((argc - optind) != 1 || error)
display_help ();
mtddev = argv[optind];
}
/*
* Buffers for reading data from flash
*/
unsigned char readbuf[8192];
unsigned char oobbuf[256];
/*
* Main program
*/
int main(int argc, char **argv)
{
unsigned long ofs, end_addr = 0;
unsigned long long blockstart = 1;
int ret, fd, ofd, bs, badblock = 0;
struct mtd_oob_buf oob = {0, 16, oobbuf};
mtd_info_t meminfo;
int oobinfochanged = 0 ;
struct nand_oobinfo old_oobinfo;
struct mtd_ecc_stats stat1, stat2;
int eccstats = 0;
process_options(argc, argv);
/* Open MTD device */
if ((fd = open(mtddev, O_RDONLY)) == -1) {
perror("open flash");
exit (1);
}
/* Fill in MTD device capability structure */
if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
perror("MEMGETINFO");
close(fd);
exit (1);
}
/* Make sure device page sizes are valid */
if (!(meminfo.oobsize == 256 && meminfo.writesize == 8192) &&
!(meminfo.oobsize == 128 && meminfo.writesize == 4096) &&
!(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
!(meminfo.oobsize == 32 && meminfo.writesize == 1024) &&
!(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
!(meminfo.oobsize == 8 && meminfo.writesize == 256)) {
fprintf(stderr, "Unknown flash (not normal NAND)\n");
close(fd);
exit(1);
}
/* Read the real oob length */
oob.length = meminfo.oobsize;
if (noecc) {
ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW);
if (ret == 0) {
oobinfochanged = 2;
} else {
switch (errno) {
case ENOTTY:
if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMGETOOBSEL");
close (fd);
exit (1);
}
if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close (fd);
exit (1);
}
oobinfochanged = 1;
break;
default:
perror ("MTDFILEMODE");
close (fd);
exit (1);
}
}
} else {
/* check if we can read ecc stats */
if (!ioctl(fd, ECCGETSTATS, &stat1)) {
eccstats = 1;
fprintf(stderr, "ECC failed: %d\n", stat1.failed);
fprintf(stderr, "ECC corrected: %d\n", stat1.corrected);
fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks);
fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks);
} else
perror("No ECC status information available");
}
/* Open output file for writing. If file name is "-", write to standard
* output. */
if (!dumpfile) {
ofd = STDOUT_FILENO;
} else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) {
perror ("open outfile");
close(fd);
exit(1);
}
/* Initialize start/end addresses and block size */
if (length)
end_addr = start_addr + length;
if (!length || end_addr > meminfo.size)
end_addr = meminfo.size;
bs = meminfo.writesize;
/* Print informative message */
fprintf(stderr, "Block size %u, page size %u, OOB size %u\n",
meminfo.erasesize, meminfo.writesize, meminfo.oobsize);
fprintf(stderr,
"Dumping data starting at 0x%08x and ending at 0x%08x...\n",
(unsigned int) start_addr, (unsigned int) end_addr);
/* Dump the flash contents */
for (ofs = start_addr; ofs < end_addr ; ofs+=bs) {
// new eraseblock , check for bad block
if (blockstart != (ofs & (~meminfo.erasesize + 1))) {
blockstart = ofs & (~meminfo.erasesize + 1);
if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) {
perror("ioctl(MEMGETBADBLOCK)");
goto closeall;
}
}
if (badblock) {
//skip bad block;
ofs += meminfo.erasesize - bs;
continue;
} else {
/* Read page data and exit on failure */
if (pread(fd, readbuf, bs, ofs) != bs) {
perror("pread");
goto closeall;
}
}
/* ECC stats available ? */
if (eccstats) {
if (ioctl(fd, ECCGETSTATS, &stat2)) {
perror("ioctl(ECCGETSTATS)");
goto closeall;
}
if (stat1.failed != stat2.failed)
fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
" at offset 0x%08lx\n",
stat2.failed - stat1.failed, ofs);
if (stat1.corrected != stat2.corrected)
fprintf(stderr, "ECC: %d corrected bitflip(s) at"
" offset 0x%08lx\n",
stat2.corrected - stat1.corrected, ofs);
stat1 = stat2;
}
if (badblock) {
memset (readbuf, 0xff, meminfo.oobsize);
} else {
/* Read OOB data and exit on failure */
oob.start = ofs;
if (ioctl(fd, MEMREADOOB, &oob) != 0) {
perror("ioctl(MEMREADOOB)");
goto closeall;
}
if(oobbuf[2]==0xff && oobbuf[3]==0xff && oobbuf[4]==0xff && oobbuf[5]==0xff){
//skip free block;
ofs += meminfo.erasesize - bs;
continue;
}
}
/* Write out page data */
write(ofd, readbuf, bs);
if (omitoob)
continue;
/* Write out OOB data */
write(ofd, oobbuf, meminfo.oobsize);
}
/* reset oobinfo */
if (oobinfochanged == 1) {
if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close(fd);
close(ofd);
return 1;
}
}
/* Close the output file and MTD device */
close(fd);
close(ofd);
/* Exit happy */
return 0;
closeall:
/* The new mode change is per file descriptor ! */
if (oobinfochanged == 1) {
if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
}
}
close(fd);
close(ofd);
exit(1);
}

View File

@ -1,284 +0,0 @@
#define _GNU_SOURCE
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <getopt.h>
#include <asm/types.h>
#include "mtd/mtd-user.h"
void usage(void)
{
fprintf(stderr, "usage: nandtest [OPTIONS] <device>\n\n"
" -h, --help Display this help output\n"
" -m, --markbad Mark blocks bad if they appear so\n"
" -s, --seed Supply random seed\n"
" -p, --passes Number of passes\n"
" -o, --offset Start offset on flash\n"
" -l, --length Length of flash to test\n"
" -k, --keep Restore existing contents after test\n"
"Warning: it is just used for SLC NAND!\n");
exit(1);
}
struct mtd_info_user meminfo;
struct mtd_ecc_stats oldstats, newstats;
int fd;
int markbad=0;
int seed;
int erase_and_write(loff_mtd_t ofs, unsigned char *data, unsigned char *rbuf)
{
struct erase_info_user er;
ssize_t len;
int i;
printf("\r%09llx: erasing... ", (loff_mtd_t)ofs);
fflush(stdout);
er.start = ofs;
er.length = meminfo.erasesize;
if (ioctl(fd, MEMERASE, &er)) {
perror("MEMERASE");
if (markbad) {
printf("Mark block bad at %09llx\n", (loff_mtd_t)ofs);
ioctl(fd, MEMSETBADBLOCK, &ofs);
}
return 1;
}
printf("\r%09llx: writing...", (loff_mtd_t)ofs);
fflush(stdout);
len = pwrite(fd, data, meminfo.erasesize, ofs);
if (len < 0) {
printf("\n");
perror("write");
if (markbad) {
printf("Mark block bad at %09llx\n", (loff_mtd_t)ofs);
ioctl(fd, MEMSETBADBLOCK, &ofs);
}
return 1;
}
if (len < meminfo.erasesize) {
printf("\n");
fprintf(stderr, "Short write (%d bytes)\n", len);
exit(1);
}
printf("\r%09llx: reading...", (loff_mtd_t)ofs);
fflush(stdout);
len = pread(fd, rbuf, meminfo.erasesize, ofs);
if (len < meminfo.erasesize) {
printf("\n");
if (len)
fprintf(stderr, "Short read (%d bytes)\n", len);
else
perror("read");
exit(1);
}
if (ioctl(fd, ECCGETSTATS, &newstats)) {
printf("\n");
perror("ECCGETSTATS");
close(fd);
exit(1);
}
if (newstats.corrected > oldstats.corrected) {
printf("\nECC corrected at %09llx\n", (loff_mtd_t) ofs);
oldstats.corrected = newstats.corrected;
}
if (newstats.failed > oldstats.failed) {
printf("\nECC failed at %09llx\n", (loff_mtd_t) ofs);
oldstats.corrected = newstats.corrected;
}
if (len < meminfo.erasesize)
exit(1);
printf("\r%09llx: checking...", (loff_mtd_t)ofs);
fflush(stdout);
if (memcmp(data, rbuf, meminfo.erasesize)) {
printf("\n");
fprintf(stderr, "compare failed. seed %d\n", seed);
for (i=0; i<meminfo.erasesize; i++) {
if (data[i] != rbuf[i])
printf("Byte 0x%x is %02x should be %02x\n",
i, rbuf[i], data[i]);
}
exit(1);
}
return 0;
}
/*
* Main program
*/
int main(int argc, char **argv)
{
int i;
unsigned char *wbuf, *rbuf, *kbuf;
int pass;
int nr_passes = 1;
int keep_contents = 0;
uint64_t offset = 0;
uint64_t length = -1;
for (;;) {
static const char *short_options="hkl:mo:p:s:";
static const struct option long_options[] = {
{ "help", no_argument, 0, 'h' },
{ "markbad", no_argument, 0, 'm' },
{ "seed", required_argument, 0, 's' },
{ "passes", required_argument, 0, 'p' },
{ "offset", required_argument, 0, 'o' },
{ "length", required_argument, 0, 'l' },
{ "keep", no_argument, 0, 'k' },
{0, 0, 0, 0},
};
int option_index = 0;
int c = getopt_long(argc, argv, short_options, long_options, &option_index);
if (c == EOF)
break;
switch (c) {
case 'h':
case '?':
usage();
break;
case 'm':
markbad = 1;
break;
case 'k':
keep_contents = 1;
break;
case 's':
seed = atol(optarg);
break;
case 'p':
nr_passes = atol(optarg);
break;
case 'o':
offset = atol(optarg);
break;
case 'l':
length = strtol(optarg, NULL, 0);
break;
}
}
if (argc - optind != 1)
usage();
fd = open(argv[optind], O_RDWR);
if (fd < 0) {
perror("open");
exit(1);
}
if (ioctl(fd, MEMGETINFO, &meminfo)) {
perror("MEMGETINFO");
close(fd);
exit(1);
}
if (length == -1)
length = meminfo.size;
if (offset % meminfo.erasesize) {
fprintf(stderr, "Offset %09llx not multiple of erase size %x\n",
offset, meminfo.erasesize);
exit(1);
}
if (length % meminfo.erasesize) {
fprintf(stderr, "Length %09llx not multiple of erase size %x\n",
length, meminfo.erasesize);
exit(1);
}
if (length + offset > meminfo.size) {
fprintf(stderr, "Length %09llx + offset %09llx exceeds device size %09llx\n",
length, offset, meminfo.size);
exit(1);
}
wbuf = malloc(meminfo.erasesize * 3);
if (!wbuf) {
fprintf(stderr, "Could not allocate %d bytes for buffer\n",
meminfo.erasesize * 2);
exit(1);
}
rbuf = wbuf + meminfo.erasesize;
kbuf = rbuf + meminfo.erasesize;
if (ioctl(fd, ECCGETSTATS, &oldstats)) {
perror("ECCGETSTATS");
close(fd);
exit(1);
}
printf("ECC corrections: %d\n", oldstats.corrected);
printf("ECC failures : %d\n", oldstats.failed);
printf("Bad blocks : %d\n", oldstats.badblocks);
printf("BBT blocks : %d\n", oldstats.bbtblocks);
for (pass = 0; pass < nr_passes; pass++) {
loff_mtd_t test_ofs;
for (test_ofs = offset; test_ofs < offset+length; test_ofs += meminfo.erasesize) {
ssize_t len;
seed = rand();
srand(seed);
if (ioctl(fd, MEMGETBADBLOCK, &test_ofs)) {
printf("\rBad block at 0x%09llx\n", test_ofs);
continue;
}
for (i=0; i<meminfo.erasesize; i++)
wbuf[i] = rand();
if (keep_contents) {
printf("\r%09llx: reading... ", test_ofs);
fflush(stdout);
len = pread(fd, rbuf, meminfo.erasesize, test_ofs);
if (len < meminfo.erasesize) {
printf("\n");
if (len)
fprintf(stderr, "Short read (%d bytes)\n", len);
else
perror("read");
exit(1);
}
}
if (erase_and_write(test_ofs, wbuf, rbuf))
continue;
if (keep_contents)
erase_and_write(test_ofs, kbuf, rbuf);
}
printf("\nFinished pass %d successfully\n", pass+1);
}
/* Return happy */
return 0;
}

View File

@ -1,525 +0,0 @@
/*
* nandwrite.c
*
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
* 2003 Thomas Gleixner (tglx@linutronix.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Overview:
* This utility writes a binary image directly to a NAND flash
* chip or NAND chips contained in DoC devices. This is the
* "inverse operation" of nanddump.
*
* tglx: Major rewrite to handle bad blocks, write data with or without ECC
* write oob data only on request
*
* Bug/ToDo:
*/
#define _GNU_SOURCE
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <getopt.h>
#include <asm/types.h>
#include "mtd/mtd-user.h"
#define PROGRAM "nandwrite"
#define VERSION "$Revision: 1.1.1.1 $"
#define MAX_PAGE_SIZE 4096
#define MAX_OOB_SIZE 128
/*
* Buffer array used for writing data
*/
unsigned char writebuf[MAX_PAGE_SIZE];
unsigned char oobbuf[MAX_OOB_SIZE];
unsigned char oobreadbuf[MAX_OOB_SIZE];
// oob layouts to pass into the kernel as default
struct nand_oobinfo none_oobinfo = {
.useecc = MTD_NANDECC_OFF,
};
struct nand_oobinfo jffs2_oobinfo = {
.useecc = MTD_NANDECC_PLACE,
.eccbytes = 6,
.eccpos = { 0, 1, 2, 3, 6, 7 }
};
struct nand_oobinfo yaffs_oobinfo = {
.useecc = MTD_NANDECC_PLACE,
.eccbytes = 6,
.eccpos = { 8, 9, 10, 13, 14, 15}
};
struct nand_oobinfo autoplace_oobinfo = {
.useecc = MTD_NANDECC_AUTOPLACE
};
void display_help (void)
{
printf("Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILE\n"
"Writes to the specified MTD device.\n"
"\n"
" -a, --autoplace Use auto oob layout\n"
" -j, --jffs2 force jffs2 oob layout (legacy support)\n"
" -y, --yaffs force yaffs oob layout (legacy support)\n"
" -f, --forcelegacy force legacy support on autoplacement enabled mtd device\n"
" -m, --markbad mark blocks bad if write fails\n"
" -n, --noecc write without ecc\n"
" -o, --oob image contains oob data\n"
" -s addr, --start=addr set start address (default is 0)\n"
" -p, --pad pad to page size\n"
" -b, --blockalign=1|2|4 set multiple of eraseblocks to align to\n"
" -q, --quiet don't display progress messages\n"
" --help display this help and exit\n"
" --version output version information and exit\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);
}
char *mtd_device, *img;
int mtdoffset = 0;
int quiet = 0;
int writeoob = 0;
int markbad = 0;
int autoplace = 0;
int forcejffs2 = 0;
int forceyaffs = 0;
int forcelegacy = 0;
int noecc = 0;
int pad = 0;
int blockalign = 1; /*default to using 16K block size */
void process_options (int argc, char *argv[])
{
int error = 0;
for (;;) {
int option_index = 0;
static const char *short_options = "ab:fjmnopqs:y";
static const struct option long_options[] = {
{"help", no_argument, 0, 0},
{"version", no_argument, 0, 0},
{"autoplace", no_argument, 0, 'a'},
{"blockalign", required_argument, 0, 'b'},
{"forcelegacy", no_argument, 0, 'f'},
{"jffs2", no_argument, 0, 'j'},
{"markbad", no_argument, 0, 'm'},
{"noecc", no_argument, 0, 'n'},
{"oob", no_argument, 0, 'o'},
{"pad", no_argument, 0, 'p'},
{"quiet", no_argument, 0, 'q'},
{"start", required_argument, 0, 's'},
{"yaffs", no_argument, 0, 'y'},
{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 'a':
autoplace = 1;
break;
case 'j':
forcejffs2 = 1;
break;
case 'y':
forceyaffs = 1;
break;
case 'f':
forcelegacy = 1;
break;
case 'n':
noecc = 1;
break;
case 'm':
markbad = 1;
break;
case 'o':
writeoob = 1;
break;
case 'p':
pad = 1;
break;
case 's':
mtdoffset = strtol (optarg, NULL, 0);
break;
case 'b':
blockalign = atoi (optarg);
break;
case '?':
error = 1;
break;
}
}
if ((argc - optind) != 2 || error)
display_help ();
mtd_device = argv[optind++];
img = argv[optind];
}
/*
* Main program
*/
int main(int argc, char **argv)
{
int cnt, fd, ifd, imglen = 0, pagelen, baderaseblock, blockstart = -1;
struct mtd_info_user meminfo;
struct mtd_oob_buf oob;
loff_mtd_t offs;
int ret, readlen;
int oobinfochanged = 0;
struct nand_oobinfo old_oobinfo;
printf("Warning: nandwrite_mlc instead of nandwrite is used for MLC NAND!\n");
process_options(argc, argv);
memset(oobbuf, 0xff, sizeof(oobbuf));
if (pad && writeoob) {
fprintf(stderr, "Can't pad when oob data is present.\n");
exit(1);
}
/* Open the device */
if ((fd = open(mtd_device, O_RDWR)) == -1) {
perror("open flash");
exit(1);
}
/* Fill in MTD device capability structure */
if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
perror("MEMGETINFO");
close(fd);
exit(1);
}
/* Set erasesize to specified number of blocks - to match jffs2
* (virtual) block size */
meminfo.erasesize *= blockalign;
/* Make sure device page sizes are valid */
if (!(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
!(meminfo.oobsize == 8 && meminfo.writesize == 256) &&
!(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
!(meminfo.oobsize == 128 && meminfo.writesize == 4096)) {
fprintf(stderr, "Unknown flash (not normal NAND)\n");
close(fd);
exit(1);
}
if (autoplace) {
/* Read the current oob info */
if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMGETOOBSEL");
close (fd);
exit (1);
}
// autoplace ECC ?
if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
if (ioctl (fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close (fd);
exit (1);
}
oobinfochanged = 1;
}
}
if (noecc) {
ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW);
if (ret == 0) {
oobinfochanged = 2;
} else {
switch (errno) {
case ENOTTY:
if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMGETOOBSEL");
close (fd);
exit (1);
}
if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close (fd);
exit (1);
}
oobinfochanged = 1;
break;
default:
perror ("MTDFILEMODE");
close (fd);
exit (1);
}
}
}
/*
* force oob layout for jffs2 or yaffs ?
* Legacy support
*/
if (forcejffs2 || forceyaffs) {
struct nand_oobinfo *oobsel = forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
if (autoplace) {
fprintf(stderr, "Autoplacement is not possible for legacy -j/-y options\n");
goto restoreoob;
}
if ((old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) && !forcelegacy) {
fprintf(stderr, "Use -f option to enforce legacy placement on autoplacement enabled mtd device\n");
goto restoreoob;
}
if (meminfo.oobsize == 8) {
if (forceyaffs) {
fprintf (stderr, "YAFSS cannot operate on 256 Byte page size");
goto restoreoob;
}
/* Adjust number of ecc bytes */
jffs2_oobinfo.eccbytes = 3;
}
if (ioctl (fd, MEMSETOOBSEL, oobsel) != 0) {
perror ("MEMSETOOBSEL");
goto restoreoob;
}
}
oob.length = meminfo.oobsize;
oob.ptr = noecc ? oobreadbuf : oobbuf;
/* Open the input file */
if ((ifd = open(img, O_RDONLY)) == -1) {
perror("open input file");
goto restoreoob;
}
// get image length
imglen = lseek(ifd, 0, SEEK_END);
lseek (ifd, 0, SEEK_SET);
pagelen = meminfo.writesize + ((writeoob == 1) ? meminfo.oobsize : 0);
// Check, if file is pagealigned
if ((!pad) && ((imglen % pagelen) != 0)) {
fprintf (stderr, "Input file is not page aligned\n");
goto closeall;
}
// Check, if length fits into device
if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) {
fprintf (stderr, "Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %llu bytes\n",
imglen, pagelen, meminfo.writesize, meminfo.size);
perror ("Input file does not fit into device");
goto closeall;
}
/* Get data from input and write to the device */
while (imglen && (mtdoffset < meminfo.size)) {
// new eraseblock , check for bad block(s)
// Stay in the loop to be sure if the mtdoffset changes because
// of a bad block, that the next block that will be written to
// is also checked. Thus avoiding errors if the block(s) after the
// skipped block(s) is also bad (number of blocks depending on
// the blockalign
while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) {
blockstart = mtdoffset & (~meminfo.erasesize + 1);
offs = blockstart;
baderaseblock = 0;
if (!quiet)
fprintf (stdout, "Writing data to block %x\n", blockstart);
/* Check all the blocks in an erase block for bad blocks */
do {
if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) {
perror("ioctl(MEMGETBADBLOCK)");
goto closeall;
}
if (ret == 1) {
baderaseblock = 1;
if (!quiet)
fprintf (stderr, "Bad block at %x, %u block(s) "
"from %x will be skipped\n",
(int) offs, blockalign, blockstart);
}
if (baderaseblock) {
mtdoffset = blockstart + meminfo.erasesize;
}
offs += meminfo.erasesize / blockalign ;
} while ( offs < blockstart + meminfo.erasesize );
}
readlen = meminfo.writesize;
if (pad && (imglen < readlen))
{
readlen = imglen;
memset(writebuf + readlen, 0xff, meminfo.writesize - readlen);
}
/* Read Page Data from input file */
if ((cnt = read(ifd, writebuf, readlen)) != readlen) {
if (cnt == 0) // EOF
break;
perror ("File I/O error on input file");
goto closeall;
}
if (writeoob) {
/* Read OOB data from input file, exit on failure */
if ((cnt = read(ifd, oobreadbuf, meminfo.oobsize)) != meminfo.oobsize) {
perror ("File I/O error on input file");
goto closeall;
}
if (!noecc) {
int i, start, len;
/*
* We use autoplacement and have the oobinfo with the autoplacement
* information from the kernel available
*
* Modified to support out of order oobfree segments,
* such as the layout used by diskonchip.c
*/
if (!oobinfochanged && (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE)) {
for (i = 0;old_oobinfo.oobfree[i][1]; i++) {
/* Set the reserved bytes to 0xff */
start = old_oobinfo.oobfree[i][0];
len = old_oobinfo.oobfree[i][1];
memcpy(oobbuf + start,
oobreadbuf + start,
len);
}
} else {
/* Set at least the ecc byte positions to 0xff */
start = old_oobinfo.eccbytes;
len = meminfo.oobsize - start;
memcpy(oobbuf + start,
oobreadbuf + start,
len);
}
}
/* Write OOB data first, as ecc will be placed in there*/
oob.start = mtdoffset;
if (ioctl(fd, MEMWRITEOOB, &oob) != 0) {
perror ("ioctl(MEMWRITEOOB)");
goto closeall;
}
imglen -= meminfo.oobsize;
}
/* Write out the Page data */
if (pwrite(fd, writebuf, meminfo.writesize, mtdoffset) != meminfo.writesize) {
int rewind_blocks;
off_t rewind_bytes;
erase_info_t erase;
perror ("pwrite");
/* Must rewind to blockstart if we can */
rewind_blocks = (mtdoffset - blockstart) / meminfo.writesize; /* Not including the one we just attempted */
rewind_bytes = (rewind_blocks * meminfo.writesize) + readlen;
if (writeoob)
rewind_bytes += (rewind_blocks + 1) * meminfo.oobsize;
if (lseek(ifd, -rewind_bytes, SEEK_CUR) == -1) {
perror("lseek");
fprintf(stderr, "Failed to seek backwards to recover from write error\n");
goto closeall;
}
erase.start = blockstart;
erase.length = meminfo.erasesize;
fprintf(stderr, "Erasing failed write from 0x%09llx-0x%09llx\n",
erase.start, erase.start+erase.length-1);
if (ioctl(fd, MEMERASE, &erase) != 0) {
perror("MEMERASE");
goto closeall;
}
if (markbad) {
loff_mtd_t bad_addr = mtdoffset & (~(meminfo.erasesize / blockalign) + 1);
fprintf(stderr, "Marking block at %09llx bad\n", (long long)bad_addr);
if (ioctl(fd, MEMSETBADBLOCK, &bad_addr)) {
perror("MEMSETBADBLOCK");
/* But continue anyway */
}
}
mtdoffset = blockstart + meminfo.erasesize;
imglen += rewind_blocks * meminfo.writesize;
continue;
}
imglen -= readlen;
mtdoffset += meminfo.writesize;
}
closeall:
close(ifd);
restoreoob:
if (oobinfochanged == 1) {
if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close (fd);
exit (1);
}
}
close(fd);
if (imglen > 0) {
perror ("Data was only partially written due to error\n");
exit (1);
}
/* Return happy */
return 0;
}

View File

@ -1,446 +0,0 @@
/*
* nandwrite.c
*
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
* 2003 Thomas Gleixner (tglx@linutronix.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Overview:
* This utility writes a binary image directly to a NAND flash
* chip or NAND chips contained in DoC devices. This is the
* "inverse operation" of nanddump.
*
* tglx: Major rewrite to handle bad blocks, write data with or without ECC
* write oob data only on request
*
* Bug/ToDo:
*/
#define _GNU_SOURCE
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <getopt.h>
#include <asm/types.h>
#include "mtd/mtd-user.h"
#define PROGRAM "nandwrite"
#define VERSION "$Revision: 1.1.1.1 $"
#define MAX_PAGE_SIZE 8192
#define MAX_OOB_SIZE 256
/*
* Buffer array used for writing data
*/
unsigned char writebuf[MAX_PAGE_SIZE];
unsigned char oobreadbuf[MAX_OOB_SIZE];
// oob layouts to pass into the kernel as default
struct nand_oobinfo none_oobinfo = {
.useecc = MTD_NANDECC_OFF,
};
struct nand_oobinfo jffs2_oobinfo = {
.useecc = MTD_NANDECC_PLACE,
.eccbytes = 6,
.eccpos = { 0, 1, 2, 3, 6, 7 }
};
struct nand_oobinfo yaffs_oobinfo = {
.useecc = MTD_NANDECC_PLACE,
.eccbytes = 6,
.eccpos = { 8, 9, 10, 13, 14, 15}
};
struct nand_oobinfo autoplace_oobinfo = {
.useecc = MTD_NANDECC_AUTOPLACE,
.eccbytes = 36
};
void display_help (void)
{
printf("Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILE\n"
"Writes to the specified MTD device.\n"
"\n"
" -a, --autoplace Use auto oob layout\n"
" -j, --jffs2 force jffs2 oob layout (legacy support)\n"
" -y, --yaffs force yaffs oob layout (legacy support)\n"
" -f, --forcelegacy force legacy support on autoplacement enabled mtd device\n"
" -m, --markbad mark blocks bad if write fails\n"
" -n, --noecc write without ecc\n"
" -o, --oob image contains oob data\n"
" -s addr, --start=addr set start address (default is 0)\n"
" -p, --pad pad to page size\n"
" -b, --blockalign=1|2|4 set multiple of eraseblocks to align to\n"
" -q, --quiet don't display progress messages\n"
" --help display this help and exit\n"
" --version output version information and exit\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);
}
char *mtd_device, *img;
unsigned long long mtdoffset = 0;
int quiet = 0;
int writeoob = 0;
int markbad = 1;
int autoplace = 0;
int forcejffs2 = 0;
int forceyaffs = 0;
int forcelegacy = 0;
int noecc = 0;
int pad = 0;
int blockalign = 1; /*default to using 16K block size */
void process_options (int argc, char *argv[])
{
int error = 0;
for (;;) {
int option_index = 0;
static const char *short_options = "ab:fjmnopqs:y";
static const struct option long_options[] = {
{"help", no_argument, 0, 0},
{"version", no_argument, 0, 0},
{"autoplace", no_argument, 0, 'a'},
{"blockalign", required_argument, 0, 'b'},
{"forcelegacy", no_argument, 0, 'f'},
{"jffs2", no_argument, 0, 'j'},
{"markbad", no_argument, 0, 'm'},
{"noecc", no_argument, 0, 'n'},
{"oob", no_argument, 0, 'o'},
{"pad", no_argument, 0, 'p'},
{"quiet", no_argument, 0, 'q'},
{"start", required_argument, 0, 's'},
{"yaffs", no_argument, 0, 'y'},
{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 'a':
autoplace = 1;
break;
case 'j':
forcejffs2 = 1;
break;
case 'y':
forceyaffs = 1;
break;
case 'f':
forcelegacy = 1;
break;
case 'n':
noecc = 1;
break;
case 'm':
markbad = 1;
break;
case 'o':
writeoob = 1;
break;
case 'p':
pad = 1;
break;
case 's':
mtdoffset = strtol (optarg, NULL, 0);
break;
case 'b':
blockalign = atoi (optarg);
break;
case '?':
error = 1;
break;
}
}
if ((argc - optind) != 2 || error)
display_help ();
mtd_device = argv[optind++];
img = argv[optind];
}
/*
* Main program
*/
int main(int argc, char **argv)
{
int cnt, fd, ifd, imglen = 0, pagelen, baderaseblock, blockstart = -1;
struct mtd_info_user meminfo;
struct mtd_page_buf oob;
loff_mtd_t offs;
int ret, readlen;
int oobinfochanged = 0;
struct nand_oobinfo old_oobinfo;
int i;
process_options(argc, argv);
if (pad && writeoob) {
fprintf(stderr, "Can't pad when oob data is present.\n");
exit(1);
}
/* Open the device */
if ((fd = open(mtd_device, O_RDWR)) == -1) {
perror("open flash");
exit(1);
}
/* Fill in MTD device capability structure */
if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
perror("MEMGETINFO");
close(fd);
exit(1);
}
/* Set erasesize to specified number of blocks - to match jffs2
* (virtual) block size */
meminfo.erasesize *= blockalign;
/* Make sure device page sizes are valid */
if (!(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
!(meminfo.oobsize == 8 && meminfo.writesize == 256) &&
!(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
!(meminfo.oobsize == 128 && meminfo.writesize == 4096) &&
!(meminfo.oobsize == 256 && meminfo.writesize == 8192)) {
fprintf(stderr, "Unknown flash (not normal NAND)\n");
close(fd);
exit(1);
}
if (autoplace) {
/* Read the current oob info */
if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMGETOOBSEL");
close (fd);
exit (1);
}
// autoplace ECC ?
if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
if (ioctl (fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close (fd);
exit (1);
}
oobinfochanged = 1;
}
}
memset(oobreadbuf, 0xff, MAX_OOB_SIZE);
if (autoplace) {
oob.ooblength = meminfo.oobsize-old_oobinfo.eccbytes; /* Get ooblength from kernel */
printf("oobsize=%d eccbytes=%d\n", meminfo.oobsize, old_oobinfo.eccbytes);
} else {
oob.ooblength = meminfo.oobsize-autoplace_oobinfo.eccbytes;
printf("oobsize=%d eccbytes=%d\n", meminfo.oobsize, autoplace_oobinfo.eccbytes);
}
oob.oobptr = oobreadbuf;
oob.datptr = writebuf;
/* Open the input file */
if ((ifd = open(img, O_RDONLY)) == -1) {
perror("open input file");
goto restoreoob;
}
// get image length
imglen = lseek(ifd, 0, SEEK_END);
lseek (ifd, 0, SEEK_SET);
pagelen = meminfo.writesize + ((writeoob == 1) ? meminfo.oobsize : 0);
// Check, if file is pagealigned
if ((!pad) && ((imglen % pagelen) != 0)) {
fprintf (stderr, "Input file is not page aligned\n");
goto closeall;
}
// Check, if length fits into device
if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) {
fprintf (stderr, "Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %lld bytes\n",
imglen, pagelen, meminfo.writesize, meminfo.size);
perror ("Input file does not fit into device");
goto closeall;
}
/* Get data from input and write to the device */
while (imglen && (mtdoffset < meminfo.size)) {
// new eraseblock , check for bad block(s)
// Stay in the loop to be sure if the mtdoffset changes because
// of a bad block, that the next block that will be written to
// is also checked. Thus avoiding errors if the block(s) after the
// skipped block(s) is also bad (number of blocks depending on
// the blockalign
while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) {
blockstart = mtdoffset & (~meminfo.erasesize + 1);
offs = blockstart;
baderaseblock = 0;
i=0;
if (!quiet)
fprintf (stdout, "Writing data to block 0x%x\n", blockstart);
/* Check all the blocks in an erase block for bad blocks */
do {
if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) {
perror("ioctl(MEMGETBADBLOCK)");
goto closeall;
}
if (ret == 1) {
baderaseblock = 1;
if (!quiet)
fprintf (stderr, "Bad block at 0x%llx, %u block(s) "
"from 0x%x will be skipped\n",
offs, blockalign, blockstart);
}
if (baderaseblock) {
mtdoffset = blockstart + meminfo.erasesize;
}
offs += meminfo.erasesize / blockalign ;
} while ( offs < blockstart + meminfo.erasesize );
}
readlen = meminfo.writesize;
if (pad && (imglen < readlen))
{
readlen = imglen;
memset(writebuf + readlen, 0xff, meminfo.writesize - readlen);
}
/* Read Page Data from input file */
if ((cnt = read(ifd, writebuf, readlen)) != readlen) {
if (cnt == 0) // EOF
break;
perror ("File I/O error 1 on input file");
goto closeall;
}
/* Read OOB data from input file, exit on failure */
if(writeoob) {
if ((cnt = read(ifd, oobreadbuf, meminfo.oobsize)) != meminfo.oobsize) {
perror ("File I/O error 2 on input file");
goto closeall;
}
}
oob.start = mtdoffset;
// write a page include its oob to nand
ioctl(fd, MEMWRITEPAGE, &oob);
if(oob.datlength != meminfo.writesize){
perror ("ioctl(MEMWRITEPAGE)");
int rewind_blocks;
off_t rewind_bytes;
erase_info_t erase;
/* Must rewind to blockstart if we can */
rewind_blocks = (mtdoffset - blockstart) / meminfo.writesize; /* Not including the one we just attempted */
rewind_bytes = (rewind_blocks * meminfo.writesize) + readlen;
if (writeoob)
rewind_bytes += (rewind_blocks + 1) * meminfo.oobsize;
if (lseek(ifd, -rewind_bytes, SEEK_CUR) == -1) {
perror("lseek");
fprintf(stderr, "Failed to seek backwards to recover from write error\n");
goto closeall;
}
erase.start = blockstart;
erase.length = meminfo.erasesize;
fprintf(stderr, "Erasing failed write from 0x%09llx-0x%09llx\n",
erase.start, erase.start+erase.length-1);
if (ioctl(fd, MEMERASE, &erase) != 0) {
perror("MEMERASE");
goto closeall;
}
if (markbad) {
loff_mtd_t bad_addr = mtdoffset & (~(meminfo.erasesize / blockalign) + 1);
fprintf(stderr, "Marking block at %09llx bad\n", (long long)bad_addr);
if (ioctl(fd, MEMSETBADBLOCK, &bad_addr)) {
perror("MEMSETBADBLOCK");
/* But continue anyway */
}
}
mtdoffset = blockstart + meminfo.erasesize;
imglen += rewind_blocks * meminfo.writesize;
continue;
}
if(writeoob)
imglen -= meminfo.oobsize;
imglen -= readlen;
mtdoffset += meminfo.writesize;
}
closeall:
close(ifd);
restoreoob:
if (oobinfochanged == 1) {
if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close (fd);
exit (1);
}
}
close(fd);
if (imglen > 0) {
perror ("Data was only partially written due to error\n");
exit (1);
}
/* Return happy */
return 0;
}

View File

@ -1,419 +0,0 @@
/*
* nftl_format.c: Creating a NFTL/INFTL partition on an MTD device
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ToDo:
* 1. UnitSizeFactor != 0xFF cases
* 2. test, test, and test !!!
*/
#define _XOPEN_SOURCE 500 /* for pread/pwrite */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <errno.h>
#include <string.h>
#include <asm/types.h>
#include <mtd/mtd-user.h>
#include <mtd/nftl-user.h>
#include <mtd/inftl-user.h>
#include <mtd_swab.h>
unsigned char BadUnitTable[MAX_ERASE_ZONES];
unsigned char *readbuf;
unsigned char *writebuf[4];
mtd_info_t meminfo;
erase_info_t erase;
int fd;
struct NFTLMediaHeader *NFTLhdr;
struct INFTLMediaHeader *INFTLhdr;
static int do_oobcheck = 1;
static int do_rwecheck = 1;
static unsigned char check_block_1(unsigned long block)
{
unsigned char oobbuf[16];
struct mtd_oob_buf oob = { 0, 16, oobbuf };
oob.start = block * meminfo.erasesize;
if (ioctl(fd, MEMREADOOB, &oob))
return ZONE_BAD_ORIGINAL;
if(oobbuf[5] == 0)
return ZONE_BAD_ORIGINAL;
oob.start = block * meminfo.erasesize + 512 /* FIXME */;
if (ioctl(fd, MEMREADOOB, &oob))
return ZONE_BAD_ORIGINAL;
if(oobbuf[5] == 0)
return ZONE_BAD_ORIGINAL;
return ZONE_GOOD;
}
static unsigned char check_block_2(unsigned long block)
{
unsigned long ofs = block * meminfo.erasesize;
unsigned long blockofs;
/* Erase test */
erase.start = ofs;
for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
pread(fd, readbuf, 512, ofs + blockofs);
if (memcmp(readbuf, writebuf[0], 512)) {
/* Block wasn't 0xff after erase */
printf(": Block not 0xff after erase\n");
return ZONE_BAD_ORIGINAL;
}
pwrite(fd, writebuf[1], 512, blockofs + ofs);
pread(fd, readbuf, 512, blockofs + ofs);
if (memcmp(readbuf, writebuf[1], 512)) {
printf(": Block not zero after clearing\n");
return ZONE_BAD_ORIGINAL;
}
}
/* Write test */
if (ioctl(fd, MEMERASE, &erase) != 0) {
printf(": Second erase failed (%s)\n", strerror(errno));
return ZONE_BAD_ORIGINAL;
}
for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
pwrite(fd, writebuf[2], 512, blockofs + ofs);
pread(fd, readbuf, 512, blockofs + ofs);
if (memcmp(readbuf, writebuf[2], 512)) {
printf(": Block not 0x5a after writing\n");
return ZONE_BAD_ORIGINAL;
}
}
if (ioctl(fd, MEMERASE, &erase) != 0) {
printf(": Third erase failed (%s)\n", strerror(errno));
return ZONE_BAD_ORIGINAL;
}
for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
pwrite(fd, writebuf[3], 512, blockofs + ofs);
pread(fd, readbuf, 512, blockofs + ofs);
if (memcmp(readbuf, writebuf[3], 512)) {
printf(": Block not 0xa5 after writing\n");
return ZONE_BAD_ORIGINAL;
}
}
if (ioctl(fd, MEMERASE, &erase) != 0) {
printf(": Fourth erase failed (%s)\n", strerror(errno));
return ZONE_BAD_ORIGINAL;
}
return ZONE_GOOD;
}
static unsigned char erase_block(unsigned long block)
{
unsigned char status;
int ret;
status = (do_oobcheck) ? check_block_1(block) : ZONE_GOOD;
erase.start = block * meminfo.erasesize;
if (status != ZONE_GOOD) {
printf("\rSkipping bad zone (factory marked) #%ld @ 0x%x\n", block, erase.start);
fflush(stdout);
return status;
}
printf("\r\t Erasing Zone #%ld @ 0x%x", block, erase.start);
fflush(stdout);
if ((ret=ioctl(fd, MEMERASE, &erase)) != 0) {
printf(": Erase failed (%s)\n", strerror(errno));
return ZONE_BAD_ORIGINAL;
}
if (do_rwecheck) {
printf("\r\tChecking Zone #%ld @ 0x%x", block, erase.start);
fflush(stdout);
status = check_block_2(block);
if (status != ZONE_GOOD) {
printf("\rSkipping bad zone (RWE test failed) #%ld @ 0x%x\n", block, erase.start);
fflush(stdout);
}
}
return status;
}
static int checkbbt(void)
{
unsigned char bbt[512];
unsigned char bits;
int i, addr;
if (pread(fd, bbt, 512, 0x800) < 0) {
printf("nftl_format: failed to read BBT, errno=%d\n", errno);
return (-1);
}
for (i = 0; (i < 512); i++) {
addr = i / 4;
bits = 0x3 << ((i % 4) * 2);
if ((bbt[addr] & bits) == 0) {
BadUnitTable[i] = ZONE_BAD_ORIGINAL;
}
}
return (0);
}
void usage(int rc)
{
fprintf(stderr, "Usage: nftl_format [-ib] <mtddevice> [<start offset> [<size>]]\n");
exit(rc);
}
int main(int argc, char **argv)
{
unsigned long startofs = 0, part_size = 0;
unsigned long ezones = 0, ezone = 0, bad_zones = 0;
unsigned char unit_factor = 0xFF;
long MediaUnit1 = -1, MediaUnit2 = -1;
long MediaUnitOff1 = 0, MediaUnitOff2 = 0;
unsigned char oobbuf[16];
struct mtd_oob_buf oob = {0, 16, oobbuf};
char *mtddevice, *nftl;
int c, do_inftl = 0, do_bbt = 0;
printf("version 1.24 2005/11/07 11:15:13 gleixner\n");
if (argc < 2)
usage(1);
nftl = "NFTL";
while ((c = getopt(argc, argv, "?hib")) > 0) {
switch (c) {
case 'i':
nftl = "INFTL";
do_inftl = 1;
break;
case 'b':
do_bbt = 1;
break;
case 'h':
case '?':
usage(0);
break;
default:
usage(1);
break;
}
}
mtddevice = argv[optind++];
if (argc > optind) {
startofs = strtoul(argv[optind++], NULL, 0);
}
if (argc > optind) {
part_size = strtoul(argv[optind++], NULL, 0);
}
// Open and size the device
if ((fd = open(mtddevice, O_RDWR)) < 0) {
perror("Open flash device");
return 1;
}
if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
perror("ioctl(MEMGETINFO)");
close(fd);
return 1;
}
switch (meminfo.erasesize) {
case 0x1000:
case 0x2000:
case 0x4000:
case 0x8000:
break;
default:
printf("Unrecognized Erase size, 0x%x - I'm confused\n",
meminfo.erasesize);
close(fd);
return 1;
}
writebuf[0] = malloc(meminfo.erasesize * 5);
if (!writebuf[0]) {
printf("Malloc failed\n");
close(fd);
return 1;
}
writebuf[1] = writebuf[0] + meminfo.erasesize;
writebuf[2] = writebuf[1] + meminfo.erasesize;
writebuf[3] = writebuf[2] + meminfo.erasesize;
readbuf = writebuf[3] + meminfo.erasesize;
memset(writebuf[0], 0xff, meminfo.erasesize);
memset(writebuf[1], 0x00, meminfo.erasesize);
memset(writebuf[2], 0x5a, meminfo.erasesize);
memset(writebuf[3], 0xa5, meminfo.erasesize);
memset(BadUnitTable, ZONE_GOOD, MAX_ERASE_ZONES);
if (part_size == 0 || (part_size > meminfo.size - startofs))
/* the user doest not or incorrectly specify NFTL partition size */
part_size = meminfo.size - startofs;
erase.length = meminfo.erasesize;
ezones = part_size / meminfo.erasesize;
if (ezones > MAX_ERASE_ZONES) {
/* Ought to change the UnitSizeFactor. But later. */
part_size = meminfo.erasesize * MAX_ERASE_ZONES;
ezones = MAX_ERASE_ZONES;
unit_factor = 0xFF;
}
/* If using device BBT then parse that now */
if (do_bbt) {
checkbbt();
do_oobcheck = 0;
do_rwecheck = 0;
}
/* Phase 1. Erasing and checking each erase zones in the NFTL partition.
N.B. Erase Zones not used by the NFTL partition are untouched and marked ZONE_GOOD */
printf("Phase 1. Checking and erasing Erase Zones from 0x%08lx to 0x%08lx\n",
startofs, startofs + part_size);
for (ezone = startofs / meminfo.erasesize;
ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
if (BadUnitTable[ezone] != ZONE_GOOD)
continue;
if ((BadUnitTable[ezone] = erase_block(ezone)) == ZONE_GOOD) {
if (MediaUnit1 == -1) {
MediaUnit1 = ezone;
} else if (MediaUnit2 == -1) {
MediaUnit2 = ezone;
}
} else {
bad_zones++;
}
}
printf("\n");
/* N.B. from dump of M-System original chips, NumEraseUnits counts the 2 Erase Unit used
by MediaHeader and the FirstPhysicalEUN starts from the MediaHeader */
if (do_inftl) {
unsigned long maxzones, pezstart, pezend, numvunits;
INFTLhdr = (struct INFTLMediaHeader *) (writebuf[0]);
strcpy(INFTLhdr->bootRecordID, "BNAND");
INFTLhdr->NoOfBootImageBlocks = cpu_to_le32(0);
INFTLhdr->NoOfBinaryPartitions = cpu_to_le32(0);
INFTLhdr->NoOfBDTLPartitions = cpu_to_le32(1);
INFTLhdr->BlockMultiplierBits = cpu_to_le32(0);
INFTLhdr->FormatFlags = cpu_to_le32(0);
INFTLhdr->OsakVersion = cpu_to_le32(OSAK_VERSION);
INFTLhdr->PercentUsed = cpu_to_le32(PERCENTUSED);
/*
* Calculate number of virtual units we will have to work
* with. I am calculating out the known bad units here, not
* sure if that is what M-Systems do...
*/
MediaUnit2 = MediaUnit1;
MediaUnitOff2 = 4096;
maxzones = meminfo.size / meminfo.erasesize;
pezstart = startofs / meminfo.erasesize + 1;
pezend = startofs / meminfo.erasesize + ezones - 1;
numvunits = (ezones - 2) * PERCENTUSED / 100;
for (ezone = pezstart; ezone < maxzones; ezone++) {
if (BadUnitTable[ezone] != ZONE_GOOD) {
if (numvunits > 1)
numvunits--;
}
}
INFTLhdr->Partitions[0].virtualUnits = cpu_to_le32(numvunits);
INFTLhdr->Partitions[0].firstUnit = cpu_to_le32(pezstart);
INFTLhdr->Partitions[0].lastUnit = cpu_to_le32(pezend);
INFTLhdr->Partitions[0].flags = cpu_to_le32(INFTL_BDTL);
INFTLhdr->Partitions[0].spareUnits = cpu_to_le32(0);
INFTLhdr->Partitions[0].Reserved0 = INFTLhdr->Partitions[0].firstUnit;
INFTLhdr->Partitions[0].Reserved1 = cpu_to_le32(0);
} else {
NFTLhdr = (struct NFTLMediaHeader *) (writebuf[0]);
strcpy(NFTLhdr->DataOrgID, "ANAND");
NFTLhdr->NumEraseUnits = cpu_to_le16(part_size / meminfo.erasesize);
NFTLhdr->FirstPhysicalEUN = cpu_to_le16(MediaUnit1);
/* N.B. we reserve 2 more Erase Units for "folding" of Virtual Unit Chain */
NFTLhdr->FormattedSize = cpu_to_le32(part_size - ( (5+bad_zones) * meminfo.erasesize));
NFTLhdr->UnitSizeFactor = unit_factor;
}
/* Phase 2. Writing NFTL Media Headers and Bad Unit Table */
printf("Phase 2.a Writing %s Media Header and Bad Unit Table\n", nftl);
pwrite(fd, writebuf[0], 512, MediaUnit1 * meminfo.erasesize + MediaUnitOff1);
for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
pwrite(fd, BadUnitTable + ezone, 512,
(MediaUnit1 * meminfo.erasesize) + 512 * (1 + ezone / 512));
}
#if 0
printf(" MediaHeader contents:\n");
printf(" NumEraseUnits: %d\n", le16_to_cpu(NFTLhdr->NumEraseUnits));
printf(" FirstPhysicalEUN: %d\n", le16_to_cpu(NFTLhdr->FirstPhysicalEUN));
printf(" FormattedSize: %d (%d sectors)\n", le32_to_cpu(NFTLhdr->FormattedSize),
le32_to_cpu(NFTLhdr->FormattedSize)/512);
#endif
printf("Phase 2.b Writing Spare %s Media Header and Spare Bad Unit Table\n", nftl);
pwrite(fd, writebuf[0], 512, MediaUnit2 * meminfo.erasesize + MediaUnitOff2);
for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
pwrite(fd, BadUnitTable + ezone, 512,
(MediaUnit2 * meminfo.erasesize + MediaUnitOff2) + 512 * (1 + ezone / 512));
}
/* UCI #1 for newly erased Erase Unit */
memset(oobbuf, 0xff, 16);
oobbuf[11] = oobbuf[10] = oobbuf[9] = 0;
oobbuf[8] = (do_inftl) ? 0x00 : 0x03;
oobbuf[12] = oobbuf[14] = 0x69;
oobbuf[13] = oobbuf[15] = 0x3c;
/* N.B. The Media Header and Bad Erase Unit Table are considered as Free Erase Unit
by M-System i.e. their Virtual Unit Number == 0xFFFF in the Unit Control Information #0,
but their Block Status is BLOCK_USED (0x5555) in their Block Control Information */
/* Phase 3. Writing Unit Control Information for each Erase Unit */
printf("Phase 3. Writing Unit Control Information to each Erase Unit\n");
for (ezone = MediaUnit1; ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
/* write UCI #1 to each Erase Unit */
if (BadUnitTable[ezone] != ZONE_GOOD)
continue;
oob.start = (ezone * meminfo.erasesize) + 512 + (do_inftl * 512);
if (ioctl(fd, MEMWRITEOOB, &oob))
printf("MEMWRITEOOB at %lx: %s\n", (unsigned long)oob.start, strerror(errno));
}
exit(0);
}

View File

@ -1,281 +0,0 @@
/*
* nftldump.c: Dumping the content of NFTL partitions on a "Physical Disk"
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ToDo:
* 1. UnitSizeFactor != 0xFF cases
* 2. test, test, and test !!!
*/
#define _XOPEN_SOURCE 500 /* For pread */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <mtd/mtd-user.h>
#include <mtd/nftl-user.h>
#include <mtd_swab.h>
static struct NFTLMediaHeader MedHead[2];
static mtd_info_t meminfo;
static struct nftl_oob oobbuf;
static struct mtd_oob_buf oob = {0, 16, (unsigned char *)&oobbuf};
static int fd, ofd = -1;;
static int NumMedHeads;
static unsigned char BadUnitTable[MAX_ERASE_ZONES];
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define SWAP16(x) do { ; } while(0)
#define SWAP32(x) do { ; } while(0)
#else
#define SWAP16(x) do { x = swab16(x); } while(0)
#define SWAP32(x) do { x = swab32(x); } while(0)
#endif
/* VUCtable, store the Erase Unit Number of the first Erase Unit in the chain */
static unsigned short *VUCtable;
/* FixMe: make this dynamic allocated */
#define ERASESIZE 0x2000
#define NUMVUNITS ((40*1024*1024) / ERASESIZE)
static union nftl_uci UCItable[NUMVUNITS][3];
static unsigned short nextEUN(unsigned short curEUN)
{
return UCItable[curEUN][0].a.ReplUnitNum;
}
static unsigned int find_media_headers(void)
{
int i;
static unsigned long ofs = 0;
NumMedHeads = 0;
while (ofs < meminfo.size) {
pread(fd, &MedHead[NumMedHeads], sizeof(struct NFTLMediaHeader), ofs);
if (!strncmp(MedHead[NumMedHeads].DataOrgID, "ANAND", 6)) {
SWAP16(MedHead[NumMedHeads].NumEraseUnits);
SWAP16(MedHead[NumMedHeads].FirstPhysicalEUN);
SWAP32(MedHead[NumMedHeads].FormattedSize);
if (NumMedHeads == 0) {
printf("NFTL Media Header found at offset 0x%08lx:\n", ofs);
printf("NumEraseUnits: %d\n",
MedHead[NumMedHeads].NumEraseUnits);
printf("FirstPhysicalEUN: %d\n",
MedHead[NumMedHeads].FirstPhysicalEUN);
printf("Formatted Size: %d\n",
MedHead[NumMedHeads].FormattedSize);
printf("UnitSizeFactor: 0x%x\n",
MedHead[NumMedHeads].UnitSizeFactor);
/* read BadUnitTable, I don't know why pread() does not work for
larger (7680 bytes) chunks */
for (i = 0; i < MAX_ERASE_ZONES; i += 512)
pread(fd, &BadUnitTable[i], 512, ofs + 512 + i);
} else
printf("Second NFTL Media Header found at offset 0x%08lx\n",ofs);
NumMedHeads++;
}
ofs += meminfo.erasesize;
if (NumMedHeads == 2) {
if (strncmp((char *)&MedHead[0], (char *)&MedHead[1], sizeof(struct NFTLMediaHeader)) != 0) {
printf("warning: NFTL Media Header is not consistent with "
"Spare NFTL Media Header\n");
}
break;
}
}
/* allocate Virtual Unit Chain table for this NFTL partition */
VUCtable = calloc(MedHead[0].NumEraseUnits, sizeof(unsigned short));
return NumMedHeads;
}
static void dump_erase_units(void)
{
int i, j;
unsigned long ofs;
for (i = MedHead[0].FirstPhysicalEUN; i < MedHead[0].FirstPhysicalEUN +
MedHead[0].NumEraseUnits; i++) {
/* For each Erase Unit */
ofs = i * meminfo.erasesize;
/* read the Unit Control Information */
for (j = 0; j < 3; j++) {
oob.start = ofs + (j * 512);
if (ioctl(fd, MEMREADOOB, &oob))
printf("MEMREADOOB at %lx: %s\n",
(unsigned long) oob.start, strerror(errno));
memcpy(&UCItable[i][j], &oobbuf.u, 8);
}
if (UCItable[i][1].b.EraseMark != cpu_to_le16(0x3c69)) {
printf("EraseMark not present in unit %d: %x\n",
i, UCItable[i][1].b.EraseMark);
} else {
/* a properly formatted unit */
SWAP16(UCItable[i][0].a.VirtUnitNum);
SWAP16(UCItable[i][0].a.ReplUnitNum);
SWAP16(UCItable[i][0].a.SpareVirtUnitNum);
SWAP16(UCItable[i][0].a.SpareReplUnitNum);
SWAP32(UCItable[i][1].b.WearInfo);
SWAP16(UCItable[i][1].b.EraseMark);
SWAP16(UCItable[i][1].b.EraseMark1);
SWAP16(UCItable[i][2].c.FoldMark);
SWAP16(UCItable[i][2].c.FoldMark1);
if (!(UCItable[i][0].a.VirtUnitNum & 0x8000)) {
/* If this is the first in a chain, store the EUN in the VUC table */
if (VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]) {
printf("Duplicate start of chain for VUC %d: "
"Unit %d replaces Unit %d\n",
UCItable[i][0].a.VirtUnitNum & 0x7fff,
i, VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]);
}
VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff] = i;
}
}
switch (BadUnitTable[i]) {
case ZONE_BAD_ORIGINAL:
printf("Unit %d is marked as ZONE_BAD_ORIGINAL\n", i);
continue;
case ZONE_BAD_MARKED:
printf("Unit %d is marked as ZONE_BAD_MARKED\n", i);
continue;
}
/* ZONE_GOOD */
if (UCItable[i][0].a.VirtUnitNum == 0xffff)
printf("Unit %d is free\n", i);
else
printf("Unit %d is in chain %d and %s a replacement\n", i,
UCItable[i][0].a.VirtUnitNum & 0x7fff,
UCItable[i][0].a.VirtUnitNum & 0x8000 ? "is" : "is not");
}
}
static void dump_virtual_units(void)
{
int i, j;
char readbuf[512];
for (i = 0; i < (MedHead[0].FormattedSize / meminfo.erasesize); i++) {
unsigned short curEUN = VUCtable[i];
printf("Virtual Unit #%d: ", i);
if (!curEUN) {
printf("Not present\n");
continue;
}
printf("%d", curEUN);
/* walk through the Virtual Unit Chain */
while ((curEUN = nextEUN(curEUN)) != 0xffff) {
printf(", %d", curEUN & 0x7fff);
}
printf("\n");
if (ofd != -1) {
/* Actually write out the data */
for (j = 0; j < meminfo.erasesize / 512; j++) {
/* For each sector in the block */
unsigned short lastgoodEUN = 0xffff, thisEUN = VUCtable[i];
unsigned int status;
if (thisEUN == 0xffff) thisEUN = 0;
while (thisEUN && (thisEUN & 0x7fff) != 0x7fff) {
oob.start = (thisEUN * ERASESIZE) + (j * 512);
ioctl(fd, MEMREADOOB, &oob);
status = oobbuf.b.Status | oobbuf.b.Status1;
switch (status) {
case SECTOR_FREE:
/* This is still free. Don't look any more */
thisEUN = 0;
break;
case SECTOR_USED:
/* SECTOR_USED. This is a good one. */
lastgoodEUN = thisEUN;
break;
}
/* Find the next erase unit in this chain, if any */
if (thisEUN)
thisEUN = nextEUN(thisEUN) & 0x7fff;
}
if (lastgoodEUN == 0xffff)
memset(readbuf, 0, 512);
else
pread(fd, readbuf, 512,
(lastgoodEUN * ERASESIZE) + (j * 512));
write(ofd, readbuf, 512);
}
}
}
}
int main(int argc, char **argv)
{
if (argc < 2) {
printf("Usage: %s <device> [<outfile>]\n", argv[0]);
exit(1);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1) {
perror("open flash");
exit (1);
}
if (argc > 2) {
ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644);
if (ofd == -1)
perror ("open outfile");
}
/* get size information of the MTD device */
if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
perror("ioctl(MEMGETINFO)");
close(fd);
return 1;
}
while (find_media_headers() != 0) {
dump_erase_units();
dump_virtual_units();
free(VUCtable);
}
exit(0);
}

View File

@ -1,390 +0,0 @@
/*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>
(C) 2002 David Woodhouse <dwmw2@infradead.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
linux/lib/rbtree.c
*/
#include <stdlib.h>
#include "rbtree.h"
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
{
struct rb_node *right = node->rb_right;
struct rb_node *parent = rb_parent(node);
if ((node->rb_right = right->rb_left))
rb_set_parent(right->rb_left, node);
right->rb_left = node;
rb_set_parent(right, parent);
if (parent)
{
if (node == parent->rb_left)
parent->rb_left = right;
else
parent->rb_right = right;
}
else
root->rb_node = right;
rb_set_parent(node, right);
}
static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
{
struct rb_node *left = node->rb_left;
struct rb_node *parent = rb_parent(node);
if ((node->rb_left = left->rb_right))
rb_set_parent(left->rb_right, node);
left->rb_right = node;
rb_set_parent(left, parent);
if (parent)
{
if (node == parent->rb_right)
parent->rb_right = left;
else
parent->rb_left = left;
}
else
root->rb_node = left;
rb_set_parent(node, left);
}
void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
struct rb_node *parent, *gparent;
while ((parent = rb_parent(node)) && rb_is_red(parent))
{
gparent = rb_parent(parent);
if (parent == gparent->rb_left)
{
{
register struct rb_node *uncle = gparent->rb_right;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
if (parent->rb_right == node)
{
register struct rb_node *tmp;
__rb_rotate_left(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_right(gparent, root);
} else {
{
register struct rb_node *uncle = gparent->rb_left;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
if (parent->rb_left == node)
{
register struct rb_node *tmp;
__rb_rotate_right(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_left(gparent, root);
}
}
rb_set_black(root->rb_node);
}
static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
struct rb_root *root)
{
struct rb_node *other;
while ((!node || rb_is_black(node)) && node != root->rb_node)
{
if (parent->rb_left == node)
{
other = parent->rb_right;
if (rb_is_red(other))
{
rb_set_black(other);
rb_set_red(parent);
__rb_rotate_left(parent, root);
other = parent->rb_right;
}
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
(!other->rb_right || rb_is_black(other->rb_right)))
{
rb_set_red(other);
node = parent;
parent = rb_parent(node);
}
else
{
if (!other->rb_right || rb_is_black(other->rb_right))
{
struct rb_node *o_left;
if ((o_left = other->rb_left))
rb_set_black(o_left);
rb_set_red(other);
__rb_rotate_right(other, root);
other = parent->rb_right;
}
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
if (other->rb_right)
rb_set_black(other->rb_right);
__rb_rotate_left(parent, root);
node = root->rb_node;
break;
}
}
else
{
other = parent->rb_left;
if (rb_is_red(other))
{
rb_set_black(other);
rb_set_red(parent);
__rb_rotate_right(parent, root);
other = parent->rb_left;
}
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
(!other->rb_right || rb_is_black(other->rb_right)))
{
rb_set_red(other);
node = parent;
parent = rb_parent(node);
}
else
{
if (!other->rb_left || rb_is_black(other->rb_left))
{
register struct rb_node *o_right;
if ((o_right = other->rb_right))
rb_set_black(o_right);
rb_set_red(other);
__rb_rotate_left(other, root);
other = parent->rb_left;
}
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
if (other->rb_left)
rb_set_black(other->rb_left);
__rb_rotate_right(parent, root);
node = root->rb_node;
break;
}
}
}
if (node)
rb_set_black(node);
}
void rb_erase(struct rb_node *node, struct rb_root *root)
{
struct rb_node *child, *parent;
int color;
if (!node->rb_left)
child = node->rb_right;
else if (!node->rb_right)
child = node->rb_left;
else
{
struct rb_node *old = node, *left;
node = node->rb_right;
while ((left = node->rb_left) != NULL)
node = left;
child = node->rb_right;
parent = rb_parent(node);
color = rb_color(node);
if (child)
rb_set_parent(child, parent);
if (parent == old) {
parent->rb_right = child;
parent = node;
} else
parent->rb_left = child;
node->rb_parent_color = old->rb_parent_color;
node->rb_right = old->rb_right;
node->rb_left = old->rb_left;
if (rb_parent(old))
{
if (rb_parent(old)->rb_left == old)
rb_parent(old)->rb_left = node;
else
rb_parent(old)->rb_right = node;
} else
root->rb_node = node;
rb_set_parent(old->rb_left, node);
if (old->rb_right)
rb_set_parent(old->rb_right, node);
goto color;
}
parent = rb_parent(node);
color = rb_color(node);
if (child)
rb_set_parent(child, parent);
if (parent)
{
if (parent->rb_left == node)
parent->rb_left = child;
else
parent->rb_right = child;
}
else
root->rb_node = child;
color:
if (color == RB_BLACK)
__rb_erase_color(child, parent, root);
}
/*
* This function returns the first node (in sort order) of the tree.
*/
struct rb_node *rb_first(struct rb_root *root)
{
struct rb_node *n;
n = root->rb_node;
if (!n)
return NULL;
while (n->rb_left)
n = n->rb_left;
return n;
}
struct rb_node *rb_last(struct rb_root *root)
{
struct rb_node *n;
n = root->rb_node;
if (!n)
return NULL;
while (n->rb_right)
n = n->rb_right;
return n;
}
struct rb_node *rb_next(struct rb_node *node)
{
struct rb_node *parent;
if (rb_parent(node) == node)
return NULL;
/* If we have a right-hand child, go down and then left as far
as we can. */
if (node->rb_right) {
node = node->rb_right;
while (node->rb_left)
node=node->rb_left;
return node;
}
/* No right-hand children. Everything down and left is
smaller than us, so any 'next' node must be in the general
direction of our parent. Go up the tree; any time the
ancestor is a right-hand child of its parent, keep going
up. First time it's a left-hand child of its parent, said
parent is our 'next' node. */
while ((parent = rb_parent(node)) && node == parent->rb_right)
node = parent;
return parent;
}
struct rb_node *rb_prev(struct rb_node *node)
{
struct rb_node *parent;
if (rb_parent(node) == node)
return NULL;
/* If we have a left-hand child, go down and then right as far
as we can. */
if (node->rb_left) {
node = node->rb_left;
while (node->rb_right)
node=node->rb_right;
return node;
}
/* No left-hand children. Go up till we find an ancestor which
is a right-hand child of its parent */
while ((parent = rb_parent(node)) && node == parent->rb_left)
node = parent;
return parent;
}
void rb_replace_node(struct rb_node *victim, struct rb_node *new,
struct rb_root *root)
{
struct rb_node *parent = rb_parent(victim);
/* Set the surrounding nodes to point to the replacement */
if (parent) {
if (victim == parent->rb_left)
parent->rb_left = new;
else
parent->rb_right = new;
} else {
root->rb_node = new;
}
if (victim->rb_left)
rb_set_parent(victim->rb_left, new);
if (victim->rb_right)
rb_set_parent(victim->rb_right, new);
/* Copy the pointers/colour from the victim to the replacement */
*new = *victim;
}

View File

@ -1,168 +0,0 @@
/*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
linux/include/linux/rbtree.h
To use rbtrees you'll have to implement your own insert and search cores.
This will avoid us to use callbacks and to drop drammatically performances.
I know it's not the cleaner way, but in C (not in C++) to get
performances and genericity...
Some example of insert and search follows here. The search is a plain
normal search over an ordered tree. The insert instead must be implemented
int two steps: as first thing the code must insert the element in
order as a red leaf in the tree, then the support library function
rb_insert_color() must be called. Such function will do the
not trivial work to rebalance the rbtree if necessary.
-----------------------------------------------------------------------
static inline struct page * rb_search_page_cache(struct inode * inode,
unsigned long offset)
{
struct rb_node * n = inode->i_rb_page_cache.rb_node;
struct page * page;
while (n)
{
page = rb_entry(n, struct page, rb_page_cache);
if (offset < page->offset)
n = n->rb_left;
else if (offset > page->offset)
n = n->rb_right;
else
return page;
}
return NULL;
}
static inline struct page * __rb_insert_page_cache(struct inode * inode,
unsigned long offset,
struct rb_node * node)
{
struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
struct rb_node * parent = NULL;
struct page * page;
while (*p)
{
parent = *p;
page = rb_entry(parent, struct page, rb_page_cache);
if (offset < page->offset)
p = &(*p)->rb_left;
else if (offset > page->offset)
p = &(*p)->rb_right;
else
return page;
}
rb_link_node(node, parent, p);
return NULL;
}
static inline struct page * rb_insert_page_cache(struct inode * inode,
unsigned long offset,
struct rb_node * node)
{
struct page * ret;
if ((ret = __rb_insert_page_cache(inode, offset, node)))
goto out;
rb_insert_color(node, &inode->i_rb_page_cache);
out:
return ret;
}
-----------------------------------------------------------------------
*/
#ifndef _LINUX_RBTREE_H
#define _LINUX_RBTREE_H
#include <linux/kernel.h>
#include <linux/stddef.h>
struct rb_node
{
unsigned long rb_parent_color;
#define RB_RED 0
#define RB_BLACK 1
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
/* The alignment might seem pointless, but allegedly CRIS needs it */
struct rb_root
{
struct rb_node *rb_node;
};
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
#define rb_color(r) ((r)->rb_parent_color & 1)
#define rb_is_red(r) (!rb_color(r))
#define rb_is_black(r) rb_color(r)
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
{
rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
}
static inline void rb_set_color(struct rb_node *rb, int color)
{
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
}
#define RB_ROOT (struct rb_root) { NULL, }
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
extern void rb_insert_color(struct rb_node *, struct rb_root *);
extern void rb_erase(struct rb_node *, struct rb_root *);
/* Find logical next and previous nodes in a tree */
extern struct rb_node *rb_next(struct rb_node *);
extern struct rb_node *rb_prev(struct rb_node *);
extern struct rb_node *rb_first(struct rb_root *);
extern struct rb_node *rb_last(struct rb_root *);
/* Fast replacement of a single node without remove/rebalance/add/rebalance */
extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
struct rb_root *root);
static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
struct rb_node ** rb_link)
{
node->rb_parent_color = (unsigned long )parent;
node->rb_left = node->rb_right = NULL;
*rb_link = node;
}
#endif /* _LINUX_RBTREE_H */

View File

@ -1,484 +0,0 @@
#define _XOPEN_SOURCE 500
#define _USE_MISC
#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include "crc32.h"
#include "mtd/mtd-user.h"
#include "mcast_image.h"
#define min(x,y) ( (x)>(y)?(y):(x) )
#define WBUF_SIZE 4096
struct eraseblock {
uint32_t flash_offset;
unsigned char wbuf[WBUF_SIZE];
int wbuf_ofs;
int nr_pkts;
int *pkt_indices;
uint32_t crc;
};
int main(int argc, char **argv)
{
struct addrinfo *ai;
struct addrinfo hints;
struct addrinfo *runp;
int ret;
int sock;
size_t len;
int flfd;
struct mtd_info_user meminfo;
unsigned char *eb_buf, *decode_buf, **src_pkts;
int nr_blocks = 0;
int pkts_per_block;
int block_nr = -1;
uint32_t image_crc;
int total_pkts = 0;
int ignored_pkts = 0;
loff_t mtdoffset = 0;
int badcrcs = 0;
int duplicates = 0;
int file_mode = 0;
struct fec_parms *fec;
int i;
struct eraseblock *eraseblocks = NULL;
uint32_t start_seq;
struct timeval start, now;
unsigned long fec_time = 0, flash_time = 0, crc_time = 0,
rflash_time = 0, erase_time = 0, net_time = 0;
if (argc != 4) {
fprintf(stderr, "usage: %s <host> <port> <mtddev>\n",
(strrchr(argv[0], '/')?:argv[0]-1)+1);
exit(1);
}
/* Open the device */
flfd = open(argv[3], O_RDWR);
if (flfd >= 0) {
/* Fill in MTD device capability structure */
if (ioctl(flfd, MEMGETINFO, &meminfo) != 0) {
perror("MEMGETINFO");
close(flfd);
flfd = -1;
} else {
printf("Receive to MTD device %s with erasesize %d\n",
argv[3], meminfo.erasesize);
}
}
if (flfd == -1) {
/* Try again, as if it's a file */
flfd = open(argv[3], O_CREAT|O_TRUNC|O_RDWR, 0644);
if (flfd < 0) {
perror("open");
exit(1);
}
meminfo.erasesize = 131072;
file_mode = 1;
printf("Receive to file %s with (assumed) erasesize %d\n",
argv[3], meminfo.erasesize);
}
pkts_per_block = (meminfo.erasesize + PKT_SIZE - 1) / PKT_SIZE;
eb_buf = malloc(pkts_per_block * PKT_SIZE);
decode_buf = malloc(pkts_per_block * PKT_SIZE);
if (!eb_buf && !decode_buf) {
fprintf(stderr, "No memory for eraseblock buffer\n");
exit(1);
}
src_pkts = malloc(sizeof(unsigned char *) * pkts_per_block);
if (!src_pkts) {
fprintf(stderr, "No memory for decode packet pointers\n");
exit(1);
}
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_ADDRCONFIG;
hints.ai_socktype = SOCK_DGRAM;
ret = getaddrinfo(argv[1], argv[2], &hints, &ai);
if (ret) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
exit(1);
}
runp = ai;
for (runp = ai; runp; runp = runp->ai_next) {
sock = socket(runp->ai_family, runp->ai_socktype,
runp->ai_protocol);
if (sock == -1) {
perror("socket");
continue;
}
if (runp->ai_family == AF_INET &&
IN_MULTICAST( ntohl(((struct sockaddr_in *)runp->ai_addr)->sin_addr.s_addr))) {
struct ip_mreq rq;
rq.imr_multiaddr = ((struct sockaddr_in *)runp->ai_addr)->sin_addr;
rq.imr_interface.s_addr = INADDR_ANY;
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &rq, sizeof(rq))) {
perror("IP_ADD_MEMBERSHIP");
close(sock);
continue;
}
} else if (runp->ai_family == AF_INET6 &&
((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr.s6_addr[0] == 0xff) {
struct ipv6_mreq rq;
rq.ipv6mr_multiaddr = ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr;
rq.ipv6mr_interface = 0;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &rq, sizeof(rq))) {
perror("IPV6_ADD_MEMBERSHIP");
close(sock);
continue;
}
}
if (bind(sock, runp->ai_addr, runp->ai_addrlen)) {
perror("bind");
close(sock);
continue;
}
break;
}
if (!runp)
exit(1);
while (1) {
struct image_pkt thispkt;
len = read(sock, &thispkt, sizeof(thispkt));
if (len < 0) {
perror("read socket");
break;
}
if (len < sizeof(thispkt)) {
fprintf(stderr, "Wrong length %d bytes (expected %d)\n",
len, sizeof(thispkt));
continue;
}
if (!eraseblocks) {
image_crc = thispkt.hdr.totcrc;
start_seq = ntohl(thispkt.hdr.pkt_sequence);
if (meminfo.erasesize != ntohl(thispkt.hdr.blocksize)) {
fprintf(stderr, "Erasesize mismatch (0x%x not 0x%x)\n",
ntohl(thispkt.hdr.blocksize), meminfo.erasesize);
exit(1);
}
nr_blocks = ntohl(thispkt.hdr.nr_blocks);
fec = fec_new(pkts_per_block, ntohs(thispkt.hdr.nr_pkts));
eraseblocks = malloc(nr_blocks * sizeof(*eraseblocks));
if (!eraseblocks) {
fprintf(stderr, "No memory for block map\n");
exit(1);
}
for (i = 0; i < nr_blocks; i++) {
eraseblocks[i].pkt_indices = malloc(sizeof(int) * pkts_per_block);
if (!eraseblocks[i].pkt_indices) {
fprintf(stderr, "Failed to allocate packet indices\n");
exit(1);
}
eraseblocks[i].nr_pkts = 0;
if (!file_mode) {
if (mtdoffset >= meminfo.size) {
fprintf(stderr, "Run out of space on flash\n");
exit(1);
}
#if 1 /* Deliberately use bad blocks... test write failures */
while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
mtdoffset += meminfo.erasesize;
}
#endif
}
eraseblocks[i].flash_offset = mtdoffset;
mtdoffset += meminfo.erasesize;
eraseblocks[i].wbuf_ofs = 0;
}
gettimeofday(&start, NULL);
}
if (image_crc != thispkt.hdr.totcrc) {
fprintf(stderr, "\nImage CRC changed from 0x%x to 0x%x. Aborting\n",
ntohl(image_crc), ntohl(thispkt.hdr.totcrc));
exit(1);
}
block_nr = ntohl(thispkt.hdr.block_nr);
if (block_nr >= nr_blocks) {
fprintf(stderr, "\nErroneous block_nr %d (> %d)\n",
block_nr, nr_blocks);
exit(1);
}
for (i=0; i<eraseblocks[block_nr].nr_pkts; i++) {
if (eraseblocks[block_nr].pkt_indices[i] == ntohs(thispkt.hdr.pkt_nr)) {
// printf("Discarding duplicate packet at %08x pkt %d\n",
// block_nr * meminfo.erasesize, eraseblocks[block_nr].pkt_indices[i]);
duplicates++;
break;
}
}
if (i < eraseblocks[block_nr].nr_pkts) {
continue;
}
if (eraseblocks[block_nr].nr_pkts >= pkts_per_block) {
/* We have a block which we didn't really need */
eraseblocks[block_nr].nr_pkts++;
ignored_pkts++;
continue;
}
if (crc32(-1, thispkt.data, PKT_SIZE) != ntohl(thispkt.hdr.thiscrc)) {
printf("\nDiscard %08x pkt %d with bad CRC (%08x not %08x)\n",
block_nr * meminfo.erasesize, ntohs(thispkt.hdr.pkt_nr),
crc32(-1, thispkt.data, PKT_SIZE),
ntohl(thispkt.hdr.thiscrc));
badcrcs++;
continue;
}
pkt_again:
eraseblocks[block_nr].pkt_indices[eraseblocks[block_nr].nr_pkts++] =
ntohs(thispkt.hdr.pkt_nr);
total_pkts++;
if (!(total_pkts % 50) || total_pkts == pkts_per_block * nr_blocks) {
uint32_t pkts_sent = ntohl(thispkt.hdr.pkt_sequence) - start_seq + 1;
long time_msec;
gettimeofday(&now, NULL);
time_msec = ((now.tv_usec - start.tv_usec) / 1000) +
(now.tv_sec - start.tv_sec) * 1000;
printf("\rReceived %d/%d (%d%%) in %lds @%ldKiB/s, %d lost (%d%%), %d dup/xs ",
total_pkts, nr_blocks * pkts_per_block,
total_pkts * 100 / nr_blocks / pkts_per_block,
time_msec / 1000,
total_pkts * PKT_SIZE / 1024 * 1000 / time_msec,
pkts_sent - total_pkts - duplicates - ignored_pkts,
(pkts_sent - total_pkts - duplicates - ignored_pkts) * 100 / pkts_sent,
duplicates + ignored_pkts);
fflush(stdout);
}
if (eraseblocks[block_nr].wbuf_ofs + PKT_SIZE < WBUF_SIZE) {
/* New packet doesn't full the wbuf */
memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
thispkt.data, PKT_SIZE);
eraseblocks[block_nr].wbuf_ofs += PKT_SIZE;
} else {
int fits = WBUF_SIZE - eraseblocks[block_nr].wbuf_ofs;
ssize_t wrotelen;
static int faked = 1;
memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
thispkt.data, fits);
wrotelen = pwrite(flfd, eraseblocks[block_nr].wbuf, WBUF_SIZE,
eraseblocks[block_nr].flash_offset);
if (wrotelen < WBUF_SIZE || (block_nr == 5 && eraseblocks[block_nr].nr_pkts == 5 && !faked)) {
faked = 1;
if (wrotelen < 0)
perror("\npacket write");
else
fprintf(stderr, "\nshort write of packet wbuf\n");
if (!file_mode) {
struct erase_info_user erase;
/* FIXME: Perhaps we should store pkt crcs and try
to recover data from the offending eraseblock */
/* We have increased nr_pkts but not yet flash_offset */
erase.start = eraseblocks[block_nr].flash_offset &
~(meminfo.erasesize - 1);
erase.length = meminfo.erasesize;
printf("Will erase at %08lx len %08lx (bad write was at %08lx)\n",
erase.start, erase.length, eraseblocks[block_nr].flash_offset);
if (ioctl(flfd, MEMERASE, &erase)) {
perror("MEMERASE");
exit(1);
}
if (mtdoffset >= meminfo.size) {
fprintf(stderr, "Run out of space on flash\n");
exit(1);
}
while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
mtdoffset += meminfo.erasesize;
if (mtdoffset >= meminfo.size) {
fprintf(stderr, "Run out of space on flash\n");
exit(1);
}
}
eraseblocks[block_nr].flash_offset = mtdoffset;
printf("Block #%d will now be at %08lx\n", block_nr, (long)mtdoffset);
total_pkts -= eraseblocks[block_nr].nr_pkts;
eraseblocks[block_nr].nr_pkts = 0;
eraseblocks[block_nr].wbuf_ofs = 0;
mtdoffset += meminfo.erasesize;
goto pkt_again;
}
else /* Usually nothing we can do in file mode */
exit(1);
}
eraseblocks[block_nr].flash_offset += WBUF_SIZE;
/* Copy the remainder into the wbuf */
memcpy(eraseblocks[block_nr].wbuf, &thispkt.data[fits], PKT_SIZE - fits);
eraseblocks[block_nr].wbuf_ofs = PKT_SIZE - fits;
}
if (eraseblocks[block_nr].nr_pkts == pkts_per_block) {
eraseblocks[block_nr].crc = ntohl(thispkt.hdr.block_crc);
if (total_pkts == nr_blocks * pkts_per_block)
break;
}
}
printf("\n");
gettimeofday(&now, NULL);
net_time = (now.tv_usec - start.tv_usec) / 1000;
net_time += (now.tv_sec - start.tv_sec) * 1000;
close(sock);
for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
ssize_t rwlen;
gettimeofday(&start, NULL);
eraseblocks[block_nr].flash_offset -= meminfo.erasesize;
rwlen = pread(flfd, eb_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
gettimeofday(&now, NULL);
rflash_time += (now.tv_usec - start.tv_usec) / 1000;
rflash_time += (now.tv_sec - start.tv_sec) * 1000;
if (rwlen < 0) {
perror("read");
/* Argh. Perhaps we could go back and try again, but if the flash is
going to fail to read back what we write to it, and the whole point
in this program is to write to it, what's the point? */
fprintf(stderr, "Packets we wrote to flash seem to be unreadable. Aborting\n");
exit(1);
}
memcpy(eb_buf + meminfo.erasesize, eraseblocks[block_nr].wbuf,
eraseblocks[block_nr].wbuf_ofs);
for (i=0; i < pkts_per_block; i++)
src_pkts[i] = &eb_buf[i * PKT_SIZE];
gettimeofday(&start, NULL);
if (fec_decode(fec, src_pkts, eraseblocks[block_nr].pkt_indices, PKT_SIZE)) {
/* Eep. This cannot happen */
printf("The world is broken. fec_decode() returned error\n");
exit(1);
}
gettimeofday(&now, NULL);
fec_time += (now.tv_usec - start.tv_usec) / 1000;
fec_time += (now.tv_sec - start.tv_sec) * 1000;
for (i=0; i < pkts_per_block; i++)
memcpy(&decode_buf[i*PKT_SIZE], src_pkts[i], PKT_SIZE);
/* Paranoia */
gettimeofday(&start, NULL);
if (crc32(-1, decode_buf, meminfo.erasesize) != eraseblocks[block_nr].crc) {
printf("\nCRC mismatch for block #%d: want %08x got %08x\n",
block_nr, eraseblocks[block_nr].crc,
crc32(-1, decode_buf, meminfo.erasesize));
exit(1);
}
gettimeofday(&now, NULL);
crc_time += (now.tv_usec - start.tv_usec) / 1000;
crc_time += (now.tv_sec - start.tv_sec) * 1000;
start = now;
if (!file_mode) {
struct erase_info_user erase;
erase.start = eraseblocks[block_nr].flash_offset;
erase.length = meminfo.erasesize;
printf("\rErasing block at %08x...", erase.start);
if (ioctl(flfd, MEMERASE, &erase)) {
perror("MEMERASE");
/* This block has dirty data on it. If the erase failed, we're screwed */
fprintf(stderr, "Erase to clean FEC data from flash failed. Aborting\n");
exit(1);
}
gettimeofday(&now, NULL);
erase_time += (now.tv_usec - start.tv_usec) / 1000;
erase_time += (now.tv_sec - start.tv_sec) * 1000;
start = now;
}
else printf("\r");
write_again:
rwlen = pwrite(flfd, decode_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
if (rwlen < meminfo.erasesize) {
if (rwlen < 0) {
perror("\ndecoded data write");
} else
fprintf(stderr, "\nshort write of decoded data\n");
if (!file_mode) {
struct erase_info_user erase;
erase.start = eraseblocks[block_nr].flash_offset;
erase.length = meminfo.erasesize;
printf("Erasing failed block at %08x\n",
eraseblocks[block_nr].flash_offset);
if (ioctl(flfd, MEMERASE, &erase)) {
perror("MEMERASE");
exit(1);
}
if (mtdoffset >= meminfo.size) {
fprintf(stderr, "Run out of space on flash\n");
exit(1);
}
while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
mtdoffset += meminfo.erasesize;
if (mtdoffset >= meminfo.size) {
fprintf(stderr, "Run out of space on flash\n");
exit(1);
}
}
printf("Will try again at %08lx...", (long)mtdoffset);
eraseblocks[block_nr].flash_offset = mtdoffset;
goto write_again;
}
else /* Usually nothing we can do in file mode */
exit(1);
}
gettimeofday(&now, NULL);
flash_time += (now.tv_usec - start.tv_usec) / 1000;
flash_time += (now.tv_sec - start.tv_sec) * 1000;
printf("wrote image block %08x (%d pkts) ",
block_nr * meminfo.erasesize, eraseblocks[block_nr].nr_pkts);
fflush(stdout);
}
close(flfd);
printf("Net rx %ld.%03lds\n", net_time / 1000, net_time % 1000);
printf("flash rd %ld.%03lds\n", rflash_time / 1000, rflash_time % 1000);
printf("FEC time %ld.%03lds\n", fec_time / 1000, fec_time % 1000);
printf("CRC time %ld.%03lds\n", crc_time / 1000, crc_time % 1000);
printf("flash wr %ld.%03lds\n", flash_time / 1000, flash_time % 1000);
printf("flash er %ld.%03lds\n", erase_time / 1000, erase_time % 1000);
return 0;
}

View File

@ -1,336 +0,0 @@
/*
* rfddump.c
*
* Copyright (C) 2005 Sean Young <sean@mess.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#define _XOPEN_SOURCE 500 /* For pread */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include <mtd/mtd-user.h>
#include <linux/types.h>
#include <mtd_swab.h>
/* next is an array of mapping for each corresponding sector */
#define RFD_MAGIC 0x9193
#define HEADER_MAP_OFFSET 3
#define SECTOR_DELETED 0x0000
#define SECTOR_ZERO 0xfffe
#define SECTOR_FREE 0xffff
#define SECTOR_SIZE 512
#define SECTORS_PER_TRACK 63
struct rfd {
int block_size;
int block_count;
int header_sectors;
int data_sectors;
int header_size;
uint16_t *header;
int sector_count;
int *sector_map;
const char *mtd_filename;
const char *out_filename;
int verbose;
};
#define PROGRAM "rfddump"
#define VERSION "$Revision 1.0 $"
void display_help(void)
{
printf("Usage: " PROGRAM " [OPTIONS] MTD-device filename\n"
"Dumps the contents of a resident flash disk\n"
"\n"
"-h --help display this help and exit\n"
"-V --version output version information and exit\n"
"-v --verbose Be verbose\n"
"-b size --blocksize Block size (defaults to erase unit)\n");
exit(0);
}
void display_version(void)
{
printf(PROGRAM " " VERSION "\n"
"\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
exit(0);
}
void process_options(int argc, char *argv[], struct rfd *rfd)
{
int error = 0;
rfd->block_size = 0;
rfd->verbose = 0;
for (;;) {
int option_index = 0;
static const char *short_options = "hvVb:";
static const struct option long_options[] = {
{ "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V', },
{ "blocksize", required_argument, 0, 'b' },
{ "verbose", no_argument, 0, 'v' },
{ NULL, 0, 0, 0 }
};
int c = getopt_long(argc, argv, short_options,
long_options, &option_index);
if (c == EOF)
break;
switch (c) {
case 'h':
display_help();
break;
case 'V':
display_version();
break;
case 'v':
rfd->verbose = 1;
break;
case 'b':
rfd->block_size = atoi(optarg);
break;
case '?':
error = 1;
break;
}
}
if ((argc - optind) != 2 || error)
display_help();
rfd->mtd_filename = argv[optind];
rfd->out_filename = argv[optind + 1];
}
int build_block_map(struct rfd *rfd, int fd, int block)
{
int i;
int sectors;
if (pread(fd, rfd->header, rfd->header_size, block * rfd->block_size)
!= rfd->header_size) {
return -1;
}
if (le16_to_cpu(rfd->header[0]) != RFD_MAGIC) {
if (rfd->verbose)
printf("Block #%02d: Magic missing\n", block);
return 0;
}
sectors = 0;
for (i=0; i<rfd->data_sectors; i++) {
uint16_t entry = le16_to_cpu(rfd->header[i + HEADER_MAP_OFFSET]);
if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
continue;
if (entry == SECTOR_ZERO)
entry = 0;
if (entry >= rfd->sector_count) {
fprintf(stderr, "%s: warning: sector %d out of range\n",
rfd->mtd_filename, entry);
continue;
}
if (rfd->sector_map[entry] != -1) {
fprintf(stderr, "%s: warning: more than one entry "
"for sector %d\n", rfd->mtd_filename, entry);
continue;
}
rfd->sector_map[entry] = rfd->block_size * block +
(i + rfd->header_sectors) * SECTOR_SIZE;
sectors++;
}
if (rfd->verbose)
printf("Block #%02d: %d sectors\n", block, sectors);
return 1;
}
int main(int argc, char *argv[])
{
int fd, sectors_per_block;
mtd_info_t mtd_info;
struct rfd rfd;
int i, blocks_found;
int out_fd = 0;
uint8_t sector[512];
int blank, rc, cylinders;
process_options(argc, argv, &rfd);
fd = open(rfd.mtd_filename, O_RDONLY);
if (fd == -1) {
perror(rfd.mtd_filename);
return 1;
}
if (rfd.block_size == 0) {
if (ioctl(fd, MEMGETINFO, &mtd_info)) {
perror(rfd.mtd_filename);
close(fd);
return 1;
}
if (mtd_info.type != MTD_NORFLASH) {
fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename);
close(fd);
return 2;
}
sectors_per_block = mtd_info.erasesize / SECTOR_SIZE;
rfd.block_size = mtd_info.erasesize;
rfd.block_count = mtd_info.size / mtd_info.erasesize;
} else {
struct stat st;
if (fstat(fd, &st) == -1) {
perror(rfd.mtd_filename);
close(fd);
return 1;
}
if (st.st_size % SECTOR_SIZE)
fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename);
sectors_per_block = rfd.block_size / SECTOR_SIZE;
if (st.st_size % rfd.block_size)
fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename);
rfd.block_count = st.st_size / rfd.block_size;
if (!rfd.block_count) {
fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename);
close(fd);
return 2;
}
}
rfd.header_sectors =
((HEADER_MAP_OFFSET + sectors_per_block) *
sizeof(uint16_t) + SECTOR_SIZE - 1) / SECTOR_SIZE;
rfd.data_sectors = sectors_per_block - rfd.header_sectors;
cylinders = ((rfd.block_count - 1) * rfd.data_sectors - 1)
/ SECTORS_PER_TRACK;
rfd.sector_count = cylinders * SECTORS_PER_TRACK;
rfd.header_size =
(HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t);
rfd.header = malloc(rfd.header_size);
if (!rfd.header) {
perror(PROGRAM);
close(fd);
return 2;
}
rfd.sector_map = malloc(rfd.sector_count * sizeof(int));
if (!rfd.sector_map) {
perror(PROGRAM);
close(fd);
free(rfd.sector_map);
return 2;
}
rfd.mtd_filename = rfd.mtd_filename;
for (i=0; i<rfd.sector_count; i++)
rfd.sector_map[i] = -1;
for (blocks_found=i=0; i<rfd.block_count; i++) {
rc = build_block_map(&rfd, fd, i);
if (rc > 0)
blocks_found++;
if (rc < 0)
goto err;
}
if (!blocks_found) {
fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename);
goto err;
}
for (i=0; i<rfd.sector_count; i++) {
if (rfd.sector_map[i] != -1)
break;
}
if (i == rfd.sector_count) {
fprintf(stderr, "%s: no sectors found\n", rfd.mtd_filename);
goto err;
}
out_fd = open(rfd.out_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
if (out_fd == -1) {
perror(rfd.out_filename);
goto err;
}
blank = 0;
for (i=0; i<rfd.sector_count; i++) {
if (rfd.sector_map[i] == -1) {
memset(sector, 0, SECTOR_SIZE);
blank++;
} else {
if (pread(fd, sector, SECTOR_SIZE, rfd.sector_map[i])
!= SECTOR_SIZE) {
perror(rfd.mtd_filename);
goto err;
}
}
if (write(out_fd, sector, SECTOR_SIZE) != SECTOR_SIZE) {
perror(rfd.out_filename);
goto err;
}
}
if (rfd.verbose)
printf("Copied %d sectors (%d blank)\n", rfd.sector_count, blank);
close(out_fd);
close(fd);
free(rfd.header);
free(rfd.sector_map);
return 0;
err:
if (out_fd)
close(out_fd);
close(fd);
free(rfd.header);
free(rfd.sector_map);
return 2;
}

View File

@ -1,158 +0,0 @@
/*
* rfdformat.c
*
* Copyright (C) 2005 Sean Young <sean@mess.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This is very easy: just erase all the blocks and put the magic at
* the beginning of each block.
*/
#define _XOPEN_SOURCE 500 /* For pread/pwrite */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include <mtd/mtd-user.h>
#include <linux/types.h>
#define PROGRAM "rfdformat"
#define VERSION "$Revision 1.0 $"
void display_help(void)
{
printf("Usage: " PROGRAM " [OPTIONS] MTD-device\n"
"Formats NOR flash for resident flash disk\n"
"\n"
"-h --help display this help and exit\n"
"-V --version output version information and exit\n");
exit(0);
}
void display_version(void)
{
printf(PROGRAM " " VERSION "\n"
"\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
exit(0);
}
void process_options(int argc, char *argv[], const char **mtd_filename)
{
int error = 0;
for (;;) {
int option_index = 0;
static const char *short_options = "hV";
static const struct option long_options[] = {
{ "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V', },
{ NULL, 0, 0, 0 }
};
int c = getopt_long(argc, argv, short_options,
long_options, &option_index);
if (c == EOF)
break;
switch (c) {
case 'h':
display_help();
break;
case 'V':
display_version();
break;
case '?':
error = 1;
break;
}
}
if ((argc - optind) != 1 || error)
display_help();
*mtd_filename = argv[optind];
}
int main(int argc, char *argv[])
{
static const uint8_t magic[] = { 0x93, 0x91 };
int fd, block_count, i;
struct mtd_info_user mtd_info;
char buf[512];
const char *mtd_filename;
process_options(argc, argv, &mtd_filename);
fd = open(mtd_filename, O_RDWR);
if (fd == -1) {
perror(mtd_filename);
return 1;
}
if (ioctl(fd, MEMGETINFO, &mtd_info)) {
perror(mtd_filename);
close(fd);
return 1;
}
if (mtd_info.type != MTD_NORFLASH) {
fprintf(stderr, "%s: not NOR flash\n", mtd_filename);
close(fd);
return 2;
}
if (mtd_info.size > 32*1024*1024) {
fprintf(stderr, "%s: flash larger than 32MiB not supported\n",
mtd_filename);
close(fd);
return 2;
}
block_count = mtd_info.size / mtd_info.erasesize;
if (block_count < 2) {
fprintf(stderr, "%s: at least two erase units required\n",
mtd_filename);
close(fd);
return 2;
}
for (i=0; i<block_count; i++) {
struct erase_info_user erase_info;
erase_info.start = i * mtd_info.erasesize;
erase_info.length = mtd_info.erasesize;
if (ioctl(fd, MEMERASE, &erase_info) != 0) {
snprintf(buf, sizeof(buf), "%s: erase", mtd_filename);
perror(buf);
close(fd);
return 2;
}
if (pwrite(fd, magic, sizeof(magic), i * mtd_info.erasesize)
!= sizeof(magic)) {
snprintf(buf, sizeof(buf), "%s: write", mtd_filename);
perror(buf);
close(fd);
return 2;
}
}
close(fd);
return 0;
}

View File

@ -1,299 +0,0 @@
#define _POSIX_C_SOURCE 199309
#include <time.h>
#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <netinet/in.h>
#include <sys/time.h>
#include "crc32.h"
#include "mcast_image.h"
int tx_rate = 80000;
int pkt_delay;
#undef RANDOMDROP
int main(int argc, char **argv)
{
struct addrinfo *ai;
struct addrinfo hints;
struct addrinfo *runp;
int ret;
int sock;
struct image_pkt pktbuf;
int rfd;
struct stat st;
int writeerrors = 0;
uint32_t erasesize;
unsigned char *image, *blockptr = NULL;
uint32_t block_nr, pkt_nr;
int nr_blocks;
struct timeval then, now, nextpkt;
long time_msecs;
int pkts_per_block;
int total_pkts_per_block;
struct fec_parms *fec;
unsigned char *last_block;
uint32_t *block_crcs;
long tosleep;
uint32_t sequence = 0;
if (argc == 6) {
tx_rate = atol(argv[5]) * 1024;
if (tx_rate < PKT_SIZE || tx_rate > 20000000) {
fprintf(stderr, "Bogus TX rate %d KiB/s\n", tx_rate);
exit(1);
}
argc = 5;
}
if (argc != 5) {
fprintf(stderr, "usage: %s <host> <port> <image> <erasesize> [<tx_rate>]\n",
(strrchr(argv[0], '/')?:argv[0]-1)+1);
exit(1);
}
pkt_delay = (sizeof(pktbuf) * 1000000) / tx_rate;
printf("Inter-packet delay (avg): %dµs\n", pkt_delay);
printf("Transmit rate: %d KiB/s\n", tx_rate / 1024);
erasesize = atol(argv[4]);
if (!erasesize) {
fprintf(stderr, "erasesize cannot be zero\n");
exit(1);
}
pkts_per_block = (erasesize + PKT_SIZE - 1) / PKT_SIZE;
total_pkts_per_block = pkts_per_block * 3 / 2;
/* We have to pad it with zeroes, so can't use it in-place */
last_block = malloc(pkts_per_block * PKT_SIZE);
if (!last_block) {
fprintf(stderr, "Failed to allocate last-block buffer\n");
exit(1);
}
fec = fec_new(pkts_per_block, total_pkts_per_block);
if (!fec) {
fprintf(stderr, "Error initialising FEC\n");
exit(1);
}
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_ADDRCONFIG;
hints.ai_socktype = SOCK_DGRAM;
ret = getaddrinfo(argv[1], argv[2], &hints, &ai);
if (ret) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
exit(1);
}
runp = ai;
for (runp = ai; runp; runp = runp->ai_next) {
sock = socket(runp->ai_family, runp->ai_socktype,
runp->ai_protocol);
if (sock == -1) {
perror("socket");
continue;
}
if (connect(sock, runp->ai_addr, runp->ai_addrlen) == 0)
break;
perror("connect");
close(sock);
}
if (!runp)
exit(1);
rfd = open(argv[3], O_RDONLY);
if (rfd < 0) {
perror("open");
exit(1);
}
if (fstat(rfd, &st)) {
perror("fstat");
exit(1);
}
if (st.st_size % erasesize) {
fprintf(stderr, "Image size %ld bytes is not a multiple of erasesize %d bytes\n",
st.st_size, erasesize);
exit(1);
}
image = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, rfd, 0);
if (image == MAP_FAILED) {
perror("mmap");
exit(1);
}
nr_blocks = st.st_size / erasesize;
block_crcs = malloc(nr_blocks * sizeof(uint32_t));
if (!block_crcs) {
fprintf(stderr, "Failed to allocate memory for CRCs\n");
exit(1);
}
memcpy(last_block, image + (nr_blocks - 1) * erasesize, erasesize);
memset(last_block + erasesize, 0, (PKT_SIZE * pkts_per_block) - erasesize);
printf("Checking CRC....");
fflush(stdout);
pktbuf.hdr.resend = 0;
pktbuf.hdr.totcrc = htonl(crc32(-1, image, st.st_size));
pktbuf.hdr.nr_blocks = htonl(nr_blocks);
pktbuf.hdr.blocksize = htonl(erasesize);
pktbuf.hdr.thislen = htonl(PKT_SIZE);
pktbuf.hdr.nr_pkts = htons(total_pkts_per_block);
printf("%08x\n", ntohl(pktbuf.hdr.totcrc));
printf("Checking block CRCs....");
fflush(stdout);
for (block_nr=0; block_nr < nr_blocks; block_nr++) {
printf("\rChecking block CRCS.... %d/%d",
block_nr + 1, nr_blocks);
fflush(stdout);
block_crcs[block_nr] = crc32(-1, image + (block_nr * erasesize), erasesize);
}
printf("\nImage size %ld KiB (0x%08lx). %d blocks at %d pkts/block\n"
"Estimated transmit time per cycle: %ds\n",
(long)st.st_size / 1024, (long) st.st_size,
nr_blocks, pkts_per_block,
nr_blocks * pkts_per_block * pkt_delay / 1000000);
gettimeofday(&then, NULL);
nextpkt = then;
#ifdef RANDOMDROP
srand((unsigned)then.tv_usec);
printf("Random seed %u\n", (unsigned)then.tv_usec);
#endif
while (1) for (pkt_nr=0; pkt_nr < total_pkts_per_block; pkt_nr++) {
if (blockptr && pkt_nr == 0) {
unsigned long amt_sent = total_pkts_per_block * nr_blocks * sizeof(pktbuf);
gettimeofday(&now, NULL);
time_msecs = (now.tv_sec - then.tv_sec) * 1000;
time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
printf("\n%ld KiB sent in %ldms (%ld KiB/s)\n",
amt_sent / 1024, time_msecs,
amt_sent / 1024 * 1000 / time_msecs);
then = now;
}
for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
int actualpkt;
/* Calculating the redundant FEC blocks is expensive;
the first $pkts_per_block are cheap enough though
because they're just copies. So alternate between
simple and complex stuff, so that we don't start
to choke and fail to keep up with the expected
bitrate in the second half of the sequence */
if (block_nr & 1)
actualpkt = pkt_nr;
else
actualpkt = total_pkts_per_block - 1 - pkt_nr;
blockptr = image + (erasesize * block_nr);
if (block_nr == nr_blocks - 1)
blockptr = last_block;
fec_encode_linear(fec, blockptr, pktbuf.data, actualpkt, PKT_SIZE);
pktbuf.hdr.thiscrc = htonl(crc32(-1, pktbuf.data, PKT_SIZE));
pktbuf.hdr.block_crc = htonl(block_crcs[block_nr]);
pktbuf.hdr.block_nr = htonl(block_nr);
pktbuf.hdr.pkt_nr = htons(actualpkt);
pktbuf.hdr.pkt_sequence = htonl(sequence++);
printf("\rSending data block %08x packet %3d/%d",
block_nr * erasesize,
pkt_nr, total_pkts_per_block);
if (pkt_nr && !block_nr) {
unsigned long amt_sent = pkt_nr * nr_blocks * sizeof(pktbuf);
gettimeofday(&now, NULL);
time_msecs = (now.tv_sec - then.tv_sec) * 1000;
time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
printf(" (%ld KiB/s) ",
amt_sent / 1024 * 1000 / time_msecs);
}
fflush(stdout);
#ifdef RANDOMDROP
if ((rand() % 1000) < 20) {
printf("\nDropping packet %d of block %08x\n", pkt_nr+1, block_nr * erasesize);
continue;
}
#endif
gettimeofday(&now, NULL);
#if 1
tosleep = nextpkt.tv_usec - now.tv_usec +
(1000000 * (nextpkt.tv_sec - now.tv_sec));
/* We need hrtimers for this to actually work */
if (tosleep > 0) {
struct timespec req;
req.tv_nsec = (tosleep % 1000000) * 1000;
req.tv_sec = tosleep / 1000000;
nanosleep(&req, NULL);
}
#else
while (now.tv_sec < nextpkt.tv_sec ||
(now.tv_sec == nextpkt.tv_sec &&
now.tv_usec < nextpkt.tv_usec)) {
gettimeofday(&now, NULL);
}
#endif
nextpkt.tv_usec += pkt_delay;
if (nextpkt.tv_usec >= 1000000) {
nextpkt.tv_sec += nextpkt.tv_usec / 1000000;
nextpkt.tv_usec %= 1000000;
}
/* If the time for the next packet has already
passed (by some margin), then we've lost time
Adjust our expected timings accordingly. If
we're only a little way behind, don't slip yet */
if (now.tv_usec > (now.tv_usec + (5 * pkt_delay) +
1000000 * (nextpkt.tv_sec - now.tv_sec))) {
nextpkt = now;
}
if (write(sock, &pktbuf, sizeof(pktbuf)) < 0) {
perror("write");
writeerrors++;
if (writeerrors > 10) {
fprintf(stderr, "Too many consecutive write errors\n");
exit(1);
}
} else
writeerrors = 0;
}
}
munmap(image, st.st_size);
close(rfd);
close(sock);
return 0;
}

View File

@ -1,178 +0,0 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
* Zoltan Sogor <weth@inf.u-szeged.hu>,
* Patrik Kluba <pajko@halom.u-szeged.hu>,
* University of Szeged, Hungary
*
* For licensing information, see the file 'LICENCE' in this directory.
*/
#ifndef JFFS2_SUMMARY_H
#define JFFS2_SUMMARY_H
#include <linux/uio.h>
#include <linux/jffs2.h>
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->dirty_size += _x; \
jeb->free_size -= _x ; jeb->dirty_size += _x; \
}while(0)
#define USED_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->used_size += _x; \
jeb->free_size -= _x ; jeb->used_size += _x; \
}while(0)
#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->wasted_size += _x; \
jeb->free_size -= _x ; jeb->wasted_size += _x; \
}while(0)
#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->unchecked_size += _x; \
jeb->free_size -= _x ; jeb->unchecked_size += _x; \
}while(0)
#define BLK_STATE_ALLFF 0
#define BLK_STATE_CLEAN 1
#define BLK_STATE_PARTDIRTY 2
#define BLK_STATE_CLEANMARKER 3
#define BLK_STATE_ALLDIRTY 4
#define BLK_STATE_BADBLOCK 5
#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash))
#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash))
/* Summary structures used on flash */
struct jffs2_sum_unknown_flash
{
jint16_t nodetype; /* node type */
} __attribute__((packed));
struct jffs2_sum_inode_flash
{
jint16_t nodetype; /* node type */
jint32_t inode; /* inode number */
jint32_t version; /* inode version */
jint32_t offset; /* offset on jeb */
jint32_t totlen; /* record length */
} __attribute__((packed));
struct jffs2_sum_dirent_flash
{
jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
jint32_t totlen; /* record length */
jint32_t offset; /* ofset on jeb */
jint32_t pino; /* parent inode */
jint32_t version; /* dirent version */
jint32_t ino; /* == zero for unlink */
uint8_t nsize; /* dirent name size */
uint8_t type; /* dirent type */
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
struct jffs2_sum_xattr_flash
{
jint16_t nodetype; /* == JFFS2_NODETYPE_XATR */
jint32_t xid; /* xattr identifier */
jint32_t version; /* version number */
jint32_t offset; /* offset on jeb */
jint32_t totlen; /* node length */
} __attribute__((packed));
struct jffs2_sum_xref_flash
{
jint16_t nodetype; /* == JFFS2_NODETYPE_XREF */
jint32_t offset; /* offset on jeb */
} __attribute__((packed));
union jffs2_sum_flash
{
struct jffs2_sum_unknown_flash u;
struct jffs2_sum_inode_flash i;
struct jffs2_sum_dirent_flash d;
struct jffs2_sum_xattr_flash x;
struct jffs2_sum_xref_flash r;
};
/* Summary structures used in the memory */
struct jffs2_sum_unknown_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype; /* node type */
} __attribute__((packed));
struct jffs2_sum_inode_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype; /* node type */
jint32_t inode; /* inode number */
jint32_t version; /* inode version */
jint32_t offset; /* offset on jeb */
jint32_t totlen; /* record length */
} __attribute__((packed));
struct jffs2_sum_dirent_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
jint32_t totlen; /* record length */
jint32_t offset; /* ofset on jeb */
jint32_t pino; /* parent inode */
jint32_t version; /* dirent version */
jint32_t ino; /* == zero for unlink */
uint8_t nsize; /* dirent name size */
uint8_t type; /* dirent type */
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
struct jffs2_sum_xattr_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype;
jint32_t xid;
jint32_t version;
jint32_t offset;
jint32_t totlen;
} __attribute__((packed));
struct jffs2_sum_xref_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype;
jint32_t offset;
} __attribute__((packed));
union jffs2_sum_mem
{
struct jffs2_sum_unknown_mem u;
struct jffs2_sum_inode_mem i;
struct jffs2_sum_dirent_mem d;
struct jffs2_sum_xattr_mem x;
struct jffs2_sum_xref_mem r;
};
struct jffs2_summary
{
uint32_t sum_size;
uint32_t sum_num;
uint32_t sum_padded;
union jffs2_sum_mem *sum_list_head;
union jffs2_sum_mem *sum_list_tail;
};
/* Summary marker is stored at the end of every sumarized erase block */
struct jffs2_sum_marker
{
jint32_t offset; /* offset of the summary node in the jeb */
jint32_t magic; /* == JFFS2_SUM_MAGIC */
};
#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker))
#endif

View File

@ -1,951 +0,0 @@
/*
* sumtool.c
*
* Copyright (C) 2004 Zoltan Sogor <weth@inf.u-szeged.hu>,
* Ferenc Havasi <havasi@inf.u-szeged.hu>
* University of Szeged, Hungary
* 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Overview:
* This is a utility insert summary information into JFFS2 image for
* faster mount time
*
*/
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <asm/types.h>
#include <dirent.h>
#include <mtd/jffs2-user.h>
#include <endian.h>
#include <byteswap.h>
#include <getopt.h>
#include "crc32.h"
#include "summary.h"
#define PAD(x) (((x)+3)&~3)
static const char *const app_name = "sumtool";
static struct jffs2_summary *sum_collected = NULL;
static int verbose = 0;
static int padto = 0; /* pad the output with 0xFF to the end of the final eraseblock */
static int add_cleanmarkers = 1; /* add cleanmarker to output */
static int use_input_cleanmarker_size = 1; /* use input file's cleanmarker size (default) */
static int found_cleanmarkers = 0; /* cleanmarker found in input file */
static struct jffs2_unknown_node cleanmarker;
static int cleanmarker_size = sizeof(cleanmarker);
static const char *short_options = "o:i:e:hvVblnc:p";
static int erase_block_size = 65536;
static int out_fd = -1;
static int in_fd = -1;
static uint8_t *data_buffer = NULL; /* buffer for inodes */
static unsigned int data_ofs = 0; /* inode buffer offset */
static uint8_t *file_buffer = NULL; /* file buffer contains the actual erase block*/
static unsigned int file_ofs = 0; /* position in the buffer */
int target_endian = __BYTE_ORDER;
static struct option long_options[] = {
{"output", 1, NULL, 'o'},
{"input", 1, NULL, 'i'},
{"eraseblock", 1, NULL, 'e'},
{"help", 0, NULL, 'h'},
{"verbose", 0, NULL, 'v'},
{"version", 0, NULL, 'V'},
{"bigendian", 0, NULL, 'b'},
{"littleendian", 0, NULL, 'l'},
{"no-cleanmarkers", 0, NULL, 'n'},
{"cleanmarker", 1, NULL, 'c'},
{"pad", 0, NULL, 'p'},
{NULL, 0, NULL, 0}
};
static char *helptext =
"Usage: sumtool [OPTIONS] -i inputfile -o outputfile\n\n"
"Convert the input JFFS2 image to a summarized JFFS2 image\n"
"Summary makes mounting faster - if summary support enabled in your kernel\n\n"
"Options:\n"
" -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)\n"
" (usually 16KiB on NAND)\n"
" -c, --cleanmarker=SIZE Size of cleanmarker (default 12).\n"
" (usually 16 bytes on NAND, and will be set to\n"
" this value if left at the default 12). Will be\n"
" stored in OOB after each physical page composing\n"
" a physical eraseblock.\n"
" -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock\n"
" -o, --output=FILE Output to FILE \n"
" -i, --input=FILE Input from FILE \n"
" -b, --bigendian Image is big endian\n"
" -l --littleendian Image is little endian\n"
" -h, --help Display this help text\n"
" -v, --verbose Verbose operation\n"
" -V, --version Display version information\n"
" -p, --pad Pad the OUTPUT with 0xFF to the end of the final\n"
" eraseblock\n\n";
static char *revtext = "$Revision: 1.1.1.1 $";
static unsigned char ffbuf[16] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
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_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_and_die(const char *s, ...)
{
va_list p;
va_start(p, s);
vperror_msg(s, p);
va_end(p);
exit(EXIT_FAILURE);
}
static void full_write(void *target_buff, const void *buf, int len);
void setup_cleanmarker()
{
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));
}
void process_options (int argc, char **argv)
{
int opt,c;
while ((opt = getopt_long(argc, argv, short_options, long_options, &c)) >= 0) {
switch (opt) {
case 'o':
if (out_fd != -1)
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 'i':
if (in_fd != -1)
error_msg_and_die("input filename specified more than once");
in_fd = open(optarg, O_RDONLY);
if (in_fd == -1)
perror_msg_and_die("open input file");
break;
case 'b':
target_endian = __BIG_ENDIAN;
break;
case 'l':
target_endian = __LITTLE_ENDIAN;
break;
case 'h':
case '?':
error_msg_and_die(helptext);
case 'v':
verbose = 1;
break;
case 'V':
error_msg_and_die("revision %.*s\n",
(int) strlen(revtext) - 13, revtext + 11);
case 'e': {
char *next;
unsigned units = 0;
erase_block_size = strtol(optarg, &next, 0);
if (!erase_block_size)
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 '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");
}
use_input_cleanmarker_size = 0;
found_cleanmarkers = 1;
setup_cleanmarker();
break;
case 'p':
padto = 1;
break;
}
}
}
void init_buffers()
{
data_buffer = malloc(erase_block_size);
if (!data_buffer) {
perror("out of memory");
close (in_fd);
close (out_fd);
exit(1);
}
file_buffer = malloc(erase_block_size);
if (!file_buffer) {
perror("out of memory");
close (in_fd);
close (out_fd);
exit(1);
}
}
void init_sumlist()
{
sum_collected = (struct jffs2_summary *) malloc (sizeof(struct jffs2_summary));
if (!sum_collected)
error_msg_and_die("Can't allocate memory for jffs2_summary!\n");
memset(sum_collected, 0, sizeof(struct jffs2_summary));
}
void clean_buffers()
{
if (data_buffer)
free(data_buffer);
if (file_buffer)
free(file_buffer);
}
void clean_sumlist()
{
union jffs2_sum_mem *temp;
if (sum_collected) {
while (sum_collected->sum_list_head) {
temp = sum_collected->sum_list_head;
sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
free(temp);
sum_collected->sum_num--;
}
if (sum_collected->sum_num != 0)
printf("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
free(sum_collected);
}
}
int load_next_block()
{
int ret;
ret = read(in_fd, file_buffer, erase_block_size);
file_ofs = 0;
if (verbose)
printf("Load next block : %d bytes read\n",ret);
return ret;
}
void write_buff_to_file()
{
int ret;
int len = data_ofs;
uint8_t *buf = NULL;
buf = data_buffer;
while (len > 0) {
ret = write(out_fd, buf, len);
if (ret < 0)
perror_msg_and_die("write");
if (ret == 0)
perror_msg_and_die("write returned zero");
len -= ret;
buf += ret;
}
data_ofs = 0;
}
void dump_sum_records()
{
struct jffs2_raw_summary isum;
struct jffs2_sum_marker *sm;
union jffs2_sum_mem *temp;
jint32_t offset;
jint32_t *tpage;
void *wpage;
int datasize, infosize, padsize;
jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
if (!sum_collected->sum_num || !sum_collected->sum_list_head)
return;
datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
infosize = sizeof(struct jffs2_raw_summary) + datasize;
padsize = erase_block_size - data_ofs - infosize;
infosize += padsize; datasize += padsize;
offset = cpu_to_je32(data_ofs);
tpage = (jint32_t *) malloc(datasize);
if(!tpage)
error_msg_and_die("Can't allocate memory to dump summary information!\n");
memset(tpage, 0xff, datasize);
memset(&isum, 0, sizeof(isum));
isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
isum.totlen = cpu_to_je32(infosize);
isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
isum.padded = cpu_to_je32(0);
if (add_cleanmarkers && found_cleanmarkers) {
isum.cln_mkr = cpu_to_je32(cleanmarker_size);
} else {
isum.cln_mkr = cpu_to_je32(0);
}
isum.sum_num = cpu_to_je32(sum_collected->sum_num);
wpage = tpage;
while (sum_collected->sum_num) {
switch(je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) {
case JFFS2_NODETYPE_INODE : {
struct jffs2_sum_inode_flash *sino_ptr = wpage;
sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype;
sino_ptr->inode = sum_collected->sum_list_head->i.inode;
sino_ptr->version = sum_collected->sum_list_head->i.version;
sino_ptr->offset = sum_collected->sum_list_head->i.offset;
sino_ptr->totlen = sum_collected->sum_list_head->i.totlen;
wpage += JFFS2_SUMMARY_INODE_SIZE;
break;
}
case JFFS2_NODETYPE_DIRENT : {
struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype;
sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen;
sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset;
sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino;
sdrnt_ptr->version = sum_collected->sum_list_head->d.version;
sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino;
sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize;
sdrnt_ptr->type = sum_collected->sum_list_head->d.type;
memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name,
sum_collected->sum_list_head->d.nsize);
wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize);
break;
}
case JFFS2_NODETYPE_XATTR: {
struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype;
sxattr_ptr->xid = sum_collected->sum_list_head->x.xid;
sxattr_ptr->version = sum_collected->sum_list_head->x.version;
sxattr_ptr->offset = sum_collected->sum_list_head->x.offset;
sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen;
wpage += JFFS2_SUMMARY_XATTR_SIZE;
break;
}
case JFFS2_NODETYPE_XREF: {
struct jffs2_sum_xref_flash *sxref_ptr = wpage;
sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype;
sxref_ptr->offset = sum_collected->sum_list_head->r.offset;
wpage += JFFS2_SUMMARY_XREF_SIZE;
break;
}
default : {
printf("Unknown node type!\n");
}
}
temp = sum_collected->sum_list_head;
sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
free(temp);
sum_collected->sum_num--;
}
sum_collected->sum_size = 0;
sum_collected->sum_num = 0;
sum_collected->sum_list_tail = NULL;
wpage += padsize;
sm = wpage;
sm->offset = offset;
sm->magic = magic;
isum.sum_crc = cpu_to_je32(crc32(0, tpage, datasize));
isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
full_write(data_buffer + data_ofs, &isum, sizeof(isum));
full_write(data_buffer + data_ofs, tpage, datasize);
free(tpage);
}
static void full_write(void *target_buff, const void *buf, int len)
{
memcpy(target_buff, buf, len);
data_ofs += len;
}
static void pad(int req)
{
while (req) {
if (req > sizeof(ffbuf)) {
full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf));
req -= sizeof(ffbuf);
} else {
full_write(data_buffer + data_ofs, ffbuf, req);
req = 0;
}
}
}
static inline void padword()
{
if (data_ofs % 4)
full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4));
}
static inline void pad_block_if_less_than(int req,int plus)
{
int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
datasize += (4 - (datasize % 4)) % 4;
if (data_ofs + req > erase_block_size - datasize) {
dump_sum_records();
write_buff_to_file();
}
if (add_cleanmarkers && found_cleanmarkers) {
if (!data_ofs) {
full_write(data_buffer, &cleanmarker, sizeof(cleanmarker));
pad(cleanmarker_size - sizeof(cleanmarker));
padword();
}
}
}
void flush_buffers()
{
if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */
if (data_ofs != cleanmarker_size) { /* INODE BUFFER */
int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
datasize += (4 - (datasize % 4)) % 4;
/* If we have a full inode buffer, then write out inode and summary data */
if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
dump_sum_records();
write_buff_to_file();
} else { /* else just write out inode data */
if (padto)
pad(erase_block_size - data_ofs);
write_buff_to_file();
}
}
} else { /* NO CLEANMARKER */
if (data_ofs != 0) { /* INODE BUFFER */
int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
datasize += (4 - (datasize % 4)) % 4;
/* If we have a full inode buffer, then write out inode and summary data */
if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
dump_sum_records();
write_buff_to_file();
} else { /* Else just write out inode data */
if(padto)
pad(erase_block_size - data_ofs);
write_buff_to_file();
}
}
}
}
int add_sum_mem(union jffs2_sum_mem *item)
{
if (!sum_collected->sum_list_head)
sum_collected->sum_list_head = (union jffs2_sum_mem *) item;
if (sum_collected->sum_list_tail)
sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
sum_collected->sum_list_tail = (union jffs2_sum_mem *) item;
switch (je16_to_cpu(item->u.nodetype)) {
case JFFS2_NODETYPE_INODE:
sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
sum_collected->sum_num++;
break;
case JFFS2_NODETYPE_DIRENT:
sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
sum_collected->sum_num++;
break;
case JFFS2_NODETYPE_XATTR:
sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
sum_collected->sum_num++;
break;
case JFFS2_NODETYPE_XREF:
sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE;
sum_collected->sum_num++;
break;
default:
error_msg_and_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
}
return 0;
}
void add_sum_inode_mem(union jffs2_node_union *node)
{
struct jffs2_sum_inode_mem *temp = (struct jffs2_sum_inode_mem *) malloc(sizeof(struct jffs2_sum_inode_mem));
if (!temp)
error_msg_and_die("Can't allocate memory for summary information!\n");
temp->nodetype = node->i.nodetype;
temp->inode = node->i.ino;
temp->version = node->i.version;
temp->offset = cpu_to_je32(data_ofs);
temp->totlen = node->i.totlen;
temp->next = NULL;
add_sum_mem((union jffs2_sum_mem *) temp);
}
void add_sum_dirent_mem(union jffs2_node_union *node)
{
struct jffs2_sum_dirent_mem *temp = (struct jffs2_sum_dirent_mem *)
malloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize);
if (!temp)
error_msg_and_die("Can't allocate memory for summary information!\n");
temp->nodetype = node->d.nodetype;
temp->totlen = node->d.totlen;
temp->offset = cpu_to_je32(data_ofs);
temp->pino = node->d.pino;
temp->version = node->d.version;
temp->ino = node->d.ino;
temp->nsize = node->d.nsize;
temp->type = node->d.type;
temp->next = NULL;
memcpy(temp->name,node->d.name,node->d.nsize);
add_sum_mem((union jffs2_sum_mem *) temp);
}
void add_sum_xattr_mem(union jffs2_node_union *node)
{
struct jffs2_sum_xattr_mem *temp = (struct jffs2_sum_xattr_mem *)
malloc(sizeof(struct jffs2_sum_xattr_mem));
if (!temp)
error_msg_and_die("Can't allocate memory for summary information!\n");
temp->nodetype = node->x.nodetype;
temp->xid = node->x.xid;
temp->version = node->x.version;
temp->offset = cpu_to_je32(data_ofs);
temp->totlen = node->x.totlen;
temp->next = NULL;
add_sum_mem((union jffs2_sum_mem *) temp);
}
void add_sum_xref_mem(union jffs2_node_union *node)
{
struct jffs2_sum_xref_mem *temp = (struct jffs2_sum_xref_mem *)
malloc(sizeof(struct jffs2_sum_xref_mem));
if (!temp)
error_msg_and_die("Can't allocate memory for summary information!\n");
temp->nodetype = node->r.nodetype;
temp->offset = cpu_to_je32(data_ofs);
temp->next = NULL;
add_sum_mem((union jffs2_sum_mem *) temp);
}
void write_dirent_to_buff(union jffs2_node_union *node)
{
pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize));
add_sum_dirent_mem(node);
full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen));
padword();
}
void write_inode_to_buff(union jffs2_node_union *node)
{
pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE);
add_sum_inode_mem(node); /* Add inode summary mem to summary list */
full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen)); /* Write out the inode to inode_buffer */
padword();
}
void write_xattr_to_buff(union jffs2_node_union *node)
{
pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE);
add_sum_xattr_mem(node); /* Add xdatum summary mem to summary list */
full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen));
padword();
}
void write_xref_to_buff(union jffs2_node_union *node)
{
pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE);
add_sum_xref_mem(node); /* Add xref summary mem to summary list */
full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen));
padword();
}
void create_summed_image(int inp_size)
{
uint8_t *p = file_buffer;
union jffs2_node_union *node;
uint32_t crc, length;
uint16_t type;
int bitchbitmask = 0;
int obsolete;
char name[256];
while ( p < (file_buffer + inp_size)) {
node = (union jffs2_node_union *) p;
/* Skip empty space */
if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
p += 4;
continue;
}
if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
if (!bitchbitmask++)
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);
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 - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
p += 4;
continue;
}
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));
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 - file_buffer, je32_to_cpu (node->i.node_crc), crc);
p += 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 - file_buffer, je32_to_cpu (node->i.data_crc), crc);
p += PAD(je32_to_cpu (node->i.totlen));
continue;
}
write_inode_to_buff(node);
p += PAD(je32_to_cpu (node->i.totlen));
break;
case JFFS2_NODETYPE_DIRENT:
memcpy (name, node->d.name, node->d.nsize);
name [node->d.nsize] = 0x0;
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);
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 - file_buffer, je32_to_cpu (node->d.node_crc), crc);
p += 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 - file_buffer, je32_to_cpu (node->d.name_crc), crc);
p += PAD(je32_to_cpu (node->d.totlen));
continue;
}
write_dirent_to_buff(node);
p += PAD(je32_to_cpu (node->d.totlen));
break;
case JFFS2_NODETYPE_XATTR:
if (je32_to_cpu(node->x.node_crc) == 0xffffffff)
obsolete = 1;
if (verbose)
printf("%8s Xdatum node at 0x%08x, totlen 0x%08x, "
"#xid %5u, version %5u\n",
obsolete ? "Obsolete" : "",
p - file_buffer, je32_to_cpu (node->x.totlen),
je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version));
crc = crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4);
if (crc != je32_to_cpu(node->x.node_crc)) {
printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
p - file_buffer, je32_to_cpu(node->x.node_crc), crc);
p += PAD(je32_to_cpu (node->x.totlen));
continue;
}
length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len);
crc = crc32(0, node->x.data, length);
if (crc != je32_to_cpu(node->x.data_crc)) {
printf("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
p - file_buffer, je32_to_cpu(node->x.data_crc), crc);
p += PAD(je32_to_cpu (node->x.totlen));
continue;
}
write_xattr_to_buff(node);
p += PAD(je32_to_cpu (node->x.totlen));
break;
case JFFS2_NODETYPE_XREF:
if (je32_to_cpu(node->r.node_crc) == 0xffffffff)
obsolete = 1;
if (verbose)
printf("%8s Xref node at 0x%08x, totlen 0x%08x, "
"#ino %5u, xid %5u\n",
obsolete ? "Obsolete" : "",
p - file_buffer, je32_to_cpu(node->r.totlen),
je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid));
crc = crc32(0, node, sizeof (struct jffs2_raw_xref) - 4);
if (crc != je32_to_cpu(node->r.node_crc)) {
printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
p - file_buffer, je32_to_cpu(node->r.node_crc), crc);
p += PAD(je32_to_cpu (node->r.totlen));
continue;
}
write_xref_to_buff(node);
p += PAD(je32_to_cpu (node->r.totlen));
break;
case JFFS2_NODETYPE_CLEANMARKER:
if (verbose) {
printf ("%8s Cleanmarker at 0x%08x, totlen 0x%08x\n",
obsolete ? "Obsolete" : "",
p - file_buffer, je32_to_cpu (node->u.totlen));
}
if (!found_cleanmarkers) {
found_cleanmarkers = 1;
if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){
cleanmarker_size = je32_to_cpu (node->u.totlen);
setup_cleanmarker();
}
}
p += PAD(je32_to_cpu (node->u.totlen));
break;
case JFFS2_NODETYPE_PADDING:
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));
}
}
}
int main(int argc, char **argv)
{
int ret;
process_options(argc,argv);
if ((in_fd == -1) || (out_fd == -1)) {
if(in_fd != -1)
close(in_fd);
if(out_fd != -1)
close(out_fd);
fprintf(stderr,helptext);
error_msg_and_die("You must specify input and output files!\n");
}
init_buffers();
init_sumlist();
while ((ret = load_next_block())) {
create_summed_image(ret);
}
flush_buffers();
clean_buffers();
clean_sumlist();
if (in_fd != -1)
close(in_fd);
if (out_fd != -1)
close(out_fd);
return 0;
}

View File

@ -1,14 +0,0 @@
all: checkfs makefiles
checkfs: checkfs.c Makefile common.h comm.o
gcc -g -Wall checkfs.c comm.o -o checkfs
comm.o: comm.c Makefile
gcc -g -Wall -c comm.c -o comm.o
makefiles: makefiles.c Makefile common.h
gcc -g -Wall makefiles.c -o makefiles
clean:
rm -f makefiles checkfs *~ *.o

View File

@ -1,173 +0,0 @@
$Id: README,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
$Log: not supported by cvs2svn $
Revision 1.2 2001/06/21 23:07:06 dwmw2
Initial import to MTD CVS
Revision 1.1 2001/06/11 19:34:40 vipin
Added README file to dir.
This is the README file for the "checkfs" power fail test program.
By: Vipin Malik
NOTE: This program requires an external "power cycling box"
connected to one of the com ports of the system under test.
This power cycling box should wait for a random amount of time
after it receives a "ok to power me down" message over the
serial port, and then yank power to the system under test.
(The box that I rigged up tested with waits anywhere from
0 to ~40 seconds).
It should then restore power after a few seconds and wait for the
message again.
ABOUT:
This program's primary purpose it to test the reliiability
of various file systems under Linux.
SETUP:
You need to setup the file system you want to test and run the
"makefiles" program ONCE. This creates a set of files that are
required by the "checkfs" program.
Also copy the "checkfs" executable program to the same dir.
Then you need to make sure that the program "checkfs" is called
automatically on startup. You can customise the operation of
the "checkfs" program by passing it various cmd line arguments.
run "checkfs -?" for more details.
****NOTE*******
Make sure that you call the checkfs program only after you have
mounted the file system you want to test (this is obvious), but
also after you have run any "scan" utilities to check for and
fix any file systems errors. The e2fsck is one utility for the
ext2 file system. For an automated setup you of course need to
provide these scan programs to run in standalone mode (-f -y
flags for e2fsck for example).
File systems like JFFS and JFFS2 do not have any such external
utilities and you may call "checkfs" right after you have mounted
the respective file system under test.
There are two ways you can mount the file system under test:
1. Mount your root fs on a "standard" fs like ext2 and then
mount the file system under test (which may be ext2 on another
partition or device) and then run "checkfs" on this mounted
partition OR
2. Make your fs AND device that you have put this fs as your
root fs and run "checkfs" on the root device (i.e. "/").
You can of course still run checkfs under a separate dir
under your "/" root dir.
I have found the second method to be a particularly stringent
arrangement (and thus preferred when you are trying to break
something).
Using this arrangement I was able to find that JFFS clobbered
some "sister" files on the root fs even though "checkfs" would
run fine through all its own check files.
(I found this out when one of the clobbered sister file happened
to be /bin/bash. The system refused to run rc.local thus
preventing my "checkfs" program from being launched :)
"checkfs":
The "formatting" reliability of the fs as well as the file data integrity
of files on the fs can be checked using this program.
"formatiing" reliability can only be checked via an indirect method.
If there is severe formatting reliability issues with the file system,
it will most likely cause other system failures that will prevent this
program from running successfully on a power up. This will prevent
a "ok to power me down" message from going out to the power cycling
black box and prevent power being turned off again.
File data reliability is checked more directly. A fixed number of
files are created in the current dir (using the program "makefiles").
Each file has a random number of bytes in it (set by using the
-s cmd line flag). The number of "ints" in the file is stored as the
first "int" in it (note: 0 length files are not allowed). Each file
is then filled with random data and a 16 bit CRC appended at the end.
When "checkfs" is run, it runs through all files (with predetermined
file names)- one at a time- and checks for the number of "int's"
in it as well as the ending CRC.
The program exits if the numbers of files that are corrupt are greater
that a user specified parameter (set by using the -e cmd line flag).
If the number of corrupt files is less than this parameter, the corrupt
files are repaired and operation resumes as explained below.
The idea behind allowing a user specified amount of corrupt files is as
follows:
If you are testing for "formatting" reliability of a fs, and for
the data reliability of "other" files present of the fs, use -e 1.
"other" files are defined as sister files on the fs, not being written to
by the "checkfs" test program.
As mentioned, in this case you would set -e 1, or allow at most 1 file
to be corrupt each time after a power fail. This would be the file
that was probably being written to when power failed (and CRC was not
updated to reflect the new data being written). You would check file
systems like ext2 etc. with such a configuration.
(As you have no hope that these file systems provide for either your
new data or old data to be present in the file if power failed during
the write. This is called "roll back and recover".)
With JFFS2 I tested for such "roll back and recover" file data reliability
by setting -e 0 and making sure that all writes to the file being
updated are done in a *single* write().
This is how I found that JFFS2 (yet) does NOT support this functionality.
(There was a great debate if this was a bug or a feature that was lacking
or even an issue at all. See the mtd archives for more details).
In other words, JFFS2 will partially update a file on FLASH even before
the write() command has completed, thus leaving part old data part new
data in your file if power failed in the middle of a write().
This is bad functionality if you are updating a binary structure or a
CRC protected file (as in our case).
If All Files Check Out OK:
On the startup scan, if there are less errors than specified by the "-e flag"
a "ok to power me down message" is sent via the specified com port.
The actual format of this message will depend on the format expected
by the power cycling box that will receive this message. One may customise
the actual message that goes out in the "do_pwr_dn)" routine in "comm.c".
This file is called with an open file descriptor to the comm port that
this message needs to go out over and the count of the current power
cycle (in case your power cycling box can display/log this count).
After this message has been sent out, the checkfs program goes into
a while(1) loop of writing new data (with CRC), one at a time, into
all the "check files" in the dir.
Its life comes to a sudden end when power is asynchronously pulled from
under its feet (by your external power cycling box).
It comes back to life when power is restored and the system boots and
checkfs is called from the rc.local script file.
The cycle then repeats till a problem is detected, at which point
the "ok to power me down" message is not sent and the cycle stops
waiting for the user to examine the system.

View File

@ -1,695 +0,0 @@
/*
* Copyright Daniel Industries.
*
* Created by: Vipin Malik (vipin.malik@daniel.com)
*
* This code is released under the GPL version 2. See the file COPYING
* for more details.
*
* 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.
This program opens files in progression (file00001, file00002 etc),
upto MAX_NUM_FILES and checks their CRC. If a file is not found or the
CRC does not match it stops it's operation.
Everything is logged in a logfile called './logfile'.
If everything is ok this program sends a signal, via com1, to the remote
power control box to power cycle this computer.
This program then proceeds to create new files file0....file<MAX_NUM_FILES>
in a endless loop and checksum each before closing them.
STRUCTURE OF THE FILES:
The fist int is the size of the file in bytes.
The last 2 bytes are the CRC for the entire file.
There is random data in between.
The files are opened in the current dir.
$Id: checkfs.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
$Log: not supported by cvs2svn $
Revision 1.8 2005/11/07 11:15:17 gleixner
[MTD / JFFS2] Clean up trailing white spaces
Revision 1.7 2001/06/21 23:04:17 dwmw2
Initial import to MTD CVS
Revision 1.6 2001/06/08 22:26:05 vipin
Split the modbus comm part of the program (that sends the ok to pwr me down
message) into another file "comm.c"
Revision 1.5 2001/06/08 21:29:56 vipin
fixed small issue with write() checking for < 0 instead of < (bytes to be written).
Now it does the latter (as it should).
Revision 1.4 2001/05/11 22:29:40 vipin
Added a test to check and err out if the first int in file (which tells us
how many bytes there are in the file) is zero. This will prevent a corrupt
file with zero's in it from passing the crc test.
Revision 1.3 2001/05/11 21:33:54 vipin
Changed to use write() rather than fwrite() when creating new file. Additionally,
and more important, it now does a single write() for the entire data. This will
enable us to use this program to test for power fail *data* reliability when
writing over an existing file, specially on powr fail "safe" file systems as
jffs/jffs2. Also added a new cmdline parameter "-e" that specifies the max # of
errors that can be tolerated. This should be set to ZERO to test for the above,
as old data should be reliabily maintained if the newer write never "took" before
power failed. If the write did succeed, then the newer data will have its own
CRC in place when it gets checked => hence no error. In theory at least!
Revision 1.2 2001/05/11 19:27:33 vipin
Added cmd line args to change serial port, and specify max size of
random files created. Some cleanup. Added -Wall to Makefile.
Revision 1.1 2001/05/11 16:06:28 vipin
Importing checkfs (the power fail test program) into CVS. This was
originally done for NEWS. NEWS had a lot of version, this is
based off the last one done for NEWS. The "makefiles" program
is run once initially to create the files in the current dir.
"checkfs" is then run on every powerup to check consistancy
of the files. See checkfs.c for more details.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include "common.h"
extern int do_pwr_dn(int fd, int cycleCnt);
#define CMDLINE_PORT "-p"
#define CMDLINE_MAXFILEBYTES "-s"
#define CMDLINE_MAXERROR "-e"
#define CMDLINE_HELPSHORT "-?"
#define CMDLINE_HELPLONG "--help"
int CycleCount;
char SerialDevice[255] = "/dev/ttyS0"; /* default, can be changed
through cmd line. */
#define MAX_INTS_ALLOW 100000 /* max # of int's in the file written.
Statis limit to size struct. */
float FileSizeMax = 1024.0; /*= (file size in bytes), MUST be float*/
int MaxErrAllowed = 1; /* default, can ge changed thru cmd line*/
/* Needed for CRC generation/checking */
static const unsigned short crc_ccitt_table[] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
/*
Set's up the Linux serial port. Must be passed string to device to
open. Parameters are fixed to 9600,e,1
[A possible enhancement to this program would be to pass these
parameters via the command line.]
Returns file descriptor to open port. Use this fd to write to port
and close it later, when done.
*/
int setupSerial (const char *dev) {
int i, fd;
struct termios tios;
fd = open(dev,O_RDWR | O_NDELAY );
if (fd < 0) {
fprintf(stderr, "%s: %s\n", dev, sys_errlist[errno]);
exit(1);
}
if (tcgetattr(fd, &tios) < 0) {
fprintf(stderr,"Could not get terminal attributes: %s",sys_errlist[errno]);
exit(1);
}
tios.c_cflag =
CS7 |
CREAD | // Enable Receiver
HUPCL | // Hangup after close
CLOCAL | // Ignore modem control lines
PARENB; // Enable parity (even by default)
tios.c_iflag = IGNBRK; // Ignore break
tios.c_oflag = 0;
tios.c_lflag = 0;
for(i = 0; i < NCCS; i++) {
tios.c_cc[i] = '\0'; // no special characters
}
tios.c_cc[VMIN] = 1;
tios.c_cc[VTIME] = 0;
cfsetospeed (&tios, B9600);
cfsetispeed (&tios, B9600);
if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
fprintf(stderr,"Could not set attributes: ,%s",sys_errlist[errno]);
exit(1);
}
return fd;
}
//A portion of this code was taken from the AX.25 HDLC packet driver
//in LINUX. Once I test and have a better understanding of what
//it is doing, it will be better commented.
//For now one can speculate that the CRC routine always expects the
//CRC to calculate out to 0xf0b8 (the hardcoded value at the end)
//and returns TRUE if it is and FALSE if it doesn't.
//Why don't people document better!!!!
int check_crc_ccitt(char *filename)
{
FILE *fp;
FILE *logfp;
unsigned short crc = 0xffff;
int len;
char dataByte;
int retry;
char done;
fp = fopen(filename,"rb");
if(!fp){
logfp = fopen("logfile","a"); /*open for appending only.*/
fprintf(logfp, "Verify checksum:Error! Cannot open filename passed for verify checksum: %s\n",filename);
fclose(logfp);
return FALSE;
}
/*the first int contains an int that is the length of the file in long.*/
if(fread(&len, sizeof(int), 1, fp) != 1){
logfp = fopen("logfile","a"); /*open for appending only.*/
fprintf(logfp, "verify checksum:Error reading from file: %s\n", filename);
fclose(fp);
fclose(logfp);
return FALSE;
}
/* printf("Checking %i bytes for CRC in \"%s\".\n", len, filename); */
/* Make sure that we did not read 0 as the number of bytes in file. This
check prevents a corrupt file with zero's in it from passing the
CRC test. A good file will always have some data in it. */
if(len == 0)
{
logfp = fopen("logfile","a"); /*open for appending only.*/
fprintf(logfp, "verify checksum: first int claims there are 0 data in file. Error!: %s\n", filename);
fclose(fp);
fclose(logfp);
return FALSE;
}
rewind(fp);
len+=2; /*the file has two extra bytes at the end, it's checksum. Those
two MUST also be included in the checksum calculation.
*/
for (;len>0;len--){
retry=5; /*retry 5 times*/
done = FALSE;
while(!done){
if(fread(&dataByte, sizeof(char), 1, fp) != 1){
retry--;
}else{
done = TRUE;
}
if(retry == 0){
done = TRUE;
}
}
if(!retry){
logfp = fopen("logfile","a"); /*open for appending only.*/
fprintf(logfp, "Unexpected end of file: %s\n", filename);
fprintf(logfp, "...bytes left to be read %i.\n",len);
fclose(logfp);
fclose(fp);
return FALSE;
}
crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff];
}
fclose(fp);
if( (crc & 0xffff) != 0xf0b8){
/*printf("The CRC of read file:%x\n", crc); */
return FALSE;
}
return TRUE;
}/*end check_crc_ccitt() */
/*
Sends "OK to power me down" message to the remote
power cycling box, via the serial port.
Also updates the num power cycle count in a local
file.
This file "./cycleCnt" must be present. This is
initially (and once) created by the separate "makefiles.c"
program.
*/
void send_pwrdn_ok(void){
int fd;
FILE *cyclefp;
int cycle_fd;
cyclefp = fopen("cycleCnt","rb");
if(!cyclefp){
printf("expecting file \"cycleCnt\". Cannot continue.\n");
exit(1);
}
if(fread(&CycleCount, sizeof(CycleCount),1,cyclefp) != 1){
fprintf(stderr, "Error! Unexpected end of file cycleCnt.\n");
exit(1);
}
fclose(cyclefp);
CycleCount++;
/*now write this puppy back*/
cyclefp = fopen("cycleCnt","wb");
cycle_fd = fileno(cyclefp);
if(!cyclefp){
fprintf(stderr, "Error! cannot open file for write:\"cycleCnt\". Cannot continue.\n");
exit(1);
}
if(fwrite(&CycleCount, sizeof(CycleCount), 1,cyclefp) !=1){
fprintf(stderr, "Error writing to file cycleCnt. Cannot continue.\n");
exit(1);
}
if(fdatasync(cycle_fd)){
fprintf(stderr, "Error! cannot sync file buffer with disk.\n");
exit(1);
}
fclose(cyclefp);
(void)sync();
printf("\n\n Sending Power down command to the remote box.\n");
fd = setupSerial(SerialDevice);
if(do_pwr_dn(fd, CycleCount) < 0)
{
fprintf(stderr, "Error sending power down command.\n");
exit(1);
}
close(fd);
}//end send_pwrnd_ok()
/*
Appends 16bit CRC at the end of numBytes long buffer.
Make sure buf, extends at least 2 bytes beyond.
*/
void appendChecksum(char *buf, int numBytes){
unsigned short crc = 0xffff;
int index = 0;
/* printf("Added CRC (2 bytes) to %i bytes.\n", numBytes); */
for (; numBytes > 0; numBytes--){
crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ buf[index++]) & 0xff];
}
crc ^= 0xffff;
/*printf("The CRC: %x\n\n", crc);*/
buf[index++] = crc;
buf[index++] = crc >> 8;
}/*end checksum()*/
/*
This guy make a new "random data file" with the filename
passed to it. This file is checksummed with the checksum
stored at the end. The first "int" in the file is the
number of int's in it (this is needed to know how much
data to read and checksum later).
*/
void make_new_file(char *filename){
int dfd; /* data file descriptor */
int rand_data;
int data_size;
int temp_size;
int dataIndex = 0;
int err;
struct {
int sizeInBytes; /* must be int */
int dataInt[MAX_INTS_ALLOW+1]; /* how many int's can we write? */
}__attribute((packed)) dataBuf;
fprintf(stderr, "Creating File:%s. ", filename);
if((dfd = open(filename, O_RDWR | O_CREAT | O_SYNC)) <= 0)
{
printf("Error! Cannot open file: %s\n",filename);
perror("Error");
exit(1);
}
/*now write a bunch of random binary data to the file*/
/*first figure out how much data to write. That is random also.*/
/*file should not be less than 5 ints long. (so that we have decent length files,
that's all)*/
while(
((data_size = (int)(1+(int)((FileSizeMax/sizeof(int))*rand()/(RAND_MAX+1.0)))) < 5)
);
/* printf("Writing %i ints to the file.\n", data_size); */
temp_size = data_size * sizeof(int);
/* Make sure that all data is written in one go! This is important to
check for reliability of file systems like JFFS/JFFS that purport to
have "reliable" writes during powre fail.
*/
dataBuf.sizeInBytes = temp_size;
data_size--; /*one alrady written*/
dataIndex = 0;
while(data_size--){
rand_data = (int)(1 + (int)(10000.0*rand()/(RAND_MAX+1.0)));
dataBuf.dataInt[dataIndex++] = rand_data;
}
/*now calculate the file checksum and append it to the end*/
appendChecksum((char *)&dataBuf, dataBuf.sizeInBytes);
/* Don't forget to increase the size of data written by the 2 chars of CRC at end.
These 2 bytes are NOT included in the sizeInBytes field. */
if((err = write(dfd, (void *)&dataBuf, dataBuf.sizeInBytes + sizeof(short))) <
(dataBuf.sizeInBytes + sizeof(short))
)
{
printf("Error writing data buffer to file. Written %i bytes rather than %i bytes.",
err, dataBuf.sizeInBytes);
perror("Error");
exit(1);
}
/* Now that the data is (hopefully) safely written. I can truncate the file to the new
length so that I can reclaim any unused space, if the older file was larger.
*/
if(ftruncate(dfd, dataBuf.sizeInBytes + sizeof(short)) < 0)
{
perror("Error: Unable to truncate file.");
exit(1);
}
close(dfd);
}//end make_new_file()
/*
Show's help on stdout
*/
void printHelp(char **argv)
{
printf("Usage:%s <options, defined below>\n", argv[0]);
printf("%s </dev/ttyS0,1,2...>: Set com port to send ok to pwr dn msg on\n",
CMDLINE_PORT);
printf("%s <n>: Set Max size in bytes of each file to be created.\n",
CMDLINE_MAXFILEBYTES);
printf("%s <n>: Set Max errors allowed when checking all files for CRC on start.\n",
CMDLINE_MAXERROR);
printf("%s or %s: This Help screen.\n", CMDLINE_HELPSHORT,
CMDLINE_HELPLONG);
}/* end printHelp()*/
void processCmdLine(int argc, char **argv)
{
int cnt;
/* skip past name of this program, process rest */
for(cnt = 1; cnt < argc; cnt++)
{
if(strcmp(argv[cnt], CMDLINE_PORT) == 0)
{
strncpy(SerialDevice, argv[++cnt], sizeof(SerialDevice));
continue;
}else
if(strcmp(argv[cnt], CMDLINE_MAXFILEBYTES) == 0)
{
FileSizeMax = (float)atoi(argv[++cnt]);
if(FileSizeMax > (MAX_INTS_ALLOW*sizeof(int)))
{
printf("Max file size allowd is %i.\n",
MAX_INTS_ALLOW*sizeof(int));
exit(0);
}
continue;
}else
if(strcmp(argv[cnt], CMDLINE_HELPSHORT) == 0)
{
printHelp(argv);
exit(0);
}else
if(strcmp(argv[cnt], CMDLINE_HELPLONG) == 0)
{
printHelp(argv);
exit(0);
}else
if(strcmp(argv[cnt], CMDLINE_MAXERROR) == 0)
{
MaxErrAllowed = atoi(argv[++cnt]);
}
else
{
printf("Unknown cmd line option:%s\n", argv[cnt]);
printHelp(argv);
exit(0);
}
}
}/* end processCmdLine() */
int main(int argc, char **argv){
FILE *logfp;
int log_fd;
char filename[30];
short filenameCounter = 0;
unsigned short counter;
unsigned short numberFiles;
char error = FALSE;
short errorCnt = 0;
time_t timep;
char * time_string;
unsigned int seed;
numberFiles = MAX_NUM_FILES;
if(argc >= 1)
{
processCmdLine(argc, argv);
}
/*
First open MAX_NUM_FILES and make sure that the checksum is ok.
Also make an intry into the logfile.
*/
/* timestamp! */
time(&timep);
time_string = (char *)ctime((time_t *)&timep);
/*start a new check, make a log entry and continue*/
logfp = fopen("logfile","a"); /*open for appending only.*/
log_fd = fileno(logfp);
fprintf(logfp,"%s", time_string);
fprintf(logfp,"Starting new check.\n");
if(fdatasync(log_fd) == -1){
fprintf(stderr,"Error! Cannot sync file data with disk.\n");
exit(1);
}
fclose(logfp);
(void)sync();
/*
Now check all random data files in this dir.
*/
for(counter=0;counter<MAX_NUM_FILES;counter++){
fprintf(stderr, "%i.", counter);
/*create the filename in sequence. The number of files
to check and the algorithm to create the filename is
fixed and known in advance.*/
sprintf(filename,"file%i",filenameCounter++);
if(!check_crc_ccitt(filename)){
/*oops, checksum does not match. Make an entry into the log file
and decide if we can continue or not.*/
fprintf(stderr, "crcError:%s ", filename);
logfp = fopen("logfile","a"); /*open for appending only.*/
log_fd = fileno(logfp);
fprintf(logfp,"CRC error in file: %s\n", filename);
if(fdatasync(log_fd) == -1){
fprintf(stderr,"Error! Cannot sync file data with disk.\n");
exit(1);
}
fclose(logfp);
(void)sync();
error = TRUE;
errorCnt++;
if(errorCnt > MaxErrAllowed){
logfp = fopen("logfile","a"); /*open for appending only.*/
log_fd = fileno(logfp);
fprintf(logfp,"\nMax Error count exceed. Stopping!\n");
if(fdatasync(log_fd) == -1){
fprintf(stderr,"Error! Cannot sync file data with disk.\n");
exit(1);
}
fclose(logfp);
(void)sync();
fprintf(stderr, "Too many errors. See \"logfile\".\n");
exit(1);
}/* if too many errors */
/*we have decided to continue, however first repair this file
so that we do not cumulate errors across power cycles.*/
make_new_file(filename);
}
}//for
/*all files checked, make a log entry and continue*/
logfp = fopen("logfile","a"); /*open for appending only.*/
log_fd = fileno(logfp);
fprintf(logfp,"All files checked. Total errors found: %i\n\n", errorCnt);
if(fdatasync(log_fd)){
fprintf(stderr, "Error! cannot sync file buffer with disk.\n");
exit(1);
}
fclose(logfp);
(void)sync();
/*now send a message to the remote power box and have it start a random
pwer down timer after which power will be killed to this unit.
*/
send_pwrdn_ok();
/*now go into a forever loop of writing to files and CRC'ing them on
a continious basis.*/
/*start from a random file #*/
/*seed rand based on the current time*/
seed = (unsigned int)time(NULL);
srand(seed);
filenameCounter=(int)(1+(int)((float)(MAX_NUM_FILES-1)*rand()/(RAND_MAX+1.0)));
while(1){
for(;filenameCounter<MAX_NUM_FILES;filenameCounter++){
/*create the filename in sequence*/
sprintf(filename,"file%i",filenameCounter);
make_new_file(filename);
}
filenameCounter = 0;
}
exit(0); /* though we will never reach here, but keeps the compiler happy*/
}/*end main()*/

View File

@ -1,67 +0,0 @@
/*
File: comm.c
Desc: This file implements the actual transmission portion
of the "ok to power me down" message to the remote
power cycling black box.
It's been sepatated into a separate file so that
it may be replaced by any other comm mechanism desired.
(including none or non serial mode at all)
$Id: comm.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
$Log: not supported by cvs2svn $
Revision 1.3 2005/11/07 11:15:17 gleixner
[MTD / JFFS2] Clean up trailing white spaces
Revision 1.2 2001/06/21 23:07:18 dwmw2
Initial import to MTD CVS
Revision 1.1 2001/06/08 22:26:05 vipin
Split the modbus comm part of the program (that sends the ok to pwr me down
message) into another file "comm.c"
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/*
This is the routine that forms and
sends the "ok to pwr me down" message
to the remote power cycling "black box".
*/
int do_pwr_dn(int fd, int cycleCnt)
{
char buf[200];
sprintf(buf, "ok to power me down!\nCount = %i\n", cycleCnt);
if(write(fd, buf, strlen(buf)) < strlen(buf))
{
perror("write error");
return -1;
}
return 0;
}

View File

@ -1,7 +0,0 @@
/* $Id: common.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ */
//this .h file is common to both the file creation utility and
//the file checking utility.
#define TRUE 1
#define FALSE 0
#define MAX_NUM_FILES 100

View File

@ -1,264 +0,0 @@
/*
* Copyright Daniel Industries.
* Created by: Vipin Malik (vipin.malik@daniel.com)
*
* This is GPL code. See the file COPYING for more details
*
* 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.
* $Id: makefiles.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
This program creates MAX_NUM_FILES files (file00001, file00002 etc) and
fills them with random numbers till they are a random length. Then it checksums
the files (with the checksum as the last two bytes) and closes the file.
The fist int is the size of the file in bytes.
It then opens another file and the process continues.
The files are opened in the current dir.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#define FILESIZE_MAX 20000.0 /* for each file in sizeof(int). Must be a float #
Hence, 20000.0 = 20000*4 = 80KB max file size
*/
static const unsigned short crc_ccitt_table[] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
//This code was taken from the AX.25 HDLC packet driver
//in LINUX. Once I test and have a better understanding of what
//it is doing, it will be better commented.
//For now one can speculate that the CRC routine always expects the
//CRC to calculate out to 0xf0b8 (the hardcoded value at the end)
//and returns TRUE if it is and FALSE if it doesn't.
//Why don't people document better!!!!
void check_crc_ccitt(char *filename)
{
FILE *fp;
unsigned short crc = 0xffff;
int len;
char dataByte;
int retry;
fp = fopen(filename,"rb");
if(!fp){
printf("Verify checksum:Error! Cannot open filename passed for verify checksum: %s\n",filename);
exit(1);
}
/*the first int contains an int that is the length of the file in long.*/
if(fread(&len, sizeof(int), 1, fp) != 1){
printf("verify checksum:Error reading from file: %s", filename);
fclose(fp);
exit(1);
}
rewind(fp);
len+=2; /*the file has two extra bytes at the end, it's checksum. Those
two MUST also be included in the checksum calculation.
*/
for (;len>0;len--){
retry=5; /*retry 5 times*/
while(!fread(&dataByte, sizeof(char), 1, fp) && retry--);
if(!retry){
printf("Unexpected error reading from file: %s\n", filename);
printf("...bytes left to be read %i.\n\n",len);
fclose(fp);
exit(1);
}
crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff];
}
fclose(fp);
if( (crc & 0xffff) != 0xf0b8){
printf("Verify checksum: Error in file %s.\n\n",filename);
exit(1);
}
}//end check_crc_ccitt()
/*this routine opens a file 'filename' and checksumn's the entire
contents, and then appends the checksum at the end of the file,
closes the file and returns.
*/
void checksum(char *filename){
FILE *fp;
unsigned short crc = 0xffff;
int len;
char dataByte;
int retry;
fp = fopen(filename,"rb");
if(!fp){
printf("Error! Cannot open filename passed for checksum: %s\n",filename);
exit(1);
}
/*the first int contains an int that is the length of the file in longs.*/
if(fread(&len, sizeof(int), 1, fp) != 1){
printf("Error reading from file: %s", filename);
fclose(fp);
exit(1);
}
printf("Calculating checksum on %i bytes.\n",len);
rewind(fp); /*the # of bytes int is also included in the checksum.*/
for (;len>0;len--){
retry=5; /*retry 5 times*/
while(!fread(&dataByte, sizeof(char), 1, fp) && retry--);
if(!retry){
printf("Unexpected error reading from file: %s\n", filename);
printf("...bytes left to be read %i.\n\n",len);
fclose(fp);
exit(1);
}
crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff];
}
crc ^= 0xffff;
printf("The CRC: %x\n\n", crc);
/*the CRC has been calculated. now close the file and open it in append mode*/
fclose(fp);
fp = fopen(filename,"ab"); /*open in append mode. CRC goes at the end.*/
if(!fp){
printf("Error! Cannot open filename to update checksum: %s\n",filename);
exit(1);
}
if(fwrite(&crc, sizeof(crc), 1, fp) != 1){
printf("error! unable to update the file for checksum.\n");
fclose(fp);
exit(1);
}
fflush(fp);
fclose(fp);
}/*end checksum()*/
int main(void){
FILE *fp, *cyclefp;
int cycleCount;
int rand_data;
int data_size;
int temp_size;
char filename[30];
short filenameCounter = 0;
unsigned short counter;
unsigned short numberFiles;
numberFiles = MAX_NUM_FILES;
for(counter=0;counter<numberFiles;counter++){
/*create the filename in sequence*/
sprintf(filename,"file%i",filenameCounter++);
fp = fopen(filename,"wb");
if(!fp){
printf("Error! Cannot open file: %s\n",filename);
exit(1);
}
/*now write a bunch of random binary data to the file*/
/*first figure out how much data to write. That is random also.*/
while(
((data_size = (int)(1 + (int)(FILESIZE_MAX*rand()/(RAND_MAX+1.0)))) < 100)
)/*file should not be less than 100 ints long. (so that we have decent length files, that's all)*/
printf("Writing %i ints to the file.\n", data_size);
temp_size = data_size * sizeof(int);
if(!fwrite(&temp_size, sizeof(int), 1, fp)){
printf("File write error!!.\n");
fclose(fp);
exit(1);
}
data_size--; /*one alrady written*/
while(data_size--){
rand_data = (int)(1 + (int)(10000.0*rand()/(RAND_MAX+1.0)));
if(!fwrite(&rand_data, sizeof(int), 1, fp)){
printf("File write error!!.\n");
fclose(fp);
exit(1);
}
}
fflush(fp);
fclose(fp);
/*now calculate the file checksum and append it to the end*/
checksum(filename);
/*this is just a test. Check the CRC to amek sure that it is OK.*/
check_crc_ccitt(filename);
}
/*now make a file called "cycleCnt" and put a binary (int)0 in it.
This file keeps count as to how many cycles have taken place!*/
cyclefp = fopen("cycleCnt","wb");
if(!cyclefp){
printf("cannot open file \"cycleCnt\". Cannot continue.\n");
exit(1);
}
cycleCount = 0;
if(fwrite(&cycleCount, sizeof(cycleCount), 1,cyclefp) !=1){
printf("Error writing to file cycleCnt. Cannot continue.\n");
exit(1);
}
fclose(cyclefp);
exit(0);
}/*end main()*/

View File

@ -1,8 +0,0 @@
SUBDIRS = lib simple stress integrity utils
all clean tests: $(SUBDIRS)
.PHONY: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)

View File

@ -1,27 +0,0 @@
#!/bin/sh
echo -------------------------------------------------------------------------------
./simple/test_1 -h
echo -------------------------------------------------------------------------------
./simple/test_2 -h
echo -------------------------------------------------------------------------------
./stress/atoms/stress_1 -h
echo -------------------------------------------------------------------------------
./stress/atoms/stress_2 -h
echo -------------------------------------------------------------------------------
./stress/atoms/stress_3 -h
echo -------------------------------------------------------------------------------
./stress/atoms/fwrite00 -h
echo -------------------------------------------------------------------------------
./stress/atoms/gcd_hupper -h
echo -------------------------------------------------------------------------------
./stress/atoms/pdfrun -h
echo -------------------------------------------------------------------------------
./stress/atoms/rmdir00 -h
echo -------------------------------------------------------------------------------
./stress/atoms/rndrm00 -h
echo -------------------------------------------------------------------------------
./stress/atoms/rndwrite00 -h
echo -------------------------------------------------------------------------------
./integrity/integck -h
echo -------------------------------------------------------------------------------

View File

@ -1,22 +0,0 @@
ifeq ($(origin CC),default)
CC = gcc
endif
CFLAGS := $(CFLAGS) -Wall -g -O2 -I../lib
LDFLAGS := $(LDFLAGS)
TARGETS = integck
all: $(TARGETS)
$(TARGETS): ../lib/tests.o
../lib/tests.o: ../lib/tests.h
clean:
rm -f *.o $(TARGETS)
tests: all
./integck

View File

@ -1,18 +0,0 @@
ifeq ($(origin CC),default)
CC = gcc
endif
CFLAGS := $(CFLAGS) -Wall -g -O2
LDFLAGS := $(LDFLAGS)
all: tests.o
tests.o: tests.h
clean:
rm -f *.o
tests:
echo

View File

@ -1,199 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#ifndef included_tests_tests_h__
#define included_tests_tests_h__
#include <stdint.h>
/* Main macro for testing */
#define CHECK(x) tests_test((x),__func__,__FILE__,__LINE__)
/* The default directory in which tests are conducted */
#define TESTS_DEFAULT_FILE_SYSTEM_MOUNT_DIR "/mnt/test_file_system"
/* The default file system type to test */
#define TESTS_DEFAULT_FILE_SYSTEM_TYPE "jffs2"
/* Estimated size of an empty directory */
#define TESTS_EMPTY_DIR_SIZE 128
/* Function invoked by the CHECK macro */
void tests_test(int test,const char *msg,const char *file,unsigned line);
/* Handle common program options */
int tests_get_args(int argc,
char *argv[],
const char *title,
const char *desc,
const char *opts);
/* Return the number of files (or directories) in the given directory */
unsigned tests_count_files_in_dir(const char *dir_name);
/* Change to the file system mount directory, check that it is empty,
matches the file system type, and is not the root file system */
void tests_check_test_file_system(void);
/* Get the free space for the file system of the current directory */
uint64_t tests_get_free_space(void);
/* Get the total space for the file system of the current directory */
uint64_t tests_get_total_space(void);
/* Write size random bytes into file descriptor fd at the current position,
returning the number of bytes actually written */
uint64_t tests_fill_file(int fd, uint64_t size);
/* Write size random bytes into file descriptor fd at offset,
returning the number of bytes actually written */
uint64_t tests_write_filled_file(int fd, off_t offset, uint64_t size);
/* Check that a file written using tests_fill_file() and/or
tests_write_filled_file() and/or tests_create_file()
contains the expected random data */
void tests_check_filled_file_fd(int fd);
/* Check that a file written using tests_fill_file() and/or
tests_write_filled_file() and/or tests_create_file()
contains the expected random data */
void tests_check_filled_file(const char *file_name);
/* Delete a file */
void tests_delete_file(const char *file_name);
/* Create a file of size file_size */
uint64_t tests_create_file(const char *file_name, uint64_t file_size);
/* Calculate: free_space * numerator / denominator */
uint64_t tests_get_big_file_size(unsigned numerator, unsigned denominator);
/* Create file "fragment_n" where n is the file_number, and unlink it */
int tests_create_orphan(unsigned file_number);
/* Write size bytes at offset to the file "fragment_n" where n is the
file_number and file_number also determines the random data written
i.e. seed for random numbers */
unsigned tests_write_fragment_file(unsigned file_number,
int fd,
off_t offset,
unsigned size);
/* Write size bytes to the end of file descriptor fd using file_number
to determine the random data written i.e. seed for random numbers */
unsigned tests_fill_fragment_file(unsigned file_number,
int fd,
unsigned size);
/* Write size bytes to the end of file "fragment_n" where n is the file_number
and file_number also determines the random data written
i.e. seed for random numbers */
unsigned tests_append_to_fragment_file(unsigned file_number,
unsigned size,
int create);
/* Write size bytes at offset to the file "fragment_n" where n is the
file_number and file_number also determines the random data written
i.e. seed for random numbers */
unsigned tests_overwite_fragment_file( unsigned file_number,
off_t offset,
unsigned size);
/* Delete file "fragment_n" where n is the file_number */
void tests_delete_fragment_file(unsigned file_number);
/* Check the random data in file "fragment_n" is what is expected */
void tests_check_fragment_file_fd(unsigned file_number, int fd);
/* Check the random data in file "fragment_n" is what is expected */
void tests_check_fragment_file(unsigned file_number);
/* Central point to decide whether to use fsync */
void tests_maybe_sync(int fd);
/* Return O_SYNC if ok to sync otherwise return 0 */
int tests_maybe_sync_flag(void);
/* Return random number from 0 to n - 1 */
size_t tests_random_no(size_t n);
/* Make a directory empty */
void tests_clear_dir(const char *dir_name);
/* Create an empty sub-directory or small file in the current directory */
int64_t tests_create_entry(char *return_name);
/* Remove a random file of empty sub-directory from the current directory */
int64_t tests_remove_entry(void);
/* Un-mount and re-mount test file system */
void tests_remount(void);
/* Check whether the test file system is also the root file system */
int tests_fs_is_rootfs(void);
/* Try to make a directory empty */
void tests_try_to_clear_dir(const char *dir_name);
/* Check whether the test file system is also the current file system */
int tests_fs_is_currfs(void);
/* Concatenate a pid to a string in a signal safe way */
void tests_cat_pid(char *buf, const char *name, pid_t pid);
extern char *tests_file_system_mount_dir;
extern char *tests_file_system_type;
/* General purpose test parameter to specify some aspect of test size.
May be used by different tests in different ways.
Set by the -z, --size options. */
extern int64_t tests_size_parameter;
/* General purpose test parameter to specify some aspect of test repetition.
May be used by different tests in different ways.
Set by the -n, --repeat options. */
extern int64_t tests_repeat_parameter;
/* General purpose test parameter to specify some aspect of test sleeping.
May be used by different tests in different ways.
Set by the -p, --sleep options. */
extern int64_t tests_sleep_parameter;
/* General purpose test parameter to specify a file should be unlinked.
May be used by different tests in different ways or not at all. */
extern int tests_unlink_flag;
/* General purpose test parameter to specify a file should be closed.
May be used by different tests in different ways or not at all. */
extern int tests_close_flag;
/* General purpose test parameter to specify a file should be deleted.
May be used by different tests in different ways or not at all. */
extern int tests_delete_flag;
/* General purpose test parameter to specify a file have a hole.
May be used by different tests in different ways or not at all. */
extern int tests_hole_flag;
/* Program name from argv[0] */
extern char *program_name;
#endif

View File

@ -1,49 +0,0 @@
#!/bin/sh
TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR
if test -z "$TEST_DIR";
then
TEST_DIR="/mnt/test_file_system"
fi
rm -rf ${TEST_DIR}/*
./simple/test_1 || exit 1
rm -rf ${TEST_DIR}/*
./simple/test_2 || exit 1
rm -rf ${TEST_DIR}/*
./integrity/integck || exit 1
rm -rf ${TEST_DIR}/*
./stress/atoms/rndrm00 -z0 || exit 1
rm -rf ${TEST_DIR}/*
./stress/atoms/rmdir00 -z0 || exit 1
rm -rf ${TEST_DIR}/*
./stress/atoms/stress_1 -z10000000 -e || exit 1
rm -rf ${TEST_DIR}/*
./stress/atoms/stress_2 -z10000000 || exit 1
rm -rf ${TEST_DIR}/*
./stress/atoms/stress_3 -z1000000000 -e || exit 1
rm -rf ${TEST_DIR}/*
cd stress || exit 1
./stress00.sh 3600 || exit 1
./stress01.sh 3600 || exit 1
cd .. || exit 1

View File

@ -1,28 +0,0 @@
ifeq ($(origin CC),default)
CC = gcc
endif
CFLAGS := $(CFLAGS) -Wall -g -O2 -I../lib
LDFLAGS := $(LDFLAGS)
TARGETS = test_1 \
test_2 \
ftrunc \
orph
all: $(TARGETS)
$(TARGETS): ../lib/tests.o
../lib/tests.o: ../lib/tests.h
clean:
rm -f *.o $(TARGETS)
tests: all
./test_1 --sync
./test_2 --sync
./ftrunc
./orph --sync

View File

@ -1,111 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "tests.h"
#define WRITE_BUFFER_SIZE 32768
void ftrunc(void)
{
int fd, i;
pid_t pid;
ssize_t written;
int64_t remains;
size_t block;
char *file_name;
off_t actual;
char buf[WRITE_BUFFER_SIZE];
file_name = "ftrunc_test_file";
fd = open(file_name, O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
CHECK(fd != -1);
pid = getpid();
srand(pid);
for (i = 0; i < WRITE_BUFFER_SIZE;++i)
buf[i] = rand();
remains = tests_size_parameter;
actual = 0;
while (remains > 0) {
if (remains > WRITE_BUFFER_SIZE)
block = WRITE_BUFFER_SIZE;
else
block = remains;
written = write(fd, buf, block);
if (written <= 0) {
CHECK(errno == ENOSPC); /* File system full */
errno = 0;
break;
}
remains -= written;
actual += written;
}
CHECK(ftruncate(fd, (actual ? actual - 1 : actual)) != -1);
CHECK(close(fd) != -1);
CHECK(unlink(file_name) != -1);
}
/* Title of this test */
const char *ftrunc_get_title(void)
{
return "Truncate a large test file";
}
/* Description of this test */
const char *ftrunc_get_description(void)
{
return
"Create a file named ftrunc_test_file. " \
"Truncate the file to reduce its length by 1. " \
"Then remove the truncated file. "
"The size is given by the -z or --size option, " \
"otherwise it defaults to 1000000.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test file size */
tests_size_parameter = 1000000;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, ftrunc_get_title(),
ftrunc_get_description(), "z");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
ftrunc();
return 0;
}

View File

@ -1,184 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "tests.h"
#define MAX_ORPHANS 1000000
void orph(void)
{
pid_t pid;
unsigned i, j, k, n;
int fd, done, full;
int64_t repeat;
ssize_t sz;
char dir_name[256];
int fds[MAX_ORPHANS];
/* Create a directory to test in */
pid = getpid();
tests_cat_pid(dir_name, "orph_test_dir_", pid);
if (chdir(dir_name) == -1)
CHECK(mkdir(dir_name, 0777) != -1);
CHECK(chdir(dir_name) != -1);
repeat = tests_repeat_parameter;
for (;;) {
full = 0;
done = 0;
n = 0;
while (n + 100 < MAX_ORPHANS && !done) {
/* Make 100 more orphans */
for (i = 0; i < 100; i++) {
fd = tests_create_orphan(n + i);
if (fd < 0) {
done = 1;
if (errno == ENOSPC)
full = 1;
else if (errno != EMFILE)
CHECK(0);
errno = 0;
break;
}
fds[n + i] = fd;
}
if (!full) {
/* Write to orphans just created */
k = i;
for (i = 0; i < k; i++) {
if (tests_write_fragment_file(n + i,
fds[n+i],
0, 1000)
!= 1000) {
/*
* Out of space, so close
* remaining files
*/
for (j = i; j < k; j++)
CHECK(close(fds[n + j])
!= -1);
done = 1;
break;
}
}
}
if (!done)
CHECK(tests_count_files_in_dir(".") == 0);
n += i;
}
/* Check the data in the files */
for (i = 0; i < n; i++)
tests_check_fragment_file_fd(i, fds[i]);
if (!full && n) {
/* Ensure the file system is full */
n -= 1;
do {
sz = write(fds[n], fds, 4096);
if (sz == -1 && errno == ENOSPC) {
errno = 0;
break;
}
CHECK(sz >= 0);
} while (sz == 4096);
CHECK(close(fds[n]) != -1);
}
/* Check the data in the files */
for (i = 0; i < n; i++)
tests_check_fragment_file_fd(i, fds[i]);
/* Sleep */
if (tests_sleep_parameter > 0) {
unsigned us = tests_sleep_parameter * 1000;
unsigned rand_divisor = RAND_MAX / us;
unsigned s = (us / 2) + (rand() / rand_divisor);
usleep(s);
}
/* Close orphans */
for (i = 0; i < n; i++)
CHECK(close(fds[i]) != -1);
/* Break if repeat count exceeded */
if (tests_repeat_parameter > 0 && --repeat <= 0)
break;
}
CHECK(tests_count_files_in_dir(".") == 0);
CHECK(chdir("..") != -1);
CHECK(rmdir(dir_name) != -1);
}
/* Title of this test */
const char *orph_get_title(void)
{
return "Create many open unlinked files";
}
/* Description of this test */
const char *orph_get_description(void)
{
return
"Create a directory named orph_test_dir_pid, where " \
"pid is the process id. Within that directory, " \
"create files and keep them open and unlink them. " \
"Create as many files as possible until the file system is " \
"full or the maximum allowed open files is reached. " \
"If a sleep value is specified, the process sleeps. " \
"The sleep value is given by the -p or --sleep option, " \
"otherwise it defaults to 0. " \
"Sleep is specified in milliseconds. " \
"Then close the files. " \
"If a repeat count is specified, then the task repeats " \
"that number of times. " \
"The repeat count is given by the -n or --repeat option, " \
"otherwise it defaults to 1. " \
"A repeat count of zero repeats forever. " \
"Finally remove the directory.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test repetition */
tests_repeat_parameter = 1;
/* Set default test sleep */
tests_sleep_parameter = 0;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, orph_get_title(),
orph_get_description(), "nps");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
orph();
return 0;
}

View File

@ -1,150 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "tests.h"
void test_1(void)
{
int fd;
pid_t pid;
uint64_t i;
uint64_t block;
uint64_t actual_size;
char name[256];
char old[16];
char buf[16];
off_t old_len;
char dir_name[256];
/* Create a directory to test in */
pid = getpid();
tests_cat_pid(dir_name, "test_1_test_dir_", pid);
if (chdir(dir_name) == -1)
CHECK(mkdir(dir_name, 0777) != -1);
CHECK(chdir(dir_name) != -1);
/* Create a file that fills half the free space on the file system */
tests_create_file("big_file", tests_get_big_file_size(1,2));
CHECK(tests_count_files_in_dir(".") == 1);
fd = open("big_file", O_RDWR | tests_maybe_sync_flag());
CHECK(fd != -1);
CHECK(read(fd, old, 5) == 5);
CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1);
CHECK(write(fd,"start", 5) == 5);
CHECK(lseek(fd,0,SEEK_END) != (off_t) -1);
CHECK(write(fd, "end", 3) == 3);
tests_maybe_sync(fd);
/* Delete the file while it is still open */
tests_delete_file("big_file");
CHECK(tests_count_files_in_dir(".") == 0);
/* Create files to file up the file system */
for (block = 1000000, i = 1; ; block /= 10) {
while (i != 0) {
sprintf(name, "fill_up_%llu", i);
actual_size = tests_create_file(name, block);
if (actual_size != 0)
++i;
if (actual_size != block)
break;
}
if (block == 1)
break;
}
/* Check the big file */
CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1);
CHECK(read(fd, buf, 5) == 5);
CHECK(strncmp(buf, "start", 5) == 0);
CHECK(lseek(fd, -3, SEEK_END) != (off_t) -1);
CHECK(read(fd, buf, 3) == 3);
CHECK(strncmp(buf, "end", 3) == 0);
/* Check the other files and delete them */
i -= 1;
CHECK(tests_count_files_in_dir(".") == i);
for (; i > 0; --i) {
sprintf(name, "fill_up_%llu", i);
tests_check_filled_file(name);
tests_delete_file(name);
}
CHECK(tests_count_files_in_dir(".") == 0);
/* Check the big file again */
CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1);
CHECK(read(fd, buf, 5) == 5);
CHECK(strncmp(buf, "start", 5) == 0);
CHECK(lseek(fd, -3, SEEK_END) != (off_t) -1);
CHECK(read(fd, buf, 3) == 3);
CHECK(strncmp(buf, "end", 3) == 0);
CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1);
CHECK(write(fd,old, 5) == 5);
old_len = lseek(fd, -3, SEEK_END);
CHECK(old_len != (off_t) -1);
CHECK(ftruncate(fd,old_len) != -1);
tests_check_filled_file_fd(fd);
/* Close the big file*/
CHECK(close(fd) != -1);
CHECK(tests_count_files_in_dir(".") == 0);
CHECK(chdir("..") != -1);
CHECK(rmdir(dir_name) != -1);
}
/* Title of this test */
const char *test_1_get_title(void)
{
return "Fill file system while holding deleted big file descriptor";
}
/* Description of this test */
const char *test_1_get_description(void)
{
return
"Create a directory named test_1_test_dir_pid, where " \
"pid is the process id. Within that directory, " \
"create a big file (approx. half the file system in size), " \
"open it, and unlink it. " \
"Create many smaller files until the file system is full. " \
"Check the big file is ok. " \
"Delete all the smaller files. " \
"Check the big file again. " \
"Finally delete the big file and directory.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, test_1_get_title(),
test_1_get_description(), "s");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
test_1();
return 0;
}

View File

@ -1,201 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "tests.h"
void test_2(void)
{
pid_t pid;
int create, full;
unsigned i, number_of_files;
unsigned growth;
unsigned size;
uint64_t big_file_size;
int fd;
off_t offset;
char dir_name[256];
/* Create a directory to test in */
pid = getpid();
tests_cat_pid(dir_name, "test_2_test_dir_", pid);
if (chdir(dir_name) == -1)
CHECK(mkdir(dir_name, 0777) != -1);
CHECK(chdir(dir_name) != -1);
/* Create up to 1000 files appending 400 bytes at a time to each file */
/* until the file system is full.*/
create = 1;
full = 0;
number_of_files = 1000;
while (!full) {
for (i = 0; i < number_of_files; ++i) {
growth = tests_append_to_fragment_file(i, 400, create);
if (!growth) {
full = 1;
if (create)
number_of_files = i;
break;
}
}
create = 0;
}
/* Check the files */
CHECK(tests_count_files_in_dir(".") == number_of_files);
for (i = 0; i < number_of_files; ++i)
tests_check_fragment_file(i);
/* Delete half of them */
for (i = 1; i < number_of_files; i += 2)
tests_delete_fragment_file(i);
/* Check them again */
CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2);
for (i = 0; i < number_of_files; i += 2)
tests_check_fragment_file(i);
CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2);
/* Create a big file that fills two thirds of the free space */
big_file_size = tests_get_big_file_size(2,3);
/* Check the big file */
tests_create_file("big_file", big_file_size);
CHECK(tests_count_files_in_dir(".") == 1 + (number_of_files + 1) / 2);
tests_check_filled_file("big_file");
/* Open the big file */
fd = open("big_file",O_RDWR | tests_maybe_sync_flag());
CHECK(fd != -1);
/* Delete the big file while it is still open */
tests_delete_file("big_file");
/* Check the big file again */
CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2);
tests_check_filled_file_fd(fd);
/* Write parts of the files and check them */
offset = 100; /* Offset to write at, in the small files */
size = 200; /* Number of bytes to write at the offset */
for (i = 0; i < number_of_files; i += 2)
tests_overwite_fragment_file(i, offset, size);
/* Rewrite the big file entirely */
tests_write_filled_file(fd, 0, big_file_size);
for (i = 0; i < number_of_files; i += 2)
tests_check_fragment_file(i);
tests_check_filled_file_fd(fd);
offset = 300; /* Offset to write at, in the small files */
size = 400; /* Number of bytes to write at the offset */
for (i = 0; i < number_of_files; i += 2)
tests_overwite_fragment_file(i, offset, size);
/* Rewrite the big file entirely */
tests_write_filled_file(fd, 0, big_file_size);
for (i = 0; i < number_of_files; i += 2)
tests_check_fragment_file(i);
tests_check_filled_file_fd(fd);
offset = 110; /* Offset to write at, in the small files */
size = 10; /* Number of bytes to write at the offset */
for (i = 0; i < number_of_files; i += 2)
tests_overwite_fragment_file(i, offset, size);
/* Rewrite the big file entirely */
tests_write_filled_file(fd, 0, big_file_size);
for (i = 0; i < number_of_files; i += 2)
tests_check_fragment_file(i);
tests_check_filled_file_fd(fd);
offset = 10; /* Offset to write at, in the small files */
size = 1000; /* Number of bytes to write at the offset */
for (i = 0; i < number_of_files; i += 2)
tests_overwite_fragment_file(i, offset, size);
/* Rewrite the big file entirely */
tests_write_filled_file(fd, 0, big_file_size);
for (i = 0; i < number_of_files; i += 2)
tests_check_fragment_file(i);
tests_check_filled_file_fd(fd);
offset = 0; /* Offset to write at, in the small files */
size = 100000; /* Number of bytes to write at the offset */
for (i = 0; i < number_of_files; i += 2)
tests_overwite_fragment_file(i, offset, size);
/* Rewrite the big file entirely */
tests_write_filled_file(fd, 0, big_file_size);
for (i = 0; i < number_of_files; i += 2)
tests_check_fragment_file(i);
tests_check_filled_file_fd(fd);
/* Close the big file*/
CHECK(close(fd) != -1);
/* Check the small files */
CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2);
for (i = 0; i < number_of_files; i += 2)
tests_check_fragment_file(i);
/* Delete the small files */
for (i = 0; i < number_of_files; i += 2)
tests_delete_fragment_file(i);
CHECK(tests_count_files_in_dir(".") == 0);
CHECK(chdir("..") != -1);
CHECK(rmdir(dir_name) != -1);
}
/* Title of this test */
const char *test_2_get_title(void)
{
return "Repeated write many small files and one big deleted file";
}
/* Description of this test */
const char *test_2_get_description(void)
{
return
"Create a directory named test_2_test_dir_pid, where " \
"pid is the process id. Within that directory, " \
"create about 1000 files. Append 400 bytes to each until " \
"the file system is full. Then delete half of them. Then " \
"create a big file that uses about 2/3 of the remaining free " \
"space. Get a file descriptor for the big file, and delete " \
"the big file. Then repeatedly write to the small files " \
"and the big file. " \
"Finally delete the big file and directory.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, test_2_get_title(),
test_2_get_description(), "s");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
test_2();
return 0;
}

View File

@ -1,11 +0,0 @@
SUBDIRS = atoms
all tests: $(SUBDIRS)
clean: $(SUBDIRS)
rm -rf run_pdf_test_file_*
.PHONY: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)

View File

@ -1,40 +0,0 @@
ifeq ($(origin CC),default)
CC = gcc
endif
CFLAGS := $(CFLAGS) -Wall -g -O2 -I../../lib
LDFLAGS := $(LDFLAGS)
TARGETS = stress_1 \
stress_2 \
stress_3 \
pdfrun \
rndwrite00 \
fwrite00 \
rmdir00 \
rndrm00 \
rndrm99 \
gcd_hupper
all: $(TARGETS)
$(TARGETS): ../../lib/tests.o
../lib/tests.o: ../../lib/tests.h
clean:
rm -f *.o $(TARGETS) run_pdf_test_file
tests: all
./stress_1 -e
./stress_2
./stress_3 -e
./pdfrun
./rndwrite00 -e
./fwrite00
./rmdir00
./rndrm00
./rndrm99
./gcd_hupper

View File

@ -1,209 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "tests.h"
#define WRITE_BUFFER_SIZE 32768
#define HOLE_BLOCK_SIZE 10000000
void filestress00(void)
{
int fd, i, deleted;
pid_t pid;
ssize_t written;
int64_t remains;
int64_t repeat;
size_t block;
char file_name[256];
char buf[WRITE_BUFFER_SIZE];
fd = -1;
deleted = 1;
pid = getpid();
tests_cat_pid(file_name, "filestress00_test_file_", pid);
srand(pid);
repeat = tests_repeat_parameter;
for (;;) {
/* Open the file */
if (fd == -1) {
fd = open(file_name, O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
CHECK(fd != -1);
deleted = 0;
if (tests_unlink_flag) {
CHECK(unlink(file_name) != -1);
deleted = 1;
}
}
/* Get a different set of random data */
for (i = 0; i < WRITE_BUFFER_SIZE;++i)
buf[i] = rand();
if (tests_hole_flag) {
/* Make a hole */
CHECK(lseek(fd, tests_size_parameter, SEEK_SET) != -1);
written = write(fd, "!", 1);
if (written <= 0) {
/* File system full */
CHECK(errno == ENOSPC);
errno = 0;
}
CHECK(lseek(fd, 0, SEEK_SET) != -1);
/* Write at set points into the hole */
remains = tests_size_parameter;
while (remains > HOLE_BLOCK_SIZE) {
CHECK(lseek(fd, HOLE_BLOCK_SIZE,
SEEK_CUR) != -1);
written = write(fd, "!", 1);
remains -= HOLE_BLOCK_SIZE;
if (written <= 0) {
/* File system full */
CHECK(errno == ENOSPC);
errno = 0;
break;
}
}
} else {
/* Write data into the file */
CHECK(lseek(fd, 0, SEEK_SET) != -1);
remains = tests_size_parameter;
while (remains > 0) {
if (remains > WRITE_BUFFER_SIZE)
block = WRITE_BUFFER_SIZE;
else
block = remains;
written = write(fd, buf, block);
if (written <= 0) {
/* File system full */
CHECK(errno == ENOSPC);
errno = 0;
break;
}
remains -= written;
}
}
/* Break if repeat count exceeded */
if (tests_repeat_parameter > 0 && --repeat <= 0)
break;
/* Close if tests_close_flag */
if (tests_close_flag) {
CHECK(close(fd) != -1);
fd = -1;
}
/* Sleep */
if (tests_sleep_parameter > 0) {
unsigned us = tests_sleep_parameter * 1000;
unsigned rand_divisor = RAND_MAX / us;
unsigned s = (us / 2) + (rand() / rand_divisor);
usleep(s);
}
/* Delete if tests_delete flag */
if (!deleted && tests_delete_flag) {
CHECK(unlink(file_name) != -1);
deleted = 1;
}
}
CHECK(close(fd) != -1);
/* Sleep */
if (tests_sleep_parameter > 0) {
unsigned us = tests_sleep_parameter * 1000;
unsigned rand_divisor = RAND_MAX / us;
unsigned s = (us / 2) + (rand() / rand_divisor);
usleep(s);
}
/* Tidy up */
if (!deleted)
CHECK(unlink(file_name) != -1);
}
/* Title of this test */
const char *filestress00_get_title(void)
{
return "File stress test 00";
}
/* Description of this test */
const char *filestress00_get_description(void)
{
return
"Create a file named filestress00_test_file_pid, where " \
"pid is the process id. If the unlink option " \
"(-u or --unlink) is specified, " \
"unlink the file while holding the open file descriptor. " \
"If the hole option (-o or --hole) is specified, " \
"write a single character at the end of the file, creating a " \
"hole. " \
"Write a single character in the hole every 10 million " \
"bytes. " \
"If the hole option is not specified, then the file is " \
"filled with random data. " \
"If the close option (-c or --close) is specified the file " \
"is closed. " \
"If a sleep value is specified, the process sleeps. " \
"If the delete option (-e or --delete) is specified, then " \
"the file is deleted. " \
"If a repeat count is specified, then the task repeats " \
"that number of times. " \
"The repeat count is given by the -n or --repeat option, " \
"otherwise it defaults to 1. " \
"A repeat count of zero repeats forever. " \
"The file size is given by the -z or --size option, " \
"otherwise it defaults to 1000000. " \
"The sleep value is given by the -p or --sleep option, " \
"otherwise it defaults to 0. " \
"Sleep is specified in milliseconds.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test file size */
tests_size_parameter = 1000000;
/* Set default test repetition */
tests_repeat_parameter = 1;
/* Set default test sleep */
tests_sleep_parameter = 0;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, filestress00_get_title(),
filestress00_get_description(), "znpuoce");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
filestress00();
return 0;
}

View File

@ -1,259 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <dirent.h>
#include <mntent.h>
#include <signal.h>
#include "tests.h"
#define MAX_NAME_SIZE 1024
struct gcd_pid
{
struct gcd_pid *next;
int pid;
char *name;
int mtd_index;
};
struct gcd_pid *gcd_pid_list = NULL;
int add_gcd_pid(const char *number)
{
int pid;
FILE *f;
char file_name[MAX_NAME_SIZE];
char program_name[MAX_NAME_SIZE];
pid = atoi(number);
if (pid <= 0)
return 0;
snprintf(file_name, MAX_NAME_SIZE, "/proc/%s/stat", number);
f = fopen(file_name, "r");
if (f == NULL)
return 0;
if (fscanf(f, "%d %s", &pid, program_name) != 2) {
fclose(f);
return 0;
}
if (strncmp(program_name, "(jffs2_gcd_mtd", 14) != 0)
pid = 0;
if (pid) {
size_t sz;
struct gcd_pid *g;
sz = sizeof(struct gcd_pid);
g = (struct gcd_pid *) malloc(sz);
g->pid = pid;
g->name = (char *) malloc(strlen(program_name) + 1);
if (g->name)
strcpy(g->name, program_name);
else
exit(1);
g->mtd_index = atoi(program_name + 14);
g->next = gcd_pid_list;
gcd_pid_list = g;
}
fclose(f);
return pid;
}
int get_pid_list(void)
{
DIR *dir;
struct dirent *entry;
dir = opendir("/proc");
if (dir == NULL)
return 1;
for (;;) {
entry = readdir(dir);
if (entry) {
if (strcmp(".",entry->d_name) != 0 &&
strcmp("..",entry->d_name) != 0)
add_gcd_pid(entry->d_name);
} else
break;
}
closedir(dir);
return 0;
}
int parse_index_number(const char *name)
{
const char *p, *q;
int all_zero;
int index;
p = name;
while (*p && !isdigit(*p))
++p;
if (!*p)
return -1;
all_zero = 1;
for (q = p; *q; ++q) {
if (!isdigit(*q))
return -1;
if (*q != '0')
all_zero = 0;
}
if (all_zero)
return 0;
index = atoi(p);
if (index <= 0)
return -1;
return index;
}
int get_mtd_index(void)
{
FILE *f;
struct mntent *entry;
struct stat f_info;
struct stat curr_f_info;
int found;
int mtd_index = -1;
if (stat(tests_file_system_mount_dir, &f_info) == -1)
return -1;
f = fopen("/proc/mounts", "rb");
if (!f)
f = fopen("/etc/mtab", "rb");
if (f == NULL)
return -1;
found = 0;
for (;;) {
entry = getmntent(f);
if (!entry)
break;
if (stat(entry->mnt_dir, &curr_f_info) == -1)
continue;
if (f_info.st_dev == curr_f_info.st_dev) {
int i;
i = parse_index_number(entry->mnt_fsname);
if (i != -1) {
if (found && i != mtd_index)
return -1;
found = 1;
mtd_index = i;
}
}
}
fclose(f);
return mtd_index;
}
int get_gcd_pid()
{
struct gcd_pid *g;
int mtd_index;
if (get_pid_list())
return 0;
mtd_index = get_mtd_index();
if (mtd_index == -1)
return 0;
for (g = gcd_pid_list; g; g = g->next)
if (g->mtd_index == mtd_index)
return g->pid;
return 0;
}
void gcd_hupper(void)
{
int64_t repeat;
int pid;
pid = get_gcd_pid();
CHECK(pid != 0);
repeat = tests_repeat_parameter;
for (;;) {
CHECK(kill(pid, SIGHUP) != -1);
/* Break if repeat count exceeded */
if (tests_repeat_parameter > 0 && --repeat <= 0)
break;
/* Sleep */
if (tests_sleep_parameter > 0) {
unsigned us = tests_sleep_parameter * 1000;
unsigned rand_divisor = RAND_MAX / us;
unsigned s = (us / 2) + (rand() / rand_divisor);
usleep(s);
}
}
}
/* Title of this test */
const char *gcd_hupper_get_title(void)
{
return "Send HUP signals to gcd";
}
/* Description of this test */
const char *gcd_hupper_get_description(void)
{
return
"Determine the PID of the gcd process. " \
"Send it SIGHUP (may require root privileges). " \
"If a sleep value is specified, the process sleeps. " \
"If a repeat count is specified, then the task repeats " \
"that number of times. " \
"The repeat count is given by the -n or --repeat option, " \
"otherwise it defaults to 1. " \
"A repeat count of zero repeats forever. " \
"The sleep value is given by the -p or --sleep option, " \
"otherwise it defaults to 1. "
"Sleep is specified in milliseconds.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test repetition */
tests_repeat_parameter = 1;
/* Set default test sleep */
tests_sleep_parameter = 1;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, gcd_hupper_get_title(),
gcd_hupper_get_description(), "np");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
gcd_hupper();
return 0;
}

View File

@ -1,143 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "tests.h"
#define WRITE_BUFFER_SIZE 32768
void adjust_size(void)
{
char dummy[1024];
unsigned long total_memory;
FILE *f;
total_memory = 0;
f = fopen("/proc/meminfo", "r");
fscanf(f, "%s %lu", dummy, &total_memory);
fclose(f);
if (total_memory > 0 && tests_size_parameter > total_memory / 2)
tests_size_parameter = total_memory / 2;
}
void run_pdf(void)
{
int fd, i;
pid_t pid;
int64_t repeat;
ssize_t written;
int64_t remains;
size_t block;
char file_name[256];
char buf[WRITE_BUFFER_SIZE];
if (tests_fs_is_currfs())
return;
adjust_size();
pid = getpid();
tests_cat_pid(file_name, "run_pdf_test_file_", pid);
fd = open(file_name, O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
CHECK(fd != -1);
pid = getpid();
srand(pid);
repeat = tests_repeat_parameter;
for (;;) {
for (i = 0; i < WRITE_BUFFER_SIZE;++i)
buf[i] = rand();
remains = tests_size_parameter;
while (remains > 0) {
if (remains > WRITE_BUFFER_SIZE)
block = WRITE_BUFFER_SIZE;
else
block = remains;
written = write(fd, buf, block);
if (written <= 0) {
CHECK(errno == ENOSPC); /* File system full */
errno = 0;
break;
}
remains -= written;
}
/* Break if repeat count exceeded */
if (tests_repeat_parameter > 0 && --repeat <= 0)
break;
CHECK(lseek(fd, 0, SEEK_SET) == 0);
}
CHECK(close(fd) != -1);
CHECK(unlink(file_name) != -1);
}
/* Title of this test */
const char *run_pdf_get_title(void)
{
return "Create / overwrite a large file in the current directory";
}
/* Description of this test */
const char *run_pdf_get_description(void)
{
return
"Create a file named run_pdf_test_file_pid, " \
"where pid is the process id. The file is created " \
"in the current directory, " \
"if the current directory is NOT on the test " \
"file system, otherwise no action is taken. " \
"If a repeat count is specified, then the task repeats " \
"that number of times. " \
"The repeat count is given by the -n or --repeat option, " \
"otherwise it defaults to 1. " \
"A repeat count of zero repeats forever. " \
"The size is given by the -z or --size option, " \
"otherwise it defaults to 1000000. " \
"The size is adjusted so that it is not more than " \
"half the size of total memory.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test file size */
tests_size_parameter = 1000000;
/* Set default test repetition */
tests_repeat_parameter = 1;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, run_pdf_get_title(),
run_pdf_get_description(), "zn");
if (!run_test)
return 1;
/* Do the actual test */
run_pdf();
return 0;
}

View File

@ -1,133 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "tests.h"
void rmdir00(void)
{
int64_t repeat;
int64_t size, this_size;
pid_t pid;
char dir_name[256];
/* Create a directory to test in */
pid = getpid();
tests_cat_pid(dir_name, "rmdir00_test_dir_", pid);
if (chdir(dir_name) == -1)
CHECK(mkdir(dir_name, 0777) != -1);
CHECK(chdir(dir_name) != -1);
/* Repeat loop */
repeat = tests_repeat_parameter;
size = 0;
for (;;) {
/* Remove everything in the directory */
tests_clear_dir(".");
/* Fill with sub-dirs and small files */
do {
this_size = tests_create_entry(NULL);
if (!this_size)
break;
size += this_size;
} while (this_size &&
(tests_size_parameter == 0 ||
size < tests_size_parameter));
/* Break if repeat count exceeded */
if (tests_repeat_parameter > 0 && --repeat <= 0)
break;
/* Sleep */
if (tests_sleep_parameter > 0) {
unsigned us = tests_sleep_parameter * 1000;
unsigned rand_divisor = RAND_MAX / us;
unsigned s = (us / 2) + (rand() / rand_divisor);
usleep(s);
}
}
/* Tidy up by removing everything */
tests_clear_dir(".");
CHECK(chdir("..") != -1);
CHECK(rmdir(dir_name) != -1);
}
/* Title of this test */
const char *rmdir00_get_title(void)
{
return "Create and remove directories and files";
}
/* Description of this test */
const char *rmdir00_get_description(void)
{
return
"Create a directory named rmdir00_test_dir_pid, where " \
"pid is the process id. Within that directory, create " \
"a number of sub-directories and small files. " \
"The total size of all sub-directories and files " \
"is specified by the size parameter. " \
"The size parameter is given by the -z or --size option, " \
"otherwise it defaults to 1000000. " \
"A size of zero fills the file system until there is no "
"space left. " \
"The task repeats, sleeping in between each iteration, " \
"and then removing the sub-directories and files created " \
"during the last iteration. " \
"The repeat count is set by the -n or --repeat option, " \
"otherwise it defaults to 1. " \
"A repeat count of zero repeats forever. " \
"The sleep value is given by the -p or --sleep option, " \
"otherwise it defaults to 0. "
"Sleep is specified in milliseconds.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test size */
tests_size_parameter = 1000000;
/* Set default test repetition */
tests_repeat_parameter = 1;
/* Set default test sleep */
tests_sleep_parameter = 0;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, rmdir00_get_title(),
rmdir00_get_description(), "znp");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
rmdir00();
return 0;
}

View File

@ -1,157 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "tests.h"
void rndrm00(void)
{
int64_t repeat;
int64_t size, this_size;
pid_t pid;
char dir_name[256];
/* Create a directory to test in */
pid = getpid();
tests_cat_pid(dir_name, "rndrm00_test_dir_", pid);
if (chdir(dir_name) == -1)
CHECK(mkdir(dir_name, 0777) != -1);
CHECK(chdir(dir_name) != -1);
/* Repeat loop */
repeat = tests_repeat_parameter;
size = 0;
for (;;) {
/* Create and remove sub-dirs and small files, */
/* but tending to grow */
do {
if (tests_random_no(3)) {
this_size = tests_create_entry(NULL);
if (!this_size)
break;
size += this_size;
} else {
this_size = tests_remove_entry();
size -= this_size;
if (size < 0)
size = 0;
if (!this_size)
this_size = 1;
}
} while (this_size &&
(tests_size_parameter == 0 ||
size < tests_size_parameter));
/* Create and remove sub-dirs and small files, but */
/* but tending to shrink */
do {
if (!tests_random_no(3)) {
this_size = tests_create_entry(NULL);
size += this_size;
} else {
this_size = tests_remove_entry();
size -= this_size;
if (size < 0)
size = 0;
}
} while ((tests_size_parameter != 0 &&
size > tests_size_parameter / 10) ||
(tests_size_parameter == 0 && size > 100000));
/* Break if repeat count exceeded */
if (tests_repeat_parameter > 0 && --repeat <= 0)
break;
/* Sleep */
if (tests_sleep_parameter > 0) {
unsigned us = tests_sleep_parameter * 1000;
unsigned rand_divisor = RAND_MAX / us;
unsigned s = (us / 2) + (rand() / rand_divisor);
usleep(s);
}
}
/* Tidy up by removing everything */
tests_clear_dir(".");
CHECK(chdir("..") != -1);
CHECK(rmdir(dir_name) != -1);
}
/* Title of this test */
const char *rndrm00_get_title(void)
{
return "Randomly create and remove directories and files";
}
/* Description of this test */
const char *rndrm00_get_description(void)
{
return
"Create a directory named rndrm00_test_dir_pid, where " \
"pid is the process id. Within that directory, " \
"randomly create and remove " \
"a number of sub-directories and small files, " \
"but do more creates than removes. " \
"When the total size of all sub-directories and files " \
"is greater than the size specified by the size parameter, " \
"start to do more removes than creates. " \
"The size parameter is given by the -z or --size option, " \
"otherwise it defaults to 1000000. " \
"A size of zero fills the file system until there is no "
"space left. " \
"The task repeats, sleeping in between each iteration. " \
"The repeat count is set by the -n or --repeat option, " \
"otherwise it defaults to 1. " \
"A repeat count of zero repeats forever. " \
"The sleep value is given by the -p or --sleep option, " \
"otherwise it defaults to 0. "
"Sleep is specified in milliseconds.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test size */
tests_size_parameter = 1000000;
/* Set default test repetition */
tests_repeat_parameter = 1;
/* Set default test sleep */
tests_sleep_parameter = 0;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, rndrm00_get_title(),
rndrm00_get_description(), "znp");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
rndrm00();
return 0;
}

View File

@ -1,431 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <time.h>
#include <sys/vfs.h>
#include <sys/statvfs.h>
#include <dirent.h>
#include <ctype.h>
#include <limits.h>
#include "tests.h"
uint32_t files_created = 0;
uint32_t files_removed = 0;
uint32_t dirs_created = 0;
uint32_t dirs_removed = 0;
int64_t *size_ptr = 0;
void display_stats(void)
{
printf( "\nrndrm99 stats:\n"
"\tNumber of files created = %u\n"
"\tNumber of files deleted = %u\n"
"\tNumber of directories created = %u\n"
"\tNumber of directories deleted = %u\n"
"\tCurrent net size of creates and deletes = %lld\n",
(unsigned) files_created,
(unsigned) files_removed,
(unsigned) dirs_created,
(unsigned) dirs_removed,
(long long) (size_ptr ? *size_ptr : 0));
fflush(stdout);
}
struct timeval tv_before;
struct timeval tv_after;
void before(void)
{
CHECK(gettimeofday(&tv_before, NULL) != -1);
}
void after(const char *msg)
{
time_t diff;
CHECK(gettimeofday(&tv_after, NULL) != -1);
diff = tv_after.tv_sec - tv_before.tv_sec;
if (diff >= 8) {
printf("\nrndrm99: the following fn took more than 8 seconds: %s (took %u secs)\n",msg,(unsigned) diff);
fflush(stdout);
display_stats();
}
}
#define WRITE_BUFFER_SIZE 32768
static char write_buffer[WRITE_BUFFER_SIZE];
static void init_write_buffer()
{
static int init = 0;
if (!init) {
int i, d;
uint64_t u;
u = RAND_MAX;
u += 1;
u /= 256;
d = (int) u;
srand(1);
for (i = 0; i < WRITE_BUFFER_SIZE; ++i)
write_buffer[i] = rand() / d;
init = 1;
}
}
/* Write size random bytes into file descriptor fd at the current position,
returning the number of bytes actually written */
uint64_t fill_file(int fd, uint64_t size)
{
ssize_t written;
size_t sz;
unsigned start = 0, length;
uint64_t remains;
uint64_t actual_size = 0;
init_write_buffer();
remains = size;
while (remains > 0) {
length = WRITE_BUFFER_SIZE - start;
if (remains > length)
sz = length;
else
sz = (size_t) remains;
before();
written = write(fd, write_buffer + start, sz);
if (written <= 0) {
CHECK(errno == ENOSPC); /* File system full */
errno = 0;
after("write");
fprintf(stderr,"\nrndrm99: write failed with ENOSPC\n");fflush(stderr);
display_stats();
break;
}
after("write");
remains -= written;
actual_size += written;
if ((size_t) written == sz)
start = 0;
else
start += written;
}
return actual_size;
}
/* Create a file of size file_size */
uint64_t create_file(const char *file_name, uint64_t file_size)
{
int fd;
int flags;
mode_t mode;
uint64_t actual_size; /* Less than size if the file system is full */
flags = O_CREAT | O_TRUNC | O_WRONLY;
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
before();
fd = open(file_name, flags, mode);
if (fd == -1 && errno == ENOSPC) {
errno = 0;
after("open");
fprintf(stderr,"\nrndrm99: open failed with ENOSPC\n");fflush(stderr);
display_stats();
return 0; /* File system full */
}
CHECK(fd != -1);
after("open");
actual_size = fill_file(fd, file_size);
before();
CHECK(close(fd) != -1);
after("close");
if (file_size != 0 && actual_size == 0) {
printf("\nrndrm99: unlinking zero size file\n");fflush(stdout);
before();
CHECK(unlink(file_name) != -1);
after("unlink (create_file)");
}
return actual_size;
}
/* Create an empty sub-directory or small file in the current directory */
int64_t create_entry(char *return_name)
{
int fd;
char name[256];
int64_t res;
for (;;) {
sprintf(name, "%u", (unsigned) tests_random_no(10000000));
before();
fd = open(name, O_RDONLY);
after("open (create_entry)");
if (fd == -1)
break;
before();
close(fd);
after("close (create_entry)");
}
if (return_name)
strcpy(return_name, name);
if (tests_random_no(2)) {
res = create_file(name, tests_random_no(4096));
if (res > 0)
files_created += 1;
return res;
} else {
before();
if (mkdir(name, 0777) == -1) {
CHECK(errno == ENOSPC);
after("mkdir");
errno = 0;
fprintf(stderr,"\nrndrm99: mkdir failed with ENOSPC\n");fflush(stderr);
display_stats();
return 0;
}
after("mkdir");
dirs_created += 1;
return TESTS_EMPTY_DIR_SIZE;
}
}
/* Remove a random file of empty sub-directory from the current directory */
int64_t remove_entry(void)
{
DIR *dir;
struct dirent *entry;
unsigned count = 0, pos;
int64_t result = 0;
before();
dir = opendir(".");
CHECK(dir != NULL);
after("opendir");
for (;;) {
errno = 0;
before();
entry = readdir(dir);
if (entry) {
after("readdir 1");
if (strcmp(".",entry->d_name) != 0 &&
strcmp("..",entry->d_name) != 0)
++count;
} else {
CHECK(errno == 0);
after("readdir 1");
break;
}
}
pos = tests_random_no(count);
count = 0;
before();
rewinddir(dir);
after("rewinddir");
for (;;) {
errno = 0;
before();
entry = readdir(dir);
if (!entry) {
CHECK(errno == 0);
after("readdir 2");
break;
}
after("readdir 2");
if (strcmp(".",entry->d_name) != 0 &&
strcmp("..",entry->d_name) != 0) {
if (count == pos) {
if (entry->d_type == DT_DIR) {
before();
tests_clear_dir(entry->d_name);
after("tests_clear_dir");
before();
CHECK(rmdir(entry->d_name) != -1);
after("rmdir");
result = TESTS_EMPTY_DIR_SIZE;
dirs_removed += 1;
} else {
struct stat st;
before();
CHECK(stat(entry->d_name, &st) != -1);
after("stat");
result = st.st_size;
before();
CHECK(unlink(entry->d_name) != -1);
after("unlink");
files_removed += 1;
}
}
++count;
}
}
before();
CHECK(closedir(dir) != -1);
after("closedir");
return result;
}
void rndrm99(void)
{
int64_t repeat, loop_cnt;
int64_t size, this_size;
pid_t pid;
char dir_name[256];
size_ptr = &size;
/* Create a directory to test in */
pid = getpid();
tests_cat_pid(dir_name, "rndrm99_test_dir_", pid);
if (chdir(dir_name) == -1)
CHECK(mkdir(dir_name, 0777) != -1);
CHECK(chdir(dir_name) != -1);
/* Repeat loop */
repeat = tests_repeat_parameter;
size = 0;
for (;;) {
/* Create and remove sub-dirs and small files, */
/* but tending to grow */
printf("\nrndrm99: growing\n");fflush(stdout);
loop_cnt = 0;
do {
if (loop_cnt++ % 2000 == 0)
display_stats();
if (tests_random_no(3)) {
this_size = create_entry(NULL);
if (!this_size)
break;
size += this_size;
} else {
this_size = remove_entry();
size -= this_size;
if (size < 0)
size = 0;
if (!this_size)
this_size = 1;
}
} while (this_size &&
(tests_size_parameter == 0 ||
size < tests_size_parameter));
/* Create and remove sub-dirs and small files, but */
/* but tending to shrink */
printf("\nrndrm99: shrinking\n");fflush(stdout);
loop_cnt = 0;
do {
if (loop_cnt++ % 2000 == 0)
display_stats();
if (!tests_random_no(3)) {
this_size = create_entry(NULL);
size += this_size;
} else {
this_size = remove_entry();
size -= this_size;
if (size < 0)
size = 0;
}
} while ((tests_size_parameter != 0 &&
size > tests_size_parameter / 10) ||
(tests_size_parameter == 0 && size > 100000));
/* Break if repeat count exceeded */
if (tests_repeat_parameter > 0 && --repeat <= 0)
break;
/* Sleep */
if (tests_sleep_parameter > 0) {
unsigned us = tests_sleep_parameter * 1000;
unsigned rand_divisor = RAND_MAX / us;
unsigned s = (us / 2) + (rand() / rand_divisor);
printf("\nrndrm99: sleeping\n");fflush(stdout);
usleep(s);
}
}
printf("\nrndrm99: tidying\n");fflush(stdout);
display_stats();
/* Tidy up by removing everything */
tests_clear_dir(".");
CHECK(chdir("..") != -1);
CHECK(rmdir(dir_name) != -1);
size_ptr = 0;
}
/* Title of this test */
const char *rndrm99_get_title(void)
{
return "Randomly create and remove directories and files";
}
/* Description of this test */
const char *rndrm99_get_description(void)
{
return
"Create a directory named rndrm99_test_dir_pid, where " \
"pid is the process id. Within that directory, " \
"randomly create and remove " \
"a number of sub-directories and small files, " \
"but do more creates than removes. " \
"When the total size of all sub-directories and files " \
"is greater than the size specified by the size parameter, " \
"start to do more removes than creates. " \
"The size parameter is given by the -z or --size option, " \
"otherwise it defaults to 1000000. " \
"A size of zero fills the file system until there is no "
"space left. " \
"The task repeats, sleeping in between each iteration. " \
"The repeat count is set by the -n or --repeat option, " \
"otherwise it defaults to 1. " \
"A repeat count of zero repeats forever. " \
"The sleep value is given by the -p or --sleep option, " \
"otherwise it defaults to 0. "
"Sleep is specified in milliseconds.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test size */
tests_size_parameter = 1000000;
/* Set default test repetition */
tests_repeat_parameter = 1;
/* Set default test sleep */
tests_sleep_parameter = 0;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, rndrm99_get_title(),
rndrm99_get_description(), "znp");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
rndrm99();
return 0;
}

View File

@ -1,201 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include "tests.h"
#define BLOCK_SIZE 32768
#define BUFFER_SIZE 32768
static void check_file(int fd, char *data, size_t length)
{
size_t n, i;
char buf[BUFFER_SIZE];
CHECK(lseek(fd, 0, SEEK_SET) != -1);
n = 0;
for (;;) {
i = read(fd, buf, BUFFER_SIZE);
CHECK(i >= 0);
if (i == 0)
break;
CHECK(memcmp(buf, data + n, i) == 0);
n += i;
}
CHECK(n == length);
}
void rndwrite00(void)
{
int fd;
pid_t pid;
ssize_t written;
size_t remains;
size_t block;
size_t actual_size;
size_t check_every;
char *data, *p, *q;
off_t offset;
size_t size;
int64_t repeat;
char file_name[256];
char buf[4096];
/* Create file */
pid = getpid();
tests_cat_pid(file_name, "rndwrite00_test_file_", pid);
fd = open(file_name, O_CREAT | O_RDWR | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
CHECK(fd != -1);
/* Allocate memory to hold file data */
CHECK(tests_size_parameter > 0);
CHECK(tests_size_parameter <= SIZE_MAX);
data = (char *) malloc(tests_size_parameter);
CHECK(data != NULL);
/* Fill with random data */
srand(pid);
for (p = data, q = data + tests_size_parameter; p != q; ++p)
*p = rand();
/* Write to file */
p = data;
remains = tests_size_parameter;
while (remains > 0) {
if (remains > BLOCK_SIZE)
block = BLOCK_SIZE;
else
block = remains;
written = write(fd, p, block);
if (written <= 0) {
CHECK(errno == ENOSPC); /* File system full */
errno = 0;
break;
}
remains -= written;
p += written;
}
actual_size = p - data;
/* Repeating bit */
repeat = tests_repeat_parameter;
check_every = actual_size / 8192;
for (;;) {
offset = tests_random_no(actual_size);
size = tests_random_no(4096);
/* Don't change the file size */
if (offset + size > actual_size)
size = actual_size - offset;
if (!size)
continue;
for (p = buf, q = p + size; p != q; ++p)
*p = rand();
CHECK(lseek(fd, offset, SEEK_SET) != -1);
written = write(fd, buf, size);
if (written <= 0) {
CHECK(errno == ENOSPC); /* File system full */
errno = 0;
} else
memcpy(data + offset, buf, written);
/* Break if repeat count exceeded */
if (tests_repeat_parameter > 0 && --repeat <= 0)
break;
if (repeat % check_every == 0)
check_file(fd, data, actual_size);
/* Sleep */
if (tests_sleep_parameter > 0) {
unsigned us = tests_sleep_parameter * 1000;
unsigned rand_divisor = RAND_MAX / us;
unsigned s = (us / 2) + (rand() / rand_divisor);
usleep(s);
}
}
/* Check and close file */
check_file(fd, data, actual_size);
CHECK(close(fd) != -1);
if (tests_delete_flag)
CHECK(unlink(file_name) != -1);
}
/* Title of this test */
const char *rndwrite00_get_title(void)
{
return "Randomly write a large test file";
}
/* Description of this test */
const char *rndwrite00_get_description(void)
{
return
"Create a file named rndwrite00_test_file_pid, where " \
"pid is the process id. " \
"The file is filled with random data. " \
"The size of the file is given by the -z or --size option, " \
"otherwise it defaults to 1000000. " \
"Then a randomly sized block of random data is written at a " \
"random location in the file. "\
"The block size is always in the range 1 to 4095. " \
"If a sleep value is specified, the process sleeps. " \
"The number of writes is given by the repeat count. " \
"The repeat count is set by the -n or --repeat option, " \
"otherwise it defaults to 10000. " \
"A repeat count of zero repeats forever. " \
"The sleep value is given by the -p or --sleep option, " \
"otherwise it defaults to 0. "
"Sleep is specified in milliseconds. " \
"Periodically the data in the file is checked with a copy " \
"held in memory. " \
"If the delete option is specified the file is finally " \
"deleted.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test file size */
tests_size_parameter = 1000000;
/* Set default test repetition */
tests_repeat_parameter = 10000;
/* Set default test sleep */
tests_sleep_parameter = 0;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, rndwrite00_get_title(),
rndwrite00_get_description(), "zne");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
rndwrite00();
return 0;
}

View File

@ -1,109 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "tests.h"
#define WRITE_BUFFER_SIZE 32768
void stress_1(void)
{
int fd, i;
pid_t pid;
ssize_t written;
int64_t remains;
size_t block;
char file_name[256];
char buf[WRITE_BUFFER_SIZE];
pid = getpid();
tests_cat_pid(file_name, "stress_1_test_file_", pid);
fd = open(file_name, O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
CHECK(fd != -1);
srand(pid);
for (i = 0; i < WRITE_BUFFER_SIZE;++i)
buf[i] = rand();
remains = tests_size_parameter;
while (remains > 0) {
if (remains > WRITE_BUFFER_SIZE)
block = WRITE_BUFFER_SIZE;
else
block = remains;
written = write(fd, buf, block);
if (written <= 0) {
CHECK(errno == ENOSPC); /* File system full */
errno = 0;
break;
}
remains -= written;
}
CHECK(close(fd) != -1);
if (tests_delete_flag)
CHECK(unlink(file_name) != -1);
}
/* Title of this test */
const char *stress_1_get_title(void)
{
return "Create / overwrite a large file";
}
/* Description of this test */
const char *stress_1_get_description(void)
{
return
"Create a file named stress_1_test_file_pid, " \
"where pid is the process id. " \
"The size is given by the -z or --size option, " \
"otherwise it defaults to 1000000. " \
"The file will be deleted if the delete option " \
"is specified. ";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test file size */
tests_size_parameter = 1000000;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, stress_1_get_title(),
stress_1_get_description(), "ze");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
stress_1();
return 0;
}

View File

@ -1,120 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "tests.h"
#define WRITE_BUFFER_SIZE 32768
void stress_2(void)
{
int fd, i;
pid_t pid;
ssize_t written;
int64_t remains;
int64_t repeat;
size_t block;
char *file_name;
char buf[WRITE_BUFFER_SIZE];
file_name = "stress_2_test_file";
fd = open(file_name, O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
CHECK(fd != -1);
CHECK(unlink(file_name) != -1);
pid = getpid();
srand(pid);
repeat = tests_repeat_parameter;
for (;;) {
for (i = 0; i < WRITE_BUFFER_SIZE;++i)
buf[i] = rand();
CHECK(lseek(fd, 0, SEEK_SET) != -1);
remains = tests_size_parameter;
while (remains > 0) {
if (remains > WRITE_BUFFER_SIZE)
block = WRITE_BUFFER_SIZE;
else
block = remains;
written = write(fd, buf, block);
if (written <= 0) {
CHECK(errno == ENOSPC); /* File system full */
errno = 0;
break;
}
remains -= written;
}
if (tests_repeat_parameter > 0 && --repeat <= 0)
break;
}
CHECK(close(fd) != -1);
}
/* Title of this test */
const char *stress_2_get_title(void)
{
return "Create / overwrite a large deleted file";
}
/* Description of this test */
const char *stress_2_get_description(void)
{
return
"Create a file named stress_2_test_file. " \
"Open it, delete it while holding the open file descriptor, " \
"then fill it with random data. " \
"Repeated re-write the file some number of times. " \
"The repeat count is given by the -n or --repeat option, " \
"otherwise it defaults to 10. " \
"The file size is given by the -z or --size option, " \
"otherwise it defaults to 1000000.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test file size */
tests_size_parameter = 1000000;
/* Set default test repetition */
tests_repeat_parameter = 10;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, stress_2_get_title(),
stress_2_get_description(), "zn");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
stress_2();
return 0;
}

View File

@ -1,122 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "tests.h"
#define WRITE_BUFFER_SIZE 32768
void stress_3(void)
{
int fd, i;
pid_t pid;
ssize_t written;
int64_t remains;
size_t block;
char file_name[256];
char buf[WRITE_BUFFER_SIZE];
pid = getpid();
tests_cat_pid(file_name, "stress_3_test_file_", pid);
fd = open(file_name, O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
CHECK(fd != -1);
pid = getpid();
srand(pid);
for (i = 0; i < WRITE_BUFFER_SIZE;++i)
buf[i] = rand();
CHECK(lseek(fd, tests_size_parameter, SEEK_SET) != -1);
CHECK(write(fd, "!", 1) == 1);
CHECK(lseek(fd, 0, SEEK_SET) != -1);
remains = tests_size_parameter;
while (remains > 0) {
if (remains > WRITE_BUFFER_SIZE)
block = WRITE_BUFFER_SIZE;
else
block = remains;
written = write(fd, buf, block);
if (written <= 0) {
CHECK(errno == ENOSPC); /* File system full */
errno = 0;
break;
}
remains -= written;
}
if (ftruncate(fd, 0) == -1) {
CHECK(errno == ENOSPC); /* File system full */
errno = 0;
}
CHECK(close(fd) != -1);
if (tests_delete_flag)
CHECK(unlink(file_name) != -1);
}
/* Title of this test */
const char *stress_3_get_title(void)
{
return "Create a file with a large hole and fill it";
}
/* Description of this test */
const char *stress_3_get_description(void)
{
return
"Create a file named stress_3_test_file_pid, " \
"where pid is the process id. " \
"Write a single character past the end of the file, " \
"based on the specified file size, " \
"which creates a hole in the file. "
"Fill the hole with random data. " \
"Then truncate the file length to zero. " \
"The size is given by the -z or --size option, " \
"otherwise it defaults to 1000000. " \
"The file will be deleted if the delete option " \
"is specified.";
}
int main(int argc, char *argv[])
{
int run_test;
/* Set default test file size */
tests_size_parameter = 1000000;
/* Handle common arguments */
run_test = tests_get_args(argc, argv, stress_3_get_title(),
stress_3_get_description(), "ze");
if (!run_test)
return 1;
/* Change directory to the file system and check it is ok for testing */
tests_check_test_file_system();
/* Do the actual test */
stress_3();
return 0;
}

View File

@ -1,52 +0,0 @@
#!/bin/sh
TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR
if test -z "$TEST_DIR";
then
TEST_DIR="/mnt/test_file_system"
fi
FREESPACE=`../utils/free_space "$TEST_DIR"`
if test -z "$FREESPACE";
then
echo "Failed to determine free space"
exit 1
fi
if test -n "$1";
then
DURATION="-d$1";
else
DURATION="";
fi
FWRITE00=atoms/fwrite00
RNDWR=atoms/rndwrite00
GCHUP=atoms/gcd_hupper
PDFLUSH=atoms/pdfrun
FSIZE=$(( $FREESPACE/15 ));
../utils/fstest_monitor $DURATION \
"$FWRITE00 -z $FSIZE -n0 -p 20" \
"$FWRITE00 -z $FSIZE -n0 -p 10 -s" \
"$FWRITE00 -z $FSIZE -n0 -p 20 -u" \
"$FWRITE00 -z $FSIZE -n0 -p 70 -o" \
"$FWRITE00 -z $FSIZE -n0 -p 15 -s -o -u" \
"$FWRITE00 -z $FSIZE -n0 -p 10 -u -c" \
"$FWRITE00 -z $FSIZE -n0 -p 10 -u -o -c" \
"$FWRITE00 -z $FSIZE -n0 -p 10 -o -c" \
"$FWRITE00 -z $FSIZE -n0 -p 100 -o -u" \
"$FWRITE00 -z $FSIZE -n0 -p 100 -s -o -u -c" \
"$FWRITE00 -z $FSIZE -n0 -p 100 -o -u" \
"$FWRITE00 -z $FSIZE -n0 -p 100 -u" \
"$FWRITE00 -z $FSIZE -n0 -p 100 -s -o" \
"$RNDWR -z $FSIZE -n0 -p 10 -e" \
"$RNDWR -z $FSIZE -n0 -p 100 -e" \
"$PDFLUSH -z 1073741824 -n0"
STATUS=$?
rm -rf ${TEST_DIR}/*
exit $STATUS

View File

@ -1,40 +0,0 @@
#!/bin/sh
TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR
if test -z "$TEST_DIR";
then
TEST_DIR="/mnt/test_file_system"
fi
FREESPACE=`../utils/free_space "$TEST_DIR"`
if test -z "$FREESPACE";
then
echo "Failed to determine free space"
exit 1
fi
if test -n "$1";
then
DURATION="-d$1";
else
DURATION="";
fi
FWRITE00=atoms/fwrite00
RNDWR=atoms/rndwrite00
PDFLUSH=atoms/pdfrun
FSIZE=$(( $FREESPACE/15 ));
../utils/fstest_monitor $DURATION \
"$FWRITE00 -z $FSIZE -n0 -p 300" \
"$FWRITE00 -z $FSIZE -n0 -u" \
"$FWRITE00 -z $FSIZE -n0 -u -c" \
"$FWRITE00 -z $FSIZE -n0 -s -o" \
"$RNDWR -z $FSIZE -n0 -e"
STATUS=$?
rm -rf ${TEST_DIR}/*
exit $STATUS

View File

@ -1,19 +0,0 @@
ifeq ($(origin CC),default)
CC = gcc
endif
CFLAGS := $(CFLAGS) -Wall -g -O2 -I../lib
LDFLAGS := $(LDFLAGS)
TARGETS = fstest_monitor free_space
all: $(TARGETS)
clean:
rm -f *.o $(TARGETS)
tests: all
./fstest_monitor
./free_space > /dev/null

View File

@ -1,56 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/statvfs.h>
int main(int argc, char *argv[])
{
char *dir_name = ".";
uint64_t free_space;
struct statvfs fs_info;
if (argc > 1) {
if (strncmp(argv[1], "--help", 6) == 0 ||
strncmp(argv[1], "-h", 2) == 0) {
printf( "Usage is: "
"free_space [directory]\n"
"\n"
"Display the free space of the file system "
"of the directory given\n"
"or the current directory if no "
"directory is given.\nThe value output is "
"in bytes.\n"
);
return 1;
}
dir_name = argv[1];
}
if (statvfs(dir_name, &fs_info) == -1)
return 1;
free_space = (uint64_t) fs_info.f_bavail * (uint64_t) fs_info.f_frsize;
printf("%llu\n", (unsigned long long) free_space);
return 0;
}

View File

@ -1,281 +0,0 @@
/*
* Copyright (C) 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
*
* Author: Adrian Hunter
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
struct child_info {
struct child_info *next;
pid_t pid;
int terminated;
int killed;
int gone;
};
struct child_info *children = 0;
void kill_children(void)
{
struct child_info *child;
child = children;
while (child) {
if (!child->gone) {
if (!child->terminated) {
child->terminated = 1;
kill(child->pid, SIGTERM);
} /*else if (!child->killed) {
child->killed = 1;
kill(child->pid, SIGKILL);
}*/
}
child = child->next;
}
}
void add_child(pid_t child_pid)
{
struct child_info *child;
size_t sz;
sz = sizeof(struct child_info);
child = (struct child_info *) malloc(sz);
memset(child, 0, sz);
child->pid = child_pid;
child->next = children;
children = child;
}
void mark_child_gone(pid_t child_pid)
{
struct child_info *child;
child = children;
while (child) {
if (child->pid == child_pid) {
child->gone = 1;
break;
}
child = child->next;
}
}
int have_children(void)
{
struct child_info *child;
child = children;
while (child) {
if (!child->gone)
return 1;
child = child->next;
}
return 0;
}
int parse_command_line(char *cmdline, int *pargc, char ***pargv)
{
char **tmp;
char *p, *v, *q;
size_t sz;
int argc = 0;
int state = 0;
char *argv[1024];
if (!cmdline)
return 1;
q = v = (char *) malloc(strlen(cmdline) + 1024);
if (!v)
return 1;
p = cmdline;
for (;;) {
char c = *p++;
if (!c) {
*v++ = 0;
break;
}
switch (state) {
case 0: /* Between args */
if (isspace(c))
break;
argv[argc++] = v;
if (c == '"') {
state = 2;
break;
} else if (c == '\'') {
state = 3;
break;
}
state = 1;
case 1: /* Not quoted */
if (c == '\\') {
if (*p)
*v++ = *p;
} else if (isspace(c)) {
*v++ = 0;
state = 0;
} else
*v++ = c;
break;
case 2: /* Double quoted */
if (c == '\\' && *p == '"') {
*v++ = '"';
++p;
} else if (c == '"') {
*v++ = 0;
state = 0;
} else
*v++ = c;
break;
case 3: /* Single quoted */
if (c == '\'') {
*v++ = 0;
state = 0;
} else
*v++ = c;
break;
}
}
argv[argc] = 0;
sz = sizeof(char *) * (argc + 1);
tmp = (char **) malloc(sz);
if (!tmp) {
free(q);
return 1;
}
if (argc == 0)
free(q);
memcpy(tmp, argv, sz);
*pargc = argc;
*pargv = tmp;
return 0;
}
void signal_handler(int signum)
{
kill_children();
}
int result = 0;
int alarm_gone_off = 0;
void alarm_handler(int signum)
{
if (!result)
alarm_gone_off = 1;
kill_children();
}
int main(int argc, char *argv[], char **env)
{
int p;
pid_t child_pid;
int status;
int duration = 0;
p = 1;
if (argc > 1) {
if (strncmp(argv[p], "--help", 6) == 0 ||
strncmp(argv[p], "-h", 2) == 0) {
printf( "Usage is: "
"fstest_monitor options programs...\n"
" Options are:\n"
" -h, --help "
"This help message\n"
" -d, --duration arg "
"Stop after arg seconds\n"
"\n"
"Run programs and wait for them."
" If duration is specified,\n"
"kill all programs"
" after that number of seconds have elapsed.\n"
"Example: "
"fstest_monitor \"/bin/ls -l\" /bin/date\n"
);
return 1;
}
if (strncmp(argv[p], "--duration", 10) == 0 ||
strncmp(argv[p], "-d", 2) == 0) {
char *s;
if (p+1 < argc && !isdigit(argv[p][strlen(argv[p])-1]))
++p;
s = argv[p];
while (*s && !isdigit(*s))
++s;
duration = atoi(s);
++p;
}
}
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
for (; p < argc; ++p) {
child_pid = fork();
if (child_pid) {
/* Parent */
if (child_pid == (pid_t) -1) {
kill_children();
result = 1;
break;
}
add_child(child_pid);
} else {
/* Child */
int cargc;
char **cargv;
if (parse_command_line(argv[p], &cargc, &cargv))
return 1;
execve(cargv[0], cargv, env);
return 1;
}
}
if (!result && duration > 0) {
signal(SIGALRM, alarm_handler);
alarm(duration);
}
while (have_children()) {
status = 0;
child_pid = wait(&status);
if (child_pid == (pid_t) -1) {
if (errno == EINTR)
continue;
kill_children();
return 1;
}
mark_child_gone(child_pid);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
result = 1;
kill_children();
}
}
if (alarm_gone_off)
return 0;
return result;
}

View File

@ -1,340 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

Some files were not shown because too many files have changed in this diff Show More