ext4_common.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. /*
  2. * (C) Copyright 2011 - 2012 Samsung Electronics
  3. * EXT4 filesystem implementation in Uboot by
  4. * Uma Shankar <uma.shankar@samsung.com>
  5. * Manjunatha C Achar <a.manjunatha@samsung.com>
  6. *
  7. * ext4ls and ext4load : Based on ext2 ls load support in Uboot.
  8. *
  9. * (C) Copyright 2004
  10. * esd gmbh <www.esd-electronics.com>
  11. * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
  12. *
  13. * based on code from grub2 fs/ext2.c and fs/fshelp.c by
  14. * GRUB -- GRand Unified Bootloader
  15. * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
  16. *
  17. * This program is free software; you can redistribute it and/or modify
  18. * it under the terms of the GNU General Public License as published by
  19. * the Free Software Foundation; either version 2 of the License, or
  20. * (at your option) any later version.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU General Public License
  28. * along with this program; if not, write to the Free Software
  29. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  30. */
  31. #include <common.h>
  32. #include <ext_common.h>
  33. #include <ext4fs.h>
  34. #include <malloc.h>
  35. #include <stddef.h>
  36. #include <linux/stat.h>
  37. #include <linux/time.h>
  38. #include <asm/byteorder.h>
  39. #include "ext4_common.h"
  40. struct ext2_data *ext4fs_root;
  41. struct ext2fs_node *ext4fs_file;
  42. uint32_t *ext4fs_indir1_block;
  43. int ext4fs_indir1_size;
  44. int ext4fs_indir1_blkno = -1;
  45. uint32_t *ext4fs_indir2_block;
  46. int ext4fs_indir2_size;
  47. int ext4fs_indir2_blkno = -1;
  48. uint32_t *ext4fs_indir3_block;
  49. int ext4fs_indir3_size;
  50. int ext4fs_indir3_blkno = -1;
  51. struct ext2_inode *g_parent_inode;
  52. static int symlinknest;
  53. static struct ext4_extent_header *ext4fs_get_extent_block
  54. (struct ext2_data *data, char *buf,
  55. struct ext4_extent_header *ext_block,
  56. uint32_t fileblock, int log2_blksz)
  57. {
  58. struct ext4_extent_idx *index;
  59. unsigned long long block;
  60. struct ext_filesystem *fs = get_fs();
  61. int i;
  62. while (1) {
  63. index = (struct ext4_extent_idx *)(ext_block + 1);
  64. if (le32_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC)
  65. return 0;
  66. if (ext_block->eh_depth == 0)
  67. return ext_block;
  68. i = -1;
  69. do {
  70. i++;
  71. if (i >= le32_to_cpu(ext_block->eh_entries))
  72. break;
  73. } while (fileblock > le32_to_cpu(index[i].ei_block));
  74. if (--i < 0)
  75. return 0;
  76. block = le32_to_cpu(index[i].ei_leaf_hi);
  77. block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo);
  78. if (ext4fs_devread(block << log2_blksz, 0, fs->blksz, buf))
  79. ext_block = (struct ext4_extent_header *)buf;
  80. else
  81. return 0;
  82. }
  83. }
  84. static int ext4fs_blockgroup
  85. (struct ext2_data *data, int group, struct ext2_block_group *blkgrp)
  86. {
  87. long int blkno;
  88. unsigned int blkoff, desc_per_blk;
  89. desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group);
  90. blkno = __le32_to_cpu(data->sblock.first_data_block) + 1 +
  91. group / desc_per_blk;
  92. blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group);
  93. debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n",
  94. group, blkno, blkoff);
  95. return ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data),
  96. blkoff, sizeof(struct ext2_block_group),
  97. (char *)blkgrp);
  98. }
  99. int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
  100. {
  101. struct ext2_block_group blkgrp;
  102. struct ext2_sblock *sblock = &data->sblock;
  103. struct ext_filesystem *fs = get_fs();
  104. int inodes_per_block, status;
  105. long int blkno;
  106. unsigned int blkoff;
  107. /* It is easier to calculate if the first inode is 0. */
  108. ino--;
  109. status = ext4fs_blockgroup(data, ino / __le32_to_cpu
  110. (sblock->inodes_per_group), &blkgrp);
  111. if (status == 0)
  112. return 0;
  113. inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz;
  114. blkno = __le32_to_cpu(blkgrp.inode_table_id) +
  115. (ino % __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
  116. blkoff = (ino % inodes_per_block) * fs->inodesz;
  117. /* Read the inode. */
  118. status = ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data), blkoff,
  119. sizeof(struct ext2_inode), (char *)inode);
  120. if (status == 0)
  121. return 0;
  122. return 1;
  123. }
  124. long int read_allocated_block(struct ext2_inode *inode, int fileblock)
  125. {
  126. long int blknr;
  127. int blksz;
  128. int log2_blksz;
  129. int status;
  130. long int rblock;
  131. long int perblock_parent;
  132. long int perblock_child;
  133. unsigned long long start;
  134. /* get the blocksize of the filesystem */
  135. blksz = EXT2_BLOCK_SIZE(ext4fs_root);
  136. log2_blksz = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
  137. if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
  138. char *buf = zalloc(blksz);
  139. if (!buf)
  140. return -ENOMEM;
  141. struct ext4_extent_header *ext_block;
  142. struct ext4_extent *extent;
  143. int i = -1;
  144. ext_block = ext4fs_get_extent_block(ext4fs_root, buf,
  145. (struct ext4_extent_header
  146. *)inode->b.
  147. blocks.dir_blocks,
  148. fileblock, log2_blksz);
  149. if (!ext_block) {
  150. printf("invalid extent block\n");
  151. free(buf);
  152. return -EINVAL;
  153. }
  154. extent = (struct ext4_extent *)(ext_block + 1);
  155. do {
  156. i++;
  157. if (i >= le32_to_cpu(ext_block->eh_entries))
  158. break;
  159. } while (fileblock >= le32_to_cpu(extent[i].ee_block));
  160. if (--i >= 0) {
  161. fileblock -= le32_to_cpu(extent[i].ee_block);
  162. if (fileblock >= le32_to_cpu(extent[i].ee_len)) {
  163. free(buf);
  164. return 0;
  165. }
  166. start = le32_to_cpu(extent[i].ee_start_hi);
  167. start = (start << 32) +
  168. le32_to_cpu(extent[i].ee_start_lo);
  169. free(buf);
  170. return fileblock + start;
  171. }
  172. printf("Extent Error\n");
  173. free(buf);
  174. return -1;
  175. }
  176. /* Direct blocks. */
  177. if (fileblock < INDIRECT_BLOCKS)
  178. blknr = __le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]);
  179. /* Indirect. */
  180. else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
  181. if (ext4fs_indir1_block == NULL) {
  182. ext4fs_indir1_block = zalloc(blksz);
  183. if (ext4fs_indir1_block == NULL) {
  184. printf("** SI ext2fs read block (indir 1)"
  185. "malloc failed. **\n");
  186. return -1;
  187. }
  188. ext4fs_indir1_size = blksz;
  189. ext4fs_indir1_blkno = -1;
  190. }
  191. if (blksz != ext4fs_indir1_size) {
  192. free(ext4fs_indir1_block);
  193. ext4fs_indir1_block = NULL;
  194. ext4fs_indir1_size = 0;
  195. ext4fs_indir1_blkno = -1;
  196. ext4fs_indir1_block = zalloc(blksz);
  197. if (ext4fs_indir1_block == NULL) {
  198. printf("** SI ext2fs read block (indir 1):"
  199. "malloc failed. **\n");
  200. return -1;
  201. }
  202. ext4fs_indir1_size = blksz;
  203. }
  204. if ((__le32_to_cpu(inode->b.blocks.indir_block) <<
  205. log2_blksz) != ext4fs_indir1_blkno) {
  206. status =
  207. ext4fs_devread(__le32_to_cpu
  208. (inode->b.blocks.
  209. indir_block) << log2_blksz, 0,
  210. blksz, (char *)ext4fs_indir1_block);
  211. if (status == 0) {
  212. printf("** SI ext2fs read block (indir 1)"
  213. "failed. **\n");
  214. return 0;
  215. }
  216. ext4fs_indir1_blkno =
  217. __le32_to_cpu(inode->b.blocks.
  218. indir_block) << log2_blksz;
  219. }
  220. blknr = __le32_to_cpu(ext4fs_indir1_block
  221. [fileblock - INDIRECT_BLOCKS]);
  222. }
  223. /* Double indirect. */
  224. else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4 *
  225. (blksz / 4 + 1)))) {
  226. long int perblock = blksz / 4;
  227. long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4);
  228. if (ext4fs_indir1_block == NULL) {
  229. ext4fs_indir1_block = zalloc(blksz);
  230. if (ext4fs_indir1_block == NULL) {
  231. printf("** DI ext2fs read block (indir 2 1)"
  232. "malloc failed. **\n");
  233. return -1;
  234. }
  235. ext4fs_indir1_size = blksz;
  236. ext4fs_indir1_blkno = -1;
  237. }
  238. if (blksz != ext4fs_indir1_size) {
  239. free(ext4fs_indir1_block);
  240. ext4fs_indir1_block = NULL;
  241. ext4fs_indir1_size = 0;
  242. ext4fs_indir1_blkno = -1;
  243. ext4fs_indir1_block = zalloc(blksz);
  244. if (ext4fs_indir1_block == NULL) {
  245. printf("** DI ext2fs read block (indir 2 1)"
  246. "malloc failed. **\n");
  247. return -1;
  248. }
  249. ext4fs_indir1_size = blksz;
  250. }
  251. if ((__le32_to_cpu(inode->b.blocks.double_indir_block) <<
  252. log2_blksz) != ext4fs_indir1_blkno) {
  253. status =
  254. ext4fs_devread(__le32_to_cpu
  255. (inode->b.blocks.
  256. double_indir_block) << log2_blksz,
  257. 0, blksz,
  258. (char *)ext4fs_indir1_block);
  259. if (status == 0) {
  260. printf("** DI ext2fs read block (indir 2 1)"
  261. "failed. **\n");
  262. return -1;
  263. }
  264. ext4fs_indir1_blkno =
  265. __le32_to_cpu(inode->b.blocks.double_indir_block) <<
  266. log2_blksz;
  267. }
  268. if (ext4fs_indir2_block == NULL) {
  269. ext4fs_indir2_block = zalloc(blksz);
  270. if (ext4fs_indir2_block == NULL) {
  271. printf("** DI ext2fs read block (indir 2 2)"
  272. "malloc failed. **\n");
  273. return -1;
  274. }
  275. ext4fs_indir2_size = blksz;
  276. ext4fs_indir2_blkno = -1;
  277. }
  278. if (blksz != ext4fs_indir2_size) {
  279. free(ext4fs_indir2_block);
  280. ext4fs_indir2_block = NULL;
  281. ext4fs_indir2_size = 0;
  282. ext4fs_indir2_blkno = -1;
  283. ext4fs_indir2_block = zalloc(blksz);
  284. if (ext4fs_indir2_block == NULL) {
  285. printf("** DI ext2fs read block (indir 2 2)"
  286. "malloc failed. **\n");
  287. return -1;
  288. }
  289. ext4fs_indir2_size = blksz;
  290. }
  291. if ((__le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) <<
  292. log2_blksz) != ext4fs_indir2_blkno) {
  293. status = ext4fs_devread(__le32_to_cpu
  294. (ext4fs_indir1_block
  295. [rblock /
  296. perblock]) << log2_blksz, 0,
  297. blksz,
  298. (char *)ext4fs_indir2_block);
  299. if (status == 0) {
  300. printf("** DI ext2fs read block (indir 2 2)"
  301. "failed. **\n");
  302. return -1;
  303. }
  304. ext4fs_indir2_blkno =
  305. __le32_to_cpu(ext4fs_indir1_block[rblock
  306. /
  307. perblock]) <<
  308. log2_blksz;
  309. }
  310. blknr = __le32_to_cpu(ext4fs_indir2_block[rblock % perblock]);
  311. }
  312. /* Tripple indirect. */
  313. else {
  314. rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 +
  315. (blksz / 4 * blksz / 4));
  316. perblock_child = blksz / 4;
  317. perblock_parent = ((blksz / 4) * (blksz / 4));
  318. if (ext4fs_indir1_block == NULL) {
  319. ext4fs_indir1_block = zalloc(blksz);
  320. if (ext4fs_indir1_block == NULL) {
  321. printf("** TI ext2fs read block (indir 2 1)"
  322. "malloc failed. **\n");
  323. return -1;
  324. }
  325. ext4fs_indir1_size = blksz;
  326. ext4fs_indir1_blkno = -1;
  327. }
  328. if (blksz != ext4fs_indir1_size) {
  329. free(ext4fs_indir1_block);
  330. ext4fs_indir1_block = NULL;
  331. ext4fs_indir1_size = 0;
  332. ext4fs_indir1_blkno = -1;
  333. ext4fs_indir1_block = zalloc(blksz);
  334. if (ext4fs_indir1_block == NULL) {
  335. printf("** TI ext2fs read block (indir 2 1)"
  336. "malloc failed. **\n");
  337. return -1;
  338. }
  339. ext4fs_indir1_size = blksz;
  340. }
  341. if ((__le32_to_cpu(inode->b.blocks.triple_indir_block) <<
  342. log2_blksz) != ext4fs_indir1_blkno) {
  343. status = ext4fs_devread
  344. (__le32_to_cpu(inode->b.blocks.triple_indir_block)
  345. << log2_blksz, 0, blksz,
  346. (char *)ext4fs_indir1_block);
  347. if (status == 0) {
  348. printf("** TI ext2fs read block (indir 2 1)"
  349. "failed. **\n");
  350. return -1;
  351. }
  352. ext4fs_indir1_blkno =
  353. __le32_to_cpu(inode->b.blocks.triple_indir_block) <<
  354. log2_blksz;
  355. }
  356. if (ext4fs_indir2_block == NULL) {
  357. ext4fs_indir2_block = zalloc(blksz);
  358. if (ext4fs_indir2_block == NULL) {
  359. printf("** TI ext2fs read block (indir 2 2)"
  360. "malloc failed. **\n");
  361. return -1;
  362. }
  363. ext4fs_indir2_size = blksz;
  364. ext4fs_indir2_blkno = -1;
  365. }
  366. if (blksz != ext4fs_indir2_size) {
  367. free(ext4fs_indir2_block);
  368. ext4fs_indir2_block = NULL;
  369. ext4fs_indir2_size = 0;
  370. ext4fs_indir2_blkno = -1;
  371. ext4fs_indir2_block = zalloc(blksz);
  372. if (ext4fs_indir2_block == NULL) {
  373. printf("** TI ext2fs read block (indir 2 2)"
  374. "malloc failed. **\n");
  375. return -1;
  376. }
  377. ext4fs_indir2_size = blksz;
  378. }
  379. if ((__le32_to_cpu(ext4fs_indir1_block[rblock /
  380. perblock_parent]) <<
  381. log2_blksz)
  382. != ext4fs_indir2_blkno) {
  383. status = ext4fs_devread(__le32_to_cpu
  384. (ext4fs_indir1_block
  385. [rblock /
  386. perblock_parent]) <<
  387. log2_blksz, 0, blksz,
  388. (char *)ext4fs_indir2_block);
  389. if (status == 0) {
  390. printf("** TI ext2fs read block (indir 2 2)"
  391. "failed. **\n");
  392. return -1;
  393. }
  394. ext4fs_indir2_blkno =
  395. __le32_to_cpu(ext4fs_indir1_block[rblock /
  396. perblock_parent])
  397. << log2_blksz;
  398. }
  399. if (ext4fs_indir3_block == NULL) {
  400. ext4fs_indir3_block = zalloc(blksz);
  401. if (ext4fs_indir3_block == NULL) {
  402. printf("** TI ext2fs read block (indir 2 2)"
  403. "malloc failed. **\n");
  404. return -1;
  405. }
  406. ext4fs_indir3_size = blksz;
  407. ext4fs_indir3_blkno = -1;
  408. }
  409. if (blksz != ext4fs_indir3_size) {
  410. free(ext4fs_indir3_block);
  411. ext4fs_indir3_block = NULL;
  412. ext4fs_indir3_size = 0;
  413. ext4fs_indir3_blkno = -1;
  414. ext4fs_indir3_block = zalloc(blksz);
  415. if (ext4fs_indir3_block == NULL) {
  416. printf("** TI ext2fs read block (indir 2 2)"
  417. "malloc failed. **\n");
  418. return -1;
  419. }
  420. ext4fs_indir3_size = blksz;
  421. }
  422. if ((__le32_to_cpu(ext4fs_indir2_block[rblock
  423. /
  424. perblock_child]) <<
  425. log2_blksz) != ext4fs_indir3_blkno) {
  426. status =
  427. ext4fs_devread(__le32_to_cpu
  428. (ext4fs_indir2_block
  429. [(rblock / perblock_child)
  430. % (blksz / 4)]) << log2_blksz, 0,
  431. blksz, (char *)ext4fs_indir3_block);
  432. if (status == 0) {
  433. printf("** TI ext2fs read block (indir 2 2)"
  434. "failed. **\n");
  435. return -1;
  436. }
  437. ext4fs_indir3_blkno =
  438. __le32_to_cpu(ext4fs_indir2_block[(rblock /
  439. perblock_child) %
  440. (blksz /
  441. 4)]) <<
  442. log2_blksz;
  443. }
  444. blknr = __le32_to_cpu(ext4fs_indir3_block
  445. [rblock % perblock_child]);
  446. }
  447. debug("ext4fs_read_block %ld\n", blknr);
  448. return blknr;
  449. }
  450. void ext4fs_close(void)
  451. {
  452. if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
  453. ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
  454. ext4fs_file = NULL;
  455. }
  456. if (ext4fs_root != NULL) {
  457. free(ext4fs_root);
  458. ext4fs_root = NULL;
  459. }
  460. if (ext4fs_indir1_block != NULL) {
  461. free(ext4fs_indir1_block);
  462. ext4fs_indir1_block = NULL;
  463. ext4fs_indir1_size = 0;
  464. ext4fs_indir1_blkno = -1;
  465. }
  466. if (ext4fs_indir2_block != NULL) {
  467. free(ext4fs_indir2_block);
  468. ext4fs_indir2_block = NULL;
  469. ext4fs_indir2_size = 0;
  470. ext4fs_indir2_blkno = -1;
  471. }
  472. if (ext4fs_indir3_block != NULL) {
  473. free(ext4fs_indir3_block);
  474. ext4fs_indir3_block = NULL;
  475. ext4fs_indir3_size = 0;
  476. ext4fs_indir3_blkno = -1;
  477. }
  478. }
  479. int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
  480. struct ext2fs_node **fnode, int *ftype)
  481. {
  482. unsigned int fpos = 0;
  483. int status;
  484. struct ext2fs_node *diro = (struct ext2fs_node *) dir;
  485. #ifdef DEBUG
  486. if (name != NULL)
  487. printf("Iterate dir %s\n", name);
  488. #endif /* of DEBUG */
  489. if (!diro->inode_read) {
  490. status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
  491. if (status == 0)
  492. return 0;
  493. }
  494. /* Search the file. */
  495. while (fpos < __le32_to_cpu(diro->inode.size)) {
  496. struct ext2_dirent dirent;
  497. status = ext4fs_read_file(diro, fpos,
  498. sizeof(struct ext2_dirent),
  499. (char *) &dirent);
  500. if (status < 1)
  501. return 0;
  502. if (dirent.namelen != 0) {
  503. char filename[dirent.namelen + 1];
  504. struct ext2fs_node *fdiro;
  505. int type = FILETYPE_UNKNOWN;
  506. status = ext4fs_read_file(diro,
  507. fpos +
  508. sizeof(struct ext2_dirent),
  509. dirent.namelen, filename);
  510. if (status < 1)
  511. return 0;
  512. fdiro = zalloc(sizeof(struct ext2fs_node));
  513. if (!fdiro)
  514. return 0;
  515. fdiro->data = diro->data;
  516. fdiro->ino = __le32_to_cpu(dirent.inode);
  517. filename[dirent.namelen] = '\0';
  518. if (dirent.filetype != FILETYPE_UNKNOWN) {
  519. fdiro->inode_read = 0;
  520. if (dirent.filetype == FILETYPE_DIRECTORY)
  521. type = FILETYPE_DIRECTORY;
  522. else if (dirent.filetype == FILETYPE_SYMLINK)
  523. type = FILETYPE_SYMLINK;
  524. else if (dirent.filetype == FILETYPE_REG)
  525. type = FILETYPE_REG;
  526. } else {
  527. status = ext4fs_read_inode(diro->data,
  528. __le32_to_cpu
  529. (dirent.inode),
  530. &fdiro->inode);
  531. if (status == 0) {
  532. free(fdiro);
  533. return 0;
  534. }
  535. fdiro->inode_read = 1;
  536. if ((__le16_to_cpu(fdiro->inode.mode) &
  537. FILETYPE_INO_MASK) ==
  538. FILETYPE_INO_DIRECTORY) {
  539. type = FILETYPE_DIRECTORY;
  540. } else if ((__le16_to_cpu(fdiro->inode.mode)
  541. & FILETYPE_INO_MASK) ==
  542. FILETYPE_INO_SYMLINK) {
  543. type = FILETYPE_SYMLINK;
  544. } else if ((__le16_to_cpu(fdiro->inode.mode)
  545. & FILETYPE_INO_MASK) ==
  546. FILETYPE_INO_REG) {
  547. type = FILETYPE_REG;
  548. }
  549. }
  550. #ifdef DEBUG
  551. printf("iterate >%s<\n", filename);
  552. #endif /* of DEBUG */
  553. if ((name != NULL) && (fnode != NULL)
  554. && (ftype != NULL)) {
  555. if (strcmp(filename, name) == 0) {
  556. *ftype = type;
  557. *fnode = fdiro;
  558. return 1;
  559. }
  560. } else {
  561. if (fdiro->inode_read == 0) {
  562. status = ext4fs_read_inode(diro->data,
  563. __le32_to_cpu(
  564. dirent.inode),
  565. &fdiro->inode);
  566. if (status == 0) {
  567. free(fdiro);
  568. return 0;
  569. }
  570. fdiro->inode_read = 1;
  571. }
  572. switch (type) {
  573. case FILETYPE_DIRECTORY:
  574. printf("<DIR> ");
  575. break;
  576. case FILETYPE_SYMLINK:
  577. printf("<SYM> ");
  578. break;
  579. case FILETYPE_REG:
  580. printf(" ");
  581. break;
  582. default:
  583. printf("< ? > ");
  584. break;
  585. }
  586. printf("%10d %s\n",
  587. __le32_to_cpu(fdiro->inode.size),
  588. filename);
  589. }
  590. free(fdiro);
  591. }
  592. fpos += __le16_to_cpu(dirent.direntlen);
  593. }
  594. return 0;
  595. }
  596. static char *ext4fs_read_symlink(struct ext2fs_node *node)
  597. {
  598. char *symlink;
  599. struct ext2fs_node *diro = node;
  600. int status;
  601. if (!diro->inode_read) {
  602. status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
  603. if (status == 0)
  604. return 0;
  605. }
  606. symlink = zalloc(__le32_to_cpu(diro->inode.size) + 1);
  607. if (!symlink)
  608. return 0;
  609. if (__le32_to_cpu(diro->inode.size) <= 60) {
  610. strncpy(symlink, diro->inode.b.symlink,
  611. __le32_to_cpu(diro->inode.size));
  612. } else {
  613. status = ext4fs_read_file(diro, 0,
  614. __le32_to_cpu(diro->inode.size),
  615. symlink);
  616. if (status == 0) {
  617. free(symlink);
  618. return 0;
  619. }
  620. }
  621. symlink[__le32_to_cpu(diro->inode.size)] = '\0';
  622. return symlink;
  623. }
  624. static int ext4fs_find_file1(const char *currpath,
  625. struct ext2fs_node *currroot,
  626. struct ext2fs_node **currfound, int *foundtype)
  627. {
  628. char fpath[strlen(currpath) + 1];
  629. char *name = fpath;
  630. char *next;
  631. int status;
  632. int type = FILETYPE_DIRECTORY;
  633. struct ext2fs_node *currnode = currroot;
  634. struct ext2fs_node *oldnode = currroot;
  635. strncpy(fpath, currpath, strlen(currpath) + 1);
  636. /* Remove all leading slashes. */
  637. while (*name == '/')
  638. name++;
  639. if (!*name) {
  640. *currfound = currnode;
  641. return 1;
  642. }
  643. for (;;) {
  644. int found;
  645. /* Extract the actual part from the pathname. */
  646. next = strchr(name, '/');
  647. if (next) {
  648. /* Remove all leading slashes. */
  649. while (*next == '/')
  650. *(next++) = '\0';
  651. }
  652. if (type != FILETYPE_DIRECTORY) {
  653. ext4fs_free_node(currnode, currroot);
  654. return 0;
  655. }
  656. oldnode = currnode;
  657. /* Iterate over the directory. */
  658. found = ext4fs_iterate_dir(currnode, name, &currnode, &type);
  659. if (found == 0)
  660. return 0;
  661. if (found == -1)
  662. break;
  663. /* Read in the symlink and follow it. */
  664. if (type == FILETYPE_SYMLINK) {
  665. char *symlink;
  666. /* Test if the symlink does not loop. */
  667. if (++symlinknest == 8) {
  668. ext4fs_free_node(currnode, currroot);
  669. ext4fs_free_node(oldnode, currroot);
  670. return 0;
  671. }
  672. symlink = ext4fs_read_symlink(currnode);
  673. ext4fs_free_node(currnode, currroot);
  674. if (!symlink) {
  675. ext4fs_free_node(oldnode, currroot);
  676. return 0;
  677. }
  678. debug("Got symlink >%s<\n", symlink);
  679. if (symlink[0] == '/') {
  680. ext4fs_free_node(oldnode, currroot);
  681. oldnode = &ext4fs_root->diropen;
  682. }
  683. /* Lookup the node the symlink points to. */
  684. status = ext4fs_find_file1(symlink, oldnode,
  685. &currnode, &type);
  686. free(symlink);
  687. if (status == 0) {
  688. ext4fs_free_node(oldnode, currroot);
  689. return 0;
  690. }
  691. }
  692. ext4fs_free_node(oldnode, currroot);
  693. /* Found the node! */
  694. if (!next || *next == '\0') {
  695. *currfound = currnode;
  696. *foundtype = type;
  697. return 1;
  698. }
  699. name = next;
  700. }
  701. return -1;
  702. }
  703. int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
  704. struct ext2fs_node **foundnode, int expecttype)
  705. {
  706. int status;
  707. int foundtype = FILETYPE_DIRECTORY;
  708. symlinknest = 0;
  709. if (!path)
  710. return 0;
  711. status = ext4fs_find_file1(path, rootnode, foundnode, &foundtype);
  712. if (status == 0)
  713. return 0;
  714. /* Check if the node that was found was of the expected type. */
  715. if ((expecttype == FILETYPE_REG) && (foundtype != expecttype))
  716. return 0;
  717. else if ((expecttype == FILETYPE_DIRECTORY)
  718. && (foundtype != expecttype))
  719. return 0;
  720. return 1;
  721. }
  722. int ext4fs_open(const char *filename)
  723. {
  724. struct ext2fs_node *fdiro = NULL;
  725. int status;
  726. int len;
  727. if (ext4fs_root == NULL)
  728. return -1;
  729. ext4fs_file = NULL;
  730. status = ext4fs_find_file(filename, &ext4fs_root->diropen, &fdiro,
  731. FILETYPE_REG);
  732. if (status == 0)
  733. goto fail;
  734. if (!fdiro->inode_read) {
  735. status = ext4fs_read_inode(fdiro->data, fdiro->ino,
  736. &fdiro->inode);
  737. if (status == 0)
  738. goto fail;
  739. }
  740. len = __le32_to_cpu(fdiro->inode.size);
  741. ext4fs_file = fdiro;
  742. return len;
  743. fail:
  744. ext4fs_free_node(fdiro, &ext4fs_root->diropen);
  745. return -1;
  746. }
  747. int ext4fs_mount(unsigned part_length)
  748. {
  749. struct ext2_data *data;
  750. int status;
  751. struct ext_filesystem *fs = get_fs();
  752. data = zalloc(sizeof(struct ext2_data));
  753. if (!data)
  754. return 0;
  755. /* Read the superblock. */
  756. status = ext4fs_devread(1 * 2, 0, sizeof(struct ext2_sblock),
  757. (char *)&data->sblock);
  758. if (status == 0)
  759. goto fail;
  760. /* Make sure this is an ext2 filesystem. */
  761. if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC)
  762. goto fail;
  763. if (__le32_to_cpu(data->sblock.revision_level == 0))
  764. fs->inodesz = 128;
  765. else
  766. fs->inodesz = __le16_to_cpu(data->sblock.inode_size);
  767. debug("EXT2 rev %d, inode_size %d\n",
  768. __le32_to_cpu(data->sblock.revision_level), fs->inodesz);
  769. data->diropen.data = data;
  770. data->diropen.ino = 2;
  771. data->diropen.inode_read = 1;
  772. data->inode = &data->diropen.inode;
  773. status = ext4fs_read_inode(data, 2, data->inode);
  774. if (status == 0)
  775. goto fail;
  776. ext4fs_root = data;
  777. return 1;
  778. fail:
  779. printf("Failed to mount ext2 filesystem...\n");
  780. free(data);
  781. ext4fs_root = NULL;
  782. return 0;
  783. }