ext2.c 32 KB

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