sumtool.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. /*
  2. * sumtool.c
  3. *
  4. * Copyright (C) 2004 Zoltan Sogor <weth@inf.u-szeged.hu>,
  5. * Ferenc Havasi <havasi@inf.u-szeged.hu>
  6. * University of Szeged, Hungary
  7. * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. *
  23. * Overview:
  24. * This is a utility insert summary information into JFFS2 image for
  25. * faster mount time
  26. *
  27. */
  28. #define PROGRAM_NAME "sumtool"
  29. #include <errno.h>
  30. #include <stdint.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <stdarg.h>
  34. #include <string.h>
  35. #include <unistd.h>
  36. #include <fcntl.h>
  37. #include <time.h>
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #include <sys/param.h>
  41. #include <asm/types.h>
  42. #include <dirent.h>
  43. #include <mtd/jffs2-user.h>
  44. #include <endian.h>
  45. #include <byteswap.h>
  46. #include <getopt.h>
  47. #include <crc32.h>
  48. #include "summary.h"
  49. #include "common.h"
  50. #define PAD(x) (((x)+3)&~3)
  51. static struct jffs2_summary *sum_collected = NULL;
  52. static int verbose = 0;
  53. static int padto = 0; /* pad the output with 0xFF to the end of the final eraseblock */
  54. static int add_cleanmarkers = 1; /* add cleanmarker to output */
  55. static int use_input_cleanmarker_size = 1; /* use input file's cleanmarker size (default) */
  56. static int found_cleanmarkers = 0; /* cleanmarker found in input file */
  57. static struct jffs2_unknown_node cleanmarker;
  58. static int cleanmarker_size = sizeof(cleanmarker);
  59. static const char *short_options = "o:i:e:hvVblnc:p";
  60. static int erase_block_size = 65536;
  61. static int out_fd = -1;
  62. static int in_fd = -1;
  63. static uint8_t *data_buffer = NULL; /* buffer for inodes */
  64. static unsigned int data_ofs = 0; /* inode buffer offset */
  65. static uint8_t *file_buffer = NULL; /* file buffer contains the actual erase block*/
  66. static unsigned int file_ofs = 0; /* position in the buffer */
  67. int target_endian = __BYTE_ORDER;
  68. static struct option long_options[] = {
  69. {"output", 1, NULL, 'o'},
  70. {"input", 1, NULL, 'i'},
  71. {"eraseblock", 1, NULL, 'e'},
  72. {"help", 0, NULL, 'h'},
  73. {"verbose", 0, NULL, 'v'},
  74. {"version", 0, NULL, 'V'},
  75. {"bigendian", 0, NULL, 'b'},
  76. {"littleendian", 0, NULL, 'l'},
  77. {"no-cleanmarkers", 0, NULL, 'n'},
  78. {"cleanmarker", 1, NULL, 'c'},
  79. {"pad", 0, NULL, 'p'},
  80. {NULL, 0, NULL, 0}
  81. };
  82. static const char helptext[] =
  83. "Usage: sumtool [OPTIONS] -i inputfile -o outputfile\n\n"
  84. "Convert the input JFFS2 image to a summarized JFFS2 image\n"
  85. "Summary makes mounting faster - if summary support enabled in your kernel\n\n"
  86. "Options:\n"
  87. " -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)\n"
  88. " (usually 16KiB on NAND)\n"
  89. " -c, --cleanmarker=SIZE Size of cleanmarker (default 12).\n"
  90. " (usually 16 bytes on NAND, and will be set to\n"
  91. " this value if left at the default 12). Will be\n"
  92. " stored in OOB after each physical page composing\n"
  93. " a physical eraseblock.\n"
  94. " -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock\n"
  95. " -o, --output=FILE Output to FILE \n"
  96. " -i, --input=FILE Input from FILE \n"
  97. " -b, --bigendian Image is big endian\n"
  98. " -l --littleendian Image is little endian\n"
  99. " -h, --help Display this help text\n"
  100. " -v, --verbose Verbose operation\n"
  101. " -V, --version Display version information\n"
  102. " -p, --pad Pad the OUTPUT with 0xFF to the end of the final\n"
  103. " eraseblock\n\n";
  104. static unsigned char ffbuf[16] = {
  105. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  106. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  107. };
  108. static void full_write(void *target_buff, const void *buf, int len);
  109. static void setup_cleanmarker(void)
  110. {
  111. cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  112. cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
  113. cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
  114. cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
  115. }
  116. static void process_options (int argc, char **argv)
  117. {
  118. int opt,c;
  119. while ((opt = getopt_long(argc, argv, short_options, long_options, &c)) >= 0) {
  120. switch (opt) {
  121. case 'o':
  122. if (out_fd != -1)
  123. errmsg_die("output filename specified more than once");
  124. out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
  125. if (out_fd == -1)
  126. sys_errmsg_die("open output file");
  127. break;
  128. case 'i':
  129. if (in_fd != -1)
  130. errmsg_die("input filename specified more than once");
  131. in_fd = open(optarg, O_RDONLY);
  132. if (in_fd == -1)
  133. sys_errmsg_die("open input file");
  134. break;
  135. case 'b':
  136. target_endian = __BIG_ENDIAN;
  137. break;
  138. case 'l':
  139. target_endian = __LITTLE_ENDIAN;
  140. break;
  141. case 'h':
  142. puts(helptext);
  143. exit(EXIT_SUCCESS);
  144. case '?':
  145. puts(helptext);
  146. exit(EXIT_FAILURE);
  147. case 'v':
  148. verbose = 1;
  149. break;
  150. case 'V':
  151. common_print_version();
  152. exit(EXIT_SUCCESS);
  153. case 'e': {
  154. char *next;
  155. unsigned units = 0;
  156. erase_block_size = strtol(optarg, &next, 0);
  157. if (!erase_block_size)
  158. errmsg_die("Unrecognisable erase size\n");
  159. if (*next) {
  160. if (!strcmp(next, "KiB")) {
  161. units = 1024;
  162. } else if (!strcmp(next, "MiB")) {
  163. units = 1024 * 1024;
  164. } else {
  165. errmsg_die("Unknown units in erasesize\n");
  166. }
  167. } else {
  168. if (erase_block_size < 0x1000)
  169. units = 1024;
  170. else
  171. units = 1;
  172. }
  173. erase_block_size *= units;
  174. /* If it's less than 8KiB, they're not allowed */
  175. if (erase_block_size < 0x2000) {
  176. warnmsg("Erase size 0x%x too small. Increasing to 8KiB minimum\n",
  177. erase_block_size);
  178. erase_block_size = 0x2000;
  179. }
  180. break;
  181. }
  182. case 'n':
  183. add_cleanmarkers = 0;
  184. break;
  185. case 'c':
  186. cleanmarker_size = strtol(optarg, NULL, 0);
  187. if (cleanmarker_size < sizeof(cleanmarker)) {
  188. errmsg_die("cleanmarker size must be >= 12");
  189. }
  190. if (cleanmarker_size >= erase_block_size) {
  191. errmsg_die("cleanmarker size must be < eraseblock size");
  192. }
  193. use_input_cleanmarker_size = 0;
  194. found_cleanmarkers = 1;
  195. setup_cleanmarker();
  196. break;
  197. case 'p':
  198. padto = 1;
  199. break;
  200. }
  201. }
  202. }
  203. static void init_buffers(void)
  204. {
  205. data_buffer = xmalloc(erase_block_size);
  206. file_buffer = xmalloc(erase_block_size);
  207. }
  208. static void init_sumlist(void)
  209. {
  210. sum_collected = xzalloc(sizeof(*sum_collected));
  211. }
  212. static void clean_buffers(void)
  213. {
  214. free(data_buffer);
  215. free(file_buffer);
  216. }
  217. static void clean_sumlist(void)
  218. {
  219. union jffs2_sum_mem *temp;
  220. if (sum_collected) {
  221. while (sum_collected->sum_list_head) {
  222. temp = sum_collected->sum_list_head;
  223. sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
  224. free(temp);
  225. sum_collected->sum_num--;
  226. }
  227. if (sum_collected->sum_num != 0)
  228. warnmsg("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
  229. free(sum_collected);
  230. }
  231. }
  232. static int load_next_block(void)
  233. {
  234. int ret;
  235. ret = read(in_fd, file_buffer, erase_block_size);
  236. file_ofs = 0;
  237. bareverbose(verbose, "Load next block : %d bytes read\n", ret);
  238. return ret;
  239. }
  240. static void write_buff_to_file(void)
  241. {
  242. int ret;
  243. int len = data_ofs;
  244. uint8_t *buf = NULL;
  245. buf = data_buffer;
  246. while (len > 0) {
  247. ret = write(out_fd, buf, len);
  248. if (ret < 0)
  249. sys_errmsg_die("write");
  250. if (ret == 0)
  251. sys_errmsg_die("write returned zero");
  252. len -= ret;
  253. buf += ret;
  254. }
  255. data_ofs = 0;
  256. }
  257. static void dump_sum_records(void)
  258. {
  259. struct jffs2_raw_summary isum;
  260. struct jffs2_sum_marker *sm;
  261. union jffs2_sum_mem *temp;
  262. jint32_t offset;
  263. jint32_t *tpage;
  264. void *wpage;
  265. int datasize, infosize, padsize;
  266. jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
  267. if (!sum_collected->sum_num || !sum_collected->sum_list_head)
  268. return;
  269. datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
  270. infosize = sizeof(struct jffs2_raw_summary) + datasize;
  271. padsize = erase_block_size - data_ofs - infosize;
  272. infosize += padsize; datasize += padsize;
  273. offset = cpu_to_je32(data_ofs);
  274. tpage = xmalloc(datasize);
  275. memset(tpage, 0xff, datasize);
  276. memset(&isum, 0, sizeof(isum));
  277. isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  278. isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
  279. isum.totlen = cpu_to_je32(infosize);
  280. isum.hdr_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
  281. isum.padded = cpu_to_je32(0);
  282. if (add_cleanmarkers && found_cleanmarkers) {
  283. isum.cln_mkr = cpu_to_je32(cleanmarker_size);
  284. } else {
  285. isum.cln_mkr = cpu_to_je32(0);
  286. }
  287. isum.sum_num = cpu_to_je32(sum_collected->sum_num);
  288. wpage = tpage;
  289. while (sum_collected->sum_num) {
  290. switch(je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) {
  291. case JFFS2_NODETYPE_INODE : {
  292. struct jffs2_sum_inode_flash *sino_ptr = wpage;
  293. sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype;
  294. sino_ptr->inode = sum_collected->sum_list_head->i.inode;
  295. sino_ptr->version = sum_collected->sum_list_head->i.version;
  296. sino_ptr->offset = sum_collected->sum_list_head->i.offset;
  297. sino_ptr->totlen = sum_collected->sum_list_head->i.totlen;
  298. wpage += JFFS2_SUMMARY_INODE_SIZE;
  299. break;
  300. }
  301. case JFFS2_NODETYPE_DIRENT : {
  302. struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
  303. sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype;
  304. sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen;
  305. sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset;
  306. sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino;
  307. sdrnt_ptr->version = sum_collected->sum_list_head->d.version;
  308. sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino;
  309. sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize;
  310. sdrnt_ptr->type = sum_collected->sum_list_head->d.type;
  311. memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name,
  312. sum_collected->sum_list_head->d.nsize);
  313. wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize);
  314. break;
  315. }
  316. case JFFS2_NODETYPE_XATTR: {
  317. struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
  318. sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype;
  319. sxattr_ptr->xid = sum_collected->sum_list_head->x.xid;
  320. sxattr_ptr->version = sum_collected->sum_list_head->x.version;
  321. sxattr_ptr->offset = sum_collected->sum_list_head->x.offset;
  322. sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen;
  323. wpage += JFFS2_SUMMARY_XATTR_SIZE;
  324. break;
  325. }
  326. case JFFS2_NODETYPE_XREF: {
  327. struct jffs2_sum_xref_flash *sxref_ptr = wpage;
  328. sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype;
  329. sxref_ptr->offset = sum_collected->sum_list_head->r.offset;
  330. wpage += JFFS2_SUMMARY_XREF_SIZE;
  331. break;
  332. }
  333. default : {
  334. warnmsg("Unknown node type!\n");
  335. }
  336. }
  337. temp = sum_collected->sum_list_head;
  338. sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
  339. free(temp);
  340. sum_collected->sum_num--;
  341. }
  342. sum_collected->sum_size = 0;
  343. sum_collected->sum_num = 0;
  344. sum_collected->sum_list_tail = NULL;
  345. wpage += padsize;
  346. sm = wpage;
  347. sm->offset = offset;
  348. sm->magic = magic;
  349. isum.sum_crc = cpu_to_je32(mtd_crc32(0, tpage, datasize));
  350. isum.node_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(isum) - 8));
  351. full_write(data_buffer + data_ofs, &isum, sizeof(isum));
  352. full_write(data_buffer + data_ofs, tpage, datasize);
  353. free(tpage);
  354. }
  355. static void full_write(void *target_buff, const void *buf, int len)
  356. {
  357. memcpy(target_buff, buf, len);
  358. data_ofs += len;
  359. }
  360. static void pad(int req)
  361. {
  362. while (req) {
  363. if (req > sizeof(ffbuf)) {
  364. full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf));
  365. req -= sizeof(ffbuf);
  366. } else {
  367. full_write(data_buffer + data_ofs, ffbuf, req);
  368. req = 0;
  369. }
  370. }
  371. }
  372. static inline void padword(void)
  373. {
  374. if (data_ofs % 4)
  375. full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4));
  376. }
  377. static inline void pad_block_if_less_than(int req,int plus)
  378. {
  379. int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
  380. datasize += (4 - (datasize % 4)) % 4;
  381. if (data_ofs + req > erase_block_size - datasize) {
  382. dump_sum_records();
  383. write_buff_to_file();
  384. }
  385. if (add_cleanmarkers && found_cleanmarkers) {
  386. if (!data_ofs) {
  387. full_write(data_buffer, &cleanmarker, sizeof(cleanmarker));
  388. pad(cleanmarker_size - sizeof(cleanmarker));
  389. padword();
  390. }
  391. }
  392. }
  393. static void flush_buffers(void)
  394. {
  395. if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */
  396. if (data_ofs != cleanmarker_size) { /* INODE BUFFER */
  397. int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
  398. datasize += (4 - (datasize % 4)) % 4;
  399. /* If we have a full inode buffer, then write out inode and summary data */
  400. if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
  401. dump_sum_records();
  402. write_buff_to_file();
  403. } else { /* else just write out inode data */
  404. if (padto)
  405. pad(erase_block_size - data_ofs);
  406. write_buff_to_file();
  407. }
  408. }
  409. } else { /* NO CLEANMARKER */
  410. if (data_ofs != 0) { /* INODE BUFFER */
  411. int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
  412. datasize += (4 - (datasize % 4)) % 4;
  413. /* If we have a full inode buffer, then write out inode and summary data */
  414. if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
  415. dump_sum_records();
  416. write_buff_to_file();
  417. } else { /* Else just write out inode data */
  418. if(padto)
  419. pad(erase_block_size - data_ofs);
  420. write_buff_to_file();
  421. }
  422. }
  423. }
  424. }
  425. static int add_sum_mem(union jffs2_sum_mem *item)
  426. {
  427. if (!sum_collected->sum_list_head)
  428. sum_collected->sum_list_head = (union jffs2_sum_mem *) item;
  429. if (sum_collected->sum_list_tail)
  430. sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
  431. sum_collected->sum_list_tail = (union jffs2_sum_mem *) item;
  432. switch (je16_to_cpu(item->u.nodetype)) {
  433. case JFFS2_NODETYPE_INODE:
  434. sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
  435. sum_collected->sum_num++;
  436. break;
  437. case JFFS2_NODETYPE_DIRENT:
  438. sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
  439. sum_collected->sum_num++;
  440. break;
  441. case JFFS2_NODETYPE_XATTR:
  442. sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
  443. sum_collected->sum_num++;
  444. break;
  445. case JFFS2_NODETYPE_XREF:
  446. sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE;
  447. sum_collected->sum_num++;
  448. break;
  449. default:
  450. errmsg_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
  451. }
  452. return 0;
  453. }
  454. static void add_sum_inode_mem(union jffs2_node_union *node)
  455. {
  456. struct jffs2_sum_inode_mem *temp = xmalloc(sizeof(*temp));
  457. temp->nodetype = node->i.nodetype;
  458. temp->inode = node->i.ino;
  459. temp->version = node->i.version;
  460. temp->offset = cpu_to_je32(data_ofs);
  461. temp->totlen = node->i.totlen;
  462. temp->next = NULL;
  463. add_sum_mem((union jffs2_sum_mem *) temp);
  464. }
  465. static void add_sum_dirent_mem(union jffs2_node_union *node)
  466. {
  467. struct jffs2_sum_dirent_mem *temp = xmalloc(sizeof(*temp) + node->d.nsize);
  468. temp->nodetype = node->d.nodetype;
  469. temp->totlen = node->d.totlen;
  470. temp->offset = cpu_to_je32(data_ofs);
  471. temp->pino = node->d.pino;
  472. temp->version = node->d.version;
  473. temp->ino = node->d.ino;
  474. temp->nsize = node->d.nsize;
  475. temp->type = node->d.type;
  476. temp->next = NULL;
  477. memcpy(temp->name,node->d.name,node->d.nsize);
  478. add_sum_mem((union jffs2_sum_mem *) temp);
  479. }
  480. static void add_sum_xattr_mem(union jffs2_node_union *node)
  481. {
  482. struct jffs2_sum_xattr_mem *temp = xmalloc(sizeof(*temp));
  483. temp->nodetype = node->x.nodetype;
  484. temp->xid = node->x.xid;
  485. temp->version = node->x.version;
  486. temp->offset = cpu_to_je32(data_ofs);
  487. temp->totlen = node->x.totlen;
  488. temp->next = NULL;
  489. add_sum_mem((union jffs2_sum_mem *) temp);
  490. }
  491. static void add_sum_xref_mem(union jffs2_node_union *node)
  492. {
  493. struct jffs2_sum_xref_mem *temp = xmalloc(sizeof(*temp));
  494. temp->nodetype = node->r.nodetype;
  495. temp->offset = cpu_to_je32(data_ofs);
  496. temp->next = NULL;
  497. add_sum_mem((union jffs2_sum_mem *) temp);
  498. }
  499. static void write_dirent_to_buff(union jffs2_node_union *node)
  500. {
  501. pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize));
  502. add_sum_dirent_mem(node);
  503. full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen));
  504. padword();
  505. }
  506. static void write_inode_to_buff(union jffs2_node_union *node)
  507. {
  508. pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE);
  509. add_sum_inode_mem(node); /* Add inode summary mem to summary list */
  510. full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen)); /* Write out the inode to inode_buffer */
  511. padword();
  512. }
  513. static void write_xattr_to_buff(union jffs2_node_union *node)
  514. {
  515. pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE);
  516. add_sum_xattr_mem(node); /* Add xdatum summary mem to summary list */
  517. full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen));
  518. padword();
  519. }
  520. static void write_xref_to_buff(union jffs2_node_union *node)
  521. {
  522. pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE);
  523. add_sum_xref_mem(node); /* Add xref summary mem to summary list */
  524. full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen));
  525. padword();
  526. }
  527. static void create_summed_image(int inp_size)
  528. {
  529. uint8_t *p = file_buffer;
  530. union jffs2_node_union *node;
  531. uint32_t crc, length;
  532. uint16_t type;
  533. int bitchbitmask = 0;
  534. int obsolete;
  535. char name[256];
  536. while ( p < (file_buffer + inp_size)) {
  537. node = (union jffs2_node_union *) p;
  538. /* Skip empty space */
  539. if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
  540. p += 4;
  541. continue;
  542. }
  543. if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
  544. if (!bitchbitmask++)
  545. warnmsg("Wrong bitmask at 0x%08zx, 0x%04x\n",
  546. p - file_buffer, je16_to_cpu (node->u.magic));
  547. p += 4;
  548. continue;
  549. }
  550. bitchbitmask = 0;
  551. type = je16_to_cpu(node->u.nodetype);
  552. if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
  553. obsolete = 1;
  554. type |= JFFS2_NODE_ACCURATE;
  555. } else {
  556. obsolete = 0;
  557. }
  558. node->u.nodetype = cpu_to_je16(type);
  559. crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
  560. if (crc != je32_to_cpu (node->u.hdr_crc)) {
  561. warnmsg("Wrong hdr_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
  562. p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
  563. p += 4;
  564. continue;
  565. }
  566. switch(je16_to_cpu(node->u.nodetype)) {
  567. case JFFS2_NODETYPE_INODE:
  568. bareverbose(verbose,
  569. "%8s Inode node at 0x%08zx, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
  570. obsolete ? "Obsolete" : "",
  571. p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
  572. je32_to_cpu (node->i.version), je32_to_cpu (node->i.isize),
  573. je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
  574. crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
  575. if (crc != je32_to_cpu (node->i.node_crc)) {
  576. warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
  577. p - file_buffer, je32_to_cpu (node->i.node_crc), crc);
  578. p += PAD(je32_to_cpu (node->i.totlen));
  579. continue;
  580. }
  581. crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
  582. if (crc != je32_to_cpu(node->i.data_crc)) {
  583. warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
  584. p - file_buffer, je32_to_cpu (node->i.data_crc), crc);
  585. p += PAD(je32_to_cpu (node->i.totlen));
  586. continue;
  587. }
  588. write_inode_to_buff(node);
  589. p += PAD(je32_to_cpu (node->i.totlen));
  590. break;
  591. case JFFS2_NODETYPE_DIRENT:
  592. memcpy (name, node->d.name, node->d.nsize);
  593. name [node->d.nsize] = 0x0;
  594. bareverbose(verbose,
  595. "%8s Dirent node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n",
  596. obsolete ? "Obsolete" : "",
  597. p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
  598. je32_to_cpu (node->d.version), je32_to_cpu (node->d.ino),
  599. node->d.nsize, name);
  600. crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
  601. if (crc != je32_to_cpu (node->d.node_crc)) {
  602. warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
  603. p - file_buffer, je32_to_cpu (node->d.node_crc), crc);
  604. p += PAD(je32_to_cpu (node->d.totlen));
  605. continue;
  606. }
  607. crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
  608. if (crc != je32_to_cpu(node->d.name_crc)) {
  609. warnmsg("Wrong name_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
  610. p - file_buffer, je32_to_cpu (node->d.name_crc), crc);
  611. p += PAD(je32_to_cpu (node->d.totlen));
  612. continue;
  613. }
  614. write_dirent_to_buff(node);
  615. p += PAD(je32_to_cpu (node->d.totlen));
  616. break;
  617. case JFFS2_NODETYPE_XATTR:
  618. if (je32_to_cpu(node->x.node_crc) == 0xffffffff)
  619. obsolete = 1;
  620. bareverbose(verbose,
  621. "%8s Xdatum node at 0x%08zx, totlen 0x%08x, #xid %5u, version %5u\n",
  622. obsolete ? "Obsolete" : "",
  623. p - file_buffer, je32_to_cpu (node->x.totlen),
  624. je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version));
  625. crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4);
  626. if (crc != je32_to_cpu(node->x.node_crc)) {
  627. warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
  628. p - file_buffer, je32_to_cpu(node->x.node_crc), crc);
  629. p += PAD(je32_to_cpu (node->x.totlen));
  630. continue;
  631. }
  632. length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len);
  633. crc = mtd_crc32(0, node->x.data, length);
  634. if (crc != je32_to_cpu(node->x.data_crc)) {
  635. warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
  636. p - file_buffer, je32_to_cpu(node->x.data_crc), crc);
  637. p += PAD(je32_to_cpu (node->x.totlen));
  638. continue;
  639. }
  640. write_xattr_to_buff(node);
  641. p += PAD(je32_to_cpu (node->x.totlen));
  642. break;
  643. case JFFS2_NODETYPE_XREF:
  644. if (je32_to_cpu(node->r.node_crc) == 0xffffffff)
  645. obsolete = 1;
  646. bareverbose(verbose,
  647. "%8s Xref node at 0x%08zx, totlen 0x%08x, #ino %5u, xid %5u\n",
  648. obsolete ? "Obsolete" : "",
  649. p - file_buffer, je32_to_cpu(node->r.totlen),
  650. je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid));
  651. crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xref) - 4);
  652. if (crc != je32_to_cpu(node->r.node_crc)) {
  653. warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
  654. p - file_buffer, je32_to_cpu(node->r.node_crc), crc);
  655. p += PAD(je32_to_cpu (node->r.totlen));
  656. continue;
  657. }
  658. write_xref_to_buff(node);
  659. p += PAD(je32_to_cpu (node->r.totlen));
  660. break;
  661. case JFFS2_NODETYPE_CLEANMARKER:
  662. bareverbose(verbose,
  663. "%8s Cleanmarker at 0x%08zx, totlen 0x%08x\n",
  664. obsolete ? "Obsolete" : "",
  665. p - file_buffer, je32_to_cpu (node->u.totlen));
  666. if (!found_cleanmarkers) {
  667. found_cleanmarkers = 1;
  668. if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){
  669. cleanmarker_size = je32_to_cpu (node->u.totlen);
  670. setup_cleanmarker();
  671. }
  672. }
  673. p += PAD(je32_to_cpu (node->u.totlen));
  674. break;
  675. case JFFS2_NODETYPE_PADDING:
  676. bareverbose(verbose,
  677. "%8s Padding node at 0x%08zx, totlen 0x%08x\n",
  678. obsolete ? "Obsolete" : "",
  679. p - file_buffer, je32_to_cpu (node->u.totlen));
  680. p += PAD(je32_to_cpu (node->u.totlen));
  681. break;
  682. case 0xffff:
  683. p += 4;
  684. break;
  685. default:
  686. bareverbose(verbose,
  687. "%8s Unknown node at 0x%08zx, totlen 0x%08x\n",
  688. obsolete ? "Obsolete" : "",
  689. p - file_buffer, je32_to_cpu (node->u.totlen));
  690. p += PAD(je32_to_cpu (node->u.totlen));
  691. }
  692. }
  693. }
  694. int main(int argc, char **argv)
  695. {
  696. int ret;
  697. process_options(argc,argv);
  698. if ((in_fd == -1) || (out_fd == -1)) {
  699. if(in_fd != -1)
  700. close(in_fd);
  701. if(out_fd != -1)
  702. close(out_fd);
  703. fprintf(stderr, "%s", helptext);
  704. errmsg_die("You must specify input and output files!\n");
  705. }
  706. init_buffers();
  707. init_sumlist();
  708. while ((ret = load_next_block())) {
  709. create_summed_image(ret);
  710. }
  711. flush_buffers();
  712. clean_buffers();
  713. clean_sumlist();
  714. if (in_fd != -1)
  715. close(in_fd);
  716. if (out_fd != -1)
  717. close(out_fd);
  718. return 0;
  719. }