ext2.c 30 KB

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