aboutsummaryrefslogtreecommitdiff
path: root/jffsX-utils/sumtool.c
diff options
context:
space:
mode:
authorDongsheng Yang <yangds.fnst@cn.fujitsu.com>2015-10-31 11:12:01 +0800
committerBrian Norris <computersforpeace@gmail.com>2015-11-11 14:38:40 -0800
commit7d81790ced345585b1e647ca9d0f6678e7062fa4 (patch)
tree02f61270c7a0fff7bb6b2e28f247a3d2fd6ff490 /jffsX-utils/sumtool.c
parent344753f2aacb94d98ce238f81fc4a4b6ef6adea9 (diff)
mtd-utils: Restructure the mtd-utils source.
* There is no code modification in this commit, only moving * the files to proper place. The user tools looks a little messy as we place almost the all tools in the root directory of mtd-utils. To make it more clear, I propose to introduce the following structure for our source code. mtd-utils/ |-- lib |-- include |-- misc-utils |-- jffsX-utils |-- nand-utils |-- nor-utils |-- ubi-utils |-- ubifs-utils `-- tests Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'jffsX-utils/sumtool.c')
-rw-r--r--jffsX-utils/sumtool.c872
1 files changed, 872 insertions, 0 deletions
diff --git a/jffsX-utils/sumtool.c b/jffsX-utils/sumtool.c
new file mode 100644
index 0000000..886b545
--- /dev/null
+++ b/jffsX-utils/sumtool.c
@@ -0,0 +1,872 @@
+/*
+ * sumtool.c
+ *
+ * Copyright (C) 2004 Zoltan Sogor <weth@inf.u-szeged.hu>,
+ * Ferenc Havasi <havasi@inf.u-szeged.hu>
+ * University of Szeged, Hungary
+ * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Overview:
+ * This is a utility insert summary information into JFFS2 image for
+ * faster mount time
+ *
+ */
+
+#define PROGRAM_NAME "sumtool"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <asm/types.h>
+#include <dirent.h>
+#include <mtd/jffs2-user.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <getopt.h>
+#include <crc32.h>
+#include "summary.h"
+#include "common.h"
+
+#define PAD(x) (((x)+3)&~3)
+
+static struct jffs2_summary *sum_collected = NULL;
+
+static int verbose = 0;
+static int padto = 0; /* pad the output with 0xFF to the end of the final eraseblock */
+static int add_cleanmarkers = 1; /* add cleanmarker to output */
+static int use_input_cleanmarker_size = 1; /* use input file's cleanmarker size (default) */
+static int found_cleanmarkers = 0; /* cleanmarker found in input file */
+static struct jffs2_unknown_node cleanmarker;
+static int cleanmarker_size = sizeof(cleanmarker);
+static const char *short_options = "o:i:e:hvVblnc:p";
+static int erase_block_size = 65536;
+static int out_fd = -1;
+static int in_fd = -1;
+
+static uint8_t *data_buffer = NULL; /* buffer for inodes */
+static unsigned int data_ofs = 0; /* inode buffer offset */
+
+static uint8_t *file_buffer = NULL; /* file buffer contains the actual erase block*/
+static unsigned int file_ofs = 0; /* position in the buffer */
+
+int target_endian = __BYTE_ORDER;
+
+static struct option long_options[] = {
+ {"output", 1, NULL, 'o'},
+ {"input", 1, NULL, 'i'},
+ {"eraseblock", 1, NULL, 'e'},
+ {"help", 0, NULL, 'h'},
+ {"verbose", 0, NULL, 'v'},
+ {"version", 0, NULL, 'V'},
+ {"bigendian", 0, NULL, 'b'},
+ {"littleendian", 0, NULL, 'l'},
+ {"no-cleanmarkers", 0, NULL, 'n'},
+ {"cleanmarker", 1, NULL, 'c'},
+ {"pad", 0, NULL, 'p'},
+ {NULL, 0, NULL, 0}
+};
+
+static const char helptext[] =
+"Usage: sumtool [OPTIONS] -i inputfile -o outputfile\n\n"
+"Convert the input JFFS2 image to a summarized JFFS2 image\n"
+"Summary makes mounting faster - if summary support enabled in your kernel\n\n"
+"Options:\n"
+" -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)\n"
+" (usually 16KiB on NAND)\n"
+" -c, --cleanmarker=SIZE Size of cleanmarker (default 12).\n"
+" (usually 16 bytes on NAND, and will be set to\n"
+" this value if left at the default 12). Will be\n"
+" stored in OOB after each physical page composing\n"
+" a physical eraseblock.\n"
+" -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock\n"
+" -o, --output=FILE Output to FILE \n"
+" -i, --input=FILE Input from FILE \n"
+" -b, --bigendian Image is big endian\n"
+" -l --littleendian Image is little endian\n"
+" -h, --help Display this help text\n"
+" -v, --verbose Verbose operation\n"
+" -V, --version Display version information\n"
+" -p, --pad Pad the OUTPUT with 0xFF to the end of the final\n"
+" eraseblock\n\n";
+
+
+static const char revtext[] = "$Revision: 1.9 $";
+
+static unsigned char ffbuf[16] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static void full_write(void *target_buff, const void *buf, int len);
+
+void setup_cleanmarker(void)
+{
+ cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
+ cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
+ cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
+}
+
+void process_options (int argc, char **argv)
+{
+ int opt,c;
+
+ while ((opt = getopt_long(argc, argv, short_options, long_options, &c)) >= 0) {
+ switch (opt) {
+ case 'o':
+ if (out_fd != -1)
+ errmsg_die("output filename specified more than once");
+ out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
+ if (out_fd == -1)
+ sys_errmsg_die("open output file");
+ break;
+
+ case 'i':
+ if (in_fd != -1)
+ errmsg_die("input filename specified more than once");
+ in_fd = open(optarg, O_RDONLY);
+ if (in_fd == -1)
+ sys_errmsg_die("open input file");
+ break;
+ case 'b':
+ target_endian = __BIG_ENDIAN;
+ break;
+ case 'l':
+ target_endian = __LITTLE_ENDIAN;
+ break;
+ case 'h':
+ case '?':
+ errmsg_die("%s", helptext);
+ case 'v':
+ verbose = 1;
+ break;
+
+ case 'V':
+ errmsg_die("revision %.*s\n",
+ (int) strlen(revtext) - 13, revtext + 11);
+
+ case 'e': {
+ char *next;
+ unsigned units = 0;
+ erase_block_size = strtol(optarg, &next, 0);
+ if (!erase_block_size)
+ errmsg_die("Unrecognisable erase size\n");
+
+ if (*next) {
+ if (!strcmp(next, "KiB")) {
+ units = 1024;
+ } else if (!strcmp(next, "MiB")) {
+ units = 1024 * 1024;
+ } else {
+ errmsg_die("Unknown units in erasesize\n");
+ }
+ } else {
+ if (erase_block_size < 0x1000)
+ units = 1024;
+ else
+ units = 1;
+ }
+ erase_block_size *= units;
+
+ /* If it's less than 8KiB, they're not allowed */
+ if (erase_block_size < 0x2000) {
+ warnmsg("Erase size 0x%x too small. Increasing to 8KiB minimum\n",
+ erase_block_size);
+ erase_block_size = 0x2000;
+ }
+ break;
+ }
+
+ case 'n':
+ add_cleanmarkers = 0;
+ break;
+ case 'c':
+ cleanmarker_size = strtol(optarg, NULL, 0);
+
+ if (cleanmarker_size < sizeof(cleanmarker)) {
+ errmsg_die("cleanmarker size must be >= 12");
+ }
+ if (cleanmarker_size >= erase_block_size) {
+ errmsg_die("cleanmarker size must be < eraseblock size");
+ }
+
+ use_input_cleanmarker_size = 0;
+ found_cleanmarkers = 1;
+ setup_cleanmarker();
+
+ break;
+ case 'p':
+ padto = 1;
+ break;
+ }
+ }
+}
+
+
+void init_buffers(void)
+{
+ data_buffer = xmalloc(erase_block_size);
+ file_buffer = xmalloc(erase_block_size);
+}
+
+void init_sumlist(void)
+{
+ sum_collected = xzalloc(sizeof(*sum_collected));
+}
+
+void clean_buffers(void)
+{
+ free(data_buffer);
+ free(file_buffer);
+}
+
+void clean_sumlist(void)
+{
+ union jffs2_sum_mem *temp;
+
+ if (sum_collected) {
+
+ while (sum_collected->sum_list_head) {
+ temp = sum_collected->sum_list_head;
+ sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+ free(temp);
+ sum_collected->sum_num--;
+ }
+
+ if (sum_collected->sum_num != 0)
+ warnmsg("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
+
+ free(sum_collected);
+ }
+}
+
+int load_next_block(void)
+{
+ int ret;
+ ret = read(in_fd, file_buffer, erase_block_size);
+ file_ofs = 0;
+
+ bareverbose(verbose, "Load next block : %d bytes read\n", ret);
+
+ return ret;
+}
+
+void write_buff_to_file(void)
+{
+ int ret;
+ int len = data_ofs;
+
+ uint8_t *buf = NULL;
+
+ buf = data_buffer;
+ while (len > 0) {
+ ret = write(out_fd, buf, len);
+
+ if (ret < 0)
+ sys_errmsg_die("write");
+
+ if (ret == 0)
+ sys_errmsg_die("write returned zero");
+
+ len -= ret;
+ buf += ret;
+ }
+
+ data_ofs = 0;
+}
+
+void dump_sum_records(void)
+{
+
+ struct jffs2_raw_summary isum;
+ struct jffs2_sum_marker *sm;
+ union jffs2_sum_mem *temp;
+ jint32_t offset;
+ jint32_t *tpage;
+ void *wpage;
+ int datasize, infosize, padsize;
+ jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
+
+ if (!sum_collected->sum_num || !sum_collected->sum_list_head)
+ return;
+
+ datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
+ infosize = sizeof(struct jffs2_raw_summary) + datasize;
+ padsize = erase_block_size - data_ofs - infosize;
+ infosize += padsize; datasize += padsize;
+ offset = cpu_to_je32(data_ofs);
+
+ tpage = xmalloc(datasize);
+
+ memset(tpage, 0xff, datasize);
+ memset(&isum, 0, sizeof(isum));
+
+ isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
+ isum.totlen = cpu_to_je32(infosize);
+ isum.hdr_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
+ isum.padded = cpu_to_je32(0);
+
+ if (add_cleanmarkers && found_cleanmarkers) {
+ isum.cln_mkr = cpu_to_je32(cleanmarker_size);
+ } else {
+ isum.cln_mkr = cpu_to_je32(0);
+ }
+
+ isum.sum_num = cpu_to_je32(sum_collected->sum_num);
+ wpage = tpage;
+
+ while (sum_collected->sum_num) {
+ switch(je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) {
+
+ case JFFS2_NODETYPE_INODE : {
+ struct jffs2_sum_inode_flash *sino_ptr = wpage;
+
+ sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype;
+ sino_ptr->inode = sum_collected->sum_list_head->i.inode;
+ sino_ptr->version = sum_collected->sum_list_head->i.version;
+ sino_ptr->offset = sum_collected->sum_list_head->i.offset;
+ sino_ptr->totlen = sum_collected->sum_list_head->i.totlen;
+
+ wpage += JFFS2_SUMMARY_INODE_SIZE;
+ break;
+ }
+
+ case JFFS2_NODETYPE_DIRENT : {
+ struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
+
+ sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype;
+ sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen;
+ sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset;
+ sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino;
+ sdrnt_ptr->version = sum_collected->sum_list_head->d.version;
+ sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino;
+ sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize;
+ sdrnt_ptr->type = sum_collected->sum_list_head->d.type;
+
+ memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name,
+ sum_collected->sum_list_head->d.nsize);
+
+ wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize);
+ break;
+ }
+
+ case JFFS2_NODETYPE_XATTR: {
+ struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
+
+ sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype;
+ sxattr_ptr->xid = sum_collected->sum_list_head->x.xid;
+ sxattr_ptr->version = sum_collected->sum_list_head->x.version;
+ sxattr_ptr->offset = sum_collected->sum_list_head->x.offset;
+ sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen;
+
+ wpage += JFFS2_SUMMARY_XATTR_SIZE;
+ break;
+ }
+
+ case JFFS2_NODETYPE_XREF: {
+ struct jffs2_sum_xref_flash *sxref_ptr = wpage;
+
+ sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype;
+ sxref_ptr->offset = sum_collected->sum_list_head->r.offset;
+
+ wpage += JFFS2_SUMMARY_XREF_SIZE;
+ break;
+ }
+
+ default : {
+ warnmsg("Unknown node type!\n");
+ }
+ }
+
+ temp = sum_collected->sum_list_head;
+ sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+ free(temp);
+
+ sum_collected->sum_num--;
+ }
+
+ sum_collected->sum_size = 0;
+ sum_collected->sum_num = 0;
+ sum_collected->sum_list_tail = NULL;
+
+ wpage += padsize;
+
+ sm = wpage;
+ sm->offset = offset;
+ sm->magic = magic;
+
+ isum.sum_crc = cpu_to_je32(mtd_crc32(0, tpage, datasize));
+ isum.node_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(isum) - 8));
+
+ full_write(data_buffer + data_ofs, &isum, sizeof(isum));
+ full_write(data_buffer + data_ofs, tpage, datasize);
+
+ free(tpage);
+}
+
+static void full_write(void *target_buff, const void *buf, int len)
+{
+ memcpy(target_buff, buf, len);
+ data_ofs += len;
+}
+
+static void pad(int req)
+{
+ while (req) {
+ if (req > sizeof(ffbuf)) {
+ full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf));
+ req -= sizeof(ffbuf);
+ } else {
+ full_write(data_buffer + data_ofs, ffbuf, req);
+ req = 0;
+ }
+ }
+}
+
+static inline void padword(void)
+{
+ if (data_ofs % 4)
+ full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4));
+}
+
+
+static inline void pad_block_if_less_than(int req,int plus)
+{
+
+ int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+ datasize += (4 - (datasize % 4)) % 4;
+
+ if (data_ofs + req > erase_block_size - datasize) {
+ dump_sum_records();
+ write_buff_to_file();
+ }
+
+ if (add_cleanmarkers && found_cleanmarkers) {
+ if (!data_ofs) {
+ full_write(data_buffer, &cleanmarker, sizeof(cleanmarker));
+ pad(cleanmarker_size - sizeof(cleanmarker));
+ padword();
+ }
+ }
+}
+
+void flush_buffers(void)
+{
+
+ if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */
+ if (data_ofs != cleanmarker_size) { /* INODE BUFFER */
+
+ int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+ datasize += (4 - (datasize % 4)) % 4;
+
+ /* If we have a full inode buffer, then write out inode and summary data */
+ if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+ dump_sum_records();
+ write_buff_to_file();
+ } else { /* else just write out inode data */
+ if (padto)
+ pad(erase_block_size - data_ofs);
+ write_buff_to_file();
+ }
+ }
+ } else { /* NO CLEANMARKER */
+ if (data_ofs != 0) { /* INODE BUFFER */
+
+ int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+ datasize += (4 - (datasize % 4)) % 4;
+
+ /* If we have a full inode buffer, then write out inode and summary data */
+ if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+ dump_sum_records();
+ write_buff_to_file();
+ } else { /* Else just write out inode data */
+ if(padto)
+ pad(erase_block_size - data_ofs);
+ write_buff_to_file();
+ }
+ }
+ }
+}
+
+int add_sum_mem(union jffs2_sum_mem *item)
+{
+
+ if (!sum_collected->sum_list_head)
+ sum_collected->sum_list_head = (union jffs2_sum_mem *) item;
+ if (sum_collected->sum_list_tail)
+ sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
+ sum_collected->sum_list_tail = (union jffs2_sum_mem *) item;
+
+ switch (je16_to_cpu(item->u.nodetype)) {
+ case JFFS2_NODETYPE_INODE:
+ sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
+ sum_collected->sum_num++;
+ break;
+
+ case JFFS2_NODETYPE_DIRENT:
+ sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
+ sum_collected->sum_num++;
+ break;
+
+ case JFFS2_NODETYPE_XATTR:
+ sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
+ sum_collected->sum_num++;
+ break;
+
+ case JFFS2_NODETYPE_XREF:
+ sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE;
+ sum_collected->sum_num++;
+ break;
+
+ default:
+ errmsg_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
+ }
+ return 0;
+}
+
+void add_sum_inode_mem(union jffs2_node_union *node)
+{
+ struct jffs2_sum_inode_mem *temp = xmalloc(sizeof(*temp));
+
+ temp->nodetype = node->i.nodetype;
+ temp->inode = node->i.ino;
+ temp->version = node->i.version;
+ temp->offset = cpu_to_je32(data_ofs);
+ temp->totlen = node->i.totlen;
+ temp->next = NULL;
+
+ add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_dirent_mem(union jffs2_node_union *node)
+{
+ struct jffs2_sum_dirent_mem *temp = xmalloc(sizeof(*temp) + node->d.nsize);
+
+ temp->nodetype = node->d.nodetype;
+ temp->totlen = node->d.totlen;
+ temp->offset = cpu_to_je32(data_ofs);
+ temp->pino = node->d.pino;
+ temp->version = node->d.version;
+ temp->ino = node->d.ino;
+ temp->nsize = node->d.nsize;
+ temp->type = node->d.type;
+ temp->next = NULL;
+
+ memcpy(temp->name,node->d.name,node->d.nsize);
+ add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_xattr_mem(union jffs2_node_union *node)
+{
+ struct jffs2_sum_xattr_mem *temp = xmalloc(sizeof(*temp));
+
+ temp->nodetype = node->x.nodetype;
+ temp->xid = node->x.xid;
+ temp->version = node->x.version;
+ temp->offset = cpu_to_je32(data_ofs);
+ temp->totlen = node->x.totlen;
+ temp->next = NULL;
+
+ add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_xref_mem(union jffs2_node_union *node)
+{
+ struct jffs2_sum_xref_mem *temp = xmalloc(sizeof(*temp));
+
+ temp->nodetype = node->r.nodetype;
+ temp->offset = cpu_to_je32(data_ofs);
+ temp->next = NULL;
+
+ add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void write_dirent_to_buff(union jffs2_node_union *node)
+{
+ pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize));
+ add_sum_dirent_mem(node);
+ full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen));
+ padword();
+}
+
+
+void write_inode_to_buff(union jffs2_node_union *node)
+{
+ pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE);
+ add_sum_inode_mem(node); /* Add inode summary mem to summary list */
+ full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen)); /* Write out the inode to inode_buffer */
+ padword();
+}
+
+void write_xattr_to_buff(union jffs2_node_union *node)
+{
+ pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE);
+ add_sum_xattr_mem(node); /* Add xdatum summary mem to summary list */
+ full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen));
+ padword();
+}
+
+void write_xref_to_buff(union jffs2_node_union *node)
+{
+ pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE);
+ add_sum_xref_mem(node); /* Add xref summary mem to summary list */
+ full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen));
+ padword();
+}
+
+void create_summed_image(int inp_size)
+{
+ uint8_t *p = file_buffer;
+ union jffs2_node_union *node;
+ uint32_t crc, length;
+ uint16_t type;
+ int bitchbitmask = 0;
+ int obsolete;
+ char name[256];
+
+ while ( p < (file_buffer + inp_size)) {
+
+ node = (union jffs2_node_union *) p;
+
+ /* Skip empty space */
+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+ p += 4;
+ continue;
+ }
+
+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
+ if (!bitchbitmask++)
+ warnmsg("Wrong bitmask at 0x%08zx, 0x%04x\n",
+ p - file_buffer, je16_to_cpu (node->u.magic));
+ p += 4;
+ continue;
+ }
+
+ bitchbitmask = 0;
+
+ type = je16_to_cpu(node->u.nodetype);
+ if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+ obsolete = 1;
+ type |= JFFS2_NODE_ACCURATE;
+ } else {
+ obsolete = 0;
+ }
+
+ node->u.nodetype = cpu_to_je16(type);
+
+ crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+ if (crc != je32_to_cpu (node->u.hdr_crc)) {
+ warnmsg("Wrong hdr_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
+ p += 4;
+ continue;
+ }
+
+ switch(je16_to_cpu(node->u.nodetype)) {
+ case JFFS2_NODETYPE_INODE:
+ bareverbose(verbose,
+ "%8s Inode node at 0x%08zx, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+ je32_to_cpu (node->i.version), je32_to_cpu (node->i.isize),
+ je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+ crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
+ if (crc != je32_to_cpu (node->i.node_crc)) {
+ warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu (node->i.node_crc), crc);
+ p += PAD(je32_to_cpu (node->i.totlen));
+ continue;
+ }
+
+ crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
+ if (crc != je32_to_cpu(node->i.data_crc)) {
+ warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu (node->i.data_crc), crc);
+ p += PAD(je32_to_cpu (node->i.totlen));
+ continue;
+ }
+
+ write_inode_to_buff(node);
+
+ p += PAD(je32_to_cpu (node->i.totlen));
+ break;
+
+ case JFFS2_NODETYPE_DIRENT:
+ memcpy (name, node->d.name, node->d.nsize);
+ name [node->d.nsize] = 0x0;
+
+ bareverbose(verbose,
+ "%8s Dirent node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+ je32_to_cpu (node->d.version), je32_to_cpu (node->d.ino),
+ node->d.nsize, name);
+
+ crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
+ if (crc != je32_to_cpu (node->d.node_crc)) {
+ warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu (node->d.node_crc), crc);
+ p += PAD(je32_to_cpu (node->d.totlen));
+ continue;
+ }
+
+ crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
+ if (crc != je32_to_cpu(node->d.name_crc)) {
+ warnmsg("Wrong name_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu (node->d.name_crc), crc);
+ p += PAD(je32_to_cpu (node->d.totlen));
+ continue;
+ }
+
+ write_dirent_to_buff(node);
+
+ p += PAD(je32_to_cpu (node->d.totlen));
+ break;
+
+ case JFFS2_NODETYPE_XATTR:
+ if (je32_to_cpu(node->x.node_crc) == 0xffffffff)
+ obsolete = 1;
+ bareverbose(verbose,
+ "%8s Xdatum node at 0x%08zx, totlen 0x%08x, #xid %5u, version %5u\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->x.totlen),
+ je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version));
+ crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4);
+ if (crc != je32_to_cpu(node->x.node_crc)) {
+ warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu(node->x.node_crc), crc);
+ p += PAD(je32_to_cpu (node->x.totlen));
+ continue;
+ }
+ length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len);
+ crc = mtd_crc32(0, node->x.data, length);
+ if (crc != je32_to_cpu(node->x.data_crc)) {
+ warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu(node->x.data_crc), crc);
+ p += PAD(je32_to_cpu (node->x.totlen));
+ continue;
+ }
+
+ write_xattr_to_buff(node);
+ p += PAD(je32_to_cpu (node->x.totlen));
+ break;
+
+ case JFFS2_NODETYPE_XREF:
+ if (je32_to_cpu(node->r.node_crc) == 0xffffffff)
+ obsolete = 1;
+ bareverbose(verbose,
+ "%8s Xref node at 0x%08zx, totlen 0x%08x, #ino %5u, xid %5u\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu(node->r.totlen),
+ je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid));
+ crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xref) - 4);
+ if (crc != je32_to_cpu(node->r.node_crc)) {
+ warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu(node->r.node_crc), crc);
+ p += PAD(je32_to_cpu (node->r.totlen));
+ continue;
+ }
+
+ write_xref_to_buff(node);
+ p += PAD(je32_to_cpu (node->r.totlen));
+ break;
+
+ case JFFS2_NODETYPE_CLEANMARKER:
+ bareverbose(verbose,
+ "%8s Cleanmarker at 0x%08zx, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->u.totlen));
+
+ if (!found_cleanmarkers) {
+ found_cleanmarkers = 1;
+
+ if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){
+ cleanmarker_size = je32_to_cpu (node->u.totlen);
+ setup_cleanmarker();
+ }
+ }
+
+ p += PAD(je32_to_cpu (node->u.totlen));
+ break;
+
+ case JFFS2_NODETYPE_PADDING:
+ bareverbose(verbose,
+ "%8s Padding node at 0x%08zx, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->u.totlen));
+ p += PAD(je32_to_cpu (node->u.totlen));
+ break;
+
+ case 0xffff:
+ p += 4;
+ break;
+
+ default:
+ bareverbose(verbose,
+ "%8s Unknown node at 0x%08zx, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->u.totlen));
+
+ p += PAD(je32_to_cpu (node->u.totlen));
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ process_options(argc,argv);
+
+ if ((in_fd == -1) || (out_fd == -1)) {
+ if(in_fd != -1)
+ close(in_fd);
+ if(out_fd != -1)
+ close(out_fd);
+ fprintf(stderr, "%s", helptext);
+ errmsg_die("You must specify input and output files!\n");
+ }
+
+ init_buffers();
+ init_sumlist();
+
+ while ((ret = load_next_block())) {
+ create_summed_image(ret);
+ }
+
+ flush_buffers();
+ clean_buffers();
+ clean_sumlist();
+
+ if (in_fd != -1)
+ close(in_fd);
+ if (out_fd != -1)
+ close(out_fd);
+
+ return 0;
+}