ext2.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. /* ext2.c - Second Extended filesystem */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /* Magic value used to identify an ext2 filesystem. */
  20. #define EXT2_MAGIC 0xEF53
  21. /* Amount of indirect blocks in an inode. */
  22. #define INDIRECT_BLOCKS 12
  23. /* Maximum length of a pathname. */
  24. #define EXT2_PATH_MAX 4096
  25. /* Maximum nesting of symlinks, used to prevent a loop. */
  26. #define EXT2_MAX_SYMLINKCNT 8
  27. /* The good old revision and the default inode size. */
  28. #define EXT2_GOOD_OLD_REVISION 0
  29. #define EXT2_GOOD_OLD_INODE_SIZE 128
  30. /* Filetype used in directory entry. */
  31. #define FILETYPE_UNKNOWN 0
  32. #define FILETYPE_REG 1
  33. #define FILETYPE_DIRECTORY 2
  34. #define FILETYPE_SYMLINK 7
  35. /* Filetype information as used in inodes. */
  36. #define FILETYPE_INO_MASK 0170000
  37. #define FILETYPE_INO_REG 0100000
  38. #define FILETYPE_INO_DIRECTORY 0040000
  39. #define FILETYPE_INO_SYMLINK 0120000
  40. #include <grub/err.h>
  41. #include <grub/file.h>
  42. #include <grub/mm.h>
  43. #include <grub/misc.h>
  44. #include <grub/disk.h>
  45. #include <grub/dl.h>
  46. #include <grub/types.h>
  47. #include <grub/fshelp.h>
  48. /* Log2 size of ext2 block in 512 blocks. */
  49. #define LOG2_EXT2_BLOCK_SIZE(data) \
  50. (grub_le_to_cpu32 (data->sblock.log2_block_size) + 1)
  51. /* Log2 size of ext2 block in bytes. */
  52. #define LOG2_BLOCK_SIZE(data) \
  53. (grub_le_to_cpu32 (data->sblock.log2_block_size) + 10)
  54. /* The size of an ext2 block in bytes. */
  55. #define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE (data))
  56. /* The revision level. */
  57. #define EXT2_REVISION(data) grub_le_to_cpu32 (data->sblock.revision_level)
  58. /* The inode size. */
  59. #define EXT2_INODE_SIZE(data) \
  60. (EXT2_REVISION (data) == EXT2_GOOD_OLD_REVISION \
  61. ? EXT2_GOOD_OLD_INODE_SIZE \
  62. : grub_le_to_cpu16 (data->sblock.inode_size))
  63. /* Superblock filesystem feature flags (RW compatible)
  64. * A filesystem with any of these enabled can be read and written by a driver
  65. * that does not understand them without causing metadata/data corruption. */
  66. #define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
  67. #define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
  68. #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
  69. #define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
  70. #define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
  71. #define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
  72. /* Superblock filesystem feature flags (RO compatible)
  73. * A filesystem with any of these enabled can be safely read by a driver that
  74. * does not understand them, but should not be written to, usually because
  75. * additional metadata is required. */
  76. #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
  77. #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
  78. #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
  79. #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
  80. #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
  81. #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
  82. /* Superblock filesystem feature flags (back-incompatible)
  83. * A filesystem with any of these enabled should not be attempted to be read
  84. * by a driver that does not understand them, since they usually indicate
  85. * metadata format changes that might confuse the reader. */
  86. #define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
  87. #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
  88. #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
  89. #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Volume is journal device */
  90. #define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
  91. #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* Extents used */
  92. #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
  93. #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
  94. /* The set of back-incompatible features this driver DOES support. Add (OR)
  95. * flags here as the related features are implemented into the driver. */
  96. #define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
  97. | EXT4_FEATURE_INCOMPAT_EXTENTS \
  98. | EXT4_FEATURE_INCOMPAT_FLEX_BG )
  99. /* List of rationales for the ignored "incompatible" features:
  100. * needs_recovery: Not really back-incompatible - was added as such to forbid
  101. * ext2 drivers from mounting an ext3 volume with a dirty
  102. * journal because they will ignore the journal, but the next
  103. * ext3 driver to mount the volume will find the journal and
  104. * replay it, potentially corrupting the metadata written by
  105. * the ext2 drivers. Safe to ignore for this RO driver. */
  106. #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER )
  107. #define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
  108. #define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1
  109. #define EXT3_JOURNAL_COMMIT_BLOCK 2
  110. #define EXT3_JOURNAL_SUPERBLOCK_V1 3
  111. #define EXT3_JOURNAL_SUPERBLOCK_V2 4
  112. #define EXT3_JOURNAL_REVOKE_BLOCK 5
  113. #define EXT3_JOURNAL_FLAG_ESCAPE 1
  114. #define EXT3_JOURNAL_FLAG_SAME_UUID 2
  115. #define EXT3_JOURNAL_FLAG_DELETED 4
  116. #define EXT3_JOURNAL_FLAG_LAST_TAG 8
  117. #define EXT4_EXTENTS_FLAG 0x80000
  118. /* The ext2 superblock. */
  119. struct grub_ext2_sblock
  120. {
  121. grub_uint32_t total_inodes;
  122. grub_uint32_t total_blocks;
  123. grub_uint32_t reserved_blocks;
  124. grub_uint32_t free_blocks;
  125. grub_uint32_t free_inodes;
  126. grub_uint32_t first_data_block;
  127. grub_uint32_t log2_block_size;
  128. grub_uint32_t log2_fragment_size;
  129. grub_uint32_t blocks_per_group;
  130. grub_uint32_t fragments_per_group;
  131. grub_uint32_t inodes_per_group;
  132. grub_uint32_t mtime;
  133. grub_uint32_t utime;
  134. grub_uint16_t mnt_count;
  135. grub_uint16_t max_mnt_count;
  136. grub_uint16_t magic;
  137. grub_uint16_t fs_state;
  138. grub_uint16_t error_handling;
  139. grub_uint16_t minor_revision_level;
  140. grub_uint32_t lastcheck;
  141. grub_uint32_t checkinterval;
  142. grub_uint32_t creator_os;
  143. grub_uint32_t revision_level;
  144. grub_uint16_t uid_reserved;
  145. grub_uint16_t gid_reserved;
  146. grub_uint32_t first_inode;
  147. grub_uint16_t inode_size;
  148. grub_uint16_t block_group_number;
  149. grub_uint32_t feature_compatibility;
  150. grub_uint32_t feature_incompat;
  151. grub_uint32_t feature_ro_compat;
  152. grub_uint16_t uuid[8];
  153. char volume_name[16];
  154. char last_mounted_on[64];
  155. grub_uint32_t compression_info;
  156. grub_uint8_t prealloc_blocks;
  157. grub_uint8_t prealloc_dir_blocks;
  158. grub_uint16_t reserved_gdt_blocks;
  159. grub_uint8_t journal_uuid[16];
  160. grub_uint32_t journal_inum;
  161. grub_uint32_t journal_dev;
  162. grub_uint32_t last_orphan;
  163. grub_uint32_t hash_seed[4];
  164. grub_uint8_t def_hash_version;
  165. grub_uint8_t jnl_backup_type;
  166. grub_uint16_t reserved_word_pad;
  167. grub_uint32_t default_mount_opts;
  168. grub_uint32_t first_meta_bg;
  169. grub_uint32_t mkfs_time;
  170. grub_uint32_t jnl_blocks[17];
  171. };
  172. /* The ext2 blockgroup. */
  173. struct grub_ext2_block_group
  174. {
  175. grub_uint32_t block_id;
  176. grub_uint32_t inode_id;
  177. grub_uint32_t inode_table_id;
  178. grub_uint16_t free_blocks;
  179. grub_uint16_t free_inodes;
  180. grub_uint16_t used_dirs;
  181. grub_uint16_t pad;
  182. grub_uint32_t reserved[3];
  183. };
  184. /* The ext2 inode. */
  185. struct grub_ext2_inode
  186. {
  187. grub_uint16_t mode;
  188. grub_uint16_t uid;
  189. grub_uint32_t size;
  190. grub_uint32_t atime;
  191. grub_uint32_t ctime;
  192. grub_uint32_t mtime;
  193. grub_uint32_t dtime;
  194. grub_uint16_t gid;
  195. grub_uint16_t nlinks;
  196. grub_uint32_t blockcnt; /* Blocks of 512 bytes!! */
  197. grub_uint32_t flags;
  198. grub_uint32_t osd1;
  199. union
  200. {
  201. struct datablocks
  202. {
  203. grub_uint32_t dir_blocks[INDIRECT_BLOCKS];
  204. grub_uint32_t indir_block;
  205. grub_uint32_t double_indir_block;
  206. grub_uint32_t triple_indir_block;
  207. } blocks;
  208. char symlink[60];
  209. };
  210. grub_uint32_t version;
  211. grub_uint32_t acl;
  212. grub_uint32_t dir_acl;
  213. grub_uint32_t fragment_addr;
  214. grub_uint32_t osd2[3];
  215. };
  216. /* The header of an ext2 directory entry. */
  217. struct ext2_dirent
  218. {
  219. grub_uint32_t inode;
  220. grub_uint16_t direntlen;
  221. grub_uint8_t namelen;
  222. grub_uint8_t filetype;
  223. };
  224. struct grub_ext3_journal_header
  225. {
  226. grub_uint32_t magic;
  227. grub_uint32_t block_type;
  228. grub_uint32_t sequence;
  229. };
  230. struct grub_ext3_journal_revoke_header
  231. {
  232. struct grub_ext3_journal_header header;
  233. grub_uint32_t count;
  234. grub_uint32_t data[0];
  235. };
  236. struct grub_ext3_journal_block_tag
  237. {
  238. grub_uint32_t block;
  239. grub_uint32_t flags;
  240. };
  241. struct grub_ext3_journal_sblock
  242. {
  243. struct grub_ext3_journal_header header;
  244. grub_uint32_t block_size;
  245. grub_uint32_t maxlen;
  246. grub_uint32_t first;
  247. grub_uint32_t sequence;
  248. grub_uint32_t start;
  249. };
  250. #define EXT4_EXT_MAGIC 0xf30a
  251. struct grub_ext4_extent_header
  252. {
  253. grub_uint16_t magic;
  254. grub_uint16_t entries;
  255. grub_uint16_t max;
  256. grub_uint16_t depth;
  257. grub_uint32_t generation;
  258. };
  259. struct grub_ext4_extent
  260. {
  261. grub_uint32_t block;
  262. grub_uint16_t len;
  263. grub_uint16_t start_hi;
  264. grub_uint32_t start;
  265. };
  266. struct grub_ext4_extent_idx
  267. {
  268. grub_uint32_t block;
  269. grub_uint32_t leaf;
  270. grub_uint16_t leaf_hi;
  271. grub_uint16_t unused;
  272. };
  273. struct grub_fshelp_node
  274. {
  275. struct grub_ext2_data *data;
  276. struct grub_ext2_inode inode;
  277. int ino;
  278. int inode_read;
  279. };
  280. /* Information about a "mounted" ext2 filesystem. */
  281. struct grub_ext2_data
  282. {
  283. struct grub_ext2_sblock sblock;
  284. grub_disk_t disk;
  285. struct grub_ext2_inode *inode;
  286. struct grub_fshelp_node diropen;
  287. };
  288. static grub_dl_t my_mod;
  289. /* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
  290. the mounted filesystem DATA. */
  291. inline static grub_err_t
  292. grub_ext2_blockgroup (struct grub_ext2_data *data, int group,
  293. struct grub_ext2_block_group *blkgrp)
  294. {
  295. return grub_disk_read (data->disk,
  296. ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1)
  297. << LOG2_EXT2_BLOCK_SIZE (data)),
  298. group * sizeof (struct grub_ext2_block_group),
  299. sizeof (struct grub_ext2_block_group), blkgrp);
  300. }
  301. static struct grub_ext4_extent_header *
  302. grub_ext4_find_leaf (struct grub_ext2_data *data, char *buf,
  303. struct grub_ext4_extent_header *ext_block,
  304. grub_uint32_t fileblock)
  305. {
  306. struct grub_ext4_extent_idx *index;
  307. while (1)
  308. {
  309. int i;
  310. grub_disk_addr_t block;
  311. index = (struct grub_ext4_extent_idx *) (ext_block + 1);
  312. if (grub_le_to_cpu16(ext_block->magic) != EXT4_EXT_MAGIC)
  313. return 0;
  314. if (ext_block->depth == 0)
  315. return ext_block;
  316. for (i = 0; i < grub_le_to_cpu16 (ext_block->entries); i++)
  317. {
  318. if (fileblock < grub_le_to_cpu32(index[i].block))
  319. break;
  320. }
  321. if (--i < 0)
  322. return 0;
  323. block = grub_le_to_cpu16 (index[i].leaf_hi);
  324. block = (block << 32) + grub_le_to_cpu32 (index[i].leaf);
  325. if (grub_disk_read (data->disk,
  326. block << LOG2_EXT2_BLOCK_SIZE (data),
  327. 0, EXT2_BLOCK_SIZE(data), buf))
  328. return 0;
  329. ext_block = (struct grub_ext4_extent_header *) buf;
  330. }
  331. }
  332. static grub_disk_addr_t
  333. grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
  334. {
  335. struct grub_ext2_data *data = node->data;
  336. struct grub_ext2_inode *inode = &node->inode;
  337. int blknr = -1;
  338. unsigned int blksz = EXT2_BLOCK_SIZE (data);
  339. int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
  340. if (grub_le_to_cpu32(inode->flags) & EXT4_EXTENTS_FLAG)
  341. {
  342. char buf[EXT2_BLOCK_SIZE(data)];
  343. struct grub_ext4_extent_header *leaf;
  344. struct grub_ext4_extent *ext;
  345. int i;
  346. leaf = grub_ext4_find_leaf (data, buf,
  347. (struct grub_ext4_extent_header *) inode->blocks.dir_blocks,
  348. fileblock);
  349. if (! leaf)
  350. {
  351. grub_error (GRUB_ERR_BAD_FS, "invalid extent");
  352. return -1;
  353. }
  354. ext = (struct grub_ext4_extent *) (leaf + 1);
  355. for (i = 0; i < grub_le_to_cpu16 (leaf->entries); i++)
  356. {
  357. if (fileblock < grub_le_to_cpu32 (ext[i].block))
  358. break;
  359. }
  360. if (--i >= 0)
  361. {
  362. fileblock -= grub_le_to_cpu32 (ext[i].block);
  363. if (fileblock >= grub_le_to_cpu16 (ext[i].len))
  364. return 0;
  365. else
  366. {
  367. grub_disk_addr_t start;
  368. start = grub_le_to_cpu16 (ext[i].start_hi);
  369. start = (start << 32) + grub_le_to_cpu32 (ext[i].start);
  370. return fileblock + start;
  371. }
  372. }
  373. else
  374. {
  375. grub_error (GRUB_ERR_BAD_FS, "something wrong with extent");
  376. return -1;
  377. }
  378. }
  379. /* Direct blocks. */
  380. if (fileblock < INDIRECT_BLOCKS)
  381. blknr = grub_le_to_cpu32 (inode->blocks.dir_blocks[fileblock]);
  382. /* Indirect. */
  383. else if (fileblock < INDIRECT_BLOCKS + blksz / 4)
  384. {
  385. grub_uint32_t *indir;
  386. indir = grub_malloc (blksz);
  387. if (! indir)
  388. return grub_errno;
  389. if (grub_disk_read (data->disk,
  390. ((grub_disk_addr_t)
  391. grub_le_to_cpu32 (inode->blocks.indir_block))
  392. << log2_blksz,
  393. 0, blksz, indir))
  394. return grub_errno;
  395. blknr = grub_le_to_cpu32 (indir[fileblock - INDIRECT_BLOCKS]);
  396. grub_free (indir);
  397. }
  398. /* Double indirect. */
  399. else if (fileblock < INDIRECT_BLOCKS + blksz / 4 * (blksz / 4 + 1))
  400. {
  401. unsigned int perblock = blksz / 4;
  402. unsigned int rblock = fileblock - (INDIRECT_BLOCKS
  403. + blksz / 4);
  404. grub_uint32_t *indir;
  405. indir = grub_malloc (blksz);
  406. if (! indir)
  407. return grub_errno;
  408. if (grub_disk_read (data->disk,
  409. ((grub_disk_addr_t)
  410. grub_le_to_cpu32 (inode->blocks.double_indir_block))
  411. << log2_blksz,
  412. 0, blksz, indir))
  413. return grub_errno;
  414. if (grub_disk_read (data->disk,
  415. ((grub_disk_addr_t)
  416. grub_le_to_cpu32 (indir[rblock / perblock]))
  417. << log2_blksz,
  418. 0, blksz, indir))
  419. return grub_errno;
  420. blknr = grub_le_to_cpu32 (indir[rblock % perblock]);
  421. grub_free (indir);
  422. }
  423. /* triple indirect. */
  424. else
  425. {
  426. grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
  427. "ext2fs doesn't support triple indirect blocks");
  428. }
  429. return blknr;
  430. }
  431. /* Read LEN bytes from the file described by DATA starting with byte
  432. POS. Return the amount of read bytes in READ. */
  433. static grub_ssize_t
  434. grub_ext2_read_file (grub_fshelp_node_t node,
  435. void (*read_hook) (grub_disk_addr_t sector,
  436. unsigned offset, unsigned length,
  437. void *closure),
  438. void *closure, int flags,
  439. int pos, grub_size_t len, char *buf)
  440. {
  441. return grub_fshelp_read_file (node->data->disk, node, read_hook, closure,
  442. flags, pos, len, buf, grub_ext2_read_block,
  443. node->inode.size,
  444. LOG2_EXT2_BLOCK_SIZE (node->data));
  445. }
  446. /* Read the inode INO for the file described by DATA into INODE. */
  447. static grub_err_t
  448. grub_ext2_read_inode (struct grub_ext2_data *data,
  449. int ino, struct grub_ext2_inode *inode)
  450. {
  451. struct grub_ext2_block_group blkgrp;
  452. struct grub_ext2_sblock *sblock = &data->sblock;
  453. int inodes_per_block;
  454. unsigned int blkno;
  455. unsigned int blkoff;
  456. /* It is easier to calculate if the first inode is 0. */
  457. ino--;
  458. grub_ext2_blockgroup (data,
  459. ino / grub_le_to_cpu32 (sblock->inodes_per_group),
  460. &blkgrp);
  461. if (grub_errno)
  462. return grub_errno;
  463. inodes_per_block = EXT2_BLOCK_SIZE (data) / EXT2_INODE_SIZE (data);
  464. blkno = (ino % grub_le_to_cpu32 (sblock->inodes_per_group))
  465. / inodes_per_block;
  466. blkoff = (ino % grub_le_to_cpu32 (sblock->inodes_per_group))
  467. % inodes_per_block;
  468. /* Read the inode. */
  469. if (grub_disk_read (data->disk,
  470. ((grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno)
  471. << LOG2_EXT2_BLOCK_SIZE (data)),
  472. EXT2_INODE_SIZE (data) * blkoff,
  473. sizeof (struct grub_ext2_inode), inode))
  474. return grub_errno;
  475. return 0;
  476. }
  477. static struct grub_ext2_data *
  478. grub_ext2_mount (grub_disk_t disk)
  479. {
  480. struct grub_ext2_data *data;
  481. data = grub_malloc (sizeof (struct grub_ext2_data));
  482. if (!data)
  483. return 0;
  484. /* Read the superblock. */
  485. grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_ext2_sblock),
  486. &data->sblock);
  487. if (grub_errno)
  488. goto fail;
  489. /* Make sure this is an ext2 filesystem. */
  490. if (grub_le_to_cpu16 (data->sblock.magic) != EXT2_MAGIC)
  491. {
  492. grub_error (GRUB_ERR_BAD_FS, "not an ext2 filesystem");
  493. goto fail;
  494. }
  495. /* Check the FS doesn't have feature bits enabled that we don't support. */
  496. if (grub_le_to_cpu32 (data->sblock.feature_incompat)
  497. & ~(EXT2_DRIVER_SUPPORTED_INCOMPAT | EXT2_DRIVER_IGNORED_INCOMPAT))
  498. {
  499. grub_error (GRUB_ERR_BAD_FS, "filesystem has unsupported incompatible features");
  500. goto fail;
  501. }
  502. data->disk = disk;
  503. data->diropen.data = data;
  504. data->diropen.ino = 2;
  505. data->diropen.inode_read = 1;
  506. data->inode = &data->diropen.inode;
  507. grub_ext2_read_inode (data, 2, data->inode);
  508. if (grub_errno)
  509. goto fail;
  510. return data;
  511. fail:
  512. if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
  513. grub_error (GRUB_ERR_BAD_FS, "not an ext2 filesystem");
  514. grub_free (data);
  515. return 0;
  516. }
  517. static char *
  518. grub_ext2_read_symlink (grub_fshelp_node_t node)
  519. {
  520. char *symlink;
  521. struct grub_fshelp_node *diro = node;
  522. if (! diro->inode_read)
  523. {
  524. grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
  525. if (grub_errno)
  526. return 0;
  527. }
  528. symlink = grub_malloc (grub_le_to_cpu32 (diro->inode.size) + 1);
  529. if (! symlink)
  530. return 0;
  531. /* If the filesize of the symlink is bigger than
  532. 60 the symlink is stored in a separate block,
  533. otherwise it is stored in the inode. */
  534. if (grub_le_to_cpu32 (diro->inode.size) <= 60)
  535. grub_strncpy (symlink,
  536. diro->inode.symlink,
  537. grub_le_to_cpu32 (diro->inode.size));
  538. else
  539. {
  540. grub_ext2_read_file (diro, 0, 0, 0, 0,
  541. grub_le_to_cpu32 (diro->inode.size),
  542. symlink);
  543. if (grub_errno)
  544. {
  545. grub_free (symlink);
  546. return 0;
  547. }
  548. }
  549. symlink[grub_le_to_cpu32 (diro->inode.size)] = '\0';
  550. return symlink;
  551. }
  552. static int
  553. grub_ext2_iterate_dir (grub_fshelp_node_t dir,
  554. int (*hook) (const char *filename,
  555. enum grub_fshelp_filetype filetype,
  556. grub_fshelp_node_t node,
  557. void *closure),
  558. void *closure)
  559. {
  560. unsigned int fpos = 0;
  561. struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
  562. if (! diro->inode_read)
  563. {
  564. grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
  565. if (grub_errno)
  566. return 0;
  567. }
  568. /* Search the file. */
  569. while (fpos < grub_le_to_cpu32 (diro->inode.size))
  570. {
  571. struct ext2_dirent dirent;
  572. grub_ext2_read_file (diro, 0, 0, 0, fpos, sizeof (struct ext2_dirent),
  573. (char *) &dirent);
  574. if (grub_errno)
  575. return 0;
  576. if (dirent.direntlen == 0)
  577. return 0;
  578. if (dirent.namelen != 0)
  579. {
  580. char filename[dirent.namelen + 1];
  581. struct grub_fshelp_node *fdiro;
  582. enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
  583. grub_ext2_read_file (diro, 0, 0, 0,
  584. fpos + sizeof (struct ext2_dirent),
  585. dirent.namelen, filename);
  586. if (grub_errno)
  587. return 0;
  588. fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
  589. if (! fdiro)
  590. return 0;
  591. fdiro->data = diro->data;
  592. fdiro->ino = grub_le_to_cpu32 (dirent.inode);
  593. filename[dirent.namelen] = '\0';
  594. if (dirent.filetype != FILETYPE_UNKNOWN)
  595. {
  596. fdiro->inode_read = 0;
  597. if (dirent.filetype == FILETYPE_DIRECTORY)
  598. type = GRUB_FSHELP_DIR;
  599. else if (dirent.filetype == FILETYPE_SYMLINK)
  600. type = GRUB_FSHELP_SYMLINK;
  601. else if (dirent.filetype == FILETYPE_REG)
  602. type = GRUB_FSHELP_REG;
  603. }
  604. else
  605. {
  606. /* The filetype can not be read from the dirent, read
  607. the inode to get more information. */
  608. grub_ext2_read_inode (diro->data,
  609. grub_le_to_cpu32 (dirent.inode),
  610. &fdiro->inode);
  611. if (grub_errno)
  612. {
  613. grub_free (fdiro);
  614. return 0;
  615. }
  616. fdiro->inode_read = 1;
  617. if ((grub_le_to_cpu16 (fdiro->inode.mode)
  618. & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
  619. type = GRUB_FSHELP_DIR;
  620. else if ((grub_le_to_cpu16 (fdiro->inode.mode)
  621. & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
  622. type = GRUB_FSHELP_SYMLINK;
  623. else if ((grub_le_to_cpu16 (fdiro->inode.mode)
  624. & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
  625. type = GRUB_FSHELP_REG;
  626. }
  627. if (hook (filename, type, fdiro, closure))
  628. return 1;
  629. }
  630. fpos += grub_le_to_cpu16 (dirent.direntlen);
  631. }
  632. return 0;
  633. }
  634. /* Open a file named NAME and initialize FILE. */
  635. static grub_err_t
  636. grub_ext2_open (struct grub_file *file, const char *name)
  637. {
  638. struct grub_ext2_data *data;
  639. struct grub_fshelp_node *fdiro = 0;
  640. grub_dl_ref (my_mod);
  641. data = grub_ext2_mount (file->device->disk);
  642. if (! data)
  643. goto fail;
  644. grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_ext2_iterate_dir, 0,
  645. grub_ext2_read_symlink, GRUB_FSHELP_REG);
  646. if (grub_errno)
  647. goto fail;
  648. if (! fdiro->inode_read)
  649. {
  650. grub_ext2_read_inode (data, fdiro->ino, &fdiro->inode);
  651. if (grub_errno)
  652. goto fail;
  653. }
  654. grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_ext2_inode));
  655. grub_free (fdiro);
  656. file->size = grub_le_to_cpu32 (data->inode->size);
  657. file->data = data;
  658. file->offset = 0;
  659. return 0;
  660. fail:
  661. if (fdiro != &data->diropen)
  662. grub_free (fdiro);
  663. grub_free (data);
  664. grub_dl_unref (my_mod);
  665. return grub_errno;
  666. }
  667. static grub_err_t
  668. grub_ext2_close (grub_file_t file)
  669. {
  670. grub_free (file->data);
  671. grub_dl_unref (my_mod);
  672. return GRUB_ERR_NONE;
  673. }
  674. /* Read LEN bytes data from FILE into BUF. */
  675. static grub_ssize_t
  676. grub_ext2_read (grub_file_t file, char *buf, grub_size_t len)
  677. {
  678. struct grub_ext2_data *data = (struct grub_ext2_data *) file->data;
  679. return grub_ext2_read_file (&data->diropen, file->read_hook, file->closure,
  680. file->flags, file->offset, len, buf);
  681. }
  682. struct grub_ext2_dir_closure
  683. {
  684. int (*hook) (const char *filename,
  685. const struct grub_dirhook_info *info,
  686. void *closure);
  687. void *closure;
  688. struct grub_ext2_data *data;
  689. };
  690. static int
  691. iterate (const char *filename,
  692. enum grub_fshelp_filetype filetype,
  693. grub_fshelp_node_t node,
  694. void *closure)
  695. {
  696. struct grub_ext2_dir_closure *c = closure;
  697. struct grub_dirhook_info info;
  698. grub_memset (&info, 0, sizeof (info));
  699. if (! node->inode_read)
  700. {
  701. grub_ext2_read_inode (c->data, node->ino, &node->inode);
  702. if (!grub_errno)
  703. node->inode_read = 1;
  704. grub_errno = GRUB_ERR_NONE;
  705. }
  706. if (node->inode_read)
  707. {
  708. info.mtimeset = 1;
  709. info.mtime = grub_le_to_cpu32 (node->inode.mtime);
  710. }
  711. info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
  712. grub_free (node);
  713. return c->hook (filename, &info, c->closure);
  714. }
  715. static grub_err_t
  716. grub_ext2_dir (grub_device_t device, const char *path,
  717. int (*hook) (const char *filename,
  718. const struct grub_dirhook_info *info,
  719. void *closure),
  720. void *closure)
  721. {
  722. struct grub_ext2_data *data = 0;
  723. struct grub_fshelp_node *fdiro = 0;
  724. struct grub_ext2_dir_closure c;
  725. grub_dl_ref (my_mod);
  726. data = grub_ext2_mount (device->disk);
  727. if (! data)
  728. goto fail;
  729. grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_ext2_iterate_dir,
  730. 0, grub_ext2_read_symlink, GRUB_FSHELP_DIR);
  731. if (grub_errno)
  732. goto fail;
  733. c.hook = hook;
  734. c.closure = closure;
  735. c.data = data;
  736. grub_ext2_iterate_dir (fdiro, iterate, &c);
  737. fail:
  738. if (fdiro != &data->diropen)
  739. grub_free (fdiro);
  740. grub_free (data);
  741. grub_dl_unref (my_mod);
  742. return grub_errno;
  743. }
  744. static grub_err_t
  745. grub_ext2_label (grub_device_t device, char **label)
  746. {
  747. struct grub_ext2_data *data;
  748. grub_disk_t disk = device->disk;
  749. grub_dl_ref (my_mod);
  750. data = grub_ext2_mount (disk);
  751. if (data)
  752. *label = grub_strndup (data->sblock.volume_name, 14);
  753. else
  754. *label = NULL;
  755. grub_dl_unref (my_mod);
  756. grub_free (data);
  757. return grub_errno;
  758. }
  759. static grub_err_t
  760. grub_ext2_uuid (grub_device_t device, char **uuid)
  761. {
  762. struct grub_ext2_data *data;
  763. grub_disk_t disk = device->disk;
  764. grub_dl_ref (my_mod);
  765. data = grub_ext2_mount (disk);
  766. if (data)
  767. {
  768. *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
  769. grub_be_to_cpu16 (data->sblock.uuid[0]),
  770. grub_be_to_cpu16 (data->sblock.uuid[1]),
  771. grub_be_to_cpu16 (data->sblock.uuid[2]),
  772. grub_be_to_cpu16 (data->sblock.uuid[3]),
  773. grub_be_to_cpu16 (data->sblock.uuid[4]),
  774. grub_be_to_cpu16 (data->sblock.uuid[5]),
  775. grub_be_to_cpu16 (data->sblock.uuid[6]),
  776. grub_be_to_cpu16 (data->sblock.uuid[7]));
  777. }
  778. else
  779. *uuid = NULL;
  780. grub_dl_unref (my_mod);
  781. grub_free (data);
  782. return grub_errno;
  783. }
  784. /* Get mtime. */
  785. static grub_err_t
  786. grub_ext2_mtime (grub_device_t device, grub_int32_t *tm)
  787. {
  788. struct grub_ext2_data *data;
  789. grub_disk_t disk = device->disk;
  790. grub_dl_ref (my_mod);
  791. data = grub_ext2_mount (disk);
  792. if (!data)
  793. *tm = 0;
  794. else
  795. *tm = grub_le_to_cpu32 (data->sblock.utime);
  796. grub_dl_unref (my_mod);
  797. grub_free (data);
  798. return grub_errno;
  799. }
  800. static struct grub_fs grub_ext2_fs =
  801. {
  802. .name = "ext2",
  803. .dir = grub_ext2_dir,
  804. .open = grub_ext2_open,
  805. .read = grub_ext2_read,
  806. .close = grub_ext2_close,
  807. .label = grub_ext2_label,
  808. .uuid = grub_ext2_uuid,
  809. .mtime = grub_ext2_mtime,
  810. #ifdef GRUB_UTIL
  811. .reserved_first_sector = 1,
  812. #endif
  813. .next = 0
  814. };
  815. GRUB_MOD_INIT(ext2)
  816. {
  817. grub_fs_register (&grub_ext2_fs);
  818. my_mod = mod;
  819. }
  820. GRUB_MOD_FINI(ext2)
  821. {
  822. grub_fs_unregister (&grub_ext2_fs);
  823. }