ext2.c 29 KB

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