diff options
author | Dongsheng Yang <yangds.fnst@cn.fujitsu.com> | 2015-10-31 11:12:01 +0800 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2015-11-11 14:38:40 -0800 |
commit | 7d81790ced345585b1e647ca9d0f6678e7062fa4 (patch) | |
tree | 02f61270c7a0fff7bb6b2e28f247a3d2fd6ff490 /jffsX-utils/jffs2dump.c | |
parent | 344753f2aacb94d98ce238f81fc4a4b6ef6adea9 (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/jffs2dump.c')
-rw-r--r-- | jffsX-utils/jffs2dump.c | 805 |
1 files changed, 805 insertions, 0 deletions
diff --git a/jffsX-utils/jffs2dump.c b/jffsX-utils/jffs2dump.c new file mode 100644 index 0000000..f8b8ac7 --- /dev/null +++ b/jffsX-utils/jffs2dump.c @@ -0,0 +1,805 @@ +/* + * dumpjffs2.c + * + * Copyright (C) 2003 Thomas Gleixner (tglx@linutronix.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Overview: + * This utility dumps the contents of a binary JFFS2 image + * + * + * Bug/ToDo: + */ + +#define PROGRAM_NAME "jffs2dump" + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <asm/types.h> +#include <dirent.h> +#include <mtd/jffs2-user.h> +#include <endian.h> +#include <byteswap.h> +#include <getopt.h> +#include <crc32.h> +#include "summary.h" +#include "common.h" + +#define PAD(x) (((x)+3)&~3) + +/* For outputting a byte-swapped version of the input image. */ +#define cnv_e32(x) ((jint32_t){bswap_32(x.v32)}) +#define cnv_e16(x) ((jint16_t){bswap_16(x.v16)}) + +#define t32_backwards(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?bswap_32(__b):__b; }) +#define cpu_to_e32(x) ((jint32_t){t32_backwards(x)}) + +// Global variables +long imglen; // length of image +char *data; // image data + +void display_help (void) +{ + printf("Usage: %s [OPTION]... INPUTFILE\n" + "Dump the contents of a binary JFFS2 image.\n\n" + " --help display this help and exit\n" + " --version display version information and exit\n" + " -b, --bigendian image is big endian\n" + " -l, --littleendian image is little endian\n" + " -c, --content dump image contents\n" + " -e, --endianconvert=FNAME convert image endianness, output to file fname\n" + " -r, --recalccrc recalc name and data crc on endian conversion\n" + " -d, --datsize=LEN size of data chunks, when oob data in binary image (NAND only)\n" + " -o, --oobsize=LEN size of oob data chunk in binary image (NAND only)\n" + " -v, --verbose verbose output\n", + PROGRAM_NAME); + exit(0); +} + +void display_version (void) +{ + printf("%1$s " VERSION "\n" + "\n" + "Copyright (C) 2003 Thomas Gleixner \n" + "\n" + "%1$s comes with NO WARRANTY\n" + "to the extent permitted by law.\n" + "\n" + "You may redistribute copies of %1$s\n" + "under the terms of the GNU General Public Licence.\n" + "See the file `COPYING' for more information.\n", + PROGRAM_NAME); + exit(0); +} + +// Option variables + +int verbose; // verbose output +char *img; // filename of image +int dumpcontent; // dump image content +int target_endian = __BYTE_ORDER; // image endianess +int convertendian; // convert endianness +int recalccrc; // recalc name and data crc's on endian conversion +char cnvfile[256]; // filename for conversion output +int datsize; // Size of data chunks, when oob data is inside the binary image +int oobsize; // Size of oob chunks, when oob data is inside the binary image + +void process_options (int argc, char *argv[]) +{ + int error = 0; + + for (;;) { + int option_index = 0; + static const char *short_options = "blce:rd:o:v"; + static const struct option long_options[] = { + {"help", no_argument, 0, 0}, + {"version", no_argument, 0, 0}, + {"bigendian", no_argument, 0, 'b'}, + {"littleendian", no_argument, 0, 'l'}, + {"content", no_argument, 0, 'c'}, + {"endianconvert", required_argument, 0, 'e'}, + {"datsize", required_argument, 0, 'd'}, + {"oobsize", required_argument, 0, 'o'}, + {"recalccrc", required_argument, 0, 'r'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0}, + }; + + int c = getopt_long(argc, argv, short_options, + long_options, &option_index); + if (c == EOF) { + break; + } + + switch (c) { + case 0: + switch (option_index) { + case 0: + display_help(); + break; + case 1: + display_version(); + break; + } + break; + case 'v': + verbose = 1; + break; + case 'b': + target_endian = __BIG_ENDIAN; + break; + case 'l': + target_endian = __LITTLE_ENDIAN; + break; + case 'c': + dumpcontent = 1; + break; + case 'd': + datsize = atoi(optarg); + break; + case 'o': + oobsize = atoi(optarg); + break; + case 'e': + convertendian = 1; + strcpy (cnvfile, optarg); + break; + case 'r': + recalccrc = 1; + break; + case '?': + error = 1; + break; + } + } + + if ((argc - optind) != 1 || error) + display_help (); + + img = argv[optind]; +} + + +/* + * Dump image contents + */ +void do_dumpcontent (void) +{ + char *p = data, *p_free_begin; + union jffs2_node_union *node; + int empty = 0, dirty = 0; + char name[256]; + uint32_t crc; + uint16_t type; + int bitchbitmask = 0; + int obsolete; + + p_free_begin = NULL; + while ( p < (data + imglen)) { + node = (union jffs2_node_union*) p; + + /* Skip empty space */ + if (!p_free_begin) + p_free_begin = p; + if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) { + p += 4; + empty += 4; + continue; + } + + if (p != p_free_begin) + printf("Empty space found from 0x%08zx to 0x%08zx\n", p_free_begin-data, p-data); + p_free_begin = NULL; + + if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) { + if (!bitchbitmask++) + printf ("Wrong bitmask at 0x%08zx, 0x%04x\n", p - data, je16_to_cpu (node->u.magic)); + p += 4; + dirty += 4; + continue; + } + bitchbitmask = 0; + + type = je16_to_cpu(node->u.nodetype); + if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) { + obsolete = 1; + type |= JFFS2_NODE_ACCURATE; + } else + obsolete = 0; + /* Set accurate for CRC check */ + node->u.nodetype = cpu_to_je16(type); + + crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4); + if (crc != je32_to_cpu (node->u.hdr_crc)) { + printf ("Wrong hdr_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc); + p += 4; + dirty += 4; + continue; + } + + switch(je16_to_cpu(node->u.nodetype)) { + + case JFFS2_NODETYPE_INODE: + printf ("%8s Inode node at 0x%08zx, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n", + obsolete ? "Obsolete" : "", + p - data, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino), + je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize), + je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset)); + + crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8); + if (crc != je32_to_cpu (node->i.node_crc)) { + printf ("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.node_crc), crc); + p += PAD(je32_to_cpu (node->i.totlen)); + dirty += PAD(je32_to_cpu (node->i.totlen));; + continue; + } + + crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize)); + if (crc != je32_to_cpu(node->i.data_crc)) { + printf ("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.data_crc), crc); + p += PAD(je32_to_cpu (node->i.totlen)); + dirty += PAD(je32_to_cpu (node->i.totlen));; + continue; + } + + p += PAD(je32_to_cpu (node->i.totlen)); + break; + + case JFFS2_NODETYPE_DIRENT: + memcpy (name, node->d.name, node->d.nsize); + name [node->d.nsize] = 0x0; + printf ("%8s Dirent node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n", + obsolete ? "Obsolete" : "", + p - data, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino), + je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino), + node->d.nsize, name); + + crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8); + if (crc != je32_to_cpu (node->d.node_crc)) { + printf ("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.node_crc), crc); + p += PAD(je32_to_cpu (node->d.totlen)); + dirty += PAD(je32_to_cpu (node->d.totlen));; + continue; + } + + crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize); + if (crc != je32_to_cpu(node->d.name_crc)) { + printf ("Wrong name_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.name_crc), crc); + p += PAD(je32_to_cpu (node->d.totlen)); + dirty += PAD(je32_to_cpu (node->d.totlen));; + continue; + } + + p += PAD(je32_to_cpu (node->d.totlen)); + break; + + case JFFS2_NODETYPE_XATTR: + memcpy(name, node->x.data, node->x.name_len); + name[node->x.name_len] = '\x00'; + printf ("%8s Xattr node at 0x%08zx, totlen 0x%08x, xid %5d, version %5d, name_len %3d, name %s\n", + obsolete ? "Obsolete" : "", + p - data, + je32_to_cpu (node->x.totlen), + je32_to_cpu (node->x.xid), + je32_to_cpu (node->x.version), + node->x.name_len, + name); + + crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_xattr) - sizeof (node->x.node_crc)); + if (crc != je32_to_cpu (node->x.node_crc)) { + printf ("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->x.node_crc), crc); + p += PAD(je32_to_cpu (node->x.totlen)); + dirty += PAD(je32_to_cpu (node->x.totlen)); + continue; + } + + crc = mtd_crc32 (0, p + sizeof (struct jffs2_raw_xattr), node->x.name_len + je16_to_cpu (node->x.value_len) + 1); + if (crc != je32_to_cpu (node->x.data_crc)) { + printf ("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->x.data_crc), crc); + p += PAD(je32_to_cpu (node->x.totlen)); + dirty += PAD(je32_to_cpu (node->x.totlen)); + continue; + } + p += PAD(je32_to_cpu (node->x.totlen)); + break; + + case JFFS2_NODETYPE_XREF: + printf ("%8s Xref node at 0x%08zx, totlen 0x%08x, xid %5d, xseqno %5d, #ino %8d\n", + obsolete ? "Obsolete" : "", + p - data, + je32_to_cpu (node->r.totlen), + je32_to_cpu (node->r.xid), + je32_to_cpu (node->r.xseqno), + je32_to_cpu (node->r.ino)); + p += PAD(je32_to_cpu (node->r.totlen)); + break; + + case JFFS2_NODETYPE_SUMMARY: { + + int i; + struct jffs2_sum_marker * sm; + + printf("%8s Inode Sum node at 0x%08zx, totlen 0x%08x, sum_num %5d, cleanmarker size %5d\n", + obsolete ? "Obsolete" : "", + p - data, + je32_to_cpu (node->s.totlen), + je32_to_cpu (node->s.sum_num), + je32_to_cpu (node->s.cln_mkr)); + + crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_summary) - 8); + if (crc != je32_to_cpu (node->s.node_crc)) { + printf ("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.node_crc), crc); + p += PAD(je32_to_cpu (node->s.totlen)); + dirty += PAD(je32_to_cpu (node->s.totlen));; + continue; + } + + crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_summary), je32_to_cpu (node->s.totlen) - sizeof(struct jffs2_raw_summary)); + if (crc != je32_to_cpu(node->s.sum_crc)) { + printf ("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.sum_crc), crc); + p += PAD(je32_to_cpu (node->s.totlen)); + dirty += PAD(je32_to_cpu (node->s.totlen));; + continue; + } + + if (verbose) { + void *sp; + sp = (p + sizeof(struct jffs2_raw_summary)); + + for(i=0; i<je32_to_cpu(node->s.sum_num); i++) { + + switch(je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { + case JFFS2_NODETYPE_INODE : { + + struct jffs2_sum_inode_flash *spi; + spi = sp; + + printf ("%14s #ino %5d, version %5d, offset 0x%08x, totlen 0x%08x\n", + "", + je32_to_cpu (spi->inode), + je32_to_cpu (spi->version), + je32_to_cpu (spi->offset), + je32_to_cpu (spi->totlen)); + + sp += JFFS2_SUMMARY_INODE_SIZE; + break; + } + + case JFFS2_NODETYPE_DIRENT : { + + char name[255]; + struct jffs2_sum_dirent_flash *spd; + spd = sp; + + memcpy(name,spd->name,spd->nsize); + name [spd->nsize] = 0x0; + + printf ("%14s dirent offset 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s \n", + "", + je32_to_cpu (spd->offset), + je32_to_cpu (spd->totlen), + je32_to_cpu (spd->pino), + je32_to_cpu (spd->version), + je32_to_cpu (spd->ino), + spd->nsize, + name); + + sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); + break; + } + + case JFFS2_NODETYPE_XATTR : { + struct jffs2_sum_xattr_flash *spx; + spx = sp; + printf ("%14s Xattr offset 0x%08x, totlen 0x%08x, version %5d, #xid %8d\n", + "", + je32_to_cpu (spx->offset), + je32_to_cpu (spx->totlen), + je32_to_cpu (spx->version), + je32_to_cpu (spx->xid)); + sp += JFFS2_SUMMARY_XATTR_SIZE; + break; + } + + case JFFS2_NODETYPE_XREF : { + struct jffs2_sum_xref_flash *spr; + spr = sp; + printf ("%14s Xref offset 0x%08x\n", + "", + je32_to_cpu (spr->offset)); + sp += JFFS2_SUMMARY_XREF_SIZE; + break; + } + + default : + printf("Unknown summary node!\n"); + break; + } + } + + sm = (struct jffs2_sum_marker *) ((char *)p + je32_to_cpu(node->s.totlen) - sizeof(struct jffs2_sum_marker)); + + printf("%14s Sum Node Offset 0x%08x, Magic 0x%08x, Padded size 0x%08x\n", + "", + je32_to_cpu(sm->offset), + je32_to_cpu(sm->magic), + je32_to_cpu(node->s.padded)); + } + + p += PAD(je32_to_cpu (node->s.totlen)); + break; + } + + case JFFS2_NODETYPE_CLEANMARKER: + if (verbose) { + printf ("%8s Cleanmarker at 0x%08zx, totlen 0x%08x\n", + obsolete ? "Obsolete" : "", + p - data, je32_to_cpu (node->u.totlen)); + } + p += PAD(je32_to_cpu (node->u.totlen)); + break; + + case JFFS2_NODETYPE_PADDING: + if (verbose) { + printf ("%8s Padding node at 0x%08zx, totlen 0x%08x\n", + obsolete ? "Obsolete" : "", + p - data, je32_to_cpu (node->u.totlen)); + } + p += PAD(je32_to_cpu (node->u.totlen)); + break; + + case 0xffff: + p += 4; + empty += 4; + break; + + default: + if (verbose) { + printf ("%8s Unknown node at 0x%08zx, totlen 0x%08x\n", + obsolete ? "Obsolete" : "", + p - data, je32_to_cpu (node->u.totlen)); + } + p += PAD(je32_to_cpu (node->u.totlen)); + dirty += PAD(je32_to_cpu (node->u.totlen)); + + } + } + + if (verbose) + printf ("Empty space: %d, dirty space: %d\n", empty, dirty); +} + +/* + * Convert endianess + */ +void do_endianconvert (void) +{ + char *p = data; + union jffs2_node_union *node, newnode; + int fd, len; + jint32_t mode; + uint32_t crc; + + fd = open (cnvfile, O_WRONLY | O_CREAT, 0644); + if (fd < 0) { + fprintf (stderr, "Cannot open / create file: %s\n", cnvfile); + return; + } + + while ( p < (data + imglen)) { + node = (union jffs2_node_union*) p; + + /* Skip empty space */ + if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) { + write (fd, p, 4); + p += 4; + continue; + } + + if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) { + printf ("Wrong bitmask at 0x%08zx, 0x%04x\n", p - data, je16_to_cpu (node->u.magic)); + newnode.u.magic = cnv_e16 (node->u.magic); + newnode.u.nodetype = cnv_e16 (node->u.nodetype); + write (fd, &newnode, 4); + p += 4; + continue; + } + + crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4); + if (crc != je32_to_cpu (node->u.hdr_crc)) { + printf ("Wrong hdr_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc); + } + + switch(je16_to_cpu(node->u.nodetype)) { + + case JFFS2_NODETYPE_INODE: + + newnode.i.magic = cnv_e16 (node->i.magic); + newnode.i.nodetype = cnv_e16 (node->i.nodetype); + newnode.i.totlen = cnv_e32 (node->i.totlen); + newnode.i.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); + newnode.i.ino = cnv_e32 (node->i.ino); + newnode.i.version = cnv_e32 (node->i.version); + mode.v32 = node->i.mode.m; + mode = cnv_e32 (mode); + newnode.i.mode.m = mode.v32; + newnode.i.uid = cnv_e16 (node->i.uid); + newnode.i.gid = cnv_e16 (node->i.gid); + newnode.i.isize = cnv_e32 (node->i.isize); + newnode.i.atime = cnv_e32 (node->i.atime); + newnode.i.mtime = cnv_e32 (node->i.mtime); + newnode.i.ctime = cnv_e32 (node->i.ctime); + newnode.i.offset = cnv_e32 (node->i.offset); + newnode.i.csize = cnv_e32 (node->i.csize); + newnode.i.dsize = cnv_e32 (node->i.dsize); + newnode.i.compr = node->i.compr; + newnode.i.usercompr = node->i.usercompr; + newnode.i.flags = cnv_e16 (node->i.flags); + if (recalccrc) { + len = je32_to_cpu(node->i.csize); + newnode.i.data_crc = cpu_to_e32 ( mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), len)); + } else + newnode.i.data_crc = cnv_e32 (node->i.data_crc); + + newnode.i.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_inode) - 8)); + + write (fd, &newnode, sizeof (struct jffs2_raw_inode)); + write (fd, p + sizeof (struct jffs2_raw_inode), PAD (je32_to_cpu (node->i.totlen) - sizeof (struct jffs2_raw_inode))); + + p += PAD(je32_to_cpu (node->i.totlen)); + break; + + case JFFS2_NODETYPE_DIRENT: + newnode.d.magic = cnv_e16 (node->d.magic); + newnode.d.nodetype = cnv_e16 (node->d.nodetype); + newnode.d.totlen = cnv_e32 (node->d.totlen); + newnode.d.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); + newnode.d.pino = cnv_e32 (node->d.pino); + newnode.d.version = cnv_e32 (node->d.version); + newnode.d.ino = cnv_e32 (node->d.ino); + newnode.d.mctime = cnv_e32 (node->d.mctime); + newnode.d.nsize = node->d.nsize; + newnode.d.type = node->d.type; + newnode.d.unused[0] = node->d.unused[0]; + newnode.d.unused[1] = node->d.unused[1]; + newnode.d.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_dirent) - 8)); + if (recalccrc) + newnode.d.name_crc = cpu_to_e32 ( mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize)); + else + newnode.d.name_crc = cnv_e32 (node->d.name_crc); + + write (fd, &newnode, sizeof (struct jffs2_raw_dirent)); + write (fd, p + sizeof (struct jffs2_raw_dirent), PAD (je32_to_cpu (node->d.totlen) - sizeof (struct jffs2_raw_dirent))); + p += PAD(je32_to_cpu (node->d.totlen)); + break; + + case JFFS2_NODETYPE_XATTR: + newnode.x.magic = cnv_e16 (node->x.magic); + newnode.x.nodetype = cnv_e16 (node->x.nodetype); + newnode.x.totlen = cnv_e32 (node->x.totlen); + newnode.x.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); + newnode.x.xid = cnv_e32 (node->x.xid); + newnode.x.version = cnv_e32 (node->x.version); + newnode.x.xprefix = node->x.xprefix; + newnode.x.name_len = node->x.name_len; + newnode.x.value_len = cnv_e16 (node->x.value_len); + if (recalccrc) + newnode.x.data_crc = cpu_to_e32 (mtd_crc32 (0, p + sizeof (struct jffs2_raw_xattr), node->x.name_len + je16_to_cpu (node->x.value_len) + 1)); + else + newnode.x.data_crc = cnv_e32 (node->x.data_crc); + newnode.x.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_xattr) - sizeof (newnode.x.node_crc))); + + write (fd, &newnode, sizeof (struct jffs2_raw_xattr)); + write (fd, p + sizeof (struct jffs2_raw_xattr), PAD (je32_to_cpu (node->d.totlen) - sizeof (struct jffs2_raw_xattr))); + p += PAD(je32_to_cpu (node->x.totlen)); + break; + + case JFFS2_NODETYPE_XREF: + newnode.r.magic = cnv_e16 (node->r.magic); + newnode.r.nodetype = cnv_e16 (node->r.nodetype); + newnode.r.totlen = cnv_e32 (node->r.totlen); + newnode.r.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - sizeof (newnode.r.hdr_crc))); + newnode.r.ino = cnv_e32 (node->r.ino); + newnode.r.xid = cnv_e32 (node->r.xid); + newnode.r.xseqno = cnv_e32 (node->r.xseqno); + newnode.r.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_xref) - sizeof (newnode.r.node_crc))); + p += PAD(je32_to_cpu (node->x.totlen)); + break; + + case JFFS2_NODETYPE_CLEANMARKER: + case JFFS2_NODETYPE_PADDING: + newnode.u.magic = cnv_e16 (node->u.magic); + newnode.u.nodetype = cnv_e16 (node->u.nodetype); + newnode.u.totlen = cnv_e32 (node->u.totlen); + newnode.u.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); + + write (fd, &newnode, sizeof (struct jffs2_unknown_node)); + len = PAD(je32_to_cpu (node->u.totlen) - sizeof (struct jffs2_unknown_node)); + if (len > 0) + write (fd, p + sizeof (struct jffs2_unknown_node), len); + + p += PAD(je32_to_cpu (node->u.totlen)); + break; + + case JFFS2_NODETYPE_SUMMARY : { + struct jffs2_sum_marker *sm_ptr; + int i,sum_len; + int counter = 0; + + newnode.s.magic = cnv_e16 (node->s.magic); + newnode.s.nodetype = cnv_e16 (node->s.nodetype); + newnode.s.totlen = cnv_e32 (node->s.totlen); + newnode.s.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); + newnode.s.sum_num = cnv_e32 (node->s.sum_num); + newnode.s.cln_mkr = cnv_e32 (node->s.cln_mkr); + newnode.s.padded = cnv_e32 (node->s.padded); + + newnode.s.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_summary) - 8)); + + // summary header + p += sizeof (struct jffs2_raw_summary); + + // summary data + sum_len = je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary) - sizeof (struct jffs2_sum_marker); + + for (i=0; i<je32_to_cpu (node->s.sum_num); i++) { + union jffs2_sum_flash *fl_ptr; + + fl_ptr = (union jffs2_sum_flash *) p; + + switch (je16_to_cpu (fl_ptr->u.nodetype)) { + case JFFS2_NODETYPE_INODE: + + fl_ptr->i.nodetype = cnv_e16 (fl_ptr->i.nodetype); + fl_ptr->i.inode = cnv_e32 (fl_ptr->i.inode); + fl_ptr->i.version = cnv_e32 (fl_ptr->i.version); + fl_ptr->i.offset = cnv_e32 (fl_ptr->i.offset); + fl_ptr->i.totlen = cnv_e32 (fl_ptr->i.totlen); + p += sizeof (struct jffs2_sum_inode_flash); + counter += sizeof (struct jffs2_sum_inode_flash); + break; + + case JFFS2_NODETYPE_DIRENT: + fl_ptr->d.nodetype = cnv_e16 (fl_ptr->d.nodetype); + fl_ptr->d.totlen = cnv_e32 (fl_ptr->d.totlen); + fl_ptr->d.offset = cnv_e32 (fl_ptr->d.offset); + fl_ptr->d.pino = cnv_e32 (fl_ptr->d.pino); + fl_ptr->d.version = cnv_e32 (fl_ptr->d.version); + fl_ptr->d.ino = cnv_e32 (fl_ptr->d.ino); + p += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize; + counter += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize; + break; + + case JFFS2_NODETYPE_XATTR: + fl_ptr->x.nodetype = cnv_e16 (fl_ptr->x.nodetype); + fl_ptr->x.xid = cnv_e32 (fl_ptr->x.xid); + fl_ptr->x.version = cnv_e32 (fl_ptr->x.version); + fl_ptr->x.offset = cnv_e32 (fl_ptr->x.offset); + fl_ptr->x.totlen = cnv_e32 (fl_ptr->x.totlen); + p += sizeof (struct jffs2_sum_xattr_flash); + counter += sizeof (struct jffs2_sum_xattr_flash); + break; + + case JFFS2_NODETYPE_XREF: + fl_ptr->r.nodetype = cnv_e16 (fl_ptr->r.nodetype); + fl_ptr->r.offset = cnv_e32 (fl_ptr->r.offset); + p += sizeof (struct jffs2_sum_xref_flash); + counter += sizeof (struct jffs2_sum_xref_flash); + break; + + default : + printf("Unknown node in summary information!!! nodetype(%x)\n", je16_to_cpu (fl_ptr->u.nodetype)); + exit(EXIT_FAILURE); + break; + } + + } + + //pad + p += sum_len - counter; + + // summary marker + sm_ptr = (struct jffs2_sum_marker *) p; + sm_ptr->offset = cnv_e32 (sm_ptr->offset); + sm_ptr->magic = cnv_e32 (sm_ptr->magic); + p += sizeof (struct jffs2_sum_marker); + + // generate new crc on sum data + newnode.s.sum_crc = cpu_to_e32 ( mtd_crc32(0, ((char *) node) + sizeof (struct jffs2_raw_summary), + je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary))); + + // write out new node header + write(fd, &newnode, sizeof (struct jffs2_raw_summary)); + // write out new summary data + write(fd, &node->s.sum, sum_len + sizeof (struct jffs2_sum_marker)); + + break; + } + + case 0xffff: + write (fd, p, 4); + p += 4; + break; + + default: + printf ("Unknown node type: 0x%04x at 0x%08zx, totlen 0x%08x\n", je16_to_cpu (node->u.nodetype), p - data, je32_to_cpu (node->u.totlen)); + p += PAD(je32_to_cpu (node->u.totlen)); + + } + } + + close (fd); + +} + +/* + * Main program + */ +int main(int argc, char **argv) +{ + int fd; + + process_options(argc, argv); + + /* Open the input file */ + if ((fd = open(img, O_RDONLY)) == -1) { + perror("open input file"); + exit(1); + } + + // get image length + imglen = lseek(fd, 0, SEEK_END); + lseek (fd, 0, SEEK_SET); + + data = malloc (imglen); + if (!data) { + perror("out of memory"); + close (fd); + exit(1); + } + + if (datsize && oobsize) { + int idx = 0; + long len = imglen; + uint8_t oob[oobsize]; + printf ("Peeling data out of combined data/oob image\n"); + while (len) { + // read image data + read (fd, &data[idx], datsize); + read (fd, oob, oobsize); + idx += datsize; + imglen -= oobsize; + len -= datsize + oobsize; + } + + } else { + // read image data + read (fd, data, imglen); + } + // Close the input file + close(fd); + + if (dumpcontent) + do_dumpcontent (); + + if (convertendian) + do_endianconvert (); + + // free memory + free (data); + + // Return happy + exit (0); +} |