jffs2reader.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * jffs2reader v0.0.18 A jffs2 image reader
  4. *
  5. * Copyright (c) 2001 Jari Kirma <Jari.Kirma@hut.fi>
  6. *
  7. * This software is provided 'as-is', without any express or implied
  8. * warranty. In no event will the author be held liable for any damages
  9. * arising from the use of this software.
  10. *
  11. * Permission is granted to anyone to use this software for any
  12. * purpose, including commercial applications, and to alter it and
  13. * redistribute it freely, subject to the following restrictions:
  14. *
  15. * 1. The origin of this software must not be misrepresented; you must
  16. * not claim that you wrote the original software. If you use this
  17. * software in a product, an acknowledgment in the product
  18. * documentation would be appreciated but is not required.
  19. *
  20. * 2. Altered source versions must be plainly marked as such, and must
  21. * not be misrepresented as being the original software.
  22. *
  23. * 3. This notice may not be removed or altered from any source
  24. * distribution.
  25. *
  26. *
  27. *********
  28. * This code was altered September 2001
  29. * Changes are Copyright (c) Erik Andersen <andersen@codepoet.org>
  30. *
  31. * In compliance with (2) above, this is hereby marked as an altered
  32. * version of this software. It has been altered as follows:
  33. * *) Listing a directory now mimics the behavior of 'ls -l'
  34. * *) Support for recursive listing has been added
  35. * *) Without options, does a recursive 'ls' on the whole filesystem
  36. * *) option parsing now uses getopt()
  37. * *) Now uses printf, and error messages go to stderr.
  38. * *) The copyright notice has been cleaned up and reformatted
  39. * *) The code has been reformatted
  40. * *) Several twisty code paths have been fixed so I can understand them.
  41. * -Erik, 1 September 2001
  42. *
  43. * *) Made it show major/minor numbers for device nodes
  44. * *) Made it show symlink targets
  45. * -Erik, 13 September 2001
  46. */
  47. /*
  48. TODO:
  49. - Add CRC checking code to places marked with XXX.
  50. - Add support for other node compression types.
  51. - Test with real life images.
  52. - Maybe port into bootloader.
  53. */
  54. /*
  55. BUGS:
  56. - Doesn't check CRC checksums.
  57. */
  58. #define PROGRAM_NAME "jffs2reader"
  59. #include <stdint.h>
  60. #include <stdio.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <unistd.h>
  64. #include <fcntl.h>
  65. #include <time.h>
  66. #include <getopt.h>
  67. #include <sys/types.h>
  68. #include <sys/stat.h>
  69. #include <dirent.h>
  70. #include <zlib.h>
  71. #include "mtd/jffs2-user.h"
  72. #include "common.h"
  73. static struct option long_opt[] = {
  74. {"help", 0, NULL, 'h'},
  75. {"version", 0, NULL, 'V'},
  76. {NULL, 0, NULL, 0},
  77. };
  78. static const char *short_opt = "rd:f:tVh";
  79. #define SCRATCH_SIZE (5*1024*1024)
  80. /* macro to avoid "lvalue required as left operand of assignment" error */
  81. #define ADD_BYTES(p, n) ((p) = (typeof(p))((char *)(p) + (n)))
  82. #define DIRENT_INO(dirent) ((dirent) !=NULL ? je32_to_cpu((dirent)->ino) : 0)
  83. #define DIRENT_PINO(dirent) ((dirent) !=NULL ? je32_to_cpu((dirent)->pino) : 0)
  84. struct dir {
  85. struct dir *next;
  86. uint8_t type;
  87. uint8_t nsize;
  88. uint32_t ino;
  89. char name[256];
  90. };
  91. int target_endian = __BYTE_ORDER;
  92. static struct jffs2_raw_inode *find_raw_inode(char *, size_t, uint32_t);
  93. static void lsdir(char *, size_t, const char *, int, int);
  94. /* writes file node into buffer, to the proper position. */
  95. /* reading all valid nodes in version order reconstructs the file. */
  96. /*
  97. b - buffer
  98. bsize - buffer size
  99. rsize - result size
  100. n - node
  101. */
  102. static void putblock(char *b, size_t bsize, size_t * rsize,
  103. struct jffs2_raw_inode *n)
  104. {
  105. uLongf dlen = je32_to_cpu(n->dsize);
  106. if (je32_to_cpu(n->isize) > bsize || (je32_to_cpu(n->offset) + dlen) > bsize)
  107. errmsg_die("File does not fit into buffer!");
  108. if (*rsize < je32_to_cpu(n->isize))
  109. bzero(b + *rsize, je32_to_cpu(n->isize) - *rsize);
  110. switch (n->compr) {
  111. case JFFS2_COMPR_ZLIB:
  112. uncompress((Bytef *) b + je32_to_cpu(n->offset), &dlen,
  113. (Bytef *) ((char *) n) + sizeof(struct jffs2_raw_inode),
  114. (uLongf) je32_to_cpu(n->csize));
  115. break;
  116. case JFFS2_COMPR_NONE:
  117. memcpy(b + je32_to_cpu(n->offset),
  118. ((char *) n) + sizeof(struct jffs2_raw_inode), dlen);
  119. break;
  120. case JFFS2_COMPR_ZERO:
  121. bzero(b + je32_to_cpu(n->offset), dlen);
  122. break;
  123. /* [DYN]RUBIN support required! */
  124. default:
  125. errmsg_die("Unsupported compression method!");
  126. }
  127. *rsize = je32_to_cpu(n->isize);
  128. }
  129. /* adds/removes directory node into dir struct. */
  130. /* reading all valid nodes in version order reconstructs the directory. */
  131. /*
  132. dd - directory struct being processed
  133. n - node
  134. return value: directory struct value replacing dd
  135. */
  136. static struct dir *putdir(struct dir *dd, struct jffs2_raw_dirent *n)
  137. {
  138. struct dir *o, *d, *p;
  139. o = dd;
  140. if (je32_to_cpu(n->ino)) {
  141. if (dd == NULL) {
  142. d = xmalloc(sizeof(struct dir));
  143. d->type = n->type;
  144. memcpy(d->name, n->name, n->nsize);
  145. d->nsize = n->nsize;
  146. d->ino = je32_to_cpu(n->ino);
  147. d->next = NULL;
  148. return d;
  149. }
  150. while (1) {
  151. if (n->nsize == dd->nsize &&
  152. !memcmp(n->name, dd->name, n->nsize)) {
  153. dd->type = n->type;
  154. dd->ino = je32_to_cpu(n->ino);
  155. return o;
  156. }
  157. if (dd->next == NULL) {
  158. dd->next = xmalloc(sizeof(struct dir));
  159. dd->next->type = n->type;
  160. memcpy(dd->next->name, n->name, n->nsize);
  161. dd->next->nsize = n->nsize;
  162. dd->next->ino = je32_to_cpu(n->ino);
  163. dd->next->next = NULL;
  164. return o;
  165. }
  166. dd = dd->next;
  167. }
  168. } else {
  169. if (dd == NULL)
  170. return NULL;
  171. if (n->nsize == dd->nsize && !memcmp(n->name, dd->name, n->nsize)) {
  172. d = dd->next;
  173. free(dd);
  174. return d;
  175. }
  176. while (1) {
  177. p = dd;
  178. dd = dd->next;
  179. if (dd == NULL)
  180. return o;
  181. if (n->nsize == dd->nsize &&
  182. !memcmp(n->name, dd->name, n->nsize)) {
  183. p->next = dd->next;
  184. free(dd);
  185. return o;
  186. }
  187. }
  188. }
  189. }
  190. #define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
  191. #define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
  192. /* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
  193. static const mode_t SBIT[] = {
  194. 0, 0, S_ISUID,
  195. 0, 0, S_ISGID,
  196. 0, 0, S_ISVTX
  197. };
  198. /* The 9 mode bits to test */
  199. static const mode_t MBIT[] = {
  200. S_IRUSR, S_IWUSR, S_IXUSR,
  201. S_IRGRP, S_IWGRP, S_IXGRP,
  202. S_IROTH, S_IWOTH, S_IXOTH
  203. };
  204. static const char MODE1[] = "rwxrwxrwx";
  205. static const char MODE0[] = "---------";
  206. static const char SMODE1[] = "..s..s..t";
  207. static const char SMODE0[] = "..S..S..T";
  208. /*
  209. * Return the standard ls-like mode string from a file mode.
  210. * This is static and so is overwritten on each call.
  211. */
  212. static const char *mode_string(int mode)
  213. {
  214. static char buf[12];
  215. int i;
  216. buf[0] = TYPECHAR(mode);
  217. for (i = 0; i < 9; i++) {
  218. if (mode & SBIT[i])
  219. buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
  220. else
  221. buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
  222. }
  223. return buf;
  224. }
  225. /* prints contents of directory structure */
  226. /*
  227. d - dir struct
  228. */
  229. static void printdir(char *o, size_t size, struct dir *d, const char *path,
  230. int recurse, int want_ctime)
  231. {
  232. char m;
  233. char *filetime;
  234. time_t age;
  235. struct jffs2_raw_inode *ri;
  236. jint32_t mode;
  237. if (!path)
  238. return;
  239. if (strlen(path) == 1 && *path == '/')
  240. path++;
  241. while (d != NULL) {
  242. switch (d->type) {
  243. case DT_REG:
  244. m = ' ';
  245. break;
  246. case DT_FIFO:
  247. m = '|';
  248. break;
  249. case DT_CHR:
  250. m = ' ';
  251. break;
  252. case DT_BLK:
  253. m = ' ';
  254. break;
  255. case DT_DIR:
  256. m = '/';
  257. break;
  258. case DT_LNK:
  259. m = ' ';
  260. break;
  261. case DT_SOCK:
  262. m = '=';
  263. break;
  264. default:
  265. m = '?';
  266. }
  267. ri = find_raw_inode(o, size, d->ino);
  268. if (!ri) {
  269. warnmsg("bug: raw_inode missing!");
  270. d = d->next;
  271. continue;
  272. }
  273. filetime = ctime((const time_t *) &(ri->ctime));
  274. age = time(NULL) - je32_to_cpu(ri->ctime);
  275. mode.v32 = ri->mode.m;
  276. printf("%s %-4d %-8d %-8d ", mode_string(je32_to_cpu(mode)),
  277. 1, je16_to_cpu(ri->uid), je16_to_cpu(ri->gid));
  278. if ( d->type==DT_BLK || d->type==DT_CHR ) {
  279. dev_t rdev;
  280. size_t devsize;
  281. putblock((char*)&rdev, sizeof(rdev), &devsize, ri);
  282. printf("%4d, %3d ", major(rdev), minor(rdev));
  283. } else {
  284. printf("%9ld ", (long)je32_to_cpu(ri->dsize));
  285. }
  286. d->name[d->nsize]='\0';
  287. if (want_ctime) {
  288. if (age < 3600L * 24 * 365 / 2 && age > -15 * 60)
  289. /* hh:mm if less than 6 months old */
  290. printf("%6.6s %5.5s ", filetime + 4, filetime + 11);
  291. else
  292. printf("%6.6s %4.4s ", filetime + 4, filetime + 20);
  293. }
  294. printf("%s/%s%c", path, d->name, m);
  295. if (d->type == DT_LNK) {
  296. char symbuf[1024];
  297. size_t symsize;
  298. putblock(symbuf, sizeof(symbuf), &symsize, ri);
  299. symbuf[symsize] = 0;
  300. printf(" -> %s", symbuf);
  301. }
  302. printf("\n");
  303. if (d->type == DT_DIR && recurse) {
  304. char *tmp;
  305. tmp = xmalloc(BUFSIZ);
  306. sprintf(tmp, "%s/%s", path, d->name);
  307. lsdir(o, size, tmp, recurse, want_ctime); /* Go recursive */
  308. free(tmp);
  309. }
  310. d = d->next;
  311. }
  312. }
  313. /* frees memory used by directory structure */
  314. /*
  315. d - dir struct
  316. */
  317. static void freedir(struct dir *d)
  318. {
  319. struct dir *t;
  320. while (d != NULL) {
  321. t = d->next;
  322. free(d);
  323. d = t;
  324. }
  325. }
  326. /* collects directory/file nodes in version order. */
  327. /*
  328. f - file flag.
  329. if zero, collect file, compare ino to inode
  330. otherwise, collect directory, compare ino to parent inode
  331. o - filesystem image pointer
  332. size - size of filesystem image
  333. ino - inode to compare against. see f.
  334. return value: a jffs2_raw_inode that corresponds the the specified
  335. inode, or NULL
  336. */
  337. static struct jffs2_raw_inode *find_raw_inode(char *o, size_t size,
  338. uint32_t ino)
  339. {
  340. /* aligned! */
  341. union jffs2_node_union *n;
  342. union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
  343. union jffs2_node_union *lr; /* last block position */
  344. union jffs2_node_union *mp = NULL; /* minimum position */
  345. uint32_t vmin, vmint, vmaxt, vmax, vcur, v;
  346. vmin = 0; /* next to read */
  347. vmax = ~((uint32_t) 0); /* last to read */
  348. vmint = ~((uint32_t) 0);
  349. vmaxt = 0; /* found maximum */
  350. vcur = 0; /* XXX what is smallest version number used? */
  351. /* too low version number can easily result excess log rereading */
  352. n = (union jffs2_node_union *) o;
  353. lr = n;
  354. do {
  355. while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
  356. ADD_BYTES(n, 4);
  357. if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
  358. if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_INODE &&
  359. je32_to_cpu(n->i.ino) == ino && (v = je32_to_cpu(n->i.version)) > vcur) {
  360. /* XXX crc check */
  361. if (vmaxt < v)
  362. vmaxt = v;
  363. if (vmint > v) {
  364. vmint = v;
  365. mp = n;
  366. }
  367. if (v == (vcur + 1))
  368. return (&(n->i));
  369. }
  370. ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
  371. } else
  372. n = (union jffs2_node_union *) o; /* we're at the end, rewind to the beginning */
  373. if (lr == n) { /* whole loop since last read */
  374. vmax = vmaxt;
  375. vmin = vmint;
  376. vmint = ~((uint32_t) 0);
  377. if (vcur < vmax && vcur < vmin)
  378. return (&(mp->i));
  379. }
  380. } while (vcur < vmax);
  381. return NULL;
  382. }
  383. /* collects dir struct for selected inode */
  384. /*
  385. o - filesystem image pointer
  386. size - size of filesystem image
  387. pino - inode of the specified directory
  388. d - input directory structure
  389. return value: result directory structure, replaces d.
  390. */
  391. static struct dir *collectdir(char *o, size_t size, uint32_t ino, struct dir *d)
  392. {
  393. /* aligned! */
  394. union jffs2_node_union *n;
  395. union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
  396. union jffs2_node_union *lr; /* last block position */
  397. union jffs2_node_union *mp = NULL; /* minimum position */
  398. uint32_t vmin, vmint, vmaxt, vmax, vcur, v;
  399. vmin = 0; /* next to read */
  400. vmax = ~((uint32_t) 0); /* last to read */
  401. vmint = ~((uint32_t) 0);
  402. vmaxt = 0; /* found maximum */
  403. vcur = 0; /* XXX what is smallest version number used? */
  404. /* too low version number can easily result excess log rereading */
  405. n = (union jffs2_node_union *) o;
  406. lr = n;
  407. do {
  408. while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
  409. ADD_BYTES(n, 4);
  410. if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
  411. if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_DIRENT &&
  412. je32_to_cpu(n->d.pino) == ino && (v = je32_to_cpu(n->d.version)) > vcur) {
  413. /* XXX crc check */
  414. if (vmaxt < v)
  415. vmaxt = v;
  416. if (vmint > v) {
  417. vmint = v;
  418. mp = n;
  419. }
  420. if (v == (vcur + 1)) {
  421. d = putdir(d, &(n->d));
  422. lr = n;
  423. vcur++;
  424. vmint = ~((uint32_t) 0);
  425. }
  426. }
  427. ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
  428. } else
  429. n = (union jffs2_node_union *) o; /* we're at the end, rewind to the beginning */
  430. if (lr == n) { /* whole loop since last read */
  431. vmax = vmaxt;
  432. vmin = vmint;
  433. vmint = ~((uint32_t) 0);
  434. if (vcur < vmax && vcur < vmin) {
  435. d = putdir(d, &(mp->d));
  436. lr = n =
  437. (union jffs2_node_union *) (((char *) mp) +
  438. ((je32_to_cpu(mp->u.totlen) + 3) & ~3));
  439. vcur = vmin;
  440. }
  441. }
  442. } while (vcur < vmax);
  443. return d;
  444. }
  445. /* resolve dirent based on criteria */
  446. /*
  447. o - filesystem image pointer
  448. size - size of filesystem image
  449. ino - if zero, ignore,
  450. otherwise compare against dirent inode
  451. pino - if zero, ingore,
  452. otherwise compare against parent inode
  453. and use name and nsize as extra criteria
  454. name - name of wanted dirent, used if pino!=0
  455. nsize - length of name of wanted dirent, used if pino!=0
  456. return value: pointer to relevant dirent structure in
  457. filesystem image or NULL
  458. */
  459. static struct jffs2_raw_dirent *resolvedirent(char *o, size_t size,
  460. uint32_t ino, uint32_t pino,
  461. char *name, uint8_t nsize)
  462. {
  463. /* aligned! */
  464. union jffs2_node_union *n;
  465. union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
  466. struct jffs2_raw_dirent *dd = NULL;
  467. uint32_t vmax, v;
  468. if (!pino && ino <= 1)
  469. return dd;
  470. vmax = 0;
  471. n = (union jffs2_node_union *) o;
  472. do {
  473. while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
  474. ADD_BYTES(n, 4);
  475. if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
  476. if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_DIRENT &&
  477. (!ino || je32_to_cpu(n->d.ino) == ino) &&
  478. (v = je32_to_cpu(n->d.version)) > vmax &&
  479. (!pino || (je32_to_cpu(n->d.pino) == pino &&
  480. nsize == n->d.nsize &&
  481. !memcmp(name, n->d.name, nsize)))) {
  482. /* XXX crc check */
  483. if (vmax < v) {
  484. vmax = v;
  485. dd = &(n->d);
  486. }
  487. }
  488. ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
  489. } else
  490. return dd;
  491. } while (1);
  492. }
  493. /* resolve name under certain parent inode to dirent */
  494. /*
  495. o - filesystem image pointer
  496. size - size of filesystem image
  497. pino - requested parent inode
  498. name - name of wanted dirent
  499. nsize - length of name of wanted dirent
  500. return value: pointer to relevant dirent structure in
  501. filesystem image or NULL
  502. */
  503. static struct jffs2_raw_dirent *resolvename(char *o, size_t size, uint32_t pino,
  504. char *name, uint8_t nsize)
  505. {
  506. return resolvedirent(o, size, 0, pino, name, nsize);
  507. }
  508. /* resolve inode to dirent */
  509. /*
  510. o - filesystem image pointer
  511. size - size of filesystem image
  512. ino - compare against dirent inode
  513. return value: pointer to relevant dirent structure in
  514. filesystem image or NULL
  515. */
  516. static struct jffs2_raw_dirent *resolveinode(char *o, size_t size, uint32_t ino)
  517. {
  518. return resolvedirent(o, size, ino, 0, NULL, 0);
  519. }
  520. /* resolve slash-style path into dirent and inode.
  521. slash as first byte marks absolute path (root=inode 1).
  522. . and .. are resolved properly, and symlinks are followed.
  523. */
  524. /*
  525. o - filesystem image pointer
  526. size - size of filesystem image
  527. ino - root inode, used if path is relative
  528. p - path to be resolved
  529. inos - result inode, zero if failure
  530. recc - recursion count, to detect symlink loops
  531. return value: pointer to dirent struct in file system image.
  532. note that root directory doesn't have dirent struct
  533. (return value is NULL), but it has inode (*inos=1)
  534. */
  535. static struct jffs2_raw_dirent *resolvepath0(char *o, size_t size, uint32_t ino,
  536. const char *p, uint32_t * inos, int recc)
  537. {
  538. struct jffs2_raw_dirent *dir = NULL;
  539. int d = 1;
  540. uint32_t tino;
  541. char *next;
  542. char *path, *pp;
  543. char symbuf[1024];
  544. size_t symsize;
  545. if (recc > 16) {
  546. /* probably symlink loop */
  547. *inos = 0;
  548. return NULL;
  549. }
  550. pp = path = xstrdup(p);
  551. if (*path == '/') {
  552. path++;
  553. ino = 1;
  554. }
  555. if (ino > 1) {
  556. dir = resolveinode(o, size, ino);
  557. ino = DIRENT_INO(dir);
  558. }
  559. next = path - 1;
  560. while (ino && next != NULL && next[1] != 0 && d) {
  561. path = next + 1;
  562. next = strchr(path, '/');
  563. if (next != NULL)
  564. *next = 0;
  565. if (*path == '.' && path[1] == 0)
  566. continue;
  567. if (*path == '.' && path[1] == '.' && path[2] == 0) {
  568. if (DIRENT_PINO(dir) == 1) {
  569. ino = 1;
  570. dir = NULL;
  571. } else {
  572. dir = resolveinode(o, size, DIRENT_PINO(dir));
  573. ino = DIRENT_INO(dir);
  574. }
  575. continue;
  576. }
  577. dir = resolvename(o, size, ino, path, (uint8_t) strlen(path));
  578. if (DIRENT_INO(dir) == 0 ||
  579. (next != NULL &&
  580. !(dir->type == DT_DIR || dir->type == DT_LNK))) {
  581. free(pp);
  582. *inos = 0;
  583. return NULL;
  584. }
  585. if (dir->type == DT_LNK) {
  586. struct jffs2_raw_inode *ri;
  587. ri = find_raw_inode(o, size, DIRENT_INO(dir));
  588. putblock(symbuf, sizeof(symbuf), &symsize, ri);
  589. symbuf[symsize] = 0;
  590. tino = ino;
  591. ino = 0;
  592. dir = resolvepath0(o, size, tino, symbuf, &ino, ++recc);
  593. if (dir != NULL && next != NULL &&
  594. !(dir->type == DT_DIR || dir->type == DT_LNK)) {
  595. free(pp);
  596. *inos = 0;
  597. return NULL;
  598. }
  599. }
  600. if (dir != NULL)
  601. ino = DIRENT_INO(dir);
  602. }
  603. free(pp);
  604. *inos = ino;
  605. return dir;
  606. }
  607. /* resolve slash-style path into dirent and inode.
  608. slash as first byte marks absolute path (root=inode 1).
  609. . and .. are resolved properly, and symlinks are followed.
  610. */
  611. /*
  612. o - filesystem image pointer
  613. size - size of filesystem image
  614. ino - root inode, used if path is relative
  615. p - path to be resolved
  616. inos - result inode, zero if failure
  617. return value: pointer to dirent struct in file system image.
  618. note that root directory doesn't have dirent struct
  619. (return value is NULL), but it has inode (*inos=1)
  620. */
  621. static struct jffs2_raw_dirent *resolvepath(char *o, size_t size, uint32_t ino,
  622. const char *p, uint32_t * inos)
  623. {
  624. return resolvepath0(o, size, ino, p, inos, 0);
  625. }
  626. /* lists files on directory specified by path */
  627. /*
  628. o - filesystem image pointer
  629. size - size of filesystem image
  630. p - path to be resolved
  631. */
  632. static void lsdir(char *o, size_t size, const char *path, int recurse,
  633. int want_ctime)
  634. {
  635. struct jffs2_raw_dirent *dd;
  636. struct dir *d = NULL;
  637. uint32_t ino;
  638. dd = resolvepath(o, size, 1, path, &ino);
  639. if (ino == 0 ||
  640. (dd == NULL && ino == 0) || (dd != NULL && dd->type != DT_DIR))
  641. errmsg_die("%s: No such file or directory", path);
  642. d = collectdir(o, size, ino, d);
  643. printdir(o, size, d, path, recurse, want_ctime);
  644. freedir(d);
  645. }
  646. /* writes file specified by path to the buffer */
  647. /*
  648. o - filesystem image pointer
  649. size - size of filesystem image
  650. p - path to be resolved
  651. b - file buffer
  652. bsize - file buffer size
  653. rsize - file result size
  654. */
  655. static void catfile(char *o, size_t size, char *path, char *b, size_t bsize,
  656. size_t * rsize)
  657. {
  658. struct jffs2_raw_dirent *dd;
  659. struct jffs2_raw_inode *ri;
  660. uint32_t ino;
  661. dd = resolvepath(o, size, 1, path, &ino);
  662. if (ino == 0)
  663. errmsg_die("%s: No such file or directory", path);
  664. if (dd == NULL || dd->type != DT_REG)
  665. errmsg_die("%s: Not a regular file", path);
  666. ri = find_raw_inode(o, size, ino);
  667. putblock(b, bsize, rsize, ri);
  668. write_nocheck(1, b, *rsize);
  669. }
  670. /* usage example */
  671. int main(int argc, char **argv)
  672. {
  673. int fd, opt, c, recurse = 0, want_ctime = 0;
  674. struct stat st;
  675. char *scratch, *dir = NULL, *file = NULL;
  676. size_t ssize = 0;
  677. char *buf;
  678. while ((opt = getopt_long(argc, argv, short_opt, long_opt, &c)) > 0) {
  679. switch (opt) {
  680. case 'd':
  681. dir = optarg;
  682. break;
  683. case 'f':
  684. file = optarg;
  685. break;
  686. case 'r':
  687. recurse++;
  688. break;
  689. case 't':
  690. want_ctime++;
  691. break;
  692. case 'V':
  693. common_print_version();
  694. exit(EXIT_SUCCESS);
  695. default:
  696. fprintf(stderr,
  697. "Usage: %s <image> [-d|-f] < path >\n",
  698. PROGRAM_NAME);
  699. exit(opt == 'h' ? EXIT_SUCCESS : EXIT_FAILURE);
  700. }
  701. }
  702. fd = open(argv[optind], O_RDONLY);
  703. if (fd == -1)
  704. sys_errmsg_die("%s", argv[optind]);
  705. if (fstat(fd, &st))
  706. sys_errmsg_die("%s", argv[optind]);
  707. buf = xmalloc((size_t) st.st_size);
  708. if (read(fd, buf, st.st_size) != (ssize_t) st.st_size)
  709. sys_errmsg_die("%s", argv[optind]);
  710. if (dir)
  711. lsdir(buf, st.st_size, dir, recurse, want_ctime);
  712. if (file) {
  713. scratch = xmalloc(SCRATCH_SIZE);
  714. catfile(buf, st.st_size, file, scratch, SCRATCH_SIZE, &ssize);
  715. free(scratch);
  716. }
  717. if (!dir && !file)
  718. lsdir(buf, st.st_size, "/", 1, want_ctime);
  719. free(buf);
  720. exit(EXIT_SUCCESS);
  721. }