mirror of
https://github.com/tuxbox-fork-migrations/recycled-ni-neutrino.git
synced 2025-08-30 17:01:08 +02:00
src/system/mtdutils: Add files from mtd-utils
- based on mtd-utils http://git.infradead.org/mtd-utils.git
commit ab8c6fb93ce9db0f09401c4b819b0b277dc00340 (2013-07-01)
- Add files for create jffs2 image and using sumtool
- Creating classes for mkfs.jffs2 and sumtool
Origin commit data
------------------
Commit: d8957d17ac
Author: Michael Liebmann <tuxcode.bbg@gmail.com>
Date: 2013-09-01 (Sun, 01 Sep 2013)
Origin message was:
------------------
src/system/mtdutils: Add files from mtd-utils
- based on mtd-utils http://git.infradead.org/mtd-utils.git
commit ab8c6fb93ce9db0f09401c4b819b0b277dc00340 (2013-07-01)
- Add files for create jffs2 image and using sumtool
- Creating classes for mkfs.jffs2 and sumtool
This commit is contained in:
340
src/system/mtdutils/COPYING
Normal file
340
src/system/mtdutils/COPYING
Normal file
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
538
src/system/mtdutils/compr.cpp
Normal file
538
src/system/mtdutils/compr.cpp
Normal file
@@ -0,0 +1,538 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
||||
* University of Szeged, Hungary
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory
|
||||
* in the jffs2 directory.
|
||||
*/
|
||||
|
||||
#include "compr.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <linux/jffs2.h>
|
||||
|
||||
#define FAVOUR_LZO_PERCENT 80
|
||||
|
||||
extern int page_size;
|
||||
|
||||
/* LIST IMPLEMENTATION (from linux/list.h) */
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
static inline void __list_add(struct list_head *new_,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new_;
|
||||
new_->next = next;
|
||||
new_->prev = prev;
|
||||
prev->next = new_;
|
||||
}
|
||||
|
||||
static inline void list_add(struct list_head *new_, struct list_head *head)
|
||||
{
|
||||
__list_add(new_, head, head->next);
|
||||
}
|
||||
|
||||
static inline void list_add_tail(struct list_head *new_, struct list_head *head)
|
||||
{
|
||||
__list_add(new_, head->prev, head);
|
||||
}
|
||||
|
||||
static inline void __list_del(struct list_head *prev, struct list_head *next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
entry->next = NULL;
|
||||
entry->prev = NULL;
|
||||
}
|
||||
|
||||
#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 = (unsigned char*)malloc(page_size);
|
||||
if (!jffs2_compression_check_buf) {
|
||||
fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n");
|
||||
jffs2_compression_check = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* decompressing */
|
||||
if (!compr->decompress) {
|
||||
fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name);
|
||||
jffs2_error_cnt++;
|
||||
return;
|
||||
}
|
||||
if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen)) {
|
||||
fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name);
|
||||
jffs2_error_cnt++;
|
||||
}
|
||||
/* validate decompression */
|
||||
else {
|
||||
for (i=0;i<datalen;i++) {
|
||||
if (data_in[i]!=jffs2_compression_check_buf[i]) {
|
||||
fprintf(stderr,"JFFS2 compression check: data mismatch at %s (pos %d).\n", compr->name, i);
|
||||
jffs2_error_cnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 to use this_ compression
|
||||
*/
|
||||
static int jffs2_is_best_compression(struct jffs2_compressor *this_,
|
||||
struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
|
||||
{
|
||||
switch (jffs2_compression_mode) {
|
||||
case JFFS2_COMPR_MODE_SIZE:
|
||||
if (bestsize > size)
|
||||
return 1;
|
||||
return 0;
|
||||
case JFFS2_COMPR_MODE_FAVOURLZO:
|
||||
if ((this_->compr == JFFS2_COMPR_LZO) && (bestsize > size))
|
||||
return 1;
|
||||
if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
|
||||
return 1;
|
||||
if ((this_->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
|
||||
return 1;
|
||||
if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* Shouldn't happen */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* jffs2_compress:
|
||||
* @data: Pointer to uncompressed data
|
||||
* @cdata: Pointer to returned pointer to buffer for compressed data
|
||||
* @datalen: On entry, holds the amount of data available for compression.
|
||||
* On exit, expected to hold the amount of data actually compressed.
|
||||
* @cdatalen: On entry, holds the amount of space available for compressed
|
||||
* data. On exit, expected to hold the actual size of the compressed
|
||||
* data.
|
||||
*
|
||||
* Returns: Lower byte to be stored with data indicating compression type used.
|
||||
* Zero is used to show that the data could not be compressed - the
|
||||
* compressed version was actually larger than the original.
|
||||
* Upper byte will be used later. (soon)
|
||||
*
|
||||
* If the cdata buffer isn't large enough to hold all the uncompressed data,
|
||||
* jffs2_compress should compress as much as will fit, and should set
|
||||
* *datalen accordingly to show the amount of data which were compressed.
|
||||
*/
|
||||
uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out,
|
||||
uint32_t *datalen, uint32_t *cdatalen)
|
||||
{
|
||||
int ret = JFFS2_COMPR_NONE;
|
||||
int compr_ret;
|
||||
struct jffs2_compressor *this_, *best=NULL;
|
||||
unsigned char *output_buf = NULL, *tmp_buf;
|
||||
uint32_t orig_slen, orig_dlen;
|
||||
uint32_t best_slen=0, best_dlen=0;
|
||||
|
||||
switch (jffs2_compression_mode) {
|
||||
case JFFS2_COMPR_MODE_NONE:
|
||||
break;
|
||||
case JFFS2_COMPR_MODE_PRIORITY:
|
||||
orig_slen = *datalen;
|
||||
orig_dlen = *cdatalen;
|
||||
output_buf = (unsigned char*)malloc(orig_dlen+jffs2_compression_check);
|
||||
if (!output_buf) {
|
||||
fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n");
|
||||
goto out;
|
||||
}
|
||||
list_for_each_entry(this_, &jffs2_compressor_list, list) {
|
||||
/* Skip decompress-only backwards-compatibility and disabled modules */
|
||||
if ((!this_->compress)||(this_->disabled))
|
||||
continue;
|
||||
|
||||
this_->usecount++;
|
||||
|
||||
if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
|
||||
jffs2_decompression_test_prepare(output_buf, orig_dlen);
|
||||
|
||||
*datalen = orig_slen;
|
||||
*cdatalen = orig_dlen;
|
||||
compr_ret = this_->compress(data_in, output_buf, datalen, cdatalen);
|
||||
this_->usecount--;
|
||||
if (!compr_ret) {
|
||||
ret = this_->compr;
|
||||
this_->stat_compr_blocks++;
|
||||
this_->stat_compr_orig_size += *datalen;
|
||||
this_->stat_compr_new_size += *cdatalen;
|
||||
if (jffs2_compression_check)
|
||||
jffs2_decompression_test(this_, data_in, output_buf, *cdatalen, *datalen, orig_dlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret == JFFS2_COMPR_NONE) free(output_buf);
|
||||
break;
|
||||
case JFFS2_COMPR_MODE_FAVOURLZO:
|
||||
case JFFS2_COMPR_MODE_SIZE:
|
||||
orig_slen = *datalen;
|
||||
orig_dlen = *cdatalen;
|
||||
list_for_each_entry(this_, &jffs2_compressor_list, list) {
|
||||
uint32_t needed_buf_size;
|
||||
|
||||
if (jffs2_compression_mode == JFFS2_COMPR_MODE_FAVOURLZO)
|
||||
needed_buf_size = orig_slen + jffs2_compression_check;
|
||||
else
|
||||
needed_buf_size = orig_dlen + jffs2_compression_check;
|
||||
|
||||
/* Skip decompress-only backwards-compatibility and disabled modules */
|
||||
if ((!this_->compress)||(this_->disabled))
|
||||
continue;
|
||||
/* Allocating memory for output buffer if necessary */
|
||||
if ((this_->compr_buf_size < needed_buf_size) && (this_->compr_buf)) {
|
||||
free(this_->compr_buf);
|
||||
this_->compr_buf_size=0;
|
||||
this_->compr_buf=NULL;
|
||||
}
|
||||
if (!this_->compr_buf) {
|
||||
tmp_buf = (unsigned char*)malloc(needed_buf_size);
|
||||
if (!tmp_buf) {
|
||||
fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
this_->compr_buf = tmp_buf;
|
||||
this_->compr_buf_size = orig_dlen;
|
||||
}
|
||||
}
|
||||
this_->usecount++;
|
||||
if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
|
||||
jffs2_decompression_test_prepare(this_->compr_buf,this_->compr_buf_size);
|
||||
*datalen = orig_slen;
|
||||
*cdatalen = orig_dlen;
|
||||
compr_ret = this_->compress(data_in, this_->compr_buf, datalen, cdatalen);
|
||||
this_->usecount--;
|
||||
if (!compr_ret) {
|
||||
if (jffs2_compression_check)
|
||||
jffs2_decompression_test(this_, data_in, this_->compr_buf, *cdatalen, *datalen, this_->compr_buf_size);
|
||||
if (((!best_dlen) || jffs2_is_best_compression(this_, best, *cdatalen, best_dlen))
|
||||
&& (*cdatalen < *datalen)) {
|
||||
best_dlen = *cdatalen;
|
||||
best_slen = *datalen;
|
||||
best = this_;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (best_dlen) {
|
||||
*cdatalen = best_dlen;
|
||||
*datalen = best_slen;
|
||||
output_buf = best->compr_buf;
|
||||
best->compr_buf = NULL;
|
||||
best->compr_buf_size = 0;
|
||||
best->stat_compr_blocks++;
|
||||
best->stat_compr_orig_size += best_slen;
|
||||
best->stat_compr_new_size += best_dlen;
|
||||
ret = best->compr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"mkfs.jffs2: unknown compression mode.\n");
|
||||
}
|
||||
out:
|
||||
if (ret == JFFS2_COMPR_NONE) {
|
||||
*cpage_out = data_in;
|
||||
*datalen = *cdatalen;
|
||||
none_stat_compr_blocks++;
|
||||
none_stat_compr_size += *datalen;
|
||||
}
|
||||
else {
|
||||
*cpage_out = output_buf;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int jffs2_register_compressor(struct jffs2_compressor *comp)
|
||||
{
|
||||
struct jffs2_compressor *this_;
|
||||
|
||||
if (!comp->name) {
|
||||
fprintf(stderr,"NULL compressor name at registering JFFS2 compressor. Failed.\n");
|
||||
return -1;
|
||||
}
|
||||
comp->compr_buf_size=0;
|
||||
comp->compr_buf=NULL;
|
||||
comp->usecount=0;
|
||||
comp->stat_compr_orig_size=0;
|
||||
comp->stat_compr_new_size=0;
|
||||
comp->stat_compr_blocks=0;
|
||||
comp->stat_decompr_blocks=0;
|
||||
|
||||
list_for_each_entry(this_, &jffs2_compressor_list, list) {
|
||||
if (this_->priority < comp->priority) {
|
||||
list_add(&comp->list, this_->list.prev);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
list_add_tail(&comp->list, &jffs2_compressor_list);
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jffs2_unregister_compressor(struct jffs2_compressor *comp)
|
||||
{
|
||||
|
||||
if (comp->usecount) {
|
||||
fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n");
|
||||
return -1;
|
||||
}
|
||||
list_del(&comp->list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define JFFS2_STAT_BUF_SIZE 16000
|
||||
|
||||
char *jffs2_list_compressors(void)
|
||||
{
|
||||
struct jffs2_compressor *this_;
|
||||
char *buf, *act_buf;
|
||||
|
||||
act_buf = buf = (char*)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 = (char*)malloc(JFFS2_STAT_BUF_SIZE);
|
||||
|
||||
act_buf += sprintf(act_buf,"Compression mode: ");
|
||||
switch (jffs2_compression_mode) {
|
||||
case JFFS2_COMPR_MODE_NONE:
|
||||
act_buf += sprintf(act_buf,"none");
|
||||
break;
|
||||
case JFFS2_COMPR_MODE_PRIORITY:
|
||||
act_buf += sprintf(act_buf,"priority");
|
||||
break;
|
||||
case JFFS2_COMPR_MODE_SIZE:
|
||||
act_buf += sprintf(act_buf,"size");
|
||||
break;
|
||||
case JFFS2_COMPR_MODE_FAVOURLZO:
|
||||
act_buf += sprintf(act_buf, "favourlzo");
|
||||
break;
|
||||
default:
|
||||
act_buf += sprintf(act_buf, "unknown");
|
||||
break;
|
||||
}
|
||||
act_buf += sprintf(act_buf,"\nCompressors:\n");
|
||||
act_buf += sprintf(act_buf,"%10s ","none");
|
||||
act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks,
|
||||
none_stat_compr_size, none_stat_decompr_blocks);
|
||||
list_for_each_entry(this_, &jffs2_compressor_list, list) {
|
||||
act_buf += sprintf(act_buf,"%10s (prio:%d) ",this_->name,this_->priority);
|
||||
if ((this_->disabled)||(!this_->compress))
|
||||
act_buf += sprintf(act_buf,"- ");
|
||||
else
|
||||
act_buf += sprintf(act_buf,"+ ");
|
||||
act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this_->stat_compr_blocks,
|
||||
this_->stat_compr_new_size, this_->stat_compr_orig_size,
|
||||
this_->stat_decompr_blocks);
|
||||
act_buf += sprintf(act_buf,"\n");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
int jffs2_set_compression_mode_name(const char *name)
|
||||
{
|
||||
if (!strcmp("none",name)) {
|
||||
jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp("priority",name)) {
|
||||
jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp("size",name)) {
|
||||
jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp("favourlzo", name)) {
|
||||
jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int jffs2_compressor_Xable(const char *name, int disabled)
|
||||
{
|
||||
struct jffs2_compressor *this_;
|
||||
list_for_each_entry(this_, &jffs2_compressor_list, list) {
|
||||
if (!strcmp(this_->name, name)) {
|
||||
this_->disabled = disabled;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int jffs2_enable_compressor_name(const char *name)
|
||||
{
|
||||
return jffs2_compressor_Xable(name, 0);
|
||||
}
|
||||
|
||||
int jffs2_disable_compressor_name(const char *name)
|
||||
{
|
||||
return jffs2_compressor_Xable(name, 1);
|
||||
}
|
||||
|
||||
int jffs2_set_compressor_priority(const char *name, int priority)
|
||||
{
|
||||
struct jffs2_compressor *this_,*comp;
|
||||
list_for_each_entry(this_, &jffs2_compressor_list, list) {
|
||||
if (!strcmp(this_->name, name)) {
|
||||
this_->priority = priority;
|
||||
comp = this_;
|
||||
goto reinsert;
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name);
|
||||
return 1;
|
||||
reinsert:
|
||||
/* list is sorted in the order of priority, so if
|
||||
we change it we have to reinsert it into the
|
||||
good place */
|
||||
list_del(&comp->list);
|
||||
list_for_each_entry(this_, &jffs2_compressor_list, list) {
|
||||
if (this_->priority < comp->priority) {
|
||||
list_add(&comp->list, this_->list.prev);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
list_add_tail(&comp->list, &jffs2_compressor_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int jffs2_compressors_init(void)
|
||||
{
|
||||
#ifdef CONFIG_JFFS2_ZLIB
|
||||
jffs2_zlib_init();
|
||||
#endif
|
||||
#ifdef CONFIG_JFFS2_RTIME
|
||||
jffs2_rtime_init();
|
||||
#endif
|
||||
#ifdef CONFIG_JFFS2_LZO
|
||||
jffs2_lzo_init();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jffs2_compressors_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_JFFS2_RTIME
|
||||
jffs2_rtime_exit();
|
||||
#endif
|
||||
#ifdef CONFIG_JFFS2_ZLIB
|
||||
jffs2_zlib_exit();
|
||||
#endif
|
||||
#ifdef CONFIG_JFFS2_LZO
|
||||
jffs2_lzo_exit();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
119
src/system/mtdutils/compr.h
Normal file
119
src/system/mtdutils/compr.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
||||
* University of Szeged, Hungary
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in the
|
||||
* jffs2 directory.
|
||||
*/
|
||||
|
||||
#ifndef __JFFS2_COMPR_H__
|
||||
#define __JFFS2_COMPR_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "linux/jffs2.h"
|
||||
|
||||
#define CONFIG_JFFS2_ZLIB
|
||||
#define CONFIG_JFFS2_RTIME
|
||||
#define CONFIG_JFFS2_LZO
|
||||
|
||||
#define JFFS2_RUBINMIPS_PRIORITY 10
|
||||
#define JFFS2_DYNRUBIN_PRIORITY 20
|
||||
#define JFFS2_RTIME_PRIORITY 50
|
||||
#define JFFS2_ZLIB_PRIORITY 60
|
||||
#define JFFS2_LZO_PRIORITY 80
|
||||
|
||||
#define JFFS2_COMPR_MODE_NONE 0
|
||||
#define JFFS2_COMPR_MODE_PRIORITY 1
|
||||
#define JFFS2_COMPR_MODE_SIZE 2
|
||||
#define JFFS2_COMPR_MODE_FAVOURLZO 3
|
||||
|
||||
#define kmalloc(a,b) malloc(a)
|
||||
#define kfree(a) free(a)
|
||||
#ifndef GFP_KERNEL
|
||||
#define GFP_KERNEL 0
|
||||
#endif
|
||||
|
||||
#define vmalloc(a) malloc(a)
|
||||
#define vfree(a) free(a)
|
||||
|
||||
#define printk(...) fprintf(stderr,__VA_ARGS__)
|
||||
|
||||
#define KERN_EMERG
|
||||
#define KERN_ALERT
|
||||
#define KERN_CRIT
|
||||
#define KERN_ERR
|
||||
#define KERN_WARNING
|
||||
#define KERN_NOTICE
|
||||
#define KERN_INFO
|
||||
#define KERN_DEBUG
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
void jffs2_set_compression_mode(int mode);
|
||||
int jffs2_get_compression_mode(void);
|
||||
int jffs2_set_compression_mode_name(const char *mode_name);
|
||||
|
||||
int jffs2_enable_compressor_name(const char *name);
|
||||
int jffs2_disable_compressor_name(const char *name);
|
||||
|
||||
int jffs2_set_compressor_priority(const char *name, int priority);
|
||||
|
||||
struct jffs2_compressor {
|
||||
struct list_head list;
|
||||
int priority; /* used by prirority comr. mode */
|
||||
const char *name;
|
||||
char compr; /* JFFS2_COMPR_XXX */
|
||||
int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
|
||||
uint32_t *srclen, uint32_t *destlen);
|
||||
int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
|
||||
uint32_t cdatalen, uint32_t datalen);
|
||||
int usecount;
|
||||
int disabled; /* if seted the compressor won't compress */
|
||||
unsigned char *compr_buf; /* used by size compr. mode */
|
||||
uint32_t compr_buf_size; /* used by size compr. mode */
|
||||
uint32_t stat_compr_orig_size;
|
||||
uint32_t stat_compr_new_size;
|
||||
uint32_t stat_compr_blocks;
|
||||
uint32_t stat_decompr_blocks;
|
||||
};
|
||||
|
||||
int jffs2_register_compressor(struct jffs2_compressor *comp);
|
||||
int jffs2_unregister_compressor(struct jffs2_compressor *comp);
|
||||
|
||||
int jffs2_compressors_init(void);
|
||||
int jffs2_compressors_exit(void);
|
||||
|
||||
uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out,
|
||||
uint32_t *datalen, uint32_t *cdatalen);
|
||||
|
||||
/* If it is setted, a decompress will be called after every compress */
|
||||
void jffs2_compression_check_set(int yesno);
|
||||
int jffs2_compression_check_get(void);
|
||||
int jffs2_compression_check_errorcnt_get(void);
|
||||
|
||||
char *jffs2_list_compressors(void);
|
||||
char *jffs2_stats(void);
|
||||
|
||||
/* Compressor modules */
|
||||
|
||||
/* These functions will be called by jffs2_compressors_init/exit */
|
||||
#ifdef CONFIG_JFFS2_ZLIB
|
||||
int jffs2_zlib_init(void);
|
||||
void jffs2_zlib_exit(void);
|
||||
#endif
|
||||
#ifdef CONFIG_JFFS2_RTIME
|
||||
int jffs2_rtime_init(void);
|
||||
void jffs2_rtime_exit(void);
|
||||
#endif
|
||||
#ifdef CONFIG_JFFS2_LZO
|
||||
int jffs2_lzo_init(void);
|
||||
void jffs2_lzo_exit(void);
|
||||
#endif
|
||||
|
||||
#endif /* __JFFS2_COMPR_H__ */
|
137
src/system/mtdutils/compr_lzo.cpp
Normal file
137
src/system/mtdutils/compr_lzo.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#define WITHOUT_LZO
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef WITHOUT_LZO
|
||||
#include <asm/types.h>
|
||||
#include <linux/jffs2.h>
|
||||
#include <lzo/lzo1x.h>
|
||||
#include "compr.h"
|
||||
|
||||
extern int page_size;
|
||||
|
||||
static void *lzo_mem;
|
||||
static void *lzo_compress_buf;
|
||||
|
||||
/*
|
||||
* Note about LZO compression.
|
||||
*
|
||||
* We want to use the _999_ compression routine which gives better compression
|
||||
* rates at the expense of time. Decompression time is unaffected. We might as
|
||||
* well use the standard lzo library routines for this but they will overflow
|
||||
* the destination buffer since they don't check the destination size.
|
||||
*
|
||||
* We therefore compress to a temporary buffer and copy if it will fit.
|
||||
*
|
||||
*/
|
||||
static int jffs2_lzo_cmpr(unsigned char *data_in, unsigned char *cpage_out,
|
||||
uint32_t *sourcelen, uint32_t *dstlen)
|
||||
{
|
||||
lzo_uint compress_size;
|
||||
int ret;
|
||||
|
||||
ret = lzo1x_999_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem);
|
||||
|
||||
if (ret != LZO_E_OK)
|
||||
return -1;
|
||||
|
||||
if (compress_size > *dstlen)
|
||||
return -1;
|
||||
|
||||
memcpy(cpage_out, lzo_compress_buf, compress_size);
|
||||
*dstlen = compress_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out,
|
||||
uint32_t srclen, uint32_t destlen)
|
||||
{
|
||||
int ret;
|
||||
lzo_uint dl;
|
||||
|
||||
ret = lzo1x_decompress_safe(data_in,srclen,cpage_out,&dl,NULL);
|
||||
|
||||
if (ret != LZO_E_OK || dl != destlen)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct jffs2_compressor jffs2_lzo_comp = {
|
||||
.priority = JFFS2_LZO_PRIORITY,
|
||||
.name = "lzo",
|
||||
.compr = JFFS2_COMPR_LZO,
|
||||
.compress = &jffs2_lzo_cmpr,
|
||||
.decompress = &jffs2_lzo_decompress,
|
||||
.disabled = 1,
|
||||
};
|
||||
|
||||
int jffs2_lzo_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
|
||||
if (!lzo_mem)
|
||||
return -1;
|
||||
|
||||
/* Worse case LZO compression size from their FAQ */
|
||||
lzo_compress_buf = malloc(page_size + (page_size / 16) + 64 + 3);
|
||||
if (!lzo_compress_buf) {
|
||||
free(lzo_mem);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = jffs2_register_compressor(&jffs2_lzo_comp);
|
||||
if (ret < 0) {
|
||||
free(lzo_compress_buf);
|
||||
free(lzo_mem);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void jffs2_lzo_exit(void)
|
||||
{
|
||||
jffs2_unregister_compressor(&jffs2_lzo_comp);
|
||||
free(lzo_compress_buf);
|
||||
free(lzo_mem);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int jffs2_lzo_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jffs2_lzo_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
124
src/system/mtdutils/compr_rtime.cpp
Normal file
124
src/system/mtdutils/compr_rtime.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
*
|
||||
* Created by Arjan van de Ven <arjanv@redhat.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* Very simple lz77-ish encoder.
|
||||
*
|
||||
* Theory of operation: Both encoder and decoder have a list of "last
|
||||
* occurrences" for every possible source-value; after sending the
|
||||
* first source-byte, the second byte indicated the "run" length of
|
||||
* matches
|
||||
*
|
||||
* The algorithm is intended to only send "whole bytes", no bit-messing.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "compr.h"
|
||||
|
||||
/* _compress returns the compressed size, -1 if bigger */
|
||||
static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
|
||||
uint32_t *sourcelen, uint32_t *dstlen)
|
||||
{
|
||||
short positions[256];
|
||||
int outpos = 0;
|
||||
int pos=0;
|
||||
|
||||
memset(positions,0,sizeof(positions));
|
||||
|
||||
while (pos < (*sourcelen) && outpos+2 <= (*dstlen)) {
|
||||
int backpos, runlen=0;
|
||||
unsigned char value;
|
||||
|
||||
value = data_in[pos];
|
||||
|
||||
cpage_out[outpos++] = data_in[pos++];
|
||||
|
||||
backpos = positions[value];
|
||||
positions[value]=pos;
|
||||
|
||||
while ((backpos < pos) && (pos < (*sourcelen)) &&
|
||||
(data_in[pos]==data_in[backpos++]) && (runlen<255)) {
|
||||
pos++;
|
||||
runlen++;
|
||||
}
|
||||
cpage_out[outpos++] = runlen;
|
||||
}
|
||||
|
||||
if (outpos >= pos) {
|
||||
/* We failed */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Tell the caller how much we managed to compress, and how much space it took */
|
||||
*sourcelen = pos;
|
||||
*dstlen = outpos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
|
||||
__attribute__((unused)) uint32_t srclen, uint32_t destlen)
|
||||
{
|
||||
short positions[256];
|
||||
uint32_t outpos = 0;
|
||||
int pos=0;
|
||||
|
||||
memset(positions,0,sizeof(positions));
|
||||
|
||||
while (outpos<destlen) {
|
||||
unsigned char value;
|
||||
uint32_t backoffs;
|
||||
uint32_t 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;
|
||||
void fill_jffs2_rtime_compressor_struct();
|
||||
|
||||
void fill_jffs2_rtime_compressor_struct()
|
||||
{
|
||||
jffs2_rtime_comp.priority = JFFS2_RTIME_PRIORITY;
|
||||
jffs2_rtime_comp.name = "rtime";
|
||||
jffs2_rtime_comp.disabled = 0;
|
||||
jffs2_rtime_comp.compr = JFFS2_COMPR_RTIME;
|
||||
jffs2_rtime_comp.compress = &jffs2_rtime_compress;
|
||||
jffs2_rtime_comp.decompress = &jffs2_rtime_decompress;
|
||||
}
|
||||
|
||||
int jffs2_rtime_init(void)
|
||||
{
|
||||
fill_jffs2_rtime_compressor_struct();
|
||||
return jffs2_register_compressor(&jffs2_rtime_comp);
|
||||
}
|
||||
|
||||
void jffs2_rtime_exit(void)
|
||||
{
|
||||
fill_jffs2_rtime_compressor_struct();
|
||||
jffs2_unregister_compressor(&jffs2_rtime_comp);
|
||||
}
|
154
src/system/mtdutils/compr_zlib.cpp
Normal file
154
src/system/mtdutils/compr_zlib.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
|
||||
*
|
||||
* The original JFFS, from which the design for JFFS2 was derived,
|
||||
* was designed and implemented by Axis Communications AB.
|
||||
*
|
||||
* The contents of this file are subject to the Red Hat eCos Public
|
||||
* License Version 1.1 (the "Licence"); you may not use this file
|
||||
* except in compliance with the Licence. You may obtain a copy of
|
||||
* the Licence at http://www.redhat.com/
|
||||
*
|
||||
* Software distributed under the Licence is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the Licence for the specific language governing rights and
|
||||
* limitations under the Licence.
|
||||
*
|
||||
* The Original Code is JFFS2 - Journalling Flash File System, version 2
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License version 2 (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of the
|
||||
* above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the RHEPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the RHEPL or the GPL.
|
||||
*/
|
||||
|
||||
#define PROGRAM_NAME "compr_zlib"
|
||||
|
||||
#include <stdint.h>
|
||||
#define crc32 __zlib_crc32
|
||||
#include <zlib.h>
|
||||
#undef crc32
|
||||
#include <stdio.h>
|
||||
#include <asm/types.h>
|
||||
#include <linux/jffs2.h>
|
||||
#include "common.h"
|
||||
#include "compr.h"
|
||||
|
||||
/* Plan: call deflate() with avail_in == *sourcelen,
|
||||
avail_out = *dstlen - 12 and flush == Z_FINISH.
|
||||
If it doesn't manage to finish, call it again with
|
||||
avail_in == 0 and avail_out set to the remaining 12
|
||||
bytes for it to clean up.
|
||||
Q: Is 12 bytes sufficient?
|
||||
*/
|
||||
#define STREAM_END_SPACE 12
|
||||
|
||||
static int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
|
||||
uint32_t *sourcelen, uint32_t *dstlen)
|
||||
{
|
||||
z_stream strm;
|
||||
int ret;
|
||||
|
||||
if (*dstlen <= STREAM_END_SPACE)
|
||||
return -1;
|
||||
|
||||
strm.zalloc = NULL;
|
||||
strm.zfree = NULL;
|
||||
|
||||
if (Z_OK != deflateInit(&strm, 3)) {
|
||||
return -1;
|
||||
}
|
||||
strm.next_in = data_in;
|
||||
strm.total_in = 0;
|
||||
|
||||
strm.next_out = cpage_out;
|
||||
strm.total_out = 0;
|
||||
|
||||
while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) {
|
||||
strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE);
|
||||
strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
|
||||
ret = deflate(&strm, Z_PARTIAL_FLUSH);
|
||||
if (ret != Z_OK) {
|
||||
deflateEnd(&strm);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
strm.avail_out += STREAM_END_SPACE;
|
||||
strm.avail_in = 0;
|
||||
ret = deflate(&strm, Z_FINISH);
|
||||
if (ret != Z_STREAM_END) {
|
||||
deflateEnd(&strm);
|
||||
return -1;
|
||||
}
|
||||
deflateEnd(&strm);
|
||||
|
||||
if (strm.total_out >= strm.total_in)
|
||||
return -1;
|
||||
|
||||
|
||||
*dstlen = strm.total_out;
|
||||
*sourcelen = strm.total_in;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
|
||||
uint32_t srclen, uint32_t destlen)
|
||||
{
|
||||
z_stream strm;
|
||||
int ret;
|
||||
|
||||
strm.zalloc = NULL;
|
||||
strm.zfree = NULL;
|
||||
|
||||
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;
|
||||
void fill_jffs2_zlib_compressor_struct();
|
||||
|
||||
void fill_jffs2_zlib_compressor_struct()
|
||||
{
|
||||
jffs2_zlib_comp.priority = JFFS2_ZLIB_PRIORITY;
|
||||
jffs2_zlib_comp.name = "zlib";
|
||||
jffs2_zlib_comp.disabled = 0;
|
||||
jffs2_zlib_comp.compr = JFFS2_COMPR_ZLIB;
|
||||
jffs2_zlib_comp.compress = &jffs2_zlib_compress;
|
||||
jffs2_zlib_comp.decompress = &jffs2_zlib_decompress;
|
||||
}
|
||||
|
||||
int jffs2_zlib_init(void)
|
||||
{
|
||||
fill_jffs2_zlib_compressor_struct();
|
||||
return jffs2_register_compressor(&jffs2_zlib_comp);
|
||||
}
|
||||
|
||||
void jffs2_zlib_exit(void)
|
||||
{
|
||||
fill_jffs2_zlib_compressor_struct();
|
||||
jffs2_unregister_compressor(&jffs2_zlib_comp);
|
||||
}
|
149
src/system/mtdutils/include/common.h
Normal file
149
src/system/mtdutils/include/common.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) Artem Bityutskiy, 2007, 2008
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_UTILS_COMMON_H__
|
||||
#define __MTD_UTILS_COMMON_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <features.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifndef PROGRAM_NAME
|
||||
# error "You must define PROGRAM_NAME before including this header"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef MIN /* some C lib headers define this for us */
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
#define min(a, b) MIN(a, b) /* glue for linux kernel source */
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
/* define a print format specifier for off_t */
|
||||
#ifdef __USE_FILE_OFFSET64
|
||||
#define PRIxoff_t PRIx64
|
||||
#define PRIdoff_t PRId64
|
||||
#else
|
||||
#define PRIxoff_t "l"PRIx32
|
||||
#define PRIdoff_t "l"PRId32
|
||||
#endif
|
||||
|
||||
/* Verbose messages */
|
||||
#define bareverbose(verbose, fmt, ...) do { \
|
||||
if (verbose) \
|
||||
printf(fmt, ##__VA_ARGS__); \
|
||||
} while(0)
|
||||
#define verbose(verbose, fmt, ...) \
|
||||
bareverbose(verbose, "%s: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__)
|
||||
|
||||
/* Normal messages */
|
||||
#define normsg_cont(fmt, ...) do { \
|
||||
printf("%s: " fmt, PROGRAM_NAME, ##__VA_ARGS__); \
|
||||
} while(0)
|
||||
#define normsg(fmt, ...) do { \
|
||||
normsg_cont(fmt "\n", ##__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
/* Error messages */
|
||||
#define errmsg(fmt, ...) ({ \
|
||||
fprintf(stderr, "%s: error!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
|
||||
-1; \
|
||||
})
|
||||
|
||||
/* System error messages */
|
||||
#define sys_errmsg(fmt, ...) ({ \
|
||||
int _err = errno; \
|
||||
errmsg(fmt, ##__VA_ARGS__); \
|
||||
fprintf(stderr, "%*serror %d (%s)\n", (int)sizeof(PROGRAM_NAME) + 1,\
|
||||
"", _err, strerror(_err)); \
|
||||
-1; \
|
||||
})
|
||||
|
||||
/* Warnings */
|
||||
#define warnmsg(fmt, ...) do { \
|
||||
fprintf(stderr, "%s: warning!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
static inline int is_power_of_2(unsigned long long n)
|
||||
{
|
||||
return (n != 0 && ((n & (n - 1)) == 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* simple_strtoX - convert a hex/dec/oct string into a number
|
||||
* @snum: buffer to convert
|
||||
* @error: set to 1 when buffer isn't fully consumed
|
||||
*
|
||||
* These functions are similar to the standard strtoX() functions, but they are
|
||||
* a little bit easier to use if you want to convert full string of digits into
|
||||
* the binary form. The typical usage:
|
||||
*
|
||||
* int error = 0;
|
||||
* unsigned long num;
|
||||
*
|
||||
* num = simple_strtoul(str, &error);
|
||||
* if (error || ... if needed, your check that num is not out of range ...)
|
||||
* error_happened();
|
||||
*/
|
||||
#define simple_strtoX(func, type) \
|
||||
static inline type simple_##func(const char *snum, int *error) \
|
||||
{ \
|
||||
char *endptr; \
|
||||
type ret = func(snum, &endptr, 0); \
|
||||
\
|
||||
if (error && (!*snum || *endptr)) { \
|
||||
errmsg("%s: unable to parse the number '%s'", #func, snum); \
|
||||
*error = 1; \
|
||||
} \
|
||||
\
|
||||
return ret; \
|
||||
}
|
||||
simple_strtoX(strtol, long int)
|
||||
simple_strtoX(strtoll, long long int)
|
||||
simple_strtoX(strtoul, unsigned long int)
|
||||
simple_strtoX(strtoull, unsigned long long int)
|
||||
|
||||
/* Simple version-printing for utils */
|
||||
#define common_print_version() \
|
||||
do { \
|
||||
printf("%s %s\n", PROGRAM_NAME, X_VERSION); \
|
||||
} while (0)
|
||||
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !__MTD_UTILS_COMMON_H__ */
|
13
src/system/mtdutils/include/crc32.h
Normal file
13
src/system/mtdutils/include/crc32.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* This code was taken from the linux kernel. The license is GPL Version 2.
|
||||
*/
|
||||
|
||||
#ifndef __CRC32_H__
|
||||
#define __CRC32_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Return a 32-bit CRC of the contents of the buffer */
|
||||
extern uint32_t mtd_crc32(uint32_t val, const void *ss, int len);
|
||||
|
||||
#endif /* __CRC32_H__ */
|
352
src/system/mtdutils/include/libmtd.h
Normal file
352
src/system/mtdutils/include/libmtd.h
Normal file
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (C) 2008, 2009 Nokia Corporation
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Author: Artem Bityutskiy
|
||||
*
|
||||
* MTD library.
|
||||
*/
|
||||
|
||||
#ifndef __LIBMTD_H__
|
||||
#define __LIBMTD_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Maximum MTD device name length */
|
||||
#define MTD_NAME_MAX 127
|
||||
/* Maximum MTD device type string length */
|
||||
#define MTD_TYPE_MAX 64
|
||||
|
||||
/* MTD library descriptor */
|
||||
typedef void * libmtd_t;
|
||||
|
||||
/* Forward decls */
|
||||
struct region_info_user;
|
||||
|
||||
/**
|
||||
* @mtd_dev_cnt: count of MTD devices in system
|
||||
* @lowest_mtd_num: lowest MTD device number in system
|
||||
* @highest_mtd_num: highest MTD device number in system
|
||||
* @sysfs_supported: non-zero if sysfs is supported by MTD
|
||||
*/
|
||||
struct mtd_info
|
||||
{
|
||||
int mtd_dev_cnt;
|
||||
int lowest_mtd_num;
|
||||
int highest_mtd_num;
|
||||
unsigned int sysfs_supported:1;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtd_dev_info - information about an MTD device.
|
||||
* @mtd_num: MTD device number
|
||||
* @major: major number of corresponding character device
|
||||
* @minor: minor number of corresponding character device
|
||||
* @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h)
|
||||
* @type_str: static R/O flash type string
|
||||
* @name: device name
|
||||
* @size: device size in bytes
|
||||
* @eb_cnt: count of eraseblocks
|
||||
* @eb_size: eraseblock size
|
||||
* @min_io_size: minimum input/output unit size
|
||||
* @subpage_size: sub-page size
|
||||
* @oob_size: OOB size (zero if the device does not have OOB area)
|
||||
* @region_cnt: count of additional erase regions
|
||||
* @writable: zero if the device is read-only
|
||||
* @bb_allowed: non-zero if the MTD device may have bad eraseblocks
|
||||
*/
|
||||
struct mtd_dev_info
|
||||
{
|
||||
int mtd_num;
|
||||
int major;
|
||||
int minor;
|
||||
int type;
|
||||
const char type_str[MTD_TYPE_MAX + 1];
|
||||
const char name[MTD_NAME_MAX + 1];
|
||||
long long size;
|
||||
int eb_cnt;
|
||||
int eb_size;
|
||||
int min_io_size;
|
||||
int subpage_size;
|
||||
int oob_size;
|
||||
int region_cnt;
|
||||
unsigned int writable:1;
|
||||
unsigned int bb_allowed:1;
|
||||
};
|
||||
|
||||
/**
|
||||
* libmtd_open - open MTD library.
|
||||
*
|
||||
* This function initializes and opens the MTD library and returns MTD library
|
||||
* descriptor in case of success and %NULL in case of failure. In case of
|
||||
* failure, errno contains zero if MTD is not present in the system, or
|
||||
* contains the error code if a real error happened.
|
||||
*/
|
||||
libmtd_t libmtd_open(void);
|
||||
|
||||
/**
|
||||
* libmtd_close - close MTD library.
|
||||
* @desc: MTD library descriptor
|
||||
*/
|
||||
void libmtd_close(libmtd_t desc);
|
||||
|
||||
/**
|
||||
* mtd_dev_present - check whether a MTD device is present.
|
||||
* @desc: MTD library descriptor
|
||||
* @mtd_num: MTD device number to check
|
||||
*
|
||||
* This function returns %1 if MTD device is present and %0 if not.
|
||||
*/
|
||||
int mtd_dev_present(libmtd_t desc, int mtd_num);
|
||||
|
||||
/**
|
||||
* mtd_get_info - get general MTD information.
|
||||
* @desc: MTD library descriptor
|
||||
* @info: the MTD device information is returned here
|
||||
*
|
||||
* This function fills the passed @info object with general MTD information and
|
||||
* returns %0 in case of success and %-1 in case of failure. If MTD subsystem is
|
||||
* not present in the system, errno is set to @ENODEV.
|
||||
*/
|
||||
int mtd_get_info(libmtd_t desc, struct mtd_info *info);
|
||||
|
||||
/**
|
||||
* mtd_get_dev_info - get information about an MTD device.
|
||||
* @desc: MTD library descriptor
|
||||
* @node: name of the MTD device node
|
||||
* @mtd: the MTD device information is returned here
|
||||
*
|
||||
* This function gets information about MTD device defined by the @node device
|
||||
* node file and saves this information in the @mtd object. Returns %0 in case
|
||||
* of success and %-1 in case of failure. If MTD subsystem is not present in the
|
||||
* system, or the MTD device does not exist, errno is set to @ENODEV.
|
||||
*/
|
||||
int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd);
|
||||
|
||||
/**
|
||||
* mtd_get_dev_info1 - get information about an MTD device.
|
||||
* @desc: MTD library descriptor
|
||||
* @mtd_num: MTD device number to fetch information about
|
||||
* @mtd: the MTD device information is returned here
|
||||
*
|
||||
* This function is identical to 'mtd_get_dev_info()' except that it accepts
|
||||
* MTD device number, not MTD character device.
|
||||
*/
|
||||
int mtd_get_dev_info1(libmtd_t desc, int mtd_num, struct mtd_dev_info *mtd);
|
||||
|
||||
/**
|
||||
* mtd_lock - lock eraseblocks.
|
||||
* @desc: MTD library descriptor
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @eb: eraseblock to lock
|
||||
*
|
||||
* This function locks eraseblock @eb. Returns %0 in case of success and %-1
|
||||
* in case of failure.
|
||||
*/
|
||||
int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb);
|
||||
|
||||
/**
|
||||
* mtd_unlock - unlock eraseblocks.
|
||||
* @desc: MTD library descriptor
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @eb: eraseblock to lock
|
||||
*
|
||||
* This function unlocks eraseblock @eb. Returns %0 in case of success and %-1
|
||||
* in case of failure.
|
||||
*/
|
||||
int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb);
|
||||
|
||||
/**
|
||||
* mtd_erase - erase an eraseblock.
|
||||
* @desc: MTD library descriptor
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @eb: eraseblock to erase
|
||||
*
|
||||
* This function erases eraseblock @eb of MTD device described by @fd. Returns
|
||||
* %0 in case of success and %-1 in case of failure.
|
||||
*/
|
||||
int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb);
|
||||
|
||||
/**
|
||||
* mtd_regioninfo - get information about an erase region.
|
||||
* @fd: MTD device node file descriptor
|
||||
* @regidx: index of region to look up
|
||||
* @reginfo: the region information is returned here
|
||||
*
|
||||
* This function gets information about an erase region defined by the
|
||||
* @regidx index and saves this information in the @reginfo object.
|
||||
* Returns %0 in case of success and %-1 in case of failure. If the
|
||||
* @regidx is not valid or unavailable, errno is set to @ENODEV.
|
||||
*/
|
||||
int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo);
|
||||
|
||||
/**
|
||||
* mtd_is_locked - see if the specified eraseblock is locked.
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @eb: eraseblock to check
|
||||
*
|
||||
* This function checks to see if eraseblock @eb of MTD device described
|
||||
* by @fd is locked. Returns %0 if it is unlocked, %1 if it is locked, and
|
||||
* %-1 in case of failure. If the ioctl is not supported (support was added in
|
||||
* Linux kernel 2.6.36) or this particular device does not support it, errno is
|
||||
* set to @ENOTSUPP.
|
||||
*/
|
||||
int mtd_is_locked(const struct mtd_dev_info *mtd, int fd, int eb);
|
||||
|
||||
/**
|
||||
* mtd_torture - torture an eraseblock.
|
||||
* @desc: MTD library descriptor
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @eb: eraseblock to torture
|
||||
*
|
||||
* This function tortures eraseblock @eb. Returns %0 in case of success and %-1
|
||||
* in case of failure.
|
||||
*/
|
||||
int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb);
|
||||
|
||||
/**
|
||||
* mtd_is_bad - check if eraseblock is bad.
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @eb: eraseblock to check
|
||||
*
|
||||
* This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes,
|
||||
* and %-1 in case of failure.
|
||||
*/
|
||||
int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb);
|
||||
|
||||
/**
|
||||
* mtd_mark_bad - mark an eraseblock as bad.
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @eb: eraseblock to mark as bad
|
||||
*
|
||||
* This function marks eraseblock @eb as bad. Returns %0 in case of success and
|
||||
* %-1 in case of failure.
|
||||
*/
|
||||
int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb);
|
||||
|
||||
/**
|
||||
* mtd_read - read data from an MTD device.
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @eb: eraseblock to read from
|
||||
* @offs: offset withing the eraseblock to read from
|
||||
* @buf: buffer to read data to
|
||||
* @len: how many bytes to read
|
||||
*
|
||||
* This function reads @len bytes of data from eraseblock @eb and offset @offs
|
||||
* of the MTD device defined by @mtd and stores the read data at buffer @buf.
|
||||
* Returns %0 in case of success and %-1 in case of failure.
|
||||
*/
|
||||
int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
|
||||
void *buf, int len);
|
||||
|
||||
/**
|
||||
* mtd_write - write data to an MTD device.
|
||||
* @desc: MTD library descriptor
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @eb: eraseblock to write to
|
||||
* @offs: offset withing the eraseblock to write to
|
||||
* @data: data buffer to write
|
||||
* @len: how many data bytes to write
|
||||
* @oob: OOB buffer to write
|
||||
* @ooblen: how many OOB bytes to write
|
||||
* @mode: write mode (e.g., %MTD_OOB_PLACE, %MTD_OOB_RAW)
|
||||
*
|
||||
* This function writes @len bytes of data to eraseblock @eb and offset @offs
|
||||
* of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in
|
||||
* case of failure.
|
||||
*
|
||||
* Can only write to a single page at a time if writing to OOB.
|
||||
*/
|
||||
int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb,
|
||||
int offs, void *data, int len, void *oob, int ooblen,
|
||||
uint8_t mode);
|
||||
|
||||
/**
|
||||
* mtd_read_oob - read out-of-band area.
|
||||
* @desc: MTD library descriptor
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @start: page-aligned start address
|
||||
* @length: number of OOB bytes to read
|
||||
* @data: read buffer
|
||||
*
|
||||
* This function reads @length OOB bytes starting from address @start on
|
||||
* MTD device described by @fd. The address is specified as page byte offset
|
||||
* from the beginning of the MTD device. This function returns %0 in case of
|
||||
* success and %-1 in case of failure.
|
||||
*/
|
||||
int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
|
||||
uint64_t start, uint64_t length, void *data);
|
||||
|
||||
/**
|
||||
* mtd_write_oob - write out-of-band area.
|
||||
* @desc: MTD library descriptor
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @start: page-aligned start address
|
||||
* @length: number of OOB bytes to write
|
||||
* @data: write buffer
|
||||
*
|
||||
* This function writes @length OOB bytes starting from address @start on
|
||||
* MTD device described by @fd. The address is specified as page byte offset
|
||||
* from the beginning of the MTD device. Returns %0 in case of success and %-1
|
||||
* in case of failure.
|
||||
*/
|
||||
int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
|
||||
uint64_t start, uint64_t length, void *data);
|
||||
|
||||
/**
|
||||
* mtd_write_img - write a file to MTD device.
|
||||
* @mtd: MTD device description object
|
||||
* @fd: MTD device node file descriptor
|
||||
* @eb: eraseblock to write to
|
||||
* @offs: offset withing the eraseblock to write to
|
||||
* @img_name: the file to write
|
||||
*
|
||||
* This function writes an image @img_name the MTD device defined by @mtd. @eb
|
||||
* and @offs are the starting eraseblock and offset on the MTD device. Returns
|
||||
* %0 in case of success and %-1 in case of failure.
|
||||
*/
|
||||
int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
|
||||
const char *img_name);
|
||||
|
||||
/**
|
||||
* mtd_probe_node - test MTD node.
|
||||
* @desc: MTD library descriptor
|
||||
* @node: the node to test
|
||||
*
|
||||
* This function tests whether @node is an MTD device node and returns %1 if it
|
||||
* is, and %-1 if it is not (errno is %ENODEV in this case) or if an error
|
||||
* occurred.
|
||||
*/
|
||||
int mtd_probe_node(libmtd_t desc, const char *node);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LIBMTD_H__ */
|
218
src/system/mtdutils/include/linux/jffs2.h
Normal file
218
src/system/mtdutils/include/linux/jffs2.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in the
|
||||
* jffs2 directory.
|
||||
*
|
||||
* $Id: jffs2.h,v 1.38 2005/09/26 11:37:23 havasi Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_JFFS2_H__
|
||||
#define __LINUX_JFFS2_H__
|
||||
|
||||
/* You must include something which defines the C99 uintXX_t types.
|
||||
We don't do it from here because this file is used in too many
|
||||
different environments. */
|
||||
|
||||
#define JFFS2_SUPER_MAGIC 0x72b6
|
||||
|
||||
/* Values we may expect to find in the 'magic' field */
|
||||
#define JFFS2_OLD_MAGIC_BITMASK 0x1984
|
||||
#define JFFS2_MAGIC_BITMASK 0x1985
|
||||
#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
|
||||
#define JFFS2_EMPTY_BITMASK 0xffff
|
||||
#define JFFS2_DIRTY_BITMASK 0x0000
|
||||
|
||||
/* Summary node MAGIC marker */
|
||||
#define JFFS2_SUM_MAGIC 0x02851885
|
||||
|
||||
/* We only allow a single char for length, and 0xFF is empty flash so
|
||||
we don't want it confused with a real length. Hence max 254.
|
||||
*/
|
||||
#define JFFS2_MAX_NAME_LEN 254
|
||||
|
||||
/* How small can we sensibly write nodes? */
|
||||
#define JFFS2_MIN_DATA_LEN 128
|
||||
|
||||
#define JFFS2_COMPR_NONE 0x00
|
||||
#define JFFS2_COMPR_ZERO 0x01
|
||||
#define JFFS2_COMPR_RTIME 0x02
|
||||
#define JFFS2_COMPR_RUBINMIPS 0x03
|
||||
#define JFFS2_COMPR_COPY 0x04
|
||||
#define JFFS2_COMPR_DYNRUBIN 0x05
|
||||
#define JFFS2_COMPR_ZLIB 0x06
|
||||
#define JFFS2_COMPR_LZO 0x07
|
||||
/* Compatibility flags. */
|
||||
#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
|
||||
#define JFFS2_NODE_ACCURATE 0x2000
|
||||
/* INCOMPAT: Fail to mount the filesystem */
|
||||
#define JFFS2_FEATURE_INCOMPAT 0xc000
|
||||
/* ROCOMPAT: Mount read-only */
|
||||
#define JFFS2_FEATURE_ROCOMPAT 0x8000
|
||||
/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
|
||||
#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
|
||||
/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
|
||||
#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
|
||||
|
||||
#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
|
||||
#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
|
||||
#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
|
||||
#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
|
||||
|
||||
#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
|
||||
|
||||
#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
|
||||
#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
|
||||
|
||||
/* XATTR Related */
|
||||
#define JFFS2_XPREFIX_USER 1 /* for "user." */
|
||||
#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */
|
||||
#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */
|
||||
#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */
|
||||
#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */
|
||||
|
||||
#define JFFS2_ACL_VERSION 0x0001
|
||||
|
||||
// Maybe later...
|
||||
//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
|
||||
//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
|
||||
|
||||
|
||||
#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at
|
||||
mount time, don't wait for it to
|
||||
happen later */
|
||||
#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific
|
||||
compression type */
|
||||
|
||||
|
||||
/* These can go once we've made sure we've caught all uses without
|
||||
byteswapping */
|
||||
|
||||
typedef struct {
|
||||
uint32_t v32;
|
||||
} __attribute__((packed)) jint32_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t m;
|
||||
} __attribute__((packed)) jmode_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t v16;
|
||||
} __attribute__((packed)) jint16_t;
|
||||
|
||||
struct jffs2_unknown_node
|
||||
{
|
||||
/* All start like this */
|
||||
jint16_t magic;
|
||||
jint16_t nodetype;
|
||||
jint32_t totlen; /* So we can skip over nodes we don't grok */
|
||||
jint32_t hdr_crc;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_raw_dirent
|
||||
{
|
||||
jint16_t magic;
|
||||
jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */
|
||||
jint32_t totlen;
|
||||
jint32_t hdr_crc;
|
||||
jint32_t pino;
|
||||
jint32_t version;
|
||||
jint32_t ino; /* == zero for unlink */
|
||||
jint32_t mctime;
|
||||
uint8_t nsize;
|
||||
uint8_t type;
|
||||
uint8_t unused[2];
|
||||
jint32_t node_crc;
|
||||
jint32_t name_crc;
|
||||
uint8_t name[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* The JFFS2 raw inode structure: Used for storage on physical media. */
|
||||
/* The uid, gid, atime, mtime and ctime members could be longer, but
|
||||
are left like this for space efficiency. If and when people decide
|
||||
they really need them extended, it's simple enough to add support for
|
||||
a new type of raw node.
|
||||
*/
|
||||
struct jffs2_raw_inode
|
||||
{
|
||||
jint16_t magic; /* A constant magic number. */
|
||||
jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */
|
||||
jint32_t totlen; /* Total length of this node (inc data, etc.) */
|
||||
jint32_t hdr_crc;
|
||||
jint32_t ino; /* Inode number. */
|
||||
jint32_t version; /* Version number. */
|
||||
jmode_t mode; /* The file's type or mode. */
|
||||
jint16_t uid; /* The file's owner. */
|
||||
jint16_t gid; /* The file's group. */
|
||||
jint32_t isize; /* Total resultant size of this inode (used for truncations) */
|
||||
jint32_t atime; /* Last access time. */
|
||||
jint32_t mtime; /* Last modification time. */
|
||||
jint32_t ctime; /* Change time. */
|
||||
jint32_t offset; /* Where to begin to write. */
|
||||
jint32_t csize; /* (Compressed) data size */
|
||||
jint32_t dsize; /* Size of the node's data. (after decompression) */
|
||||
uint8_t compr; /* Compression algorithm used */
|
||||
uint8_t usercompr; /* Compression algorithm requested by the user */
|
||||
jint16_t flags; /* See JFFS2_INO_FLAG_* */
|
||||
jint32_t data_crc; /* CRC for the (compressed) data. */
|
||||
jint32_t node_crc; /* CRC for the raw inode (excluding data) */
|
||||
uint8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_raw_xattr {
|
||||
jint16_t magic;
|
||||
jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */
|
||||
jint32_t totlen;
|
||||
jint32_t hdr_crc;
|
||||
jint32_t xid; /* XATTR identifier number */
|
||||
jint32_t version;
|
||||
uint8_t xprefix;
|
||||
uint8_t name_len;
|
||||
jint16_t value_len;
|
||||
jint32_t data_crc;
|
||||
jint32_t node_crc;
|
||||
uint8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_raw_xref
|
||||
{
|
||||
jint16_t magic;
|
||||
jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */
|
||||
jint32_t totlen;
|
||||
jint32_t hdr_crc;
|
||||
jint32_t ino; /* inode number */
|
||||
jint32_t xid; /* XATTR identifier number */
|
||||
jint32_t xseqno; /* xref sequencial number */
|
||||
jint32_t node_crc;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_raw_summary
|
||||
{
|
||||
jint16_t magic;
|
||||
jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */
|
||||
jint32_t totlen;
|
||||
jint32_t hdr_crc;
|
||||
jint32_t sum_num; /* number of sum entries*/
|
||||
jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */
|
||||
jint32_t padded; /* sum of the size of padding nodes */
|
||||
jint32_t sum_crc; /* summary information crc */
|
||||
jint32_t node_crc; /* node crc */
|
||||
jint32_t sum[0]; /* inode summary info */
|
||||
} __attribute__((packed));
|
||||
|
||||
union jffs2_node_union
|
||||
{
|
||||
struct jffs2_raw_inode i;
|
||||
struct jffs2_raw_dirent d;
|
||||
struct jffs2_raw_xattr x;
|
||||
struct jffs2_raw_xref r;
|
||||
struct jffs2_raw_summary s;
|
||||
struct jffs2_unknown_node u;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_JFFS2_H__ */
|
76
src/system/mtdutils/include/mtd/ftl-user.h
Normal file
76
src/system/mtdutils/include/mtd/ftl-user.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* $Id: ftl.h,v 1.7 2005/11/07 11:14:54 gleixner Exp $
|
||||
*
|
||||
* Derived from (and probably identical to):
|
||||
* ftl.h 1.7 1999/10/25 20:23:17
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License
|
||||
* at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* The initial developer of the original code is David A. Hinds
|
||||
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
|
||||
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License version 2 (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of the
|
||||
* above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use
|
||||
* your version of this file under the MPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the MPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_FTL_USER_H__
|
||||
#define __MTD_FTL_USER_H__
|
||||
|
||||
typedef struct erase_unit_header_t {
|
||||
u_int8_t LinkTargetTuple[5];
|
||||
u_int8_t DataOrgTuple[10];
|
||||
u_int8_t NumTransferUnits;
|
||||
u_int32_t EraseCount;
|
||||
u_int16_t LogicalEUN;
|
||||
u_int8_t BlockSize;
|
||||
u_int8_t EraseUnitSize;
|
||||
u_int16_t FirstPhysicalEUN;
|
||||
u_int16_t NumEraseUnits;
|
||||
u_int32_t FormattedSize;
|
||||
u_int32_t FirstVMAddress;
|
||||
u_int16_t NumVMPages;
|
||||
u_int8_t Flags;
|
||||
u_int8_t Code;
|
||||
u_int32_t SerialNumber;
|
||||
u_int32_t AltEUHOffset;
|
||||
u_int32_t BAMOffset;
|
||||
u_int8_t Reserved[12];
|
||||
u_int8_t EndTuple[2];
|
||||
} erase_unit_header_t;
|
||||
|
||||
/* Flags in erase_unit_header_t */
|
||||
#define HIDDEN_AREA 0x01
|
||||
#define REVERSE_POLARITY 0x02
|
||||
#define DOUBLE_BAI 0x04
|
||||
|
||||
/* Definitions for block allocation information */
|
||||
|
||||
#define BLOCK_FREE(b) ((b) == 0xffffffff)
|
||||
#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe))
|
||||
|
||||
#define BLOCK_TYPE(b) ((b) & 0x7f)
|
||||
#define BLOCK_ADDRESS(b) ((b) & ~0x7f)
|
||||
#define BLOCK_NUMBER(b) ((b) >> 9)
|
||||
#define BLOCK_CONTROL 0x30
|
||||
#define BLOCK_DATA 0x40
|
||||
#define BLOCK_REPLACEMENT 0x60
|
||||
#define BLOCK_BAD 0x70
|
||||
|
||||
#endif /* __MTD_FTL_USER_H__ */
|
89
src/system/mtdutils/include/mtd/inftl-user.h
Normal file
89
src/system/mtdutils/include/mtd/inftl-user.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* $Id: inftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
|
||||
*
|
||||
* Parts of INFTL headers shared with userspace
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MTD_INFTL_USER_H__
|
||||
#define __MTD_INFTL_USER_H__
|
||||
|
||||
#define OSAK_VERSION 0x5120
|
||||
#define PERCENTUSED 98
|
||||
|
||||
#define SECTORSIZE 512
|
||||
|
||||
/* Block Control Information */
|
||||
|
||||
struct inftl_bci {
|
||||
uint8_t ECCsig[6];
|
||||
uint8_t Status;
|
||||
uint8_t Status1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct inftl_unithead1 {
|
||||
uint16_t virtualUnitNo;
|
||||
uint16_t prevUnitNo;
|
||||
uint8_t ANAC;
|
||||
uint8_t NACs;
|
||||
uint8_t parityPerField;
|
||||
uint8_t discarded;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct inftl_unithead2 {
|
||||
uint8_t parityPerField;
|
||||
uint8_t ANAC;
|
||||
uint16_t prevUnitNo;
|
||||
uint16_t virtualUnitNo;
|
||||
uint8_t NACs;
|
||||
uint8_t discarded;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct inftl_unittail {
|
||||
uint8_t Reserved[4];
|
||||
uint16_t EraseMark;
|
||||
uint16_t EraseMark1;
|
||||
} __attribute__((packed));
|
||||
|
||||
union inftl_uci {
|
||||
struct inftl_unithead1 a;
|
||||
struct inftl_unithead2 b;
|
||||
struct inftl_unittail c;
|
||||
};
|
||||
|
||||
struct inftl_oob {
|
||||
struct inftl_bci b;
|
||||
union inftl_uci u;
|
||||
};
|
||||
|
||||
|
||||
/* INFTL Media Header */
|
||||
|
||||
struct INFTLPartition {
|
||||
__u32 virtualUnits;
|
||||
__u32 firstUnit;
|
||||
__u32 lastUnit;
|
||||
__u32 flags;
|
||||
__u32 spareUnits;
|
||||
__u32 Reserved0;
|
||||
__u32 Reserved1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct INFTLMediaHeader {
|
||||
char bootRecordID[8];
|
||||
__u32 NoOfBootImageBlocks;
|
||||
__u32 NoOfBinaryPartitions;
|
||||
__u32 NoOfBDTLPartitions;
|
||||
__u32 BlockMultiplierBits;
|
||||
__u32 FormatFlags;
|
||||
__u32 OsakVersion;
|
||||
__u32 PercentUsed;
|
||||
struct INFTLPartition Partitions[4];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Partition flag types */
|
||||
#define INFTL_BINARY 0x20000000
|
||||
#define INFTL_BDTL 0x40000000
|
||||
#define INFTL_LAST 0x80000000
|
||||
|
||||
#endif /* __MTD_INFTL_USER_H__ */
|
82
src/system/mtdutils/include/mtd/jffs2-user.h
Normal file
82
src/system/mtdutils/include/mtd/jffs2-user.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* $Id: jffs2-user.h,v 1.1 2004/05/05 11:57:54 dwmw2 Exp $
|
||||
*
|
||||
* JFFS2 definitions for use in user space only
|
||||
*/
|
||||
|
||||
#ifndef __JFFS2_USER_H__
|
||||
#define __JFFS2_USER_H__
|
||||
|
||||
/* This file is blessed for inclusion by userspace */
|
||||
#include <linux/jffs2.h>
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
|
||||
#undef cpu_to_je16
|
||||
#undef cpu_to_je32
|
||||
#undef cpu_to_jemode
|
||||
#undef je16_to_cpu
|
||||
#undef je32_to_cpu
|
||||
#undef jemode_to_cpu
|
||||
|
||||
extern int target_endian;
|
||||
|
||||
#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
|
||||
#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
|
||||
|
||||
#define cpu_to_je16(x) ((jint16_t){t16(x)})
|
||||
#define cpu_to_je32(x) ((jint32_t){t32(x)})
|
||||
#define cpu_to_jemode(x) ((jmode_t){t32(x)})
|
||||
|
||||
#define je16_to_cpu(x) (t16((x).v16))
|
||||
#define je32_to_cpu(x) (t32((x).v32))
|
||||
#define jemode_to_cpu(x) (t32((x).m))
|
||||
|
||||
#define le16_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
|
||||
#define le32_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
|
||||
#define cpu_to_le16(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
|
||||
#define cpu_to_le32(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
|
||||
|
||||
/* XATTR/POSIX-ACL related definition */
|
||||
/* Namespaces copied from xattr.h and posix_acl_xattr.h */
|
||||
#define XATTR_USER_PREFIX "user."
|
||||
#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
|
||||
#define XATTR_SECURITY_PREFIX "security."
|
||||
#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1)
|
||||
#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access"
|
||||
#define POSIX_ACL_XATTR_ACCESS_LEN (sizeof (POSIX_ACL_XATTR_ACCESS) - 1)
|
||||
#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default"
|
||||
#define POSIX_ACL_XATTR_DEFAULT_LEN (sizeof (POSIX_ACL_XATTR_DEFAULT) - 1)
|
||||
#define XATTR_TRUSTED_PREFIX "trusted."
|
||||
#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1)
|
||||
|
||||
struct jffs2_acl_entry {
|
||||
jint16_t e_tag;
|
||||
jint16_t e_perm;
|
||||
jint32_t e_id;
|
||||
};
|
||||
|
||||
struct jffs2_acl_entry_short {
|
||||
jint16_t e_tag;
|
||||
jint16_t e_perm;
|
||||
};
|
||||
|
||||
struct jffs2_acl_header {
|
||||
jint32_t a_version;
|
||||
};
|
||||
|
||||
/* copied from include/linux/posix_acl_xattr.h */
|
||||
#define POSIX_ACL_XATTR_VERSION 0x0002
|
||||
|
||||
struct posix_acl_xattr_entry {
|
||||
uint16_t e_tag;
|
||||
uint16_t e_perm;
|
||||
uint32_t e_id;
|
||||
};
|
||||
|
||||
struct posix_acl_xattr_header {
|
||||
uint32_t a_version;
|
||||
struct posix_acl_xattr_entry a_entries[0];
|
||||
};
|
||||
|
||||
#endif /* __JFFS2_USER_H__ */
|
277
src/system/mtdutils/include/mtd/mtd-abi.h
Normal file
277
src/system/mtdutils/include/mtd/mtd-abi.h
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org> et al.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MTD_ABI_H__
|
||||
#define __MTD_ABI_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct erase_info_user {
|
||||
__u32 start;
|
||||
__u32 length;
|
||||
};
|
||||
|
||||
struct erase_info_user64 {
|
||||
__u64 start;
|
||||
__u64 length;
|
||||
};
|
||||
|
||||
struct mtd_oob_buf {
|
||||
__u32 start;
|
||||
__u32 length;
|
||||
unsigned char *ptr;
|
||||
};
|
||||
|
||||
struct mtd_oob_buf64 {
|
||||
__u64 start;
|
||||
__u32 pad;
|
||||
__u32 length;
|
||||
__u64 usr_ptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* MTD operation modes
|
||||
*
|
||||
* @MTD_OPS_PLACE_OOB: OOB data are placed at the given offset (default)
|
||||
* @MTD_OPS_AUTO_OOB: OOB data are automatically placed at the free areas
|
||||
* which are defined by the internal ecclayout
|
||||
* @MTD_OPS_RAW: data are transferred as-is, with no error correction;
|
||||
* this mode implies %MTD_OPS_PLACE_OOB
|
||||
*
|
||||
* These modes can be passed to ioctl(MEMWRITE) and are also used internally.
|
||||
* See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs.
|
||||
* %MTD_FILE_MODE_RAW.
|
||||
*/
|
||||
enum {
|
||||
MTD_OPS_PLACE_OOB = 0,
|
||||
MTD_OPS_AUTO_OOB = 1,
|
||||
MTD_OPS_RAW = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtd_write_req - data structure for requesting a write operation
|
||||
*
|
||||
* @start: start address
|
||||
* @len: length of data buffer
|
||||
* @ooblen: length of OOB buffer
|
||||
* @usr_data: user-provided data buffer
|
||||
* @usr_oob: user-provided OOB buffer
|
||||
* @mode: MTD mode (see "MTD operation modes")
|
||||
* @padding: reserved, must be set to 0
|
||||
*
|
||||
* This structure supports ioctl(MEMWRITE) operations, allowing data and/or OOB
|
||||
* writes in various modes. To write to OOB-only, set @usr_data == NULL, and to
|
||||
* write data-only, set @usr_oob == NULL. However, setting both @usr_data and
|
||||
* @usr_oob to NULL is not allowed.
|
||||
*/
|
||||
struct mtd_write_req {
|
||||
__u64 start;
|
||||
__u64 len;
|
||||
__u64 ooblen;
|
||||
__u64 usr_data;
|
||||
__u64 usr_oob;
|
||||
__u8 mode;
|
||||
__u8 padding[7];
|
||||
};
|
||||
|
||||
#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_MLCNANDFLASH 8
|
||||
|
||||
#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_POWERUP_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)
|
||||
|
||||
/* Obsolete ECC byte placement modes (used with obsolete MEMGETOOBSEL) */
|
||||
#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 {
|
||||
__u8 type;
|
||||
__u32 flags;
|
||||
__u32 size; /* Total size of the MTD */
|
||||
__u32 erasesize;
|
||||
__u32 writesize;
|
||||
__u32 oobsize; /* Amount of OOB data per block (e.g. 16) */
|
||||
__u64 padding; /* Old obsolete field; do not use */
|
||||
};
|
||||
|
||||
struct region_info_user {
|
||||
__u32 offset; /* At which this region starts,
|
||||
* from the beginning of the MTD */
|
||||
__u32 erasesize; /* For this region */
|
||||
__u32 numblocks; /* Number of blocks in this region */
|
||||
__u32 regionindex;
|
||||
};
|
||||
|
||||
struct otp_info {
|
||||
__u32 start;
|
||||
__u32 length;
|
||||
__u32 locked;
|
||||
};
|
||||
|
||||
/*
|
||||
* Note, the following ioctl existed in the past and was removed:
|
||||
* #define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
|
||||
* Try to avoid adding a new ioctl with the same ioctl number.
|
||||
*/
|
||||
|
||||
/* Get basic MTD characteristics info (better to use sysfs) */
|
||||
#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
|
||||
/* Erase segment of MTD */
|
||||
#define MEMERASE _IOW('M', 2, struct erase_info_user)
|
||||
/* Write out-of-band data from MTD */
|
||||
#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
|
||||
/* Read out-of-band data from MTD */
|
||||
#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
|
||||
/* Lock a chip (for MTD that supports it) */
|
||||
#define MEMLOCK _IOW('M', 5, struct erase_info_user)
|
||||
/* Unlock a chip (for MTD that supports it) */
|
||||
#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
|
||||
/* Get the number of different erase regions */
|
||||
#define MEMGETREGIONCOUNT _IOR('M', 7, int)
|
||||
/* Get information about the erase region for a specific index */
|
||||
#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
|
||||
/* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */
|
||||
#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
|
||||
/* Check if an eraseblock is bad */
|
||||
#define MEMGETBADBLOCK _IOW('M', 11, __kernel_loff_t)
|
||||
/* Mark an eraseblock as bad */
|
||||
#define MEMSETBADBLOCK _IOW('M', 12, __kernel_loff_t)
|
||||
/* Set OTP (One-Time Programmable) mode (factory vs. user) */
|
||||
#define OTPSELECT _IOR('M', 13, int)
|
||||
/* Get number of OTP (One-Time Programmable) regions */
|
||||
#define OTPGETREGIONCOUNT _IOW('M', 14, int)
|
||||
/* Get all OTP (One-Time Programmable) info about MTD */
|
||||
#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
|
||||
/* Lock a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */
|
||||
#define OTPLOCK _IOR('M', 16, struct otp_info)
|
||||
/* Get ECC layout (deprecated) */
|
||||
#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout_user)
|
||||
/* Get statistics about corrected/uncorrected errors */
|
||||
#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
|
||||
/* Set MTD mode on a per-file-descriptor basis (see "MTD file modes") */
|
||||
#define MTDFILEMODE _IO('M', 19)
|
||||
/* Erase segment of MTD (supports 64-bit address) */
|
||||
#define MEMERASE64 _IOW('M', 20, struct erase_info_user64)
|
||||
/* Write data to OOB (64-bit version) */
|
||||
#define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64)
|
||||
/* Read data from OOB (64-bit version) */
|
||||
#define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64)
|
||||
/* Check if chip is locked (for MTD that supports it) */
|
||||
#define MEMISLOCKED _IOR('M', 23, struct erase_info_user)
|
||||
/*
|
||||
* Most generic write interface; can write in-band and/or out-of-band in various
|
||||
* modes (see "struct mtd_write_req")
|
||||
*/
|
||||
#define MEMWRITE _IOWR('M', 24, struct mtd_write_req)
|
||||
|
||||
/*
|
||||
* Obsolete legacy interface. Keep it in order not to break userspace
|
||||
* interfaces
|
||||
*/
|
||||
struct nand_oobinfo {
|
||||
__u32 useecc;
|
||||
__u32 eccbytes;
|
||||
__u32 oobfree[8][2];
|
||||
__u32 eccpos[32];
|
||||
};
|
||||
|
||||
struct nand_oobfree {
|
||||
__u32 offset;
|
||||
__u32 length;
|
||||
};
|
||||
|
||||
#define MTD_MAX_OOBFREE_ENTRIES 8
|
||||
#define MTD_MAX_ECCPOS_ENTRIES 64
|
||||
/*
|
||||
* OBSOLETE: ECC layout control structure. Exported to user-space via ioctl
|
||||
* ECCGETLAYOUT for backwards compatbility and should not be mistaken as a
|
||||
* complete set of ECC information. The ioctl truncates the larger internal
|
||||
* structure to retain binary compatibility with the static declaration of the
|
||||
* ioctl. Note that the "MTD_MAX_..._ENTRIES" macros represent the max size of
|
||||
* the user struct, not the MAX size of the internal struct nand_ecclayout.
|
||||
*/
|
||||
struct nand_ecclayout_user {
|
||||
__u32 eccbytes;
|
||||
__u32 eccpos[MTD_MAX_ECCPOS_ENTRIES];
|
||||
__u32 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 {
|
||||
__u32 corrected;
|
||||
__u32 failed;
|
||||
__u32 badblocks;
|
||||
__u32 bbtblocks;
|
||||
};
|
||||
|
||||
/*
|
||||
* MTD file modes - for read/write access to MTD
|
||||
*
|
||||
* @MTD_FILE_MODE_NORMAL: OTP disabled, ECC enabled
|
||||
* @MTD_FILE_MODE_OTP_FACTORY: OTP enabled in factory mode
|
||||
* @MTD_FILE_MODE_OTP_USER: OTP enabled in user mode
|
||||
* @MTD_FILE_MODE_RAW: OTP disabled, ECC disabled
|
||||
*
|
||||
* These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained
|
||||
* separately for each open file descriptor.
|
||||
*
|
||||
* Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW -
|
||||
* raw access to the flash, without error correction or autoplacement schemes.
|
||||
* Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode
|
||||
* (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is
|
||||
* used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)).
|
||||
*/
|
||||
enum mtd_file_modes {
|
||||
MTD_FILE_MODE_NORMAL = MTD_OTP_OFF,
|
||||
MTD_FILE_MODE_OTP_FACTORY = MTD_OTP_FACTORY,
|
||||
MTD_FILE_MODE_OTP_USER = MTD_OTP_USER,
|
||||
MTD_FILE_MODE_RAW,
|
||||
};
|
||||
|
||||
#endif /* __MTD_ABI_H__ */
|
34
src/system/mtdutils/include/mtd/mtd-user.h
Normal file
34
src/system/mtdutils/include/mtd/mtd-user.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright © 1999-2010 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#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_user nand_ecclayout_t;
|
||||
|
||||
#endif /* __MTD_USER_H__ */
|
76
src/system/mtdutils/include/mtd/nftl-user.h
Normal file
76
src/system/mtdutils/include/mtd/nftl-user.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* $Id: nftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
|
||||
*
|
||||
* Parts of NFTL headers shared with userspace
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NFTL_USER_H__
|
||||
#define __MTD_NFTL_USER_H__
|
||||
|
||||
/* Block Control Information */
|
||||
|
||||
struct nftl_bci {
|
||||
unsigned char ECCSig[6];
|
||||
uint8_t Status;
|
||||
uint8_t Status1;
|
||||
}__attribute__((packed));
|
||||
|
||||
/* Unit Control Information */
|
||||
|
||||
struct nftl_uci0 {
|
||||
uint16_t VirtUnitNum;
|
||||
uint16_t ReplUnitNum;
|
||||
uint16_t SpareVirtUnitNum;
|
||||
uint16_t SpareReplUnitNum;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct nftl_uci1 {
|
||||
uint32_t WearInfo;
|
||||
uint16_t EraseMark;
|
||||
uint16_t EraseMark1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct nftl_uci2 {
|
||||
uint16_t FoldMark;
|
||||
uint16_t FoldMark1;
|
||||
uint32_t unused;
|
||||
} __attribute__((packed));
|
||||
|
||||
union nftl_uci {
|
||||
struct nftl_uci0 a;
|
||||
struct nftl_uci1 b;
|
||||
struct nftl_uci2 c;
|
||||
};
|
||||
|
||||
struct nftl_oob {
|
||||
struct nftl_bci b;
|
||||
union nftl_uci u;
|
||||
};
|
||||
|
||||
/* NFTL Media Header */
|
||||
|
||||
struct NFTLMediaHeader {
|
||||
char DataOrgID[6];
|
||||
uint16_t NumEraseUnits;
|
||||
uint16_t FirstPhysicalEUN;
|
||||
uint32_t FormattedSize;
|
||||
unsigned char UnitSizeFactor;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define MAX_ERASE_ZONES (8192 - 512)
|
||||
|
||||
#define ERASE_MARK 0x3c69
|
||||
#define SECTOR_FREE 0xff
|
||||
#define SECTOR_USED 0x55
|
||||
#define SECTOR_IGNORE 0x11
|
||||
#define SECTOR_DELETED 0x00
|
||||
|
||||
#define FOLD_MARK_IN_PROGRESS 0x5555
|
||||
|
||||
#define ZONE_GOOD 0xff
|
||||
#define ZONE_BAD_ORIGINAL 0
|
||||
#define ZONE_BAD_MARKED 7
|
||||
|
||||
|
||||
#endif /* __MTD_NFTL_USER_H__ */
|
378
src/system/mtdutils/include/mtd/ubi-media.h
Normal file
378
src/system/mtdutils/include/mtd/ubi-media.h
Normal file
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (c) International Business Machines Corp., 2006
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Authors: Artem Bityutskiy (Битюцкий Артём)
|
||||
* Thomas Gleixner
|
||||
* Frank Haverkamp
|
||||
* Oliver Lohmann
|
||||
* Andreas Arnez
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines the layout of UBI headers and all the other UBI on-flash
|
||||
* data structures.
|
||||
*/
|
||||
|
||||
#ifndef __UBI_MEDIA_H__
|
||||
#define __UBI_MEDIA_H__
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/* The version of UBI images supported by this implementation */
|
||||
#define UBI_VERSION 1
|
||||
|
||||
/* The highest erase counter value supported by this implementation */
|
||||
#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF
|
||||
|
||||
/* The initial CRC32 value used when calculating CRC checksums */
|
||||
#define UBI_CRC32_INIT 0xFFFFFFFFU
|
||||
|
||||
/* Erase counter header magic number (ASCII "UBI#") */
|
||||
#define UBI_EC_HDR_MAGIC 0x55424923
|
||||
/* Volume identifier header magic number (ASCII "UBI!") */
|
||||
#define UBI_VID_HDR_MAGIC 0x55424921
|
||||
|
||||
/*
|
||||
* Volume type constants used in the volume identifier header.
|
||||
*
|
||||
* @UBI_VID_DYNAMIC: dynamic volume
|
||||
* @UBI_VID_STATIC: static volume
|
||||
*/
|
||||
enum {
|
||||
UBI_VID_DYNAMIC = 1,
|
||||
UBI_VID_STATIC = 2
|
||||
};
|
||||
|
||||
/*
|
||||
* Volume flags used in the volume table record.
|
||||
*
|
||||
* @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume
|
||||
*
|
||||
* %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume
|
||||
* table. UBI automatically re-sizes the volume which has this flag and makes
|
||||
* the volume to be of largest possible size. This means that if after the
|
||||
* initialization UBI finds out that there are available physical eraseblocks
|
||||
* present on the device, it automatically appends all of them to the volume
|
||||
* (the physical eraseblocks reserved for bad eraseblocks handling and other
|
||||
* reserved physical eraseblocks are not taken). So, if there is a volume with
|
||||
* the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical
|
||||
* eraseblocks will be zero after UBI is loaded, because all of them will be
|
||||
* reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared
|
||||
* after the volume had been initialized.
|
||||
*
|
||||
* The auto-resize feature is useful for device production purposes. For
|
||||
* example, different NAND flash chips may have different amount of initial bad
|
||||
* eraseblocks, depending of particular chip instance. Manufacturers of NAND
|
||||
* chips usually guarantee that the amount of initial bad eraseblocks does not
|
||||
* exceed certain percent, e.g. 2%. When one creates an UBI image which will be
|
||||
* flashed to the end devices in production, he does not know the exact amount
|
||||
* of good physical eraseblocks the NAND chip on the device will have, but this
|
||||
* number is required to calculate the volume sized and put them to the volume
|
||||
* table of the UBI image. In this case, one of the volumes (e.g., the one
|
||||
* which will store the root file system) is marked as "auto-resizable", and
|
||||
* UBI will adjust its size on the first boot if needed.
|
||||
*
|
||||
* Note, first UBI reserves some amount of physical eraseblocks for bad
|
||||
* eraseblock handling, and then re-sizes the volume, not vice-versa. This
|
||||
* means that the pool of reserved physical eraseblocks will always be present.
|
||||
*/
|
||||
enum {
|
||||
UBI_VTBL_AUTORESIZE_FLG = 0x01,
|
||||
};
|
||||
|
||||
/*
|
||||
* Compatibility constants used by internal volumes.
|
||||
*
|
||||
* @UBI_COMPAT_DELETE: delete this internal volume before anything is written
|
||||
* to the flash
|
||||
* @UBI_COMPAT_RO: attach this device in read-only mode
|
||||
* @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
|
||||
* physical eraseblocks, don't allow the wear-leveling
|
||||
* sub-system to move them
|
||||
* @UBI_COMPAT_REJECT: reject this UBI image
|
||||
*/
|
||||
enum {
|
||||
UBI_COMPAT_DELETE = 1,
|
||||
UBI_COMPAT_RO = 2,
|
||||
UBI_COMPAT_PRESERVE = 4,
|
||||
UBI_COMPAT_REJECT = 5
|
||||
};
|
||||
|
||||
/* Sizes of UBI headers */
|
||||
#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr)
|
||||
#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
|
||||
|
||||
/* Sizes of UBI headers without the ending CRC */
|
||||
#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32))
|
||||
#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
|
||||
|
||||
/**
|
||||
* struct ubi_ec_hdr - UBI erase counter header.
|
||||
* @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
|
||||
* @version: version of UBI implementation which is supposed to accept this
|
||||
* UBI image
|
||||
* @padding1: reserved for future, zeroes
|
||||
* @ec: the erase counter
|
||||
* @vid_hdr_offset: where the VID header starts
|
||||
* @data_offset: where the user data start
|
||||
* @image_seq: image sequence number
|
||||
* @padding2: reserved for future, zeroes
|
||||
* @hdr_crc: erase counter header CRC checksum
|
||||
*
|
||||
* The erase counter header takes 64 bytes and has a plenty of unused space for
|
||||
* future usage. The unused fields are zeroed. The @version field is used to
|
||||
* indicate the version of UBI implementation which is supposed to be able to
|
||||
* work with this UBI image. If @version is greater than the current UBI
|
||||
* version, the image is rejected. This may be useful in future if something
|
||||
* is changed radically. This field is duplicated in the volume identifier
|
||||
* header.
|
||||
*
|
||||
* The @vid_hdr_offset and @data_offset fields contain the offset of the the
|
||||
* volume identifier header and user data, relative to the beginning of the
|
||||
* physical eraseblock. These values have to be the same for all physical
|
||||
* eraseblocks.
|
||||
*
|
||||
* The @image_seq field is used to validate a UBI image that has been prepared
|
||||
* for a UBI device. The @image_seq value can be any value, but it must be the
|
||||
* same on all eraseblocks. UBI will ensure that all new erase counter headers
|
||||
* also contain this value, and will check the value when scanning at start-up.
|
||||
* One way to make use of @image_seq is to increase its value by one every time
|
||||
* an image is flashed over an existing image, then, if the flashing does not
|
||||
* complete, UBI will detect the error when scanning.
|
||||
*/
|
||||
struct ubi_ec_hdr {
|
||||
__be32 magic;
|
||||
__u8 version;
|
||||
__u8 padding1[3];
|
||||
__be64 ec; /* Warning: the current limit is 31-bit anyway! */
|
||||
__be32 vid_hdr_offset;
|
||||
__be32 data_offset;
|
||||
__be32 image_seq;
|
||||
__u8 padding2[32];
|
||||
__be32 hdr_crc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* struct ubi_vid_hdr - on-flash UBI volume identifier header.
|
||||
* @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
|
||||
* @version: UBI implementation version which is supposed to accept this UBI
|
||||
* image (%UBI_VERSION)
|
||||
* @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
|
||||
* @copy_flag: if this logical eraseblock was copied from another physical
|
||||
* eraseblock (for wear-leveling reasons)
|
||||
* @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
|
||||
* %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
|
||||
* @vol_id: ID of this volume
|
||||
* @lnum: logical eraseblock number
|
||||
* @padding1: reserved for future, zeroes
|
||||
* @data_size: how many bytes of data this logical eraseblock contains
|
||||
* @used_ebs: total number of used logical eraseblocks in this volume
|
||||
* @data_pad: how many bytes at the end of this physical eraseblock are not
|
||||
* used
|
||||
* @data_crc: CRC checksum of the data stored in this logical eraseblock
|
||||
* @padding2: reserved for future, zeroes
|
||||
* @sqnum: sequence number
|
||||
* @padding3: reserved for future, zeroes
|
||||
* @hdr_crc: volume identifier header CRC checksum
|
||||
*
|
||||
* The @sqnum is the value of the global sequence counter at the time when this
|
||||
* VID header was created. The global sequence counter is incremented each time
|
||||
* UBI writes a new VID header to the flash, i.e. when it maps a logical
|
||||
* eraseblock to a new physical eraseblock. The global sequence counter is an
|
||||
* unsigned 64-bit integer and we assume it never overflows. The @sqnum
|
||||
* (sequence number) is used to distinguish between older and newer versions of
|
||||
* logical eraseblocks.
|
||||
*
|
||||
* There are 2 situations when there may be more than one physical eraseblock
|
||||
* corresponding to the same logical eraseblock, i.e., having the same @vol_id
|
||||
* and @lnum values in the volume identifier header. Suppose we have a logical
|
||||
* eraseblock L and it is mapped to the physical eraseblock P.
|
||||
*
|
||||
* 1. Because UBI may erase physical eraseblocks asynchronously, the following
|
||||
* situation is possible: L is asynchronously erased, so P is scheduled for
|
||||
* erasure, then L is written to,i.e. mapped to another physical eraseblock P1,
|
||||
* so P1 is written to, then an unclean reboot happens. Result - there are 2
|
||||
* physical eraseblocks P and P1 corresponding to the same logical eraseblock
|
||||
* L. But P1 has greater sequence number, so UBI picks P1 when it attaches the
|
||||
* flash.
|
||||
*
|
||||
* 2. From time to time UBI moves logical eraseblocks to other physical
|
||||
* eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P
|
||||
* to P1, and an unclean reboot happens before P is physically erased, there
|
||||
* are two physical eraseblocks P and P1 corresponding to L and UBI has to
|
||||
* select one of them when the flash is attached. The @sqnum field says which
|
||||
* PEB is the original (obviously P will have lower @sqnum) and the copy. But
|
||||
* it is not enough to select the physical eraseblock with the higher sequence
|
||||
* number, because the unclean reboot could have happen in the middle of the
|
||||
* copying process, so the data in P is corrupted. It is also not enough to
|
||||
* just select the physical eraseblock with lower sequence number, because the
|
||||
* data there may be old (consider a case if more data was added to P1 after
|
||||
* the copying). Moreover, the unclean reboot may happen when the erasure of P
|
||||
* was just started, so it result in unstable P, which is "mostly" OK, but
|
||||
* still has unstable bits.
|
||||
*
|
||||
* UBI uses the @copy_flag field to indicate that this logical eraseblock is a
|
||||
* copy. UBI also calculates data CRC when the data is moved and stores it at
|
||||
* the @data_crc field of the copy (P1). So when UBI needs to pick one physical
|
||||
* eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is
|
||||
* examined. If it is cleared, the situation* is simple and the newer one is
|
||||
* picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC
|
||||
* checksum is correct, this physical eraseblock is selected (P1). Otherwise
|
||||
* the older one (P) is selected.
|
||||
*
|
||||
* There are 2 sorts of volumes in UBI: user volumes and internal volumes.
|
||||
* Internal volumes are not seen from outside and are used for various internal
|
||||
* UBI purposes. In this implementation there is only one internal volume - the
|
||||
* layout volume. Internal volumes are the main mechanism of UBI extensions.
|
||||
* For example, in future one may introduce a journal internal volume. Internal
|
||||
* volumes have their own reserved range of IDs.
|
||||
*
|
||||
* The @compat field is only used for internal volumes and contains the "degree
|
||||
* of their compatibility". It is always zero for user volumes. This field
|
||||
* provides a mechanism to introduce UBI extensions and to be still compatible
|
||||
* with older UBI binaries. For example, if someone introduced a journal in
|
||||
* future, he would probably use %UBI_COMPAT_DELETE compatibility for the
|
||||
* journal volume. And in this case, older UBI binaries, which know nothing
|
||||
* about the journal volume, would just delete this volume and work perfectly
|
||||
* fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image
|
||||
* - it just ignores the Ext3fs journal.
|
||||
*
|
||||
* The @data_crc field contains the CRC checksum of the contents of the logical
|
||||
* eraseblock if this is a static volume. In case of dynamic volumes, it does
|
||||
* not contain the CRC checksum as a rule. The only exception is when the
|
||||
* data of the physical eraseblock was moved by the wear-leveling sub-system,
|
||||
* then the wear-leveling sub-system calculates the data CRC and stores it in
|
||||
* the @data_crc field. And of course, the @copy_flag is %in this case.
|
||||
*
|
||||
* The @data_size field is used only for static volumes because UBI has to know
|
||||
* how many bytes of data are stored in this eraseblock. For dynamic volumes,
|
||||
* this field usually contains zero. The only exception is when the data of the
|
||||
* physical eraseblock was moved to another physical eraseblock for
|
||||
* wear-leveling reasons. In this case, UBI calculates CRC checksum of the
|
||||
* contents and uses both @data_crc and @data_size fields. In this case, the
|
||||
* @data_size field contains data size.
|
||||
*
|
||||
* The @used_ebs field is used only for static volumes and indicates how many
|
||||
* eraseblocks the data of the volume takes. For dynamic volumes this field is
|
||||
* not used and always contains zero.
|
||||
*
|
||||
* The @data_pad is calculated when volumes are created using the alignment
|
||||
* parameter. So, effectively, the @data_pad field reduces the size of logical
|
||||
* eraseblocks of this volume. This is very handy when one uses block-oriented
|
||||
* software (say, cramfs) on top of the UBI volume.
|
||||
*/
|
||||
struct ubi_vid_hdr {
|
||||
__be32 magic;
|
||||
__u8 version;
|
||||
__u8 vol_type;
|
||||
__u8 copy_flag;
|
||||
__u8 compat;
|
||||
__be32 vol_id;
|
||||
__be32 lnum;
|
||||
__be32 leb_ver;
|
||||
__be32 data_size;
|
||||
__be32 used_ebs;
|
||||
__be32 data_pad;
|
||||
__be32 data_crc;
|
||||
__u8 padding2[4];
|
||||
__be64 sqnum;
|
||||
__u8 padding3[12];
|
||||
__be32 hdr_crc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Internal UBI volumes count */
|
||||
#define UBI_INT_VOL_COUNT 1
|
||||
|
||||
/*
|
||||
* Starting ID of internal volumes. There is reserved room for 4096 internal
|
||||
* volumes.
|
||||
*/
|
||||
#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
|
||||
|
||||
/* The layout volume contains the volume table */
|
||||
|
||||
#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START
|
||||
#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC
|
||||
#define UBI_LAYOUT_VOLUME_ALIGN 1
|
||||
#define UBI_LAYOUT_VOLUME_EBS 2
|
||||
#define UBI_LAYOUT_VOLUME_NAME "layout volume"
|
||||
#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
|
||||
|
||||
/* The maximum number of volumes per one UBI device */
|
||||
#define UBI_MAX_VOLUMES 128
|
||||
|
||||
/* The maximum volume name length */
|
||||
#define UBI_VOL_NAME_MAX 127
|
||||
|
||||
/* Size of the volume table record */
|
||||
#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
|
||||
|
||||
/* Size of the volume table record without the ending CRC */
|
||||
#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
|
||||
|
||||
/**
|
||||
* struct ubi_vtbl_record - a record in the volume table.
|
||||
* @reserved_pebs: how many physical eraseblocks are reserved for this volume
|
||||
* @alignment: volume alignment
|
||||
* @data_pad: how many bytes are unused at the end of the each physical
|
||||
* eraseblock to satisfy the requested alignment
|
||||
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
|
||||
* @upd_marker: if volume update was started but not finished
|
||||
* @name_len: volume name length
|
||||
* @name: the volume name
|
||||
* @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
|
||||
* @padding: reserved, zeroes
|
||||
* @crc: a CRC32 checksum of the record
|
||||
*
|
||||
* The volume table records are stored in the volume table, which is stored in
|
||||
* the layout volume. The layout volume consists of 2 logical eraseblock, each
|
||||
* of which contains a copy of the volume table (i.e., the volume table is
|
||||
* duplicated). The volume table is an array of &struct ubi_vtbl_record
|
||||
* objects indexed by the volume ID.
|
||||
*
|
||||
* If the size of the logical eraseblock is large enough to fit
|
||||
* %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES
|
||||
* records. Otherwise, it contains as many records as it can fit (i.e., size of
|
||||
* logical eraseblock divided by sizeof(struct ubi_vtbl_record)).
|
||||
*
|
||||
* The @upd_marker flag is used to implement volume update. It is set to %1
|
||||
* before update and set to %0 after the update. So if the update operation was
|
||||
* interrupted, UBI knows that the volume is corrupted.
|
||||
*
|
||||
* The @alignment field is specified when the volume is created and cannot be
|
||||
* later changed. It may be useful, for example, when a block-oriented file
|
||||
* system works on top of UBI. The @data_pad field is calculated using the
|
||||
* logical eraseblock size and @alignment. The alignment must be multiple to the
|
||||
* minimal flash I/O unit. If @alignment is 1, all the available space of
|
||||
* the physical eraseblocks is used.
|
||||
*
|
||||
* Empty records contain all zeroes and the CRC checksum of those zeroes.
|
||||
*/
|
||||
struct ubi_vtbl_record {
|
||||
__be32 reserved_pebs;
|
||||
__be32 alignment;
|
||||
__be32 data_pad;
|
||||
__u8 vol_type;
|
||||
__u8 upd_marker;
|
||||
__be16 name_len;
|
||||
__u8 name[UBI_VOL_NAME_MAX+1];
|
||||
__u8 flags;
|
||||
__u8 padding[23];
|
||||
__be32 crc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif /* !__UBI_MEDIA_H__ */
|
418
src/system/mtdutils/include/mtd/ubi-user.h
Normal file
418
src/system/mtdutils/include/mtd/ubi-user.h
Normal file
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
* Copyright © International Business Machines Corp., 2006
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Artem Bityutskiy (Битюцкий Артём)
|
||||
*/
|
||||
|
||||
#ifndef __UBI_USER_H__
|
||||
#define __UBI_USER_H__
|
||||
|
||||
/*
|
||||
* UBI device creation (the same as MTD device attachment)
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI
|
||||
* control device. The caller has to properly fill and pass
|
||||
* &struct ubi_attach_req object - UBI will attach the MTD device specified in
|
||||
* the request and return the newly created UBI device number as the ioctl
|
||||
* return value.
|
||||
*
|
||||
* UBI device deletion (the same as MTD device detachment)
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI
|
||||
* control device.
|
||||
*
|
||||
* UBI volume creation
|
||||
* ~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* UBI volumes are created via the %UBI_IOCMKVOL ioctl command of UBI character
|
||||
* device. A &struct ubi_mkvol_req object has to be properly filled and a
|
||||
* pointer to it has to be passed to the ioctl.
|
||||
*
|
||||
* UBI volume deletion
|
||||
* ~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* To delete a volume, the %UBI_IOCRMVOL ioctl command of the UBI character
|
||||
* device should be used. A pointer to the 32-bit volume ID hast to be passed
|
||||
* to the ioctl.
|
||||
*
|
||||
* UBI volume re-size
|
||||
* ~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* To re-size a volume, the %UBI_IOCRSVOL ioctl command of the UBI character
|
||||
* device should be used. A &struct ubi_rsvol_req object has to be properly
|
||||
* filled and a pointer to it has to be passed to the ioctl.
|
||||
*
|
||||
* UBI volumes re-name
|
||||
* ~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* To re-name several volumes atomically at one go, the %UBI_IOCRNVOL command
|
||||
* of the UBI character device should be used. A &struct ubi_rnvol_req object
|
||||
* has to be properly filled and a pointer to it has to be passed to the ioctl.
|
||||
*
|
||||
* UBI volume update
|
||||
* ~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Volume update should be done via the %UBI_IOCVOLUP ioctl command of the
|
||||
* corresponding UBI volume character device. A pointer to a 64-bit update
|
||||
* size should be passed to the ioctl. After this, UBI expects user to write
|
||||
* this number of bytes to the volume character device. The update is finished
|
||||
* when the claimed number of bytes is passed. So, the volume update sequence
|
||||
* is something like:
|
||||
*
|
||||
* fd = open("/dev/my_volume");
|
||||
* ioctl(fd, UBI_IOCVOLUP, &image_size);
|
||||
* write(fd, buf, image_size);
|
||||
* close(fd);
|
||||
*
|
||||
* Logical eraseblock erase
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* To erase a logical eraseblock, the %UBI_IOCEBER ioctl command of the
|
||||
* corresponding UBI volume character device should be used. This command
|
||||
* unmaps the requested logical eraseblock, makes sure the corresponding
|
||||
* physical eraseblock is successfully erased, and returns.
|
||||
*
|
||||
* Atomic logical eraseblock change
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Atomic logical eraseblock change operation is called using the %UBI_IOCEBCH
|
||||
* ioctl command of the corresponding UBI volume character device. A pointer to
|
||||
* a &struct ubi_leb_change_req object has to be passed to the ioctl. Then the
|
||||
* user is expected to write the requested amount of bytes (similarly to what
|
||||
* should be done in case of the "volume update" ioctl).
|
||||
*
|
||||
* Logical eraseblock map
|
||||
* ~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* To map a logical eraseblock to a physical eraseblock, the %UBI_IOCEBMAP
|
||||
* ioctl command should be used. A pointer to a &struct ubi_map_req object is
|
||||
* expected to be passed. The ioctl maps the requested logical eraseblock to
|
||||
* a physical eraseblock and returns. Only non-mapped logical eraseblocks can
|
||||
* be mapped. If the logical eraseblock specified in the request is already
|
||||
* mapped to a physical eraseblock, the ioctl fails and returns error.
|
||||
*
|
||||
* Logical eraseblock unmap
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* To unmap a logical eraseblock to a physical eraseblock, the %UBI_IOCEBUNMAP
|
||||
* ioctl command should be used. The ioctl unmaps the logical eraseblocks,
|
||||
* schedules corresponding physical eraseblock for erasure, and returns. Unlike
|
||||
* the "LEB erase" command, it does not wait for the physical eraseblock being
|
||||
* erased. Note, the side effect of this is that if an unclean reboot happens
|
||||
* after the unmap ioctl returns, you may find the LEB mapped again to the same
|
||||
* physical eraseblock after the UBI is run again.
|
||||
*
|
||||
* Check if logical eraseblock is mapped
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* To check if a logical eraseblock is mapped to a physical eraseblock, the
|
||||
* %UBI_IOCEBISMAP ioctl command should be used. It returns %0 if the LEB is
|
||||
* not mapped, and %1 if it is mapped.
|
||||
*
|
||||
* Set an UBI volume property
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* To set an UBI volume property the %UBI_IOCSETPROP ioctl command should be
|
||||
* used. A pointer to a &struct ubi_set_vol_prop_req object is expected to be
|
||||
* passed. The object describes which property should be set, and to which value
|
||||
* it should be set.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When a new UBI volume or UBI device is created, users may either specify the
|
||||
* volume/device number they want to create or to let UBI automatically assign
|
||||
* the number using these constants.
|
||||
*/
|
||||
#define UBI_VOL_NUM_AUTO (-1)
|
||||
#define UBI_DEV_NUM_AUTO (-1)
|
||||
|
||||
/* Maximum volume name length */
|
||||
#define UBI_MAX_VOLUME_NAME 127
|
||||
|
||||
/* ioctl commands of UBI character devices */
|
||||
|
||||
#define UBI_IOC_MAGIC 'o'
|
||||
|
||||
/* Create an UBI volume */
|
||||
#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req)
|
||||
/* Remove an UBI volume */
|
||||
#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t)
|
||||
/* Re-size an UBI volume */
|
||||
#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req)
|
||||
/* Re-name volumes */
|
||||
#define UBI_IOCRNVOL _IOW(UBI_IOC_MAGIC, 3, struct ubi_rnvol_req)
|
||||
|
||||
/* ioctl commands of the UBI control character device */
|
||||
|
||||
#define UBI_CTRL_IOC_MAGIC 'o'
|
||||
|
||||
/* Attach an MTD device */
|
||||
#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req)
|
||||
/* Detach an MTD device */
|
||||
#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t)
|
||||
|
||||
/* ioctl commands of UBI volume character devices */
|
||||
|
||||
#define UBI_VOL_IOC_MAGIC 'O'
|
||||
|
||||
/* Start UBI volume update */
|
||||
#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)
|
||||
/* LEB erasure command, used for debugging, disabled by default */
|
||||
#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
|
||||
/* Atomic LEB change command */
|
||||
#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t)
|
||||
/* Map LEB command */
|
||||
#define UBI_IOCEBMAP _IOW(UBI_VOL_IOC_MAGIC, 3, struct ubi_map_req)
|
||||
/* Unmap LEB command */
|
||||
#define UBI_IOCEBUNMAP _IOW(UBI_VOL_IOC_MAGIC, 4, int32_t)
|
||||
/* Check if LEB is mapped command */
|
||||
#define UBI_IOCEBISMAP _IOR(UBI_VOL_IOC_MAGIC, 5, int32_t)
|
||||
/* Set an UBI volume property */
|
||||
#define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \
|
||||
struct ubi_set_vol_prop_req)
|
||||
|
||||
/* Maximum MTD device name length supported by UBI */
|
||||
#define MAX_UBI_MTD_NAME_LEN 127
|
||||
|
||||
/* Maximum amount of UBI volumes that can be re-named at one go */
|
||||
#define UBI_MAX_RNVOL 32
|
||||
|
||||
/*
|
||||
* UBI volume type constants.
|
||||
*
|
||||
* @UBI_DYNAMIC_VOLUME: dynamic volume
|
||||
* @UBI_STATIC_VOLUME: static volume
|
||||
*/
|
||||
enum {
|
||||
UBI_DYNAMIC_VOLUME = 3,
|
||||
UBI_STATIC_VOLUME = 4,
|
||||
};
|
||||
|
||||
/*
|
||||
* UBI set volume property ioctl constants.
|
||||
*
|
||||
* @UBI_VOL_PROP_DIRECT_WRITE: allow (any non-zero value) or disallow (value 0)
|
||||
* user to directly write and erase individual
|
||||
* eraseblocks on dynamic volumes
|
||||
*/
|
||||
enum {
|
||||
UBI_VOL_PROP_DIRECT_WRITE = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ubi_attach_req - attach MTD device request.
|
||||
* @ubi_num: UBI device number to create
|
||||
* @mtd_num: MTD device number to attach
|
||||
* @vid_hdr_offset: VID header offset (use defaults if %0)
|
||||
* @max_beb_per1024: maximum expected number of bad PEB per 1024 PEBs
|
||||
* @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.
|
||||
*
|
||||
* The @max_beb_per1024 is the maximum amount of bad PEBs UBI expects on the
|
||||
* UBI device per 1024 eraseblocks. This value is often given in an other form
|
||||
* in the NAND datasheet (min NVB i.e. minimal number of valid blocks). The
|
||||
* maximum expected bad eraseblocks per 1024 is then:
|
||||
* 1024 * (1 - MinNVB / MaxNVB)
|
||||
* Which gives 20 for most NAND devices. This limit is used in order to derive
|
||||
* amount of eraseblock UBI reserves for handling new bad blocks. If the device
|
||||
* has more bad eraseblocks than this limit, UBI does not reserve any physical
|
||||
* eraseblocks for new bad eraseblocks, but attempts to use available
|
||||
* eraseblocks (if any). The accepted range is 0-768. If 0 is given, the
|
||||
* default kernel value of %CONFIG_MTD_UBI_BEB_LIMIT will be used.
|
||||
*/
|
||||
struct ubi_attach_req {
|
||||
int32_t ubi_num;
|
||||
int32_t mtd_num;
|
||||
int32_t vid_hdr_offset;
|
||||
int16_t max_beb_per1024;
|
||||
int8_t padding[10];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ubi_mkvol_req - volume description data structure used in
|
||||
* volume creation requests.
|
||||
* @vol_id: volume number
|
||||
* @alignment: volume alignment
|
||||
* @bytes: volume size in bytes
|
||||
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
|
||||
* @padding1: reserved for future, not used, has to be zeroed
|
||||
* @name_len: volume name length
|
||||
* @padding2: reserved for future, not used, has to be zeroed
|
||||
* @name: volume name
|
||||
*
|
||||
* This structure is used by user-space programs when creating new volumes. The
|
||||
* @used_bytes field is only necessary when creating static volumes.
|
||||
*
|
||||
* The @alignment field specifies the required alignment of the volume logical
|
||||
* eraseblock. This means, that the size of logical eraseblocks will be aligned
|
||||
* to this number, i.e.,
|
||||
* (UBI device logical eraseblock size) mod (@alignment) = 0.
|
||||
*
|
||||
* To put it differently, the logical eraseblock of this volume may be slightly
|
||||
* shortened in order to make it properly aligned. The alignment has to be
|
||||
* multiple of the flash minimal input/output unit, or %1 to utilize the entire
|
||||
* available space of logical eraseblocks.
|
||||
*
|
||||
* The @alignment field may be useful, for example, when one wants to maintain
|
||||
* a block device on top of an UBI volume. In this case, it is desirable to fit
|
||||
* an integer number of blocks in logical eraseblocks of this UBI volume. With
|
||||
* alignment it is possible to update this volume using plane UBI volume image
|
||||
* BLOBs, without caring about how to properly align them.
|
||||
*/
|
||||
struct ubi_mkvol_req {
|
||||
int32_t vol_id;
|
||||
int32_t alignment;
|
||||
int64_t bytes;
|
||||
int8_t vol_type;
|
||||
int8_t padding1;
|
||||
int16_t name_len;
|
||||
int8_t padding2[4];
|
||||
char name[UBI_MAX_VOLUME_NAME + 1];
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* struct ubi_rsvol_req - a data structure used in volume re-size requests.
|
||||
* @vol_id: ID of the volume to re-size
|
||||
* @bytes: new size of the volume in bytes
|
||||
*
|
||||
* Re-sizing is possible for both dynamic and static volumes. But while dynamic
|
||||
* volumes may be re-sized arbitrarily, static volumes cannot be made to be
|
||||
* smaller than the number of bytes they bear. To arbitrarily shrink a static
|
||||
* volume, it must be wiped out first (by means of volume update operation with
|
||||
* zero number of bytes).
|
||||
*/
|
||||
struct ubi_rsvol_req {
|
||||
int64_t bytes;
|
||||
int32_t vol_id;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* struct ubi_rnvol_req - volumes re-name request.
|
||||
* @count: count of volumes to re-name
|
||||
* @padding1: reserved for future, not used, has to be zeroed
|
||||
* @vol_id: ID of the volume to re-name
|
||||
* @name_len: name length
|
||||
* @padding2: reserved for future, not used, has to be zeroed
|
||||
* @name: new volume name
|
||||
*
|
||||
* UBI allows to re-name up to %32 volumes at one go. The count of volumes to
|
||||
* re-name is specified in the @count field. The ID of the volumes to re-name
|
||||
* and the new names are specified in the @vol_id and @name fields.
|
||||
*
|
||||
* The UBI volume re-name operation is atomic, which means that should power cut
|
||||
* happen, the volumes will have either old name or new name. So the possible
|
||||
* use-cases of this command is atomic upgrade. Indeed, to upgrade, say, volumes
|
||||
* A and B one may create temporary volumes %A1 and %B1 with the new contents,
|
||||
* then atomically re-name A1->A and B1->B, in which case old %A and %B will
|
||||
* be removed.
|
||||
*
|
||||
* If it is not desirable to remove old A and B, the re-name request has to
|
||||
* contain 4 entries: A1->A, A->A1, B1->B, B->B1, in which case old A1 and B1
|
||||
* become A and B, and old A and B will become A1 and B1.
|
||||
*
|
||||
* It is also OK to request: A1->A, A1->X, B1->B, B->Y, in which case old A1
|
||||
* and B1 become A and B, and old A and B become X and Y.
|
||||
*
|
||||
* In other words, in case of re-naming into an existing volume name, the
|
||||
* existing volume is removed, unless it is re-named as well at the same
|
||||
* re-name request.
|
||||
*/
|
||||
struct ubi_rnvol_req {
|
||||
int32_t count;
|
||||
int8_t padding1[12];
|
||||
struct {
|
||||
int32_t vol_id;
|
||||
int16_t name_len;
|
||||
int8_t padding2[2];
|
||||
char name[UBI_MAX_VOLUME_NAME + 1];
|
||||
} ents[UBI_MAX_RNVOL];
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* struct ubi_leb_change_req - a data structure used in atomic LEB change
|
||||
* requests.
|
||||
* @lnum: logical eraseblock number to change
|
||||
* @bytes: how many bytes will be written to the logical eraseblock
|
||||
* @dtype: pass "3" for better compatibility with old kernels
|
||||
* @padding: reserved for future, not used, has to be zeroed
|
||||
*
|
||||
* The @dtype field used to inform UBI about what kind of data will be written
|
||||
* to the LEB: long term (value 1), short term (value 2), unknown (value 3).
|
||||
* UBI tried to pick a PEB with lower erase counter for short term data and a
|
||||
* PEB with higher erase counter for long term data. But this was not really
|
||||
* used because users usually do not know this and could easily mislead UBI. We
|
||||
* removed this feature in May 2012. UBI currently just ignores the @dtype
|
||||
* field. But for better compatibility with older kernels it is recommended to
|
||||
* set @dtype to 3 (unknown).
|
||||
*/
|
||||
struct ubi_leb_change_req {
|
||||
int32_t lnum;
|
||||
int32_t bytes;
|
||||
int8_t dtype; /* obsolete, do not use! */
|
||||
int8_t padding[7];
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* struct ubi_map_req - a data structure used in map LEB requests.
|
||||
* @dtype: pass "3" for better compatibility with old kernels
|
||||
* @lnum: logical eraseblock number to unmap
|
||||
* @padding: reserved for future, not used, has to be zeroed
|
||||
*/
|
||||
struct ubi_map_req {
|
||||
int32_t lnum;
|
||||
int8_t dtype; /* obsolete, do not use! */
|
||||
int8_t padding[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/**
|
||||
* struct ubi_set_vol_prop_req - a data structure used to set an UBI volume
|
||||
* property.
|
||||
* @property: property to set (%UBI_VOL_PROP_DIRECT_WRITE)
|
||||
* @padding: reserved for future, not used, has to be zeroed
|
||||
* @value: value to set
|
||||
*/
|
||||
struct ubi_set_vol_prop_req {
|
||||
uint8_t property;
|
||||
uint8_t padding[7];
|
||||
uint64_t value;
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif /* __UBI_USER_H__ */
|
51
src/system/mtdutils/include/mtd_swab.h
Normal file
51
src/system/mtdutils/include/mtd_swab.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef MTD_SWAB_H
|
||||
#define MTD_SWAB_H
|
||||
|
||||
#include <endian.h>
|
||||
|
||||
#define swab16(x) \
|
||||
((uint16_t)( \
|
||||
(((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
|
||||
(((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
|
||||
#define swab32(x) \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
|
||||
(((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
|
||||
(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
||||
(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
|
||||
|
||||
#define swab64(x) \
|
||||
((uint64_t)( \
|
||||
(((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \
|
||||
(((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
|
||||
(((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
|
||||
(((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
|
||||
(((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
|
||||
(((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
|
||||
(((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
|
||||
(((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) ))
|
||||
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define cpu_to_le16(x) ({ uint16_t _x = x; swab16(_x); })
|
||||
#define cpu_to_le32(x) ({ uint32_t _x = x; swab32(_x); })
|
||||
#define cpu_to_le64(x) ({ uint64_t _x = x; swab64(_x); })
|
||||
#define cpu_to_be16(x) (x)
|
||||
#define cpu_to_be32(x) (x)
|
||||
#define cpu_to_be64(x) (x)
|
||||
#else
|
||||
#define cpu_to_le16(x) (x)
|
||||
#define cpu_to_le32(x) (x)
|
||||
#define cpu_to_le64(x) (x)
|
||||
#define cpu_to_be16(x) ({ uint16_t _x = x; swab16(_x); })
|
||||
#define cpu_to_be32(x) ({ uint32_t _x = x; swab32(_x); })
|
||||
#define cpu_to_be64(x) ({ uint64_t _x = x; swab64(_x); })
|
||||
#endif
|
||||
#define le16_to_cpu(x) cpu_to_le16(x)
|
||||
#define be16_to_cpu(x) cpu_to_be16(x)
|
||||
#define le32_to_cpu(x) cpu_to_le32(x)
|
||||
#define be32_to_cpu(x) cpu_to_be32(x)
|
||||
#define le64_to_cpu(x) cpu_to_le64(x)
|
||||
#define be64_to_cpu(x) cpu_to_be64(x)
|
||||
|
||||
#endif
|
106
src/system/mtdutils/include/xalloc.h
Normal file
106
src/system/mtdutils/include/xalloc.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* memory wrappers
|
||||
*
|
||||
* Copyright (c) Artem Bityutskiy, 2007, 2008
|
||||
* Copyright 2001, 2002 Red Hat, Inc.
|
||||
* 2001 David A. Schleef <ds@lineo.com>
|
||||
* 2002 Axis Communications AB
|
||||
* 2001, 2002 Erik Andersen <andersen@codepoet.org>
|
||||
* 2004 University of Szeged, Hungary
|
||||
* 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_UTILS_XALLOC_H__
|
||||
#define __MTD_UTILS_XALLOC_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Mark these functions as unused so that gcc does not emit warnings
|
||||
* when people include this header but don't use every function.
|
||||
*/
|
||||
|
||||
__attribute__((unused))
|
||||
static void *xmalloc(size_t size)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
|
||||
if (ptr == NULL && size != 0)
|
||||
sys_errmsg("out of memory");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
__attribute__((unused))
|
||||
static void *xcalloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *ptr = calloc(nmemb, size);
|
||||
|
||||
if (ptr == NULL && nmemb != 0 && size != 0)
|
||||
sys_errmsg("out of memory");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
__attribute__((unused))
|
||||
static void *xzalloc(size_t size)
|
||||
{
|
||||
return xcalloc(1, size);
|
||||
}
|
||||
|
||||
__attribute__((unused))
|
||||
static void *xrealloc(void *ptr, size_t size)
|
||||
{
|
||||
ptr = realloc(ptr, size);
|
||||
if (ptr == NULL && size != 0)
|
||||
sys_errmsg("out of memory");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
__attribute__((unused))
|
||||
static char *xstrdup(const char *s)
|
||||
{
|
||||
char *t;
|
||||
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
t = strdup(s);
|
||||
if (t == NULL)
|
||||
sys_errmsg("out of memory");
|
||||
return t;
|
||||
}
|
||||
|
||||
#ifdef _GNU_SOURCE
|
||||
|
||||
__attribute__((unused))
|
||||
static int xasprintf(char **strp, const char *fmt, ...)
|
||||
{
|
||||
int cnt;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
cnt = vasprintf(strp, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (cnt == -1)
|
||||
sys_errmsg("out of memory");
|
||||
|
||||
return cnt;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !__MTD_UTILS_XALLOC_H__ */
|
104
src/system/mtdutils/lib/libcrc32.cpp
Normal file
104
src/system/mtdutils/lib/libcrc32.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
static 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
|
||||
};
|
||||
|
||||
uint32_t mtd_crc32(uint32_t val, const void *ss, int len)
|
||||
{
|
||||
const unsigned char *s = (unsigned char *)ss;
|
||||
|
||||
while (--len >= 0)
|
||||
val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
|
||||
return val;
|
||||
}
|
903
src/system/mtdutils/lib/libfec.cpp
Normal file
903
src/system/mtdutils/lib/libfec.cpp
Normal file
@@ -0,0 +1,903 @@
|
||||
/*
|
||||
* fec.c -- forward error correction based on Vandermonde matrices
|
||||
* 980624
|
||||
* (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
|
||||
*
|
||||
* Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
|
||||
* Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
|
||||
* Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following parameter defines how many bits are used for
|
||||
* field elements. The code supports any value from 2 to 16
|
||||
* but fastest operation is achieved with 8 bit elements
|
||||
* This is the only parameter you may want to change.
|
||||
*/
|
||||
#ifndef GF_BITS
|
||||
#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* stuff used for testing purposes only
|
||||
*/
|
||||
|
||||
#ifdef TEST
|
||||
#define DEB(x)
|
||||
#define DDB(x) x
|
||||
#define DEBUG 0 /* minimal debugging */
|
||||
#ifdef MSDOS
|
||||
#include <time.h>
|
||||
struct timeval {
|
||||
unsigned long ticks;
|
||||
};
|
||||
#define gettimeofday(x, dummy) { (x)->ticks = clock() ; }
|
||||
#define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC )
|
||||
typedef unsigned long u_long ;
|
||||
typedef unsigned short u_short ;
|
||||
#else /* typically, unix systems */
|
||||
#include <sys/time.h>
|
||||
#define DIFF_T(a,b) \
|
||||
(1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) )
|
||||
#endif
|
||||
|
||||
#define TICK(t) \
|
||||
{struct timeval x ; \
|
||||
gettimeofday(&x, NULL) ; \
|
||||
t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \
|
||||
}
|
||||
#define TOCK(t) \
|
||||
{ u_long t1 ; TICK(t1) ; \
|
||||
if (t1 < t) t = 256000000 + t1 - t ; \
|
||||
else t = t1 - t ; \
|
||||
if (t == 0) t = 1 ;}
|
||||
|
||||
u_long ticks[10]; /* vars for timekeeping */
|
||||
#else
|
||||
#define DEB(x)
|
||||
#define DDB(x)
|
||||
#define TICK(x)
|
||||
#define TOCK(x)
|
||||
#endif /* TEST */
|
||||
|
||||
/*
|
||||
* You should not need to change anything beyond this point.
|
||||
* The first part of the file implements linear algebra in GF.
|
||||
*
|
||||
* gf is the type used to store an element of the Galois Field.
|
||||
* Must constain at least GF_BITS bits.
|
||||
*
|
||||
* Note: unsigned char will work up to GF(256) but int seems to run
|
||||
* faster on the Pentium. We use int whenever have to deal with an
|
||||
* index, since they are generally faster.
|
||||
*/
|
||||
#if (GF_BITS < 2 && GF_BITS >16)
|
||||
#error "GF_BITS must be 2 .. 16"
|
||||
#endif
|
||||
#if (GF_BITS <= 8)
|
||||
typedef unsigned char gf;
|
||||
#else
|
||||
typedef unsigned short gf;
|
||||
#endif
|
||||
|
||||
#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
|
||||
|
||||
/*
|
||||
* Primitive polynomials - see Lin & Costello, Appendix A,
|
||||
* and Lee & Messerschmitt, p. 453.
|
||||
*/
|
||||
static const 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(void)
|
||||
{
|
||||
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, const 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;
|
||||
const 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 = (int*)my_malloc(k*sizeof(int), "indxc");
|
||||
int *indxr = (int*)my_malloc(k*sizeof(int), "indxr");
|
||||
int *ipiv = (int*)my_malloc(k*sizeof(int), "ipiv");
|
||||
gf *id_row = NEW_GF_MATRIX(1, k);
|
||||
gf *temp_row = NEW_GF_MATRIX(1, k);
|
||||
|
||||
memset(id_row, '\0', k*sizeof(gf));
|
||||
DEB( pivloops=0; pivswaps=0 ; /* diagnostic */ )
|
||||
/*
|
||||
* ipiv marks elements already used as pivots.
|
||||
*/
|
||||
for (i = 0; i < k ; i++)
|
||||
ipiv[i] = 0 ;
|
||||
|
||||
for (col = 0; col < k ; col++) {
|
||||
gf *pivot_row ;
|
||||
/*
|
||||
* Zeroing column 'col', look for a non-zero element.
|
||||
* First try on the diagonal, if it fails, look elsewhere.
|
||||
*/
|
||||
irow = icol = -1 ;
|
||||
if (ipiv[col] != 1 && src[col*k + col] != 0) {
|
||||
irow = col ;
|
||||
icol = col ;
|
||||
goto found_piv ;
|
||||
}
|
||||
for (row = 0 ; row < k ; row++) {
|
||||
if (ipiv[row] != 1) {
|
||||
for (ix = 0 ; ix < k ; ix++) {
|
||||
DEB( pivloops++ ; )
|
||||
if (ipiv[ix] == 0) {
|
||||
if (src[row*k + ix] != 0) {
|
||||
irow = row ;
|
||||
icol = ix ;
|
||||
goto found_piv ;
|
||||
}
|
||||
} else if (ipiv[ix] > 1) {
|
||||
fprintf(stderr, "singular matrix\n");
|
||||
goto fail ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (icol == -1) {
|
||||
fprintf(stderr, "XXX pivot not found!\n");
|
||||
goto fail ;
|
||||
}
|
||||
found_piv:
|
||||
++(ipiv[icol]) ;
|
||||
/*
|
||||
* swap rows irow and icol, so afterwards the diagonal
|
||||
* element will be correct. Rarely done, not worth
|
||||
* optimizing.
|
||||
*/
|
||||
if (irow != icol) {
|
||||
for (ix = 0 ; ix < k ; ix++ ) {
|
||||
SWAP( src[irow*k + ix], src[icol*k + ix], gf) ;
|
||||
}
|
||||
}
|
||||
indxr[col] = irow ;
|
||||
indxc[col] = icol ;
|
||||
pivot_row = &src[icol*k] ;
|
||||
c = pivot_row[icol] ;
|
||||
if (c == 0) {
|
||||
fprintf(stderr, "singular matrix 2\n");
|
||||
goto fail ;
|
||||
}
|
||||
if (c != 1 ) { /* otherwhise this is a NOP */
|
||||
/*
|
||||
* this is done often , but optimizing is not so
|
||||
* fruitful, at least in the obvious ways (unrolling)
|
||||
*/
|
||||
DEB( pivswaps++ ; )
|
||||
c = inverse[ c ] ;
|
||||
pivot_row[icol] = 1 ;
|
||||
for (ix = 0 ; ix < k ; ix++ )
|
||||
pivot_row[ix] = gf_mul(c, pivot_row[ix] );
|
||||
}
|
||||
/*
|
||||
* from all rows, remove multiples of the selected row
|
||||
* to zero the relevant entry (in fact, the entry is not zero
|
||||
* because we know it must be zero).
|
||||
* (Here, if we know that the pivot_row is the identity,
|
||||
* we can optimize the addmul).
|
||||
*/
|
||||
id_row[icol] = 1;
|
||||
if (memcmp(pivot_row, id_row, k*sizeof(gf)) != 0) {
|
||||
for (p = src, ix = 0 ; ix < k ; ix++, p += k ) {
|
||||
if (ix != icol) {
|
||||
c = p[icol] ;
|
||||
p[icol] = 0 ;
|
||||
addmul(p, pivot_row, c, k );
|
||||
}
|
||||
}
|
||||
}
|
||||
id_row[icol] = 0;
|
||||
} /* done all columns */
|
||||
for (col = k-1 ; col >= 0 ; col-- ) {
|
||||
if (indxr[col] <0 || indxr[col] >= k)
|
||||
fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]);
|
||||
else if (indxc[col] <0 || indxc[col] >= k)
|
||||
fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]);
|
||||
else
|
||||
if (indxr[col] != indxc[col] ) {
|
||||
for (row = 0 ; row < k ; row++ ) {
|
||||
SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
error = 0 ;
|
||||
fail:
|
||||
free(indxc);
|
||||
free(indxr);
|
||||
free(ipiv);
|
||||
free(id_row);
|
||||
free(temp_row);
|
||||
return error ;
|
||||
}
|
||||
|
||||
/*
|
||||
* fast code for inverting a vandermonde matrix.
|
||||
* XXX NOTE: It assumes that the matrix
|
||||
* is not singular and _IS_ a vandermonde matrix. Only uses
|
||||
* the second column of the matrix, containing the p_i's.
|
||||
*
|
||||
* Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but
|
||||
* largely revised for my purposes.
|
||||
* p = coefficients of the matrix (p_i)
|
||||
* q = values of the polynomial (known)
|
||||
*/
|
||||
|
||||
int
|
||||
invert_vdm(gf *src, int k)
|
||||
{
|
||||
int i, j, row, col ;
|
||||
gf *b, *c, *p;
|
||||
gf t, xx ;
|
||||
|
||||
if (k == 1) /* degenerate case, matrix must be p^0 = 1 */
|
||||
return 0 ;
|
||||
/*
|
||||
* c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1
|
||||
* b holds the coefficient for the matrix inversion
|
||||
*/
|
||||
c = NEW_GF_MATRIX(1, k);
|
||||
b = NEW_GF_MATRIX(1, k);
|
||||
|
||||
p = NEW_GF_MATRIX(1, k);
|
||||
|
||||
for ( j=1, i = 0 ; i < k ; i++, j+=k ) {
|
||||
c[i] = 0 ;
|
||||
p[i] = src[j] ; /* p[i] */
|
||||
}
|
||||
/*
|
||||
* construct coeffs. recursively. We know c[k] = 1 (implicit)
|
||||
* and start P_0 = x - p_0, then at each stage multiply by
|
||||
* x - p_i generating P_i = x P_{i-1} - p_i P_{i-1}
|
||||
* After k steps we are done.
|
||||
*/
|
||||
c[k-1] = p[0] ; /* really -p(0), but x = -x in GF(2^m) */
|
||||
for (i = 1 ; i < k ; i++ ) {
|
||||
gf p_i = p[i] ; /* see above comment */
|
||||
for (j = k-1 - ( i - 1 ) ; j < k-1 ; j++ )
|
||||
c[j] ^= gf_mul( p_i, c[j+1] ) ;
|
||||
c[k-1] ^= p_i ;
|
||||
}
|
||||
|
||||
for (row = 0 ; row < k ; row++ ) {
|
||||
/*
|
||||
* synthetic division etc.
|
||||
*/
|
||||
xx = p[row] ;
|
||||
t = 1 ;
|
||||
b[k-1] = 1 ; /* this is in fact c[k] */
|
||||
for (i = k-2 ; i >= 0 ; i-- ) {
|
||||
b[i] = c[i+1] ^ gf_mul(xx, b[i+1]) ;
|
||||
t = gf_mul(xx, t) ^ b[i] ;
|
||||
}
|
||||
for (col = 0 ; col < k ; col++ )
|
||||
src[col*k + row] = gf_mul(inverse[t], b[col] );
|
||||
}
|
||||
free(c) ;
|
||||
free(b) ;
|
||||
free(p) ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
static int fec_initialized = 0 ;
|
||||
static void
|
||||
init_fec(void)
|
||||
{
|
||||
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 ;
|
||||
} ;
|
||||
#define COMP_FEC_MAGIC(fec) \
|
||||
(((FEC_MAGIC ^ (fec)->k) ^ (fec)->n) ^ (unsigned long)((fec)->enc_matrix))
|
||||
|
||||
void
|
||||
fec_free(struct fec_parms *p)
|
||||
{
|
||||
if (p==NULL || p->magic != COMP_FEC_MAGIC(p)) {
|
||||
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 = reinterpret_cast<fec_parms*>(my_malloc(sizeof(struct fec_parms), "new_code"));
|
||||
retval->k = k ;
|
||||
retval->n = n ;
|
||||
retval->enc_matrix = NEW_GF_MATRIX(n, k);
|
||||
retval->magic = COMP_FEC_MAGIC(retval);
|
||||
tmp_m = NEW_GF_MATRIX(n, k);
|
||||
/*
|
||||
* fill the matrix with powers of field elements, starting from 0.
|
||||
* The first row is special, cannot be computed with exp. table.
|
||||
*/
|
||||
tmp_m[0] = 1 ;
|
||||
for (col = 1; col < k ; col++)
|
||||
tmp_m[col] = 0 ;
|
||||
for (p = tmp_m + k, row = 0; row < n-1 ; row++, p += k) {
|
||||
for ( col = 0 ; col < k ; col ++ )
|
||||
p[col] = gf_exp[modnn(row*col)];
|
||||
}
|
||||
|
||||
/*
|
||||
* quick code to build systematic matrix: invert the top
|
||||
* k*k vandermonde matrix, multiply right the bottom n-k rows
|
||||
* by the inverse, and construct the identity matrix at the top.
|
||||
*/
|
||||
TICK(ticks[3]);
|
||||
invert_vdm(tmp_m, k); /* much faster than invert_mat */
|
||||
matmul(tmp_m + k*k, tmp_m, retval->enc_matrix + k*k, n - k, k, k);
|
||||
/*
|
||||
* the upper matrix is I so do not bother with a slow multiply
|
||||
*/
|
||||
memset(retval->enc_matrix, '\0', k*k*sizeof(gf) );
|
||||
for (p = retval->enc_matrix, col = 0 ; col < k ; col++, p += k+1 )
|
||||
*p = 1 ;
|
||||
free(tmp_m);
|
||||
TOCK(ticks[3]);
|
||||
|
||||
DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n",
|
||||
ticks[3]);)
|
||||
DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");)
|
||||
return retval ;
|
||||
}
|
||||
|
||||
/*
|
||||
* fec_encode accepts as input pointers to n data packets of size sz,
|
||||
* and produces as output a packet pointed to by fec, computed
|
||||
* with index "index".
|
||||
*/
|
||||
void
|
||||
fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz)
|
||||
{
|
||||
int k = code->k ;
|
||||
|
||||
if (GF_BITS > 8)
|
||||
sz /= 2 ;
|
||||
|
||||
if (index < k)
|
||||
memcpy(fec, src[index], sz*sizeof(gf) ) ;
|
||||
else if (index < code->n) {
|
||||
gf* p = &(code->enc_matrix[index*k] );
|
||||
memset(fec, '\0', sz*sizeof(gf));
|
||||
for (int 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 k = code->k ;
|
||||
|
||||
if (GF_BITS > 8)
|
||||
sz /= 2 ;
|
||||
|
||||
if (index < k)
|
||||
memcpy(fec, src + (index * sz), sz*sizeof(gf) ) ;
|
||||
else if (index < code->n) {
|
||||
gf* p = &(code->enc_matrix[index*k] );
|
||||
memset(fec, '\0', sz*sizeof(gf));
|
||||
for (int 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, int index[])
|
||||
{
|
||||
int i , k = code->k ;
|
||||
gf *p, *matrix = NEW_GF_MATRIX(k, k);
|
||||
|
||||
TICK(ticks[9]);
|
||||
for (i = 0, p = matrix ; i < k ; i++, p += k ) {
|
||||
#if 1 /* this is simply an optimization, not very useful indeed */
|
||||
if (index[i] < k) {
|
||||
memset(p, '\0', k*sizeof(gf) );
|
||||
p[i] = 1 ;
|
||||
} else
|
||||
#endif
|
||||
if (index[i] < code->n )
|
||||
memcpy(p, &(code->enc_matrix[index[i]*k]), k*sizeof(gf) );
|
||||
else {
|
||||
fprintf(stderr, "decode: invalid index %d (max %d)\n",
|
||||
index[i], code->n - 1 );
|
||||
free(matrix) ;
|
||||
return NULL ;
|
||||
}
|
||||
}
|
||||
TICK(ticks[9]);
|
||||
if (invert_mat(matrix, k)) {
|
||||
free(matrix);
|
||||
matrix = NULL ;
|
||||
}
|
||||
TOCK(ticks[9]);
|
||||
return matrix ;
|
||||
}
|
||||
|
||||
/*
|
||||
* fec_decode receives as input a vector of packets, the indexes of
|
||||
* packets, and produces the correct vector as output.
|
||||
*
|
||||
* Input:
|
||||
* code: pointer to code descriptor
|
||||
* pkt: pointers to received packets. They are modified
|
||||
* to store the output packets (in place)
|
||||
* index: pointer to packet indexes (modified)
|
||||
* sz: size of each packet
|
||||
*/
|
||||
int
|
||||
fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz)
|
||||
{
|
||||
gf *m_dec ;
|
||||
gf **new_pkt ;
|
||||
int row, col , k = code->k ;
|
||||
|
||||
if (GF_BITS > 8)
|
||||
sz /= 2 ;
|
||||
|
||||
if (shuffle(pkt, index, k)) /* error if true */
|
||||
return 1 ;
|
||||
m_dec = build_decode_matrix(code, index);
|
||||
|
||||
if (m_dec == NULL)
|
||||
return 1 ; /* error */
|
||||
/*
|
||||
* do the actual decoding
|
||||
*/
|
||||
new_pkt = (gf**)my_malloc (k * sizeof (gf * ), "new pkt pointers" );
|
||||
for (row = 0 ; row < k ; row++ ) {
|
||||
if (index[row] >= k) {
|
||||
new_pkt[row] = (gf*)my_malloc (sz * sizeof (gf), "new pkt buffer" );
|
||||
memset(new_pkt[row], '\0', sz * sizeof(gf) ) ;
|
||||
for (col = 0 ; col < k ; col++ )
|
||||
addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz) ;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* move pkts to their final destination
|
||||
*/
|
||||
for (row = 0 ; row < k ; row++ ) {
|
||||
if (index[row] >= k) {
|
||||
memcpy(pkt[row], new_pkt[row], sz*sizeof(gf));
|
||||
free(new_pkt[row]);
|
||||
}
|
||||
}
|
||||
free(new_pkt);
|
||||
free(m_dec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********** end of FEC code -- beginning of test code ************/
|
||||
|
||||
#if (TEST || DEBUG)
|
||||
void
|
||||
test_gf(void)
|
||||
{
|
||||
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 */
|
1419
src/system/mtdutils/lib/libmtd.cpp
Normal file
1419
src/system/mtdutils/lib/libmtd.cpp
Normal file
File diff suppressed because it is too large
Load Diff
107
src/system/mtdutils/lib/libmtd_int.h
Normal file
107
src/system/mtdutils/lib/libmtd_int.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) International Business Machines Corp., 2006
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Author: Artem Bityutskiy
|
||||
*
|
||||
* MTD library.
|
||||
*/
|
||||
|
||||
#ifndef __LIBMTD_INT_H__
|
||||
#define __LIBMTD_INT_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PROGRAM_NAME "libmtd"
|
||||
|
||||
#define SYSFS_MTD "class/mtd"
|
||||
#define MTD_NAME_PATT "mtd%d"
|
||||
#define MTD_DEV "dev"
|
||||
#define MTD_NAME "name"
|
||||
#define MTD_TYPE "type"
|
||||
#define MTD_EB_SIZE "erasesize"
|
||||
#define MTD_SIZE "size"
|
||||
#define MTD_MIN_IO_SIZE "writesize"
|
||||
#define MTD_SUBPAGE_SIZE "subpagesize"
|
||||
#define MTD_OOB_SIZE "oobsize"
|
||||
#define MTD_REGION_CNT "numeraseregions"
|
||||
#define MTD_FLAGS "flags"
|
||||
|
||||
#define OFFS64_IOCTLS_UNKNOWN 0
|
||||
#define OFFS64_IOCTLS_NOT_SUPPORTED 1
|
||||
#define OFFS64_IOCTLS_SUPPORTED 2
|
||||
|
||||
/**
|
||||
* libmtd - MTD library description data structure.
|
||||
* @sysfs_mtd: MTD directory in sysfs
|
||||
* @mtd: MTD device sysfs directory pattern
|
||||
* @mtd_dev: MTD device major/minor numbers file pattern
|
||||
* @mtd_name: MTD device name file pattern
|
||||
* @mtd_type: MTD device type file pattern
|
||||
* @mtd_eb_size: MTD device eraseblock size file pattern
|
||||
* @mtd_size: MTD device size file pattern
|
||||
* @mtd_min_io_size: minimum I/O unit size file pattern
|
||||
* @mtd_subpage_size: sub-page size file pattern
|
||||
* @mtd_oob_size: MTD device OOB size file pattern
|
||||
* @mtd_region_cnt: count of additional erase regions file pattern
|
||||
* @mtd_flags: MTD device flags file pattern
|
||||
* @sysfs_supported: non-zero if sysfs is supported by MTD
|
||||
* @offs64_ioctls: %OFFS64_IOCTLS_SUPPORTED if 64-bit %MEMERASE64,
|
||||
* %MEMREADOOB64, %MEMWRITEOOB64 MTD device ioctls are
|
||||
* supported, %OFFS64_IOCTLS_NOT_SUPPORTED if not, and
|
||||
* %OFFS64_IOCTLS_UNKNOWN if it is not known yet;
|
||||
*
|
||||
* Note, we cannot find out whether 64-bit ioctls are supported by MTD when we
|
||||
* are initializing the library, because this requires an MTD device node.
|
||||
* Indeed, we have to actually call the ioctl and check for %ENOTTY to find
|
||||
* out whether it is supported or not.
|
||||
*
|
||||
* Thus, we leave %offs64_ioctls uninitialized in 'libmtd_open()', and
|
||||
* initialize it later, when corresponding libmtd function is used, and when
|
||||
* we actually have a device node and can invoke an ioctl command on it.
|
||||
*/
|
||||
struct libmtd
|
||||
{
|
||||
char *sysfs_mtd;
|
||||
char *mtd;
|
||||
char *mtd_dev;
|
||||
char *mtd_name;
|
||||
char *mtd_type;
|
||||
char *mtd_eb_size;
|
||||
char *mtd_size;
|
||||
char *mtd_min_io_size;
|
||||
char *mtd_subpage_size;
|
||||
char *mtd_oob_size;
|
||||
char *mtd_region_cnt;
|
||||
char *mtd_flags;
|
||||
unsigned int sysfs_supported:1;
|
||||
unsigned int offs64_ioctls:2;
|
||||
};
|
||||
|
||||
int legacy_libmtd_open(void);
|
||||
int legacy_dev_present(int mtd_num);
|
||||
int legacy_mtd_get_info(struct mtd_info *info);
|
||||
int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd);
|
||||
int legacy_get_dev_info1(int dev_num, struct mtd_dev_info *mtd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !__LIBMTD_INT_H__ */
|
379
src/system/mtdutils/lib/libmtd_legacy.cpp
Normal file
379
src/system/mtdutils/lib/libmtd_legacy.cpp
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Author: Artem Bityutskiy
|
||||
*
|
||||
* This file is part of the MTD library. Implements pre-2.6.30 kernels support,
|
||||
* where MTD did not have sysfs interface. The main limitation of the old
|
||||
* kernels was that the sub-page size was not exported to user-space, so it was
|
||||
* not possible to get sub-page size.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <mtd/mtd-user.h>
|
||||
|
||||
#include <libmtd.h>
|
||||
#include "libmtd_int.h"
|
||||
#include "common.h"
|
||||
|
||||
#define MTD_PROC_FILE "/proc/mtd"
|
||||
#define MTD_DEV_PATT "/dev/mtd%d"
|
||||
#define MTD_DEV_MAJOR 90
|
||||
|
||||
#define PROC_MTD_FIRST "dev: size erasesize name\n"
|
||||
#define PROC_MTD_FIRST_LEN (sizeof(PROC_MTD_FIRST) - 1)
|
||||
#define PROC_MTD_MAX_LEN 4096
|
||||
#define PROC_MTD_PATT "mtd%d: %llx %x"
|
||||
|
||||
/**
|
||||
* struct proc_parse_info - /proc/mtd parsing information.
|
||||
* @mtd_num: MTD device number
|
||||
* @size: device size
|
||||
* @eb_size: eraseblock size
|
||||
* @name: device name
|
||||
* @buf: contents of /proc/mtd
|
||||
* @data_size: how much data was read into @buf
|
||||
* @pos: next string in @buf to parse
|
||||
*/
|
||||
struct proc_parse_info
|
||||
{
|
||||
int mtd_num;
|
||||
long long size;
|
||||
char name[MTD_NAME_MAX + 1];
|
||||
int eb_size;
|
||||
char *buf;
|
||||
int data_size;
|
||||
char *next;
|
||||
};
|
||||
|
||||
static int proc_parse_start(struct proc_parse_info *pi)
|
||||
{
|
||||
int fd, ret;
|
||||
|
||||
fd = open(MTD_PROC_FILE, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
pi->buf = (char*)xmalloc(PROC_MTD_MAX_LEN);
|
||||
|
||||
ret = read(fd, pi->buf, PROC_MTD_MAX_LEN);
|
||||
if (ret == -1) {
|
||||
sys_errmsg("cannot read \"%s\"", MTD_PROC_FILE);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (ret < (int)PROC_MTD_FIRST_LEN ||
|
||||
memcmp(pi->buf, PROC_MTD_FIRST, PROC_MTD_FIRST_LEN)) {
|
||||
errmsg("\"%s\" does not start with \"%s\"", MTD_PROC_FILE,
|
||||
PROC_MTD_FIRST);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
pi->data_size = ret;
|
||||
pi->next = pi->buf + PROC_MTD_FIRST_LEN;
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
free(pi->buf);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int proc_parse_next(struct proc_parse_info *pi)
|
||||
{
|
||||
int ret, len, pos = pi->next - pi->buf;
|
||||
char *p, *p1;
|
||||
|
||||
if (pos >= pi->data_size) {
|
||||
free(pi->buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = sscanf(pi->next, PROC_MTD_PATT, &pi->mtd_num, &pi->size,
|
||||
&pi->eb_size);
|
||||
if (ret != 3)
|
||||
return errmsg("\"%s\" pattern not found", PROC_MTD_PATT);
|
||||
|
||||
p = (char*)memchr(pi->next, '\"', pi->data_size - pos);
|
||||
if (!p)
|
||||
return errmsg("opening \" not found");
|
||||
p += 1;
|
||||
pos = p - pi->buf;
|
||||
if (pos >= pi->data_size)
|
||||
return errmsg("opening \" not found");
|
||||
|
||||
p1 = (char*)memchr(p, '\"', pi->data_size - pos);
|
||||
if (!p1)
|
||||
return errmsg("closing \" not found");
|
||||
pos = p1 - pi->buf;
|
||||
if (pos >= pi->data_size)
|
||||
return errmsg("closing \" not found");
|
||||
|
||||
len = p1 - p;
|
||||
if (len > MTD_NAME_MAX)
|
||||
return errmsg("too long mtd%d device name", pi->mtd_num);
|
||||
|
||||
memcpy(pi->name, p, len);
|
||||
pi->name[len] = '\0';
|
||||
|
||||
if (p1[1] != '\n')
|
||||
return errmsg("opening \"\n\" not found");
|
||||
pi->next = p1 + 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* legacy_libmtd_open - legacy version of 'libmtd_open()'.
|
||||
*
|
||||
* This function is just checks that MTD is present in the system. Returns
|
||||
* zero in case of success and %-1 in case of failure. In case of failure,
|
||||
* errno contains zero if MTD is not present in the system, or contains the
|
||||
* error code if a real error happened. This is similar to the 'libmtd_open()'
|
||||
* return conventions.
|
||||
*/
|
||||
int legacy_libmtd_open(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(MTD_PROC_FILE, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT)
|
||||
errno = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* legacy_dev_presentl - legacy version of 'mtd_dev_present()'.
|
||||
* @info: the MTD device information is returned here
|
||||
*
|
||||
* When the kernel does not provide sysfs files for the MTD subsystem,
|
||||
* fall-back to parsing the /proc/mtd file to determine whether an mtd device
|
||||
* number @mtd_num is present.
|
||||
*/
|
||||
int legacy_dev_present(int mtd_num)
|
||||
{
|
||||
int ret;
|
||||
struct proc_parse_info pi;
|
||||
|
||||
ret = proc_parse_start(&pi);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
while (proc_parse_next(&pi)) {
|
||||
if (pi.mtd_num == mtd_num)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* legacy_mtd_get_info - legacy version of 'mtd_get_info()'.
|
||||
* @info: the MTD device information is returned here
|
||||
*
|
||||
* This function is similar to 'mtd_get_info()' and has the same conventions.
|
||||
*/
|
||||
int legacy_mtd_get_info(struct mtd_info *info)
|
||||
{
|
||||
int ret;
|
||||
struct proc_parse_info pi;
|
||||
|
||||
ret = proc_parse_start(&pi);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
info->lowest_mtd_num = INT_MAX;
|
||||
while (proc_parse_next(&pi)) {
|
||||
info->mtd_dev_cnt += 1;
|
||||
if (pi.mtd_num > info->highest_mtd_num)
|
||||
info->highest_mtd_num = pi.mtd_num;
|
||||
if (pi.mtd_num < info->lowest_mtd_num)
|
||||
info->lowest_mtd_num = pi.mtd_num;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* legacy_get_dev_info - legacy version of 'mtd_get_dev_info()'.
|
||||
* @node: name of the MTD device node
|
||||
* @mtd: the MTD device information is returned here
|
||||
*
|
||||
* This function is similar to 'mtd_get_dev_info()' and has the same
|
||||
* conventions.
|
||||
*/
|
||||
int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd)
|
||||
{
|
||||
struct stat st;
|
||||
struct mtd_info_user ui;
|
||||
int fd, ret;
|
||||
loff_t offs = 0;
|
||||
struct proc_parse_info pi;
|
||||
|
||||
if (stat(node, &st)) {
|
||||
sys_errmsg("cannot open \"%s\"", node);
|
||||
if (errno == ENOENT)
|
||||
normsg("MTD subsystem is old and does not support "
|
||||
"sysfs, so MTD character device nodes have "
|
||||
"to exist");
|
||||
}
|
||||
|
||||
if (!S_ISCHR(st.st_mode)) {
|
||||
errno = EINVAL;
|
||||
return errmsg("\"%s\" is not a character device", node);
|
||||
}
|
||||
|
||||
memset(mtd, '\0', sizeof(struct mtd_dev_info));
|
||||
mtd->major = major(st.st_rdev);
|
||||
mtd->minor = minor(st.st_rdev);
|
||||
|
||||
if (mtd->major != MTD_DEV_MAJOR) {
|
||||
errno = EINVAL;
|
||||
return errmsg("\"%s\" has major number %d, MTD devices have "
|
||||
"major %d", node, mtd->major, MTD_DEV_MAJOR);
|
||||
}
|
||||
|
||||
mtd->mtd_num = mtd->minor / 2;
|
||||
|
||||
fd = open(node, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return sys_errmsg("cannot open \"%s\"", node);
|
||||
|
||||
if (ioctl(fd, MEMGETINFO, &ui)) {
|
||||
sys_errmsg("MEMGETINFO ioctl request failed");
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, MEMGETBADBLOCK, &offs);
|
||||
if (ret == -1) {
|
||||
if (errno != EOPNOTSUPP) {
|
||||
sys_errmsg("MEMGETBADBLOCK ioctl failed");
|
||||
goto out_close;
|
||||
}
|
||||
errno = 0;
|
||||
mtd->bb_allowed = 0;
|
||||
} else
|
||||
mtd->bb_allowed = 1;
|
||||
|
||||
mtd->type = ui.type;
|
||||
mtd->size = ui.size;
|
||||
mtd->eb_size = ui.erasesize;
|
||||
mtd->min_io_size = ui.writesize;
|
||||
mtd->oob_size = ui.oobsize;
|
||||
|
||||
if (mtd->min_io_size <= 0) {
|
||||
errmsg("mtd%d (%s) has insane min. I/O unit size %d",
|
||||
mtd->mtd_num, node, mtd->min_io_size);
|
||||
goto out_close;
|
||||
}
|
||||
if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
|
||||
errmsg("mtd%d (%s) has insane eraseblock size %d",
|
||||
mtd->mtd_num, node, mtd->eb_size);
|
||||
goto out_close;
|
||||
}
|
||||
if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
|
||||
errmsg("mtd%d (%s) has insane size %lld",
|
||||
mtd->mtd_num, node, mtd->size);
|
||||
goto out_close;
|
||||
}
|
||||
mtd->eb_cnt = mtd->size / mtd->eb_size;
|
||||
|
||||
switch(mtd->type) {
|
||||
case MTD_ABSENT:
|
||||
errmsg("mtd%d (%s) is removable and is not present",
|
||||
mtd->mtd_num, node);
|
||||
goto out_close;
|
||||
case MTD_RAM:
|
||||
strcpy((char *)mtd->type_str, "ram");
|
||||
break;
|
||||
case MTD_ROM:
|
||||
strcpy((char *)mtd->type_str, "rom");
|
||||
break;
|
||||
case MTD_NORFLASH:
|
||||
strcpy((char *)mtd->type_str, "nor");
|
||||
break;
|
||||
case MTD_NANDFLASH:
|
||||
strcpy((char *)mtd->type_str, "nand");
|
||||
break;
|
||||
case MTD_DATAFLASH:
|
||||
strcpy((char *)mtd->type_str, "dataflash");
|
||||
break;
|
||||
case MTD_UBIVOLUME:
|
||||
strcpy((char *)mtd->type_str, "ubi");
|
||||
break;
|
||||
default:
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (ui.flags & MTD_WRITEABLE)
|
||||
mtd->writable = 1;
|
||||
mtd->subpage_size = mtd->min_io_size;
|
||||
|
||||
close(fd);
|
||||
|
||||
/*
|
||||
* Unfortunately, the device name is not available via ioctl, and
|
||||
* we have to parse /proc/mtd to get it.
|
||||
*/
|
||||
ret = proc_parse_start(&pi);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
while (proc_parse_next(&pi)) {
|
||||
if (pi.mtd_num == mtd->mtd_num) {
|
||||
strcpy((char *)mtd->name, pi.name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
errmsg("mtd%d not found in \"%s\"", mtd->mtd_num, MTD_PROC_FILE);
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
|
||||
out_close:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* legacy_get_dev_info1 - legacy version of 'mtd_get_dev_info1()'.
|
||||
* @node: name of the MTD device node
|
||||
* @mtd: the MTD device information is returned here
|
||||
*
|
||||
* This function is similar to 'mtd_get_dev_info1()' and has the same
|
||||
* conventions.
|
||||
*/
|
||||
int legacy_get_dev_info1(int mtd_num, struct mtd_dev_info *mtd)
|
||||
{
|
||||
char node[sizeof(MTD_DEV_PATT) + 20];
|
||||
|
||||
sprintf(node, MTD_DEV_PATT, mtd_num);
|
||||
return legacy_get_dev_info(node, mtd);
|
||||
}
|
54
src/system/mtdutils/mcast_image.h
Normal file
54
src/system/mtdutils/mcast_image.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define PKT_SIZE 2820
|
||||
|
||||
struct image_pkt_hdr {
|
||||
uint32_t resend;
|
||||
uint32_t totcrc;
|
||||
uint32_t nr_blocks;
|
||||
uint32_t blocksize;
|
||||
uint32_t block_crc;
|
||||
uint32_t block_nr;
|
||||
uint32_t pkt_sequence;
|
||||
uint16_t pkt_nr;
|
||||
uint16_t nr_pkts;
|
||||
uint32_t thislen;
|
||||
uint32_t thiscrc;
|
||||
};
|
||||
|
||||
struct image_pkt {
|
||||
struct image_pkt_hdr hdr;
|
||||
unsigned char data[PKT_SIZE];
|
||||
};
|
||||
|
||||
struct fec_parms;
|
||||
|
||||
/* k - number of actual data packets
|
||||
* n - total number of packets including data and redundant packets
|
||||
* (actual packet size isn't relevant here) */
|
||||
struct fec_parms *fec_new(int k, int n);
|
||||
void fec_free(struct fec_parms *p);
|
||||
|
||||
/* src - array of (n) pointers to data packets
|
||||
* fec - buffer for packet to be generated
|
||||
* index - index of packet to be generated (0 <= index < n)
|
||||
* sz - data packet size
|
||||
*
|
||||
* _linear version just takes a pointer to the raw data; no
|
||||
* mucking about with packet pointers.
|
||||
*/
|
||||
void fec_encode(struct fec_parms *code, unsigned char *src[],
|
||||
unsigned char *fec, int index, int sz);
|
||||
void fec_encode_linear(struct fec_parms *code, unsigned char *src,
|
||||
unsigned char *fec, int index, int sz);
|
||||
|
||||
/* data - array of (k) pointers to data packets, in arbitrary order (see i)
|
||||
* i - indices of (data) packets
|
||||
* sz - data packet size
|
||||
*
|
||||
* Will never fail as long as you give it (k) individual data packets.
|
||||
* Will re-order the (data) pointers but not the indices -- data packets
|
||||
* are ordered on return.
|
||||
*/
|
||||
int fec_decode(struct fec_parms *code, unsigned char *data[],
|
||||
int i[], int sz);
|
1266
src/system/mtdutils/mkfs.jffs2.cpp
Normal file
1266
src/system/mtdutils/mkfs.jffs2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
118
src/system/mtdutils/mkfs.jffs2.h
Normal file
118
src/system/mtdutils/mkfs.jffs2.h
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
#ifndef __MKFS_JFFS2__
|
||||
#define __MKFS_JFFS2__
|
||||
|
||||
/*
|
||||
Neutrino-HD
|
||||
|
||||
License: GPL
|
||||
|
||||
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., 51 Franklin St, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <gui/widget/progresswindow.h>
|
||||
#include <system/helpers.h>
|
||||
|
||||
class CMkfsJFFS2
|
||||
{
|
||||
private:
|
||||
enum {
|
||||
dev_sys = 0,
|
||||
dev_proc = 1,
|
||||
dev_tmp = 2,
|
||||
/* dev_pts = 3,*/
|
||||
dev_dev = 3,
|
||||
dev_jffs2 = 4,
|
||||
dev_max = 5
|
||||
};
|
||||
|
||||
int out_fd;
|
||||
std::string rootdir;
|
||||
int squash_uids;
|
||||
int squash_perms;
|
||||
int fake_times;
|
||||
unsigned long int all_read;
|
||||
int printProgress;
|
||||
long kbUsed;
|
||||
dev_t dev_x[dev_max];
|
||||
CProgressWindow *progressBar;
|
||||
int progressBarGlobalX1;
|
||||
int progressBarGlobalX2;
|
||||
std::string imageName_, sumName_;
|
||||
bool useSumtool_;
|
||||
|
||||
uint32_t ino;
|
||||
int out_ofs;
|
||||
int erase_block_size;
|
||||
int pad_fs_size;
|
||||
int add_cleanmarkers;
|
||||
int cleanmarker_size;
|
||||
unsigned char ffbuf[16];
|
||||
bool compressorIsInit;
|
||||
|
||||
void Init();
|
||||
void classClear();
|
||||
bool classInit();
|
||||
struct filesystem_entry *recursive_add_host_directory(
|
||||
struct filesystem_entry *parent, const char *targetpath,
|
||||
const char *hostpath,
|
||||
bool skipSpezialFolders);
|
||||
int parse_device_table(struct filesystem_entry *root, FILE * file);
|
||||
int interpret_table_entry(struct filesystem_entry *root, char *line);
|
||||
void create_target_filesystem(struct filesystem_entry *root);
|
||||
void recursive_populate_directory(struct filesystem_entry *dir);
|
||||
void padblock(void);
|
||||
void pad(int req);
|
||||
inline void padword(void) { if (out_ofs % 4) full_write(out_fd, ffbuf, 4 - (out_ofs % 4)); }
|
||||
inline void pad_block_if_less_than(int req);
|
||||
void full_write(int fd, const void *buf, int len);
|
||||
static uint32_t find_hardlink(struct filesystem_entry *e);
|
||||
void write_dirent(struct filesystem_entry *e);
|
||||
void write_special_file(struct filesystem_entry *e);
|
||||
void write_pipe(struct filesystem_entry *e);
|
||||
void write_symlink(struct filesystem_entry *e);
|
||||
unsigned int write_regular_file(struct filesystem_entry *e);
|
||||
void paintProgressBar();
|
||||
void setProgressBarGlobal(int x1, int x2);
|
||||
void printProgressData(bool finish);
|
||||
struct filesystem_entry *find_filesystem_entry(struct filesystem_entry *dir, char *fullname, uint32_t type);
|
||||
struct filesystem_entry *add_host_filesystem_entry(const char *name,
|
||||
const char *path, unsigned long uid, unsigned long gid,
|
||||
unsigned long mode, dev_t rdev, struct filesystem_entry *parent);
|
||||
void cleanup(struct filesystem_entry *dir);
|
||||
char *xreadlink(const char *path);
|
||||
|
||||
public:
|
||||
CMkfsJFFS2();
|
||||
~CMkfsJFFS2();
|
||||
|
||||
bool makeJffs2Image(std::string& path,
|
||||
std::string& imageName,
|
||||
int eraseBlockSize=0x20000,
|
||||
int padFsSize=0,
|
||||
int addCleanmarkers=0,
|
||||
int targetEndian=__LITTLE_ENDIAN,
|
||||
bool skipSpezialFolders=true,
|
||||
bool useSumtool=true,
|
||||
CProgressWindow *progress=NULL,
|
||||
bool useDevTable=true,
|
||||
std::string devTable="");
|
||||
|
||||
};
|
||||
|
||||
#endif // __MKFS_JFFS2__
|
390
src/system/mtdutils/rbtree.cpp
Normal file
390
src/system/mtdutils/rbtree.cpp
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
Red Black Trees
|
||||
(C) 1999 Andrea Arcangeli <andrea@suse.de>
|
||||
(C) 2002 David Woodhouse <dwmw2@infradead.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
linux/lib/rbtree.c
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "rbtree.h"
|
||||
|
||||
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *right = node->rb_right;
|
||||
struct rb_node *parent = rb_parent(node);
|
||||
|
||||
if ((node->rb_right = right->rb_left))
|
||||
rb_set_parent(right->rb_left, node);
|
||||
right->rb_left = node;
|
||||
|
||||
rb_set_parent(right, parent);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
if (node == parent->rb_left)
|
||||
parent->rb_left = right;
|
||||
else
|
||||
parent->rb_right = right;
|
||||
}
|
||||
else
|
||||
root->rb_node = right;
|
||||
rb_set_parent(node, right);
|
||||
}
|
||||
|
||||
static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *left = node->rb_left;
|
||||
struct rb_node *parent = rb_parent(node);
|
||||
|
||||
if ((node->rb_left = left->rb_right))
|
||||
rb_set_parent(left->rb_right, node);
|
||||
left->rb_right = node;
|
||||
|
||||
rb_set_parent(left, parent);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
if (node == parent->rb_right)
|
||||
parent->rb_right = left;
|
||||
else
|
||||
parent->rb_left = left;
|
||||
}
|
||||
else
|
||||
root->rb_node = left;
|
||||
rb_set_parent(node, left);
|
||||
}
|
||||
|
||||
void rb_insert_color(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *parent, *gparent;
|
||||
|
||||
while ((parent = rb_parent(node)) && rb_is_red(parent))
|
||||
{
|
||||
gparent = rb_parent(parent);
|
||||
|
||||
if (parent == gparent->rb_left)
|
||||
{
|
||||
{
|
||||
register struct rb_node *uncle = gparent->rb_right;
|
||||
if (uncle && rb_is_red(uncle))
|
||||
{
|
||||
rb_set_black(uncle);
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->rb_right == node)
|
||||
{
|
||||
register struct rb_node *tmp;
|
||||
__rb_rotate_left(parent, root);
|
||||
tmp = parent;
|
||||
parent = node;
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
__rb_rotate_right(gparent, root);
|
||||
} else {
|
||||
{
|
||||
register struct rb_node *uncle = gparent->rb_left;
|
||||
if (uncle && rb_is_red(uncle))
|
||||
{
|
||||
rb_set_black(uncle);
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->rb_left == node)
|
||||
{
|
||||
register struct rb_node *tmp;
|
||||
__rb_rotate_right(parent, root);
|
||||
tmp = parent;
|
||||
parent = node;
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
__rb_rotate_left(gparent, root);
|
||||
}
|
||||
}
|
||||
|
||||
rb_set_black(root->rb_node);
|
||||
}
|
||||
|
||||
static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
|
||||
struct rb_root *root)
|
||||
{
|
||||
struct rb_node *other;
|
||||
|
||||
while ((!node || rb_is_black(node)) && node != root->rb_node)
|
||||
{
|
||||
if (parent->rb_left == node)
|
||||
{
|
||||
other = parent->rb_right;
|
||||
if (rb_is_red(other))
|
||||
{
|
||||
rb_set_black(other);
|
||||
rb_set_red(parent);
|
||||
__rb_rotate_left(parent, root);
|
||||
other = parent->rb_right;
|
||||
}
|
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
|
||||
(!other->rb_right || rb_is_black(other->rb_right)))
|
||||
{
|
||||
rb_set_red(other);
|
||||
node = parent;
|
||||
parent = rb_parent(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other->rb_right || rb_is_black(other->rb_right))
|
||||
{
|
||||
struct rb_node *o_left;
|
||||
if ((o_left = other->rb_left))
|
||||
rb_set_black(o_left);
|
||||
rb_set_red(other);
|
||||
__rb_rotate_right(other, root);
|
||||
other = parent->rb_right;
|
||||
}
|
||||
rb_set_color(other, rb_color(parent));
|
||||
rb_set_black(parent);
|
||||
if (other->rb_right)
|
||||
rb_set_black(other->rb_right);
|
||||
__rb_rotate_left(parent, root);
|
||||
node = root->rb_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
other = parent->rb_left;
|
||||
if (rb_is_red(other))
|
||||
{
|
||||
rb_set_black(other);
|
||||
rb_set_red(parent);
|
||||
__rb_rotate_right(parent, root);
|
||||
other = parent->rb_left;
|
||||
}
|
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
|
||||
(!other->rb_right || rb_is_black(other->rb_right)))
|
||||
{
|
||||
rb_set_red(other);
|
||||
node = parent;
|
||||
parent = rb_parent(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other->rb_left || rb_is_black(other->rb_left))
|
||||
{
|
||||
register struct rb_node *o_right;
|
||||
if ((o_right = other->rb_right))
|
||||
rb_set_black(o_right);
|
||||
rb_set_red(other);
|
||||
__rb_rotate_left(other, root);
|
||||
other = parent->rb_left;
|
||||
}
|
||||
rb_set_color(other, rb_color(parent));
|
||||
rb_set_black(parent);
|
||||
if (other->rb_left)
|
||||
rb_set_black(other->rb_left);
|
||||
__rb_rotate_right(parent, root);
|
||||
node = root->rb_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node)
|
||||
rb_set_black(node);
|
||||
}
|
||||
|
||||
void rb_erase(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *child, *parent;
|
||||
int color;
|
||||
|
||||
if (!node->rb_left)
|
||||
child = node->rb_right;
|
||||
else if (!node->rb_right)
|
||||
child = node->rb_left;
|
||||
else
|
||||
{
|
||||
struct rb_node *old = node, *left;
|
||||
|
||||
node = node->rb_right;
|
||||
while ((left = node->rb_left) != NULL)
|
||||
node = left;
|
||||
child = node->rb_right;
|
||||
parent = rb_parent(node);
|
||||
color = rb_color(node);
|
||||
|
||||
if (child)
|
||||
rb_set_parent(child, parent);
|
||||
if (parent == old) {
|
||||
parent->rb_right = child;
|
||||
parent = node;
|
||||
} else
|
||||
parent->rb_left = child;
|
||||
|
||||
node->rb_parent_color = old->rb_parent_color;
|
||||
node->rb_right = old->rb_right;
|
||||
node->rb_left = old->rb_left;
|
||||
|
||||
if (rb_parent(old))
|
||||
{
|
||||
if (rb_parent(old)->rb_left == old)
|
||||
rb_parent(old)->rb_left = node;
|
||||
else
|
||||
rb_parent(old)->rb_right = node;
|
||||
} else
|
||||
root->rb_node = node;
|
||||
|
||||
rb_set_parent(old->rb_left, node);
|
||||
if (old->rb_right)
|
||||
rb_set_parent(old->rb_right, node);
|
||||
goto color;
|
||||
}
|
||||
|
||||
parent = rb_parent(node);
|
||||
color = rb_color(node);
|
||||
|
||||
if (child)
|
||||
rb_set_parent(child, parent);
|
||||
if (parent)
|
||||
{
|
||||
if (parent->rb_left == node)
|
||||
parent->rb_left = child;
|
||||
else
|
||||
parent->rb_right = child;
|
||||
}
|
||||
else
|
||||
root->rb_node = child;
|
||||
|
||||
color:
|
||||
if (color == RB_BLACK)
|
||||
__rb_erase_color(child, parent, root);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the first node (in sort order) of the tree.
|
||||
*/
|
||||
struct rb_node *rb_first(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *n;
|
||||
|
||||
n = root->rb_node;
|
||||
if (!n)
|
||||
return NULL;
|
||||
while (n->rb_left)
|
||||
n = n->rb_left;
|
||||
return n;
|
||||
}
|
||||
|
||||
struct rb_node *rb_last(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *n;
|
||||
|
||||
n = root->rb_node;
|
||||
if (!n)
|
||||
return NULL;
|
||||
while (n->rb_right)
|
||||
n = n->rb_right;
|
||||
return n;
|
||||
}
|
||||
|
||||
struct rb_node *rb_next(struct rb_node *node)
|
||||
{
|
||||
struct rb_node *parent;
|
||||
|
||||
if (rb_parent(node) == node)
|
||||
return NULL;
|
||||
|
||||
/* If we have a right-hand child, go down and then left as far
|
||||
as we can. */
|
||||
if (node->rb_right) {
|
||||
node = node->rb_right;
|
||||
while (node->rb_left)
|
||||
node=node->rb_left;
|
||||
return node;
|
||||
}
|
||||
|
||||
/* No right-hand children. Everything down and left is
|
||||
smaller than us, so any 'next' node must be in the general
|
||||
direction of our parent. Go up the tree; any time the
|
||||
ancestor is a right-hand child of its parent, keep going
|
||||
up. First time it's a left-hand child of its parent, said
|
||||
parent is our 'next' node. */
|
||||
while ((parent = rb_parent(node)) && node == parent->rb_right)
|
||||
node = parent;
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
struct rb_node *rb_prev(struct rb_node *node)
|
||||
{
|
||||
struct rb_node *parent;
|
||||
|
||||
if (rb_parent(node) == node)
|
||||
return NULL;
|
||||
|
||||
/* If we have a left-hand child, go down and then right as far
|
||||
as we can. */
|
||||
if (node->rb_left) {
|
||||
node = node->rb_left;
|
||||
while (node->rb_right)
|
||||
node=node->rb_right;
|
||||
return node;
|
||||
}
|
||||
|
||||
/* No left-hand children. Go up till we find an ancestor which
|
||||
is a right-hand child of its parent */
|
||||
while ((parent = rb_parent(node)) && node == parent->rb_left)
|
||||
node = parent;
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
void rb_replace_node(struct rb_node *victim, struct rb_node *new_,
|
||||
struct rb_root *root)
|
||||
{
|
||||
struct rb_node *parent = rb_parent(victim);
|
||||
|
||||
/* Set the surrounding nodes to point to the replacement */
|
||||
if (parent) {
|
||||
if (victim == parent->rb_left)
|
||||
parent->rb_left = new_;
|
||||
else
|
||||
parent->rb_right = new_;
|
||||
} else {
|
||||
root->rb_node = new_;
|
||||
}
|
||||
if (victim->rb_left)
|
||||
rb_set_parent(victim->rb_left, new_);
|
||||
if (victim->rb_right)
|
||||
rb_set_parent(victim->rb_right, new_);
|
||||
|
||||
/* Copy the pointers/colour from the victim to the replacement */
|
||||
*new_ = *victim;
|
||||
}
|
171
src/system/mtdutils/rbtree.h
Normal file
171
src/system/mtdutils/rbtree.h
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
Red Black Trees
|
||||
(C) 1999 Andrea Arcangeli <andrea@suse.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
linux/include/linux/rbtree.h
|
||||
|
||||
To use rbtrees you'll have to implement your own insert and search cores.
|
||||
This will avoid us to use callbacks and to drop drammatically performances.
|
||||
I know it's not the cleaner way, but in C (not in C++) to get
|
||||
performances and genericity...
|
||||
|
||||
Some example of insert and search follows here. The search is a plain
|
||||
normal search over an ordered tree. The insert instead must be implemented
|
||||
int two steps: as first thing the code must insert the element in
|
||||
order as a red leaf in the tree, then the support library function
|
||||
rb_insert_color() must be called. Such function will do the
|
||||
not trivial work to rebalance the rbtree if necessary.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
static inline struct page * rb_search_page_cache(struct inode * inode,
|
||||
unsigned long offset)
|
||||
{
|
||||
struct rb_node * n = inode->i_rb_page_cache.rb_node;
|
||||
struct page * page;
|
||||
|
||||
while (n)
|
||||
{
|
||||
page = rb_entry(n, struct page, rb_page_cache);
|
||||
|
||||
if (offset < page->offset)
|
||||
n = n->rb_left;
|
||||
else if (offset > page->offset)
|
||||
n = n->rb_right;
|
||||
else
|
||||
return page;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct page * __rb_insert_page_cache(struct inode * inode,
|
||||
unsigned long offset,
|
||||
struct rb_node * node)
|
||||
{
|
||||
struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
|
||||
struct rb_node * parent = NULL;
|
||||
struct page * page;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
parent = *p;
|
||||
page = rb_entry(parent, struct page, rb_page_cache);
|
||||
|
||||
if (offset < page->offset)
|
||||
p = &(*p)->rb_left;
|
||||
else if (offset > page->offset)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return page;
|
||||
}
|
||||
|
||||
rb_link_node(node, parent, p);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct page * rb_insert_page_cache(struct inode * inode,
|
||||
unsigned long offset,
|
||||
struct rb_node * node)
|
||||
{
|
||||
struct page * ret;
|
||||
if ((ret = __rb_insert_page_cache(inode, offset, node)))
|
||||
goto out;
|
||||
rb_insert_color(node, &inode->i_rb_page_cache);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_RBTREE_H
|
||||
#define _LINUX_RBTREE_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/stddef.h>
|
||||
|
||||
struct rb_node
|
||||
{
|
||||
unsigned long rb_parent_color;
|
||||
#define RB_RED 0
|
||||
#define RB_BLACK 1
|
||||
struct rb_node *rb_right;
|
||||
struct rb_node *rb_left;
|
||||
} __attribute__((aligned(sizeof(long))));
|
||||
/* The alignment might seem pointless, but allegedly CRIS needs it */
|
||||
|
||||
struct rb_root
|
||||
{
|
||||
struct rb_node *rb_node;
|
||||
};
|
||||
|
||||
|
||||
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
|
||||
#define rb_color(r) ((r)->rb_parent_color & 1)
|
||||
#define rb_is_red(r) (!rb_color(r))
|
||||
#define rb_is_black(r) rb_color(r)
|
||||
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
|
||||
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
|
||||
|
||||
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
|
||||
}
|
||||
static inline void rb_set_color(struct rb_node *rb, int color)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
|
||||
}
|
||||
|
||||
#define RB_ROOT (struct rb_root) { NULL, }
|
||||
|
||||
/* Newer gcc versions take care of exporting this */
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
|
||||
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
|
||||
|
||||
#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
|
||||
#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
|
||||
#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
|
||||
|
||||
extern void rb_insert_color(struct rb_node *, struct rb_root *);
|
||||
extern void rb_erase(struct rb_node *, struct rb_root *);
|
||||
|
||||
/* Find logical next and previous nodes in a tree */
|
||||
extern struct rb_node *rb_next(struct rb_node *);
|
||||
extern struct rb_node *rb_prev(struct rb_node *);
|
||||
extern struct rb_node *rb_first(struct rb_root *);
|
||||
extern struct rb_node *rb_last(struct rb_root *);
|
||||
|
||||
/* Fast replacement of a single node without remove/rebalance/add/rebalance */
|
||||
extern void rb_replace_node(struct rb_node *victim, struct rb_node *new_,
|
||||
struct rb_root *root);
|
||||
|
||||
static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
|
||||
struct rb_node ** rb_link)
|
||||
{
|
||||
node->rb_parent_color = (unsigned long )parent;
|
||||
node->rb_left = node->rb_right = NULL;
|
||||
|
||||
*rb_link = node;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_RBTREE_H */
|
177
src/system/mtdutils/summary.h
Normal file
177
src/system/mtdutils/summary.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
||||
* Zoltan Sogor <weth@inf.u-szeged.hu>,
|
||||
* Patrik Kluba <pajko@halom.u-szeged.hu>,
|
||||
* University of Szeged, Hungary
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*/
|
||||
|
||||
#ifndef JFFS2_SUMMARY_H
|
||||
#define JFFS2_SUMMARY_H
|
||||
|
||||
#include <linux/jffs2.h>
|
||||
|
||||
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
|
||||
c->free_size -= _x; c->dirty_size += _x; \
|
||||
jeb->free_size -= _x ; jeb->dirty_size += _x; \
|
||||
}while(0)
|
||||
#define USED_SPACE(x) do { typeof(x) _x = (x); \
|
||||
c->free_size -= _x; c->used_size += _x; \
|
||||
jeb->free_size -= _x ; jeb->used_size += _x; \
|
||||
}while(0)
|
||||
#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
|
||||
c->free_size -= _x; c->wasted_size += _x; \
|
||||
jeb->free_size -= _x ; jeb->wasted_size += _x; \
|
||||
}while(0)
|
||||
#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
|
||||
c->free_size -= _x; c->unchecked_size += _x; \
|
||||
jeb->free_size -= _x ; jeb->unchecked_size += _x; \
|
||||
}while(0)
|
||||
|
||||
#define BLK_STATE_ALLFF 0
|
||||
#define BLK_STATE_CLEAN 1
|
||||
#define BLK_STATE_PARTDIRTY 2
|
||||
#define BLK_STATE_CLEANMARKER 3
|
||||
#define BLK_STATE_ALLDIRTY 4
|
||||
#define BLK_STATE_BADBLOCK 5
|
||||
|
||||
#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
|
||||
#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
|
||||
#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
|
||||
#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash))
|
||||
#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash))
|
||||
|
||||
/* Summary structures used on flash */
|
||||
|
||||
struct jffs2_sum_unknown_flash
|
||||
{
|
||||
jint16_t nodetype; /* node type */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_sum_inode_flash
|
||||
{
|
||||
jint16_t nodetype; /* node type */
|
||||
jint32_t inode; /* inode number */
|
||||
jint32_t version; /* inode version */
|
||||
jint32_t offset; /* offset on jeb */
|
||||
jint32_t totlen; /* record length */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_sum_dirent_flash
|
||||
{
|
||||
jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
|
||||
jint32_t totlen; /* record length */
|
||||
jint32_t offset; /* ofset on jeb */
|
||||
jint32_t pino; /* parent inode */
|
||||
jint32_t version; /* dirent version */
|
||||
jint32_t ino; /* == zero for unlink */
|
||||
uint8_t nsize; /* dirent name size */
|
||||
uint8_t type; /* dirent type */
|
||||
uint8_t name[0]; /* dirent name */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_sum_xattr_flash
|
||||
{
|
||||
jint16_t nodetype; /* == JFFS2_NODETYPE_XATR */
|
||||
jint32_t xid; /* xattr identifier */
|
||||
jint32_t version; /* version number */
|
||||
jint32_t offset; /* offset on jeb */
|
||||
jint32_t totlen; /* node length */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_sum_xref_flash
|
||||
{
|
||||
jint16_t nodetype; /* == JFFS2_NODETYPE_XREF */
|
||||
jint32_t offset; /* offset on jeb */
|
||||
} __attribute__((packed));
|
||||
|
||||
union jffs2_sum_flash
|
||||
{
|
||||
struct jffs2_sum_unknown_flash u;
|
||||
struct jffs2_sum_inode_flash i;
|
||||
struct jffs2_sum_dirent_flash d;
|
||||
struct jffs2_sum_xattr_flash x;
|
||||
struct jffs2_sum_xref_flash r;
|
||||
};
|
||||
|
||||
/* Summary structures used in the memory */
|
||||
|
||||
struct jffs2_sum_unknown_mem
|
||||
{
|
||||
union jffs2_sum_mem *next;
|
||||
jint16_t nodetype; /* node type */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_sum_inode_mem
|
||||
{
|
||||
union jffs2_sum_mem *next;
|
||||
jint16_t nodetype; /* node type */
|
||||
jint32_t inode; /* inode number */
|
||||
jint32_t version; /* inode version */
|
||||
jint32_t offset; /* offset on jeb */
|
||||
jint32_t totlen; /* record length */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_sum_dirent_mem
|
||||
{
|
||||
union jffs2_sum_mem *next;
|
||||
jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
|
||||
jint32_t totlen; /* record length */
|
||||
jint32_t offset; /* ofset on jeb */
|
||||
jint32_t pino; /* parent inode */
|
||||
jint32_t version; /* dirent version */
|
||||
jint32_t ino; /* == zero for unlink */
|
||||
uint8_t nsize; /* dirent name size */
|
||||
uint8_t type; /* dirent type */
|
||||
uint8_t name[0]; /* dirent name */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_sum_xattr_mem
|
||||
{
|
||||
union jffs2_sum_mem *next;
|
||||
jint16_t nodetype;
|
||||
jint32_t xid;
|
||||
jint32_t version;
|
||||
jint32_t offset;
|
||||
jint32_t totlen;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct jffs2_sum_xref_mem
|
||||
{
|
||||
union jffs2_sum_mem *next;
|
||||
jint16_t nodetype;
|
||||
jint32_t offset;
|
||||
} __attribute__((packed));
|
||||
|
||||
union jffs2_sum_mem
|
||||
{
|
||||
struct jffs2_sum_unknown_mem u;
|
||||
struct jffs2_sum_inode_mem i;
|
||||
struct jffs2_sum_dirent_mem d;
|
||||
struct jffs2_sum_xattr_mem x;
|
||||
struct jffs2_sum_xref_mem r;
|
||||
};
|
||||
|
||||
struct jffs2_summary
|
||||
{
|
||||
uint32_t sum_size;
|
||||
uint32_t sum_num;
|
||||
uint32_t sum_padded;
|
||||
union jffs2_sum_mem *sum_list_head;
|
||||
union jffs2_sum_mem *sum_list_tail;
|
||||
};
|
||||
|
||||
/* Summary marker is stored at the end of every sumarized erase block */
|
||||
|
||||
struct jffs2_sum_marker
|
||||
{
|
||||
jint32_t offset; /* offset of the summary node in the jeb */
|
||||
jint32_t magic; /* == JFFS2_SUM_MAGIC */
|
||||
};
|
||||
|
||||
#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker))
|
||||
|
||||
#endif
|
766
src/system/mtdutils/sumtool.cpp
Normal file
766
src/system/mtdutils/sumtool.cpp
Normal file
@@ -0,0 +1,766 @@
|
||||
/*
|
||||
* sumtool.c
|
||||
*
|
||||
* Copyright (C) 2004 Zoltan Sogor <weth@inf.u-szeged.hu>,
|
||||
* Ferenc Havasi <havasi@inf.u-szeged.hu>
|
||||
* University of Szeged, Hungary
|
||||
* 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Overview:
|
||||
* This is a utility insert summary information into JFFS2 image for
|
||||
* faster mount time
|
||||
*
|
||||
*/
|
||||
|
||||
#define PROGRAM_NAME "sumtool"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <asm/types.h>
|
||||
#include <dirent.h>
|
||||
#include <mtd/jffs2-user.h>
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
#include <crc32.h>
|
||||
#include "summary.h"
|
||||
#include "common.h"
|
||||
#include "sumtool.h"
|
||||
|
||||
#define PAD(x) (((x)+3)&~3)
|
||||
|
||||
struct jffs2_summary *sum_collected = NULL;
|
||||
|
||||
extern struct jffs2_unknown_node cleanmarker;
|
||||
extern int target_endian;
|
||||
|
||||
CSumtoolJFFS2::CSumtoolJFFS2()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
CSumtoolJFFS2::~CSumtoolJFFS2()
|
||||
{
|
||||
classClear();
|
||||
}
|
||||
|
||||
bool CSumtoolJFFS2::classInit()
|
||||
{
|
||||
out_fd = open(sumName_.c_str(), O_CREAT | O_TRUNC | O_RDWR, 0644);
|
||||
if (out_fd == -1) {
|
||||
sys_errmsg("open output file: %s", sumName_.c_str());
|
||||
return false;
|
||||
}
|
||||
in_fd = open(imageName_.c_str(), O_RDONLY);
|
||||
if (in_fd == -1) {
|
||||
sys_errmsg("open input file: %s", imageName_.c_str());
|
||||
return false;
|
||||
}
|
||||
init_buffers();
|
||||
init_sumlist();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::classClear()
|
||||
{
|
||||
clean_buffers();
|
||||
clean_sumlist();
|
||||
|
||||
if (in_fd != -1) {
|
||||
close(in_fd);
|
||||
in_fd = -1;
|
||||
}
|
||||
if (out_fd != -1) {
|
||||
close(out_fd);
|
||||
out_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::Init()
|
||||
{
|
||||
verbose = 0;
|
||||
sum_collected = NULL;
|
||||
padto = 0; /* pad the output with 0xFF to the end of the final eraseblock */
|
||||
add_cleanmarkers = 1; /* add cleanmarker to output */
|
||||
use_input_cleanmarker_size = 1; /* use input file's cleanmarker size (default) */
|
||||
found_cleanmarkers = 0; /* cleanmarker found in input file */
|
||||
cleanmarker_size = sizeof(cleanmarker);
|
||||
erase_block_size = 65536;
|
||||
out_fd = -1;
|
||||
in_fd = -1;
|
||||
data_buffer = NULL; /* buffer for inodes */
|
||||
data_ofs = 0; /* inode buffer offset */
|
||||
file_buffer = NULL; /* file buffer contains the actual erase block*/
|
||||
file_ofs = 0; /* position in the buffer */
|
||||
imageName_ = "";
|
||||
sumName_ = "";
|
||||
memset(ffbuf, 0xFF, sizeof(ffbuf));
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::setup_cleanmarker(void)
|
||||
{
|
||||
cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
|
||||
cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
|
||||
cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::add_sum_inode_mem(union jffs2_node_union *node)
|
||||
{
|
||||
struct jffs2_sum_inode_mem *temp = reinterpret_cast<jffs2_sum_inode_mem*>(xmalloc(sizeof(*temp)));
|
||||
|
||||
temp->nodetype = node->i.nodetype;
|
||||
temp->inode = node->i.ino;
|
||||
temp->version = node->i.version;
|
||||
temp->offset = cpu_to_je32(data_ofs);
|
||||
temp->totlen = node->i.totlen;
|
||||
temp->next = NULL;
|
||||
|
||||
add_sum_mem((union jffs2_sum_mem *) temp);
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::add_sum_dirent_mem(union jffs2_node_union *node)
|
||||
{
|
||||
struct jffs2_sum_dirent_mem *temp = reinterpret_cast<jffs2_sum_dirent_mem*>(xmalloc(sizeof(*temp) + node->d.nsize));
|
||||
|
||||
temp->nodetype = node->d.nodetype;
|
||||
temp->totlen = node->d.totlen;
|
||||
temp->offset = cpu_to_je32(data_ofs);
|
||||
temp->pino = node->d.pino;
|
||||
temp->version = node->d.version;
|
||||
temp->ino = node->d.ino;
|
||||
temp->nsize = node->d.nsize;
|
||||
temp->type = node->d.type;
|
||||
temp->next = NULL;
|
||||
|
||||
memcpy(temp->name,node->d.name,node->d.nsize);
|
||||
add_sum_mem((union jffs2_sum_mem *) temp);
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::add_sum_xattr_mem(union jffs2_node_union *node)
|
||||
{
|
||||
struct jffs2_sum_xattr_mem *temp = reinterpret_cast<jffs2_sum_xattr_mem*>(xmalloc(sizeof(*temp)));
|
||||
|
||||
temp->nodetype = node->x.nodetype;
|
||||
temp->xid = node->x.xid;
|
||||
temp->version = node->x.version;
|
||||
temp->offset = cpu_to_je32(data_ofs);
|
||||
temp->totlen = node->x.totlen;
|
||||
temp->next = NULL;
|
||||
|
||||
add_sum_mem((union jffs2_sum_mem *) temp);
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::add_sum_xref_mem(union jffs2_node_union *node)
|
||||
{
|
||||
struct jffs2_sum_xref_mem *temp = reinterpret_cast<jffs2_sum_xref_mem*>(xmalloc(sizeof(*temp)));
|
||||
|
||||
temp->nodetype = node->r.nodetype;
|
||||
temp->offset = cpu_to_je32(data_ofs);
|
||||
temp->next = NULL;
|
||||
|
||||
add_sum_mem((union jffs2_sum_mem *) temp);
|
||||
}
|
||||
|
||||
int CSumtoolJFFS2::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:
|
||||
sys_errmsg("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::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 CSumtoolJFFS2::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 CSumtoolJFFS2::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 CSumtoolJFFS2::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 CSumtoolJFFS2::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 ((int)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 CSumtoolJFFS2::pad(int req)
|
||||
{
|
||||
while (req) {
|
||||
if (req > (int)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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::full_write(void *target_buff, const void *buf, int len)
|
||||
{
|
||||
memcpy(target_buff, buf, len);
|
||||
data_ofs += len;
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::write_buff_to_file(void)
|
||||
{
|
||||
int len = data_ofs;
|
||||
|
||||
uint8_t *buf = NULL;
|
||||
|
||||
buf = data_buffer;
|
||||
while (len > 0) {
|
||||
int ret = write(out_fd, buf, len);
|
||||
|
||||
if (ret < 0)
|
||||
sys_errmsg("write");
|
||||
|
||||
if (ret == 0)
|
||||
sys_errmsg("write returned zero");
|
||||
|
||||
len -= ret;
|
||||
buf += ret;
|
||||
}
|
||||
|
||||
data_ofs = 0;
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::dump_sum_records(void)
|
||||
{
|
||||
|
||||
struct jffs2_raw_summary isum;
|
||||
struct jffs2_sum_marker *sm;
|
||||
jint32_t offset;
|
||||
jint32_t *tpage;
|
||||
char *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*)xmalloc(datasize);
|
||||
|
||||
memset(tpage, 0xff, datasize);
|
||||
memset(&isum, 0, sizeof(isum));
|
||||
|
||||
isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
|
||||
isum.totlen = cpu_to_je32(infosize);
|
||||
isum.hdr_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
|
||||
isum.padded = cpu_to_je32(0);
|
||||
|
||||
if (add_cleanmarkers && found_cleanmarkers) {
|
||||
isum.cln_mkr = cpu_to_je32(cleanmarker_size);
|
||||
} else {
|
||||
isum.cln_mkr = cpu_to_je32(0);
|
||||
}
|
||||
|
||||
isum.sum_num = cpu_to_je32(sum_collected->sum_num);
|
||||
wpage = (char*)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 = reinterpret_cast<jffs2_sum_inode_flash*>(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 = reinterpret_cast<jffs2_sum_dirent_flash*>(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 = reinterpret_cast<jffs2_sum_xattr_flash*>(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 = reinterpret_cast<jffs2_sum_xref_flash*>(wpage);
|
||||
|
||||
sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype;
|
||||
sxref_ptr->offset = sum_collected->sum_list_head->r.offset;
|
||||
|
||||
wpage += JFFS2_SUMMARY_XREF_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
default : {
|
||||
warnmsg("Unknown node type!\n");
|
||||
}
|
||||
}
|
||||
|
||||
union jffs2_sum_mem *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 = reinterpret_cast<jffs2_sum_marker*>(wpage);
|
||||
sm->offset = offset;
|
||||
sm->magic = magic;
|
||||
|
||||
isum.sum_crc = cpu_to_je32(mtd_crc32(0, tpage, datasize));
|
||||
isum.node_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(isum) - 8));
|
||||
|
||||
full_write(data_buffer + data_ofs, &isum, sizeof(isum));
|
||||
full_write(data_buffer + data_ofs, tpage, datasize);
|
||||
|
||||
free(tpage);
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::clean_sumlist(void)
|
||||
{
|
||||
if (sum_collected) {
|
||||
while (sum_collected->sum_list_head) {
|
||||
union jffs2_sum_mem *temp = sum_collected->sum_list_head;
|
||||
sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
|
||||
free(temp);
|
||||
sum_collected->sum_num--;
|
||||
}
|
||||
|
||||
if (sum_collected->sum_num != 0)
|
||||
warnmsg("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
|
||||
|
||||
free(sum_collected);
|
||||
sum_collected = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::flush_buffers(void)
|
||||
{
|
||||
|
||||
if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */
|
||||
if ((int)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 ((int)data_ofs + (int)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 ((int)data_ofs + (int)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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::create_summed_image(int inp_size)
|
||||
{
|
||||
uint8_t *p = file_buffer;
|
||||
union jffs2_node_union *node;
|
||||
uint32_t crc, length;
|
||||
uint16_t type;
|
||||
int bitchbitmask = 0;
|
||||
int obsolete;
|
||||
char name[256];
|
||||
|
||||
while ( p < (file_buffer + inp_size)) {
|
||||
|
||||
node = (union jffs2_node_union *) p;
|
||||
|
||||
/* Skip empty space */
|
||||
if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
|
||||
p += 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
|
||||
if (!bitchbitmask++)
|
||||
warnmsg("Wrong bitmask at 0x%08zx, 0x%04x\n",
|
||||
p - file_buffer, je16_to_cpu (node->u.magic));
|
||||
p += 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
bitchbitmask = 0;
|
||||
|
||||
type = je16_to_cpu(node->u.nodetype);
|
||||
if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
|
||||
obsolete = 1;
|
||||
type |= JFFS2_NODE_ACCURATE;
|
||||
} else {
|
||||
obsolete = 0;
|
||||
}
|
||||
|
||||
node->u.nodetype = cpu_to_je16(type);
|
||||
|
||||
crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
|
||||
if (crc != je32_to_cpu (node->u.hdr_crc)) {
|
||||
warnmsg("Wrong hdr_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
|
||||
p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
|
||||
p += 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (je16_to_cpu(node->u.nodetype)) {
|
||||
case JFFS2_NODETYPE_INODE:
|
||||
bareverbose(verbose,
|
||||
"%8s Inode node at 0x%08zx, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
|
||||
obsolete ? "Obsolete" : "",
|
||||
p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
|
||||
je32_to_cpu (node->i.version), je32_to_cpu (node->i.isize),
|
||||
je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
|
||||
|
||||
crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
|
||||
if (crc != je32_to_cpu (node->i.node_crc)) {
|
||||
warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
|
||||
p - file_buffer, je32_to_cpu (node->i.node_crc), crc);
|
||||
p += PAD(je32_to_cpu (node->i.totlen));
|
||||
continue;
|
||||
}
|
||||
|
||||
crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
|
||||
if (crc != je32_to_cpu(node->i.data_crc)) {
|
||||
warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
|
||||
p - file_buffer, je32_to_cpu (node->i.data_crc), crc);
|
||||
p += PAD(je32_to_cpu (node->i.totlen));
|
||||
continue;
|
||||
}
|
||||
|
||||
write_inode_to_buff(node);
|
||||
|
||||
p += PAD(je32_to_cpu (node->i.totlen));
|
||||
break;
|
||||
|
||||
case JFFS2_NODETYPE_DIRENT:
|
||||
memcpy (name, node->d.name, node->d.nsize);
|
||||
name [node->d.nsize] = 0x0;
|
||||
|
||||
bareverbose(verbose,
|
||||
"%8s Dirent node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n",
|
||||
obsolete ? "Obsolete" : "",
|
||||
p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
|
||||
je32_to_cpu (node->d.version), je32_to_cpu (node->d.ino),
|
||||
node->d.nsize, name);
|
||||
|
||||
crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
|
||||
if (crc != je32_to_cpu (node->d.node_crc)) {
|
||||
warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
|
||||
p - file_buffer, je32_to_cpu (node->d.node_crc), crc);
|
||||
p += PAD(je32_to_cpu (node->d.totlen));
|
||||
continue;
|
||||
}
|
||||
|
||||
crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
|
||||
if (crc != je32_to_cpu(node->d.name_crc)) {
|
||||
warnmsg("Wrong name_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
|
||||
p - file_buffer, je32_to_cpu (node->d.name_crc), crc);
|
||||
p += PAD(je32_to_cpu (node->d.totlen));
|
||||
continue;
|
||||
}
|
||||
|
||||
write_dirent_to_buff(node);
|
||||
|
||||
p += PAD(je32_to_cpu (node->d.totlen));
|
||||
break;
|
||||
|
||||
case JFFS2_NODETYPE_XATTR:
|
||||
if (je32_to_cpu(node->x.node_crc) == 0xffffffff)
|
||||
obsolete = 1;
|
||||
bareverbose(verbose,
|
||||
"%8s Xdatum node at 0x%08zx, totlen 0x%08x, #xid %5u, version %5u\n",
|
||||
obsolete ? "Obsolete" : "",
|
||||
p - file_buffer, je32_to_cpu (node->x.totlen),
|
||||
je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version));
|
||||
crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4);
|
||||
if (crc != je32_to_cpu(node->x.node_crc)) {
|
||||
warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
|
||||
p - file_buffer, je32_to_cpu(node->x.node_crc), crc);
|
||||
p += PAD(je32_to_cpu (node->x.totlen));
|
||||
continue;
|
||||
}
|
||||
length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len);
|
||||
crc = mtd_crc32(0, node->x.data, length);
|
||||
if (crc != je32_to_cpu(node->x.data_crc)) {
|
||||
warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
|
||||
p - file_buffer, je32_to_cpu(node->x.data_crc), crc);
|
||||
p += PAD(je32_to_cpu (node->x.totlen));
|
||||
continue;
|
||||
}
|
||||
|
||||
write_xattr_to_buff(node);
|
||||
p += PAD(je32_to_cpu (node->x.totlen));
|
||||
break;
|
||||
|
||||
case JFFS2_NODETYPE_XREF:
|
||||
if (je32_to_cpu(node->r.node_crc) == 0xffffffff)
|
||||
obsolete = 1;
|
||||
bareverbose(verbose,
|
||||
"%8s Xref node at 0x%08zx, totlen 0x%08x, #ino %5u, xid %5u\n",
|
||||
obsolete ? "Obsolete" : "",
|
||||
p - file_buffer, je32_to_cpu(node->r.totlen),
|
||||
je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid));
|
||||
crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xref) - 4);
|
||||
if (crc != je32_to_cpu(node->r.node_crc)) {
|
||||
warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
|
||||
p - file_buffer, je32_to_cpu(node->r.node_crc), crc);
|
||||
p += PAD(je32_to_cpu (node->r.totlen));
|
||||
continue;
|
||||
}
|
||||
|
||||
write_xref_to_buff(node);
|
||||
p += PAD(je32_to_cpu (node->r.totlen));
|
||||
break;
|
||||
|
||||
case JFFS2_NODETYPE_CLEANMARKER:
|
||||
bareverbose(verbose,
|
||||
"%8s Cleanmarker at 0x%08zx, totlen 0x%08x\n",
|
||||
obsolete ? "Obsolete" : "",
|
||||
p - file_buffer, je32_to_cpu (node->u.totlen));
|
||||
|
||||
if (!found_cleanmarkers) {
|
||||
found_cleanmarkers = 1;
|
||||
|
||||
if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1) {
|
||||
cleanmarker_size = je32_to_cpu (node->u.totlen);
|
||||
setup_cleanmarker();
|
||||
}
|
||||
}
|
||||
|
||||
p += PAD(je32_to_cpu (node->u.totlen));
|
||||
break;
|
||||
|
||||
case JFFS2_NODETYPE_PADDING:
|
||||
bareverbose(verbose,
|
||||
"%8s Padding node at 0x%08zx, totlen 0x%08x\n",
|
||||
obsolete ? "Obsolete" : "",
|
||||
p - file_buffer, je32_to_cpu (node->u.totlen));
|
||||
p += PAD(je32_to_cpu (node->u.totlen));
|
||||
break;
|
||||
|
||||
case 0xffff:
|
||||
p += 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
bareverbose(verbose,
|
||||
"%8s Unknown node at 0x%08zx, totlen 0x%08x\n",
|
||||
obsolete ? "Obsolete" : "",
|
||||
p - file_buffer, je32_to_cpu (node->u.totlen));
|
||||
|
||||
p += PAD(je32_to_cpu (node->u.totlen));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CSumtoolJFFS2::load_next_block(void)
|
||||
{
|
||||
int ret;
|
||||
ret = read(in_fd, file_buffer, erase_block_size);
|
||||
file_ofs = 0;
|
||||
bareverbose(verbose, "Load next block : %d bytes read\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::init_buffers(void)
|
||||
{
|
||||
if (data_buffer == NULL)
|
||||
data_buffer = (uint8_t*)xmalloc(erase_block_size);
|
||||
if (file_buffer == NULL)
|
||||
file_buffer = (uint8_t*)xmalloc(erase_block_size);
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::init_sumlist(void)
|
||||
{
|
||||
if (sum_collected == NULL)
|
||||
sum_collected = reinterpret_cast<jffs2_summary*>(xzalloc(sizeof(*sum_collected)));
|
||||
}
|
||||
|
||||
void CSumtoolJFFS2::clean_buffers(void)
|
||||
{
|
||||
if (data_buffer != NULL) {
|
||||
free(data_buffer);
|
||||
data_buffer = NULL;
|
||||
}
|
||||
if (file_buffer != NULL) {
|
||||
free(file_buffer);
|
||||
file_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CSumtoolJFFS2::sumtool(std::string& imageName,
|
||||
std::string& sumName,
|
||||
int eraseBlockSize/*=0x20000*/,
|
||||
int padTo/*=0*/,
|
||||
int addCleanmarkers/*=0*/,
|
||||
int targetEndian/*=__LITTLE_ENDIAN*/)
|
||||
{
|
||||
Init();
|
||||
|
||||
imageName_ = imageName;
|
||||
sumName_ = sumName;
|
||||
erase_block_size = eraseBlockSize; // -e
|
||||
padto = padTo; // -p
|
||||
add_cleanmarkers = addCleanmarkers; // -n
|
||||
target_endian = targetEndian; // -l
|
||||
|
||||
classInit();
|
||||
|
||||
int ret;
|
||||
while ((ret = load_next_block())) {
|
||||
create_summed_image(ret);
|
||||
}
|
||||
|
||||
flush_buffers();
|
||||
classClear();
|
||||
|
||||
printf("##### sumtool OK.\n");
|
||||
return true;
|
||||
}
|
87
src/system/mtdutils/sumtool.h
Normal file
87
src/system/mtdutils/sumtool.h
Normal file
@@ -0,0 +1,87 @@
|
||||
|
||||
#ifndef __SUMTOOL_JFFS2__
|
||||
#define __SUMTOOL_JFFS2__
|
||||
|
||||
/*
|
||||
Neutrino-HD
|
||||
|
||||
License: GPL
|
||||
|
||||
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., 51 Franklin St, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
class CSumtoolJFFS2
|
||||
{
|
||||
private:
|
||||
int verbose;
|
||||
int padto;
|
||||
int add_cleanmarkers;
|
||||
int use_input_cleanmarker_size;
|
||||
int found_cleanmarkers;
|
||||
int cleanmarker_size;
|
||||
int erase_block_size;
|
||||
int out_fd;
|
||||
int in_fd;
|
||||
uint8_t *data_buffer;
|
||||
unsigned int data_ofs;
|
||||
uint8_t *file_buffer;
|
||||
unsigned int file_ofs;
|
||||
unsigned char ffbuf[16];
|
||||
std::string imageName_, sumName_;
|
||||
|
||||
void Init();
|
||||
void classClear();
|
||||
bool classInit();
|
||||
void clean_buffers(void);
|
||||
static void init_sumlist(void);
|
||||
void init_buffers(void);
|
||||
int load_next_block(void);
|
||||
void create_summed_image(int inp_size);
|
||||
void flush_buffers(void);
|
||||
static void clean_sumlist(void);
|
||||
void dump_sum_records(void);
|
||||
void write_buff_to_file(void);
|
||||
void full_write(void *target_buff, const void *buf, int len);
|
||||
void pad(int req);
|
||||
inline void padword(void) { if (data_ofs % 4) full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4)); }
|
||||
inline void pad_block_if_less_than(int req,int plus);
|
||||
void write_xref_to_buff(union jffs2_node_union *node);
|
||||
void write_xattr_to_buff(union jffs2_node_union *node);
|
||||
void write_inode_to_buff(union jffs2_node_union *node);
|
||||
void write_dirent_to_buff(union jffs2_node_union *node);
|
||||
static int add_sum_mem(union jffs2_sum_mem *item);
|
||||
void add_sum_xref_mem(union jffs2_node_union *node);
|
||||
void add_sum_xattr_mem(union jffs2_node_union *node);
|
||||
void add_sum_dirent_mem(union jffs2_node_union *node);
|
||||
void add_sum_inode_mem(union jffs2_node_union *node);
|
||||
void setup_cleanmarker(void);
|
||||
|
||||
public:
|
||||
CSumtoolJFFS2();
|
||||
~CSumtoolJFFS2();
|
||||
|
||||
|
||||
bool sumtool(std::string& imageName,
|
||||
std::string& sumName,
|
||||
int eraseBlockSize=0x20000,
|
||||
int padTo=0,
|
||||
int addCleanmarkers=0,
|
||||
int targetEndian=__LITTLE_ENDIAN);
|
||||
};
|
||||
|
||||
#endif // __SUMTOOL_JFFS2__
|
Reference in New Issue
Block a user