jffs2dump.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /*
  2. * dumpjffs2.c
  3. *
  4. * Copyright (C) 2003 Thomas Gleixner (tglx@linutronix.de)
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * Overview:
  11. * This utility dumps the contents of a binary JFFS2 image
  12. *
  13. *
  14. * Bug/ToDo:
  15. */
  16. #define PROGRAM_NAME "jffs2dump"
  17. #include <errno.h>
  18. #include <stdint.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <fcntl.h>
  24. #include <time.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/param.h>
  28. #include <asm/types.h>
  29. #include <dirent.h>
  30. #include <mtd/jffs2-user.h>
  31. #include <endian.h>
  32. #include <byteswap.h>
  33. #include <getopt.h>
  34. #include <crc32.h>
  35. #include "summary.h"
  36. #include "common.h"
  37. #define PAD(x) (((x)+3)&~3)
  38. /* For outputting a byte-swapped version of the input image. */
  39. #define cnv_e32(x) ((jint32_t){bswap_32(x.v32)})
  40. #define cnv_e16(x) ((jint16_t){bswap_16(x.v16)})
  41. #define t32_backwards(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?bswap_32(__b):__b; })
  42. #define cpu_to_e32(x) ((jint32_t){t32_backwards(x)})
  43. // Global variables
  44. long imglen; // length of image
  45. char *data; // image data
  46. static void display_help (int error)
  47. {
  48. printf("Usage: %s [OPTION]... INPUTFILE\n"
  49. "Dump the contents of a binary JFFS2 image.\n\n"
  50. " -h, --help display this help and exit\n"
  51. " -V, --version display version information and exit\n"
  52. " -b, --bigendian image is big endian\n"
  53. " -l, --littleendian image is little endian\n"
  54. " -c, --content dump image contents\n"
  55. " -e, --endianconvert=FNAME convert image endianness, output to file fname\n"
  56. " -r, --recalccrc recalc name and data crc on endian conversion\n"
  57. " -d, --datsize=LEN size of data chunks, when oob data in binary image (NAND only)\n"
  58. " -o, --oobsize=LEN size of oob data chunk in binary image (NAND only)\n"
  59. " -v, --verbose verbose output\n",
  60. PROGRAM_NAME);
  61. exit(error ? EXIT_FAILURE : EXIT_SUCCESS);
  62. }
  63. static void display_version (void)
  64. {
  65. common_print_version();
  66. printf("Copyright (C) 2003 Thomas Gleixner \n"
  67. "\n"
  68. "%1$s comes with NO WARRANTY\n"
  69. "to the extent permitted by law.\n"
  70. "\n"
  71. "You may redistribute copies of %1$s\n"
  72. "under the terms of the GNU General Public Licence.\n"
  73. "See the file `COPYING' for more information.\n",
  74. PROGRAM_NAME);
  75. exit(0);
  76. }
  77. // Option variables
  78. int verbose; // verbose output
  79. char *img; // filename of image
  80. int dumpcontent; // dump image content
  81. int target_endian = __BYTE_ORDER; // image endianess
  82. int convertendian; // convert endianness
  83. int recalccrc; // recalc name and data crc's on endian conversion
  84. char cnvfile[256]; // filename for conversion output
  85. int datsize; // Size of data chunks, when oob data is inside the binary image
  86. int oobsize; // Size of oob chunks, when oob data is inside the binary image
  87. static void process_options (int argc, char *argv[])
  88. {
  89. int error = 0;
  90. for (;;) {
  91. int option_index = 0;
  92. static const char *short_options = "blce:rd:o:vVh";
  93. static const struct option long_options[] = {
  94. {"help", no_argument, 0, 'h'},
  95. {"version", no_argument, 0, 'V'},
  96. {"bigendian", no_argument, 0, 'b'},
  97. {"littleendian", no_argument, 0, 'l'},
  98. {"content", no_argument, 0, 'c'},
  99. {"endianconvert", required_argument, 0, 'e'},
  100. {"datsize", required_argument, 0, 'd'},
  101. {"oobsize", required_argument, 0, 'o'},
  102. {"recalccrc", required_argument, 0, 'r'},
  103. {"verbose", no_argument, 0, 'v'},
  104. {0, 0, 0, 0},
  105. };
  106. int c = getopt_long(argc, argv, short_options,
  107. long_options, &option_index);
  108. if (c == EOF) {
  109. break;
  110. }
  111. switch (c) {
  112. case 'h':
  113. display_help(0);
  114. break;
  115. case 'V':
  116. display_version();
  117. break;
  118. case 'v':
  119. verbose = 1;
  120. break;
  121. case 'b':
  122. target_endian = __BIG_ENDIAN;
  123. break;
  124. case 'l':
  125. target_endian = __LITTLE_ENDIAN;
  126. break;
  127. case 'c':
  128. dumpcontent = 1;
  129. break;
  130. case 'd':
  131. datsize = atoi(optarg);
  132. break;
  133. case 'o':
  134. oobsize = atoi(optarg);
  135. break;
  136. case 'e':
  137. convertendian = 1;
  138. strncpy (cnvfile, optarg, sizeof(cnvfile) - 1);
  139. cnvfile[sizeof(cnvfile) - 1] = '\0';
  140. break;
  141. case 'r':
  142. recalccrc = 1;
  143. break;
  144. case '?':
  145. error = 1;
  146. break;
  147. }
  148. }
  149. if ((argc - optind) != 1 || error)
  150. display_help (error);
  151. img = argv[optind];
  152. }
  153. /*
  154. * Dump image contents
  155. */
  156. static void do_dumpcontent (void)
  157. {
  158. char *p = data, *p_free_begin;
  159. union jffs2_node_union *node;
  160. int empty = 0, dirty = 0;
  161. char name[256];
  162. uint32_t crc;
  163. uint16_t type;
  164. int bitchbitmask = 0;
  165. int obsolete;
  166. p_free_begin = NULL;
  167. while ( p < (data + imglen)) {
  168. node = (union jffs2_node_union*) p;
  169. /* Skip empty space */
  170. if (!p_free_begin)
  171. p_free_begin = p;
  172. if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
  173. p += 4;
  174. empty += 4;
  175. continue;
  176. }
  177. if (p != p_free_begin)
  178. printf("Empty space found from 0x%08zx to 0x%08zx\n", p_free_begin-data, p-data);
  179. p_free_begin = NULL;
  180. if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
  181. if (!bitchbitmask++)
  182. printf ("Wrong bitmask at 0x%08zx, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
  183. p += 4;
  184. dirty += 4;
  185. continue;
  186. }
  187. bitchbitmask = 0;
  188. type = je16_to_cpu(node->u.nodetype);
  189. if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
  190. obsolete = 1;
  191. type |= JFFS2_NODE_ACCURATE;
  192. } else
  193. obsolete = 0;
  194. /* Set accurate for CRC check */
  195. node->u.nodetype = cpu_to_je16(type);
  196. crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
  197. if (crc != je32_to_cpu (node->u.hdr_crc)) {
  198. printf ("Wrong hdr_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc);
  199. p += 4;
  200. dirty += 4;
  201. continue;
  202. }
  203. switch(je16_to_cpu(node->u.nodetype)) {
  204. case JFFS2_NODETYPE_INODE:
  205. printf ("%8s Inode node at 0x%08zx, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
  206. obsolete ? "Obsolete" : "",
  207. p - data, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
  208. je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
  209. je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
  210. crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
  211. if (crc != je32_to_cpu (node->i.node_crc)) {
  212. printf ("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.node_crc), crc);
  213. p += PAD(je32_to_cpu (node->i.totlen));
  214. dirty += PAD(je32_to_cpu (node->i.totlen));;
  215. continue;
  216. }
  217. crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
  218. if (crc != je32_to_cpu(node->i.data_crc)) {
  219. printf ("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.data_crc), crc);
  220. p += PAD(je32_to_cpu (node->i.totlen));
  221. dirty += PAD(je32_to_cpu (node->i.totlen));;
  222. continue;
  223. }
  224. p += PAD(je32_to_cpu (node->i.totlen));
  225. break;
  226. case JFFS2_NODETYPE_DIRENT:
  227. memcpy (name, node->d.name, node->d.nsize);
  228. name [node->d.nsize] = 0x0;
  229. printf ("%8s Dirent node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n",
  230. obsolete ? "Obsolete" : "",
  231. p - data, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
  232. je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
  233. node->d.nsize, name);
  234. crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
  235. if (crc != je32_to_cpu (node->d.node_crc)) {
  236. printf ("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.node_crc), crc);
  237. p += PAD(je32_to_cpu (node->d.totlen));
  238. dirty += PAD(je32_to_cpu (node->d.totlen));;
  239. continue;
  240. }
  241. crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
  242. if (crc != je32_to_cpu(node->d.name_crc)) {
  243. printf ("Wrong name_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.name_crc), crc);
  244. p += PAD(je32_to_cpu (node->d.totlen));
  245. dirty += PAD(je32_to_cpu (node->d.totlen));;
  246. continue;
  247. }
  248. p += PAD(je32_to_cpu (node->d.totlen));
  249. break;
  250. case JFFS2_NODETYPE_XATTR:
  251. memcpy(name, node->x.data, node->x.name_len);
  252. name[node->x.name_len] = '\x00';
  253. printf ("%8s Xattr node at 0x%08zx, totlen 0x%08x, xid %5d, version %5d, name_len %3d, name %s\n",
  254. obsolete ? "Obsolete" : "",
  255. p - data,
  256. je32_to_cpu (node->x.totlen),
  257. je32_to_cpu (node->x.xid),
  258. je32_to_cpu (node->x.version),
  259. node->x.name_len,
  260. name);
  261. crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_xattr) - sizeof (node->x.node_crc));
  262. if (crc != je32_to_cpu (node->x.node_crc)) {
  263. printf ("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->x.node_crc), crc);
  264. p += PAD(je32_to_cpu (node->x.totlen));
  265. dirty += PAD(je32_to_cpu (node->x.totlen));
  266. continue;
  267. }
  268. crc = mtd_crc32 (0, p + sizeof (struct jffs2_raw_xattr), node->x.name_len + je16_to_cpu (node->x.value_len) + 1);
  269. if (crc != je32_to_cpu (node->x.data_crc)) {
  270. printf ("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->x.data_crc), crc);
  271. p += PAD(je32_to_cpu (node->x.totlen));
  272. dirty += PAD(je32_to_cpu (node->x.totlen));
  273. continue;
  274. }
  275. p += PAD(je32_to_cpu (node->x.totlen));
  276. break;
  277. case JFFS2_NODETYPE_XREF:
  278. printf ("%8s Xref node at 0x%08zx, totlen 0x%08x, xid %5d, xseqno %5d, #ino %8d\n",
  279. obsolete ? "Obsolete" : "",
  280. p - data,
  281. je32_to_cpu (node->r.totlen),
  282. je32_to_cpu (node->r.xid),
  283. je32_to_cpu (node->r.xseqno),
  284. je32_to_cpu (node->r.ino));
  285. p += PAD(je32_to_cpu (node->r.totlen));
  286. break;
  287. case JFFS2_NODETYPE_SUMMARY: {
  288. int i;
  289. struct jffs2_sum_marker * sm;
  290. printf("%8s Inode Sum node at 0x%08zx, totlen 0x%08x, sum_num %5d, cleanmarker size %5d\n",
  291. obsolete ? "Obsolete" : "",
  292. p - data,
  293. je32_to_cpu (node->s.totlen),
  294. je32_to_cpu (node->s.sum_num),
  295. je32_to_cpu (node->s.cln_mkr));
  296. crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_summary) - 8);
  297. if (crc != je32_to_cpu (node->s.node_crc)) {
  298. printf ("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.node_crc), crc);
  299. p += PAD(je32_to_cpu (node->s.totlen));
  300. dirty += PAD(je32_to_cpu (node->s.totlen));;
  301. continue;
  302. }
  303. crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_summary), je32_to_cpu (node->s.totlen) - sizeof(struct jffs2_raw_summary));
  304. if (crc != je32_to_cpu(node->s.sum_crc)) {
  305. printf ("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.sum_crc), crc);
  306. p += PAD(je32_to_cpu (node->s.totlen));
  307. dirty += PAD(je32_to_cpu (node->s.totlen));;
  308. continue;
  309. }
  310. if (verbose) {
  311. void *sp;
  312. sp = (p + sizeof(struct jffs2_raw_summary));
  313. for(i=0; i<je32_to_cpu(node->s.sum_num); i++) {
  314. switch(je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
  315. case JFFS2_NODETYPE_INODE : {
  316. struct jffs2_sum_inode_flash *spi;
  317. spi = sp;
  318. printf ("%14s #ino %5d, version %5d, offset 0x%08x, totlen 0x%08x\n",
  319. "",
  320. je32_to_cpu (spi->inode),
  321. je32_to_cpu (spi->version),
  322. je32_to_cpu (spi->offset),
  323. je32_to_cpu (spi->totlen));
  324. sp += JFFS2_SUMMARY_INODE_SIZE;
  325. break;
  326. }
  327. case JFFS2_NODETYPE_DIRENT : {
  328. char name[255];
  329. struct jffs2_sum_dirent_flash *spd;
  330. spd = sp;
  331. memcpy(name,spd->name,spd->nsize);
  332. name [spd->nsize] = 0x0;
  333. printf ("%14s dirent offset 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s \n",
  334. "",
  335. je32_to_cpu (spd->offset),
  336. je32_to_cpu (spd->totlen),
  337. je32_to_cpu (spd->pino),
  338. je32_to_cpu (spd->version),
  339. je32_to_cpu (spd->ino),
  340. spd->nsize,
  341. name);
  342. sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
  343. break;
  344. }
  345. case JFFS2_NODETYPE_XATTR : {
  346. struct jffs2_sum_xattr_flash *spx;
  347. spx = sp;
  348. printf ("%14s Xattr offset 0x%08x, totlen 0x%08x, version %5d, #xid %8d\n",
  349. "",
  350. je32_to_cpu (spx->offset),
  351. je32_to_cpu (spx->totlen),
  352. je32_to_cpu (spx->version),
  353. je32_to_cpu (spx->xid));
  354. sp += JFFS2_SUMMARY_XATTR_SIZE;
  355. break;
  356. }
  357. case JFFS2_NODETYPE_XREF : {
  358. struct jffs2_sum_xref_flash *spr;
  359. spr = sp;
  360. printf ("%14s Xref offset 0x%08x\n",
  361. "",
  362. je32_to_cpu (spr->offset));
  363. sp += JFFS2_SUMMARY_XREF_SIZE;
  364. break;
  365. }
  366. default :
  367. printf("Unknown summary node!\n");
  368. break;
  369. }
  370. }
  371. sm = (struct jffs2_sum_marker *) ((char *)p + je32_to_cpu(node->s.totlen) - sizeof(struct jffs2_sum_marker));
  372. printf("%14s Sum Node Offset 0x%08x, Magic 0x%08x, Padded size 0x%08x\n",
  373. "",
  374. je32_to_cpu(sm->offset),
  375. je32_to_cpu(sm->magic),
  376. je32_to_cpu(node->s.padded));
  377. }
  378. p += PAD(je32_to_cpu (node->s.totlen));
  379. break;
  380. }
  381. case JFFS2_NODETYPE_CLEANMARKER:
  382. if (verbose) {
  383. printf ("%8s Cleanmarker at 0x%08zx, totlen 0x%08x\n",
  384. obsolete ? "Obsolete" : "",
  385. p - data, je32_to_cpu (node->u.totlen));
  386. }
  387. p += PAD(je32_to_cpu (node->u.totlen));
  388. break;
  389. case JFFS2_NODETYPE_PADDING:
  390. if (verbose) {
  391. printf ("%8s Padding node at 0x%08zx, totlen 0x%08x\n",
  392. obsolete ? "Obsolete" : "",
  393. p - data, je32_to_cpu (node->u.totlen));
  394. }
  395. p += PAD(je32_to_cpu (node->u.totlen));
  396. break;
  397. case 0xffff:
  398. p += 4;
  399. empty += 4;
  400. break;
  401. default:
  402. if (verbose) {
  403. printf ("%8s Unknown node at 0x%08zx, totlen 0x%08x\n",
  404. obsolete ? "Obsolete" : "",
  405. p - data, je32_to_cpu (node->u.totlen));
  406. }
  407. p += PAD(je32_to_cpu (node->u.totlen));
  408. dirty += PAD(je32_to_cpu (node->u.totlen));
  409. }
  410. }
  411. if (verbose)
  412. printf ("Empty space: %d, dirty space: %d\n", empty, dirty);
  413. }
  414. /*
  415. * Convert endianess
  416. */
  417. static void do_endianconvert (void)
  418. {
  419. char *p = data;
  420. union jffs2_node_union *node, newnode;
  421. int fd, len;
  422. jint32_t mode;
  423. uint32_t crc;
  424. fd = open (cnvfile, O_WRONLY | O_CREAT, 0644);
  425. if (fd < 0) {
  426. fprintf (stderr, "Cannot open / create file: %s\n", cnvfile);
  427. return;
  428. }
  429. while ( p < (data + imglen)) {
  430. node = (union jffs2_node_union*) p;
  431. /* Skip empty space */
  432. if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
  433. write_nocheck (fd, p, 4);
  434. p += 4;
  435. continue;
  436. }
  437. if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
  438. printf ("Wrong bitmask at 0x%08zx, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
  439. newnode.u.magic = cnv_e16 (node->u.magic);
  440. newnode.u.nodetype = cnv_e16 (node->u.nodetype);
  441. write_nocheck (fd, &newnode, 4);
  442. p += 4;
  443. continue;
  444. }
  445. crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
  446. if (crc != je32_to_cpu (node->u.hdr_crc)) {
  447. printf ("Wrong hdr_crc at 0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc);
  448. }
  449. switch(je16_to_cpu(node->u.nodetype)) {
  450. case JFFS2_NODETYPE_INODE:
  451. newnode.i.magic = cnv_e16 (node->i.magic);
  452. newnode.i.nodetype = cnv_e16 (node->i.nodetype);
  453. newnode.i.totlen = cnv_e32 (node->i.totlen);
  454. newnode.i.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
  455. newnode.i.ino = cnv_e32 (node->i.ino);
  456. newnode.i.version = cnv_e32 (node->i.version);
  457. mode.v32 = node->i.mode.m;
  458. mode = cnv_e32 (mode);
  459. newnode.i.mode.m = mode.v32;
  460. newnode.i.uid = cnv_e16 (node->i.uid);
  461. newnode.i.gid = cnv_e16 (node->i.gid);
  462. newnode.i.isize = cnv_e32 (node->i.isize);
  463. newnode.i.atime = cnv_e32 (node->i.atime);
  464. newnode.i.mtime = cnv_e32 (node->i.mtime);
  465. newnode.i.ctime = cnv_e32 (node->i.ctime);
  466. newnode.i.offset = cnv_e32 (node->i.offset);
  467. newnode.i.csize = cnv_e32 (node->i.csize);
  468. newnode.i.dsize = cnv_e32 (node->i.dsize);
  469. newnode.i.compr = node->i.compr;
  470. newnode.i.usercompr = node->i.usercompr;
  471. newnode.i.flags = cnv_e16 (node->i.flags);
  472. if (recalccrc) {
  473. len = je32_to_cpu(node->i.csize);
  474. newnode.i.data_crc = cpu_to_e32 ( mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), len));
  475. } else
  476. newnode.i.data_crc = cnv_e32 (node->i.data_crc);
  477. newnode.i.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_inode) - 8));
  478. write_nocheck (fd, &newnode, sizeof (struct jffs2_raw_inode));
  479. write_nocheck (fd, p + sizeof (struct jffs2_raw_inode), PAD (je32_to_cpu (node->i.totlen) - sizeof (struct jffs2_raw_inode)));
  480. p += PAD(je32_to_cpu (node->i.totlen));
  481. break;
  482. case JFFS2_NODETYPE_DIRENT:
  483. newnode.d.magic = cnv_e16 (node->d.magic);
  484. newnode.d.nodetype = cnv_e16 (node->d.nodetype);
  485. newnode.d.totlen = cnv_e32 (node->d.totlen);
  486. newnode.d.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
  487. newnode.d.pino = cnv_e32 (node->d.pino);
  488. newnode.d.version = cnv_e32 (node->d.version);
  489. newnode.d.ino = cnv_e32 (node->d.ino);
  490. newnode.d.mctime = cnv_e32 (node->d.mctime);
  491. newnode.d.nsize = node->d.nsize;
  492. newnode.d.type = node->d.type;
  493. newnode.d.unused[0] = node->d.unused[0];
  494. newnode.d.unused[1] = node->d.unused[1];
  495. newnode.d.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_dirent) - 8));
  496. if (recalccrc)
  497. newnode.d.name_crc = cpu_to_e32 ( mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize));
  498. else
  499. newnode.d.name_crc = cnv_e32 (node->d.name_crc);
  500. write_nocheck (fd, &newnode, sizeof (struct jffs2_raw_dirent));
  501. write_nocheck (fd, p + sizeof (struct jffs2_raw_dirent), PAD (je32_to_cpu (node->d.totlen) - sizeof (struct jffs2_raw_dirent)));
  502. p += PAD(je32_to_cpu (node->d.totlen));
  503. break;
  504. case JFFS2_NODETYPE_XATTR:
  505. newnode.x.magic = cnv_e16 (node->x.magic);
  506. newnode.x.nodetype = cnv_e16 (node->x.nodetype);
  507. newnode.x.totlen = cnv_e32 (node->x.totlen);
  508. newnode.x.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
  509. newnode.x.xid = cnv_e32 (node->x.xid);
  510. newnode.x.version = cnv_e32 (node->x.version);
  511. newnode.x.xprefix = node->x.xprefix;
  512. newnode.x.name_len = node->x.name_len;
  513. newnode.x.value_len = cnv_e16 (node->x.value_len);
  514. if (recalccrc)
  515. 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));
  516. else
  517. newnode.x.data_crc = cnv_e32 (node->x.data_crc);
  518. newnode.x.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_xattr) - sizeof (newnode.x.node_crc)));
  519. write_nocheck (fd, &newnode, sizeof (struct jffs2_raw_xattr));
  520. write_nocheck (fd, p + sizeof (struct jffs2_raw_xattr), PAD (je32_to_cpu (node->d.totlen) - sizeof (struct jffs2_raw_xattr)));
  521. p += PAD(je32_to_cpu (node->x.totlen));
  522. break;
  523. case JFFS2_NODETYPE_XREF:
  524. newnode.r.magic = cnv_e16 (node->r.magic);
  525. newnode.r.nodetype = cnv_e16 (node->r.nodetype);
  526. newnode.r.totlen = cnv_e32 (node->r.totlen);
  527. newnode.r.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - sizeof (newnode.r.hdr_crc)));
  528. newnode.r.ino = cnv_e32 (node->r.ino);
  529. newnode.r.xid = cnv_e32 (node->r.xid);
  530. newnode.r.xseqno = cnv_e32 (node->r.xseqno);
  531. newnode.r.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_xref) - sizeof (newnode.r.node_crc)));
  532. p += PAD(je32_to_cpu (node->x.totlen));
  533. break;
  534. case JFFS2_NODETYPE_CLEANMARKER:
  535. case JFFS2_NODETYPE_PADDING:
  536. newnode.u.magic = cnv_e16 (node->u.magic);
  537. newnode.u.nodetype = cnv_e16 (node->u.nodetype);
  538. newnode.u.totlen = cnv_e32 (node->u.totlen);
  539. newnode.u.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
  540. write_nocheck (fd, &newnode, sizeof (struct jffs2_unknown_node));
  541. len = PAD(je32_to_cpu (node->u.totlen) - sizeof (struct jffs2_unknown_node));
  542. if (len > 0)
  543. write_nocheck (fd, p + sizeof (struct jffs2_unknown_node), len);
  544. p += PAD(je32_to_cpu (node->u.totlen));
  545. break;
  546. case JFFS2_NODETYPE_SUMMARY : {
  547. struct jffs2_sum_marker *sm_ptr;
  548. int i,sum_len;
  549. int counter = 0;
  550. newnode.s.magic = cnv_e16 (node->s.magic);
  551. newnode.s.nodetype = cnv_e16 (node->s.nodetype);
  552. newnode.s.totlen = cnv_e32 (node->s.totlen);
  553. newnode.s.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
  554. newnode.s.sum_num = cnv_e32 (node->s.sum_num);
  555. newnode.s.cln_mkr = cnv_e32 (node->s.cln_mkr);
  556. newnode.s.padded = cnv_e32 (node->s.padded);
  557. newnode.s.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_summary) - 8));
  558. // summary header
  559. p += sizeof (struct jffs2_raw_summary);
  560. // summary data
  561. sum_len = je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary) - sizeof (struct jffs2_sum_marker);
  562. for (i=0; i<je32_to_cpu (node->s.sum_num); i++) {
  563. union jffs2_sum_flash *fl_ptr;
  564. fl_ptr = (union jffs2_sum_flash *) p;
  565. switch (je16_to_cpu (fl_ptr->u.nodetype)) {
  566. case JFFS2_NODETYPE_INODE:
  567. fl_ptr->i.nodetype = cnv_e16 (fl_ptr->i.nodetype);
  568. fl_ptr->i.inode = cnv_e32 (fl_ptr->i.inode);
  569. fl_ptr->i.version = cnv_e32 (fl_ptr->i.version);
  570. fl_ptr->i.offset = cnv_e32 (fl_ptr->i.offset);
  571. fl_ptr->i.totlen = cnv_e32 (fl_ptr->i.totlen);
  572. p += sizeof (struct jffs2_sum_inode_flash);
  573. counter += sizeof (struct jffs2_sum_inode_flash);
  574. break;
  575. case JFFS2_NODETYPE_DIRENT:
  576. fl_ptr->d.nodetype = cnv_e16 (fl_ptr->d.nodetype);
  577. fl_ptr->d.totlen = cnv_e32 (fl_ptr->d.totlen);
  578. fl_ptr->d.offset = cnv_e32 (fl_ptr->d.offset);
  579. fl_ptr->d.pino = cnv_e32 (fl_ptr->d.pino);
  580. fl_ptr->d.version = cnv_e32 (fl_ptr->d.version);
  581. fl_ptr->d.ino = cnv_e32 (fl_ptr->d.ino);
  582. p += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
  583. counter += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
  584. break;
  585. case JFFS2_NODETYPE_XATTR:
  586. fl_ptr->x.nodetype = cnv_e16 (fl_ptr->x.nodetype);
  587. fl_ptr->x.xid = cnv_e32 (fl_ptr->x.xid);
  588. fl_ptr->x.version = cnv_e32 (fl_ptr->x.version);
  589. fl_ptr->x.offset = cnv_e32 (fl_ptr->x.offset);
  590. fl_ptr->x.totlen = cnv_e32 (fl_ptr->x.totlen);
  591. p += sizeof (struct jffs2_sum_xattr_flash);
  592. counter += sizeof (struct jffs2_sum_xattr_flash);
  593. break;
  594. case JFFS2_NODETYPE_XREF:
  595. fl_ptr->r.nodetype = cnv_e16 (fl_ptr->r.nodetype);
  596. fl_ptr->r.offset = cnv_e32 (fl_ptr->r.offset);
  597. p += sizeof (struct jffs2_sum_xref_flash);
  598. counter += sizeof (struct jffs2_sum_xref_flash);
  599. break;
  600. default :
  601. printf("Unknown node in summary information!!! nodetype(%x)\n", je16_to_cpu (fl_ptr->u.nodetype));
  602. exit(EXIT_FAILURE);
  603. break;
  604. }
  605. }
  606. //pad
  607. p += sum_len - counter;
  608. // summary marker
  609. sm_ptr = (struct jffs2_sum_marker *) p;
  610. sm_ptr->offset = cnv_e32 (sm_ptr->offset);
  611. sm_ptr->magic = cnv_e32 (sm_ptr->magic);
  612. p += sizeof (struct jffs2_sum_marker);
  613. // generate new crc on sum data
  614. newnode.s.sum_crc = cpu_to_e32 ( mtd_crc32(0, ((char *) node) + sizeof (struct jffs2_raw_summary),
  615. je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary)));
  616. // write out new node header
  617. write_nocheck(fd, &newnode, sizeof (struct jffs2_raw_summary));
  618. // write out new summary data
  619. write_nocheck(fd, &node->s.sum, sum_len + sizeof (struct jffs2_sum_marker));
  620. break;
  621. }
  622. case 0xffff:
  623. write_nocheck (fd, p, 4);
  624. p += 4;
  625. break;
  626. default:
  627. 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));
  628. p += PAD(je32_to_cpu (node->u.totlen));
  629. }
  630. }
  631. close (fd);
  632. }
  633. /*
  634. * Main program
  635. */
  636. int main(int argc, char **argv)
  637. {
  638. int fd;
  639. process_options(argc, argv);
  640. /* Open the input file */
  641. if ((fd = open(img, O_RDONLY)) == -1) {
  642. perror("open input file");
  643. exit(EXIT_FAILURE);
  644. }
  645. // get image length
  646. imglen = lseek(fd, 0, SEEK_END);
  647. lseek (fd, 0, SEEK_SET);
  648. data = malloc (imglen);
  649. if (!data) {
  650. perror("out of memory");
  651. close (fd);
  652. exit(EXIT_FAILURE);
  653. }
  654. if (datsize && oobsize) {
  655. int idx = 0;
  656. long len = imglen;
  657. uint8_t oob[oobsize];
  658. printf ("Peeling data out of combined data/oob image\n");
  659. while (len) {
  660. // read image data
  661. read_nocheck (fd, &data[idx], datsize);
  662. read_nocheck (fd, oob, oobsize);
  663. idx += datsize;
  664. imglen -= oobsize;
  665. len -= datsize + oobsize;
  666. }
  667. } else {
  668. // read image data
  669. read_nocheck (fd, data, imglen);
  670. }
  671. // Close the input file
  672. close(fd);
  673. if (dumpcontent)
  674. do_dumpcontent ();
  675. if (convertendian)
  676. do_endianconvert ();
  677. // free memory
  678. free (data);
  679. // Return happy
  680. exit (EXIT_SUCCESS);
  681. }