1 /* ext2.c - Second Extended filesystem */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
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.
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.
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/>.
20 /* Magic value used to identify an ext2 filesystem. */
21 #define EXT2_MAGIC 0xEF53
22 /* Amount of indirect blocks in an inode. */
23 #define INDIRECT_BLOCKS 12
25 /* The good old revision and the default inode size. */
26 #define EXT2_GOOD_OLD_REVISION 0
27 #define EXT2_GOOD_OLD_INODE_SIZE 128
29 /* Filetype used in directory entry. */
30 #define FILETYPE_UNKNOWN 0
31 #define FILETYPE_REG 1
32 #define FILETYPE_DIRECTORY 2
33 #define FILETYPE_SYMLINK 7
35 /* Filetype information as used in inodes. */
36 #define FILETYPE_INO_MASK 0170000
37 #define FILETYPE_INO_REG 0100000
38 #define FILETYPE_INO_DIRECTORY 0040000
39 #define FILETYPE_INO_SYMLINK 0120000
42 #include <grub/file.h>
44 #include <grub/misc.h>
45 #include <grub/disk.h>
47 #include <grub/types.h>
48 #include <grub/fshelp.h>
49 #include <grub/ventoy.h>
51 GRUB_MOD_LICENSE ("GPLv3+");
53 /* Log2 size of ext2 block in 512 blocks. */
54 #define LOG2_EXT2_BLOCK_SIZE(data) \
55 (grub_le_to_cpu32 (data->sblock.log2_block_size) + 1)
57 /* Log2 size of ext2 block in bytes. */
58 #define LOG2_BLOCK_SIZE(data) \
59 (grub_le_to_cpu32 (data->sblock.log2_block_size) + 10)
61 /* The size of an ext2 block in bytes. */
62 #define EXT2_BLOCK_SIZE(data) (1U << LOG2_BLOCK_SIZE (data))
64 /* The revision level. */
65 #define EXT2_REVISION(data) grub_le_to_cpu32 (data->sblock.revision_level)
68 #define EXT2_INODE_SIZE(data) \
69 (data->sblock.revision_level \
70 == grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION) \
71 ? EXT2_GOOD_OLD_INODE_SIZE \
72 : grub_le_to_cpu16 (data->sblock.inode_size))
74 /* Superblock filesystem feature flags (RW compatible)
75 * A filesystem with any of these enabled can be read and written by a driver
76 * that does not understand them without causing metadata/data corruption. */
77 #define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
78 #define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
79 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
80 #define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
81 #define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
82 #define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
83 /* Superblock filesystem feature flags (RO compatible)
84 * A filesystem with any of these enabled can be safely read by a driver that
85 * does not understand them, but should not be written to, usually because
86 * additional metadata is required. */
87 #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
88 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
89 #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
90 #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
91 #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
92 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
93 /* Superblock filesystem feature flags (back-incompatible)
94 * A filesystem with any of these enabled should not be attempted to be read
95 * by a driver that does not understand them, since they usually indicate
96 * metadata format changes that might confuse the reader. */
97 #define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
98 #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
99 #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
100 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Volume is journal device */
101 #define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
102 #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* Extents used */
103 #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
104 #define EXT4_FEATURE_INCOMPAT_MMP 0x0100
105 #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
106 #define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000
107 #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
109 /* The set of back-incompatible features this driver DOES support. Add (OR)
110 * flags here as the related features are implemented into the driver. */
111 #define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
112 | EXT4_FEATURE_INCOMPAT_EXTENTS \
113 | EXT4_FEATURE_INCOMPAT_FLEX_BG \
114 | EXT2_FEATURE_INCOMPAT_META_BG \
115 | EXT4_FEATURE_INCOMPAT_64BIT \
116 | EXT4_FEATURE_INCOMPAT_ENCRYPT)
117 /* List of rationales for the ignored "incompatible" features:
118 * needs_recovery: Not really back-incompatible - was added as such to forbid
119 * ext2 drivers from mounting an ext3 volume with a dirty
120 * journal because they will ignore the journal, but the next
121 * ext3 driver to mount the volume will find the journal and
122 * replay it, potentially corrupting the metadata written by
123 * the ext2 drivers. Safe to ignore for this RO driver.
124 * mmp: Not really back-incompatible - was added as such to
125 * avoid multiple read-write mounts. Safe to ignore for this
127 * checksum seed: Not really back-incompatible - was added to allow tools
128 * such as tune2fs to change the UUID on a mounted metadata
129 * checksummed filesystem. Safe to ignore for now since the
130 * driver doesn't support checksum verification. But it must
131 * be removed from this list if that support is added later.
134 #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \
135 | EXT4_FEATURE_INCOMPAT_MMP \
136 | EXT4_FEATURE_INCOMPAT_CSUM_SEED)
139 #define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
141 #define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1
142 #define EXT3_JOURNAL_COMMIT_BLOCK 2
143 #define EXT3_JOURNAL_SUPERBLOCK_V1 3
144 #define EXT3_JOURNAL_SUPERBLOCK_V2 4
145 #define EXT3_JOURNAL_REVOKE_BLOCK 5
147 #define EXT3_JOURNAL_FLAG_ESCAPE 1
148 #define EXT3_JOURNAL_FLAG_SAME_UUID 2
149 #define EXT3_JOURNAL_FLAG_DELETED 4
150 #define EXT3_JOURNAL_FLAG_LAST_TAG 8
152 #define EXT4_ENCRYPT_FLAG 0x800
153 #define EXT4_EXTENTS_FLAG 0x80000
155 /* The ext2 superblock. */
156 struct grub_ext2_sblock
158 grub_uint32_t total_inodes
;
159 grub_uint32_t total_blocks
;
160 grub_uint32_t reserved_blocks
;
161 grub_uint32_t free_blocks
;
162 grub_uint32_t free_inodes
;
163 grub_uint32_t first_data_block
;
164 grub_uint32_t log2_block_size
;
165 grub_uint32_t log2_fragment_size
;
166 grub_uint32_t blocks_per_group
;
167 grub_uint32_t fragments_per_group
;
168 grub_uint32_t inodes_per_group
;
171 grub_uint16_t mnt_count
;
172 grub_uint16_t max_mnt_count
;
174 grub_uint16_t fs_state
;
175 grub_uint16_t error_handling
;
176 grub_uint16_t minor_revision_level
;
177 grub_uint32_t lastcheck
;
178 grub_uint32_t checkinterval
;
179 grub_uint32_t creator_os
;
180 grub_uint32_t revision_level
;
181 grub_uint16_t uid_reserved
;
182 grub_uint16_t gid_reserved
;
183 grub_uint32_t first_inode
;
184 grub_uint16_t inode_size
;
185 grub_uint16_t block_group_number
;
186 grub_uint32_t feature_compatibility
;
187 grub_uint32_t feature_incompat
;
188 grub_uint32_t feature_ro_compat
;
189 grub_uint16_t uuid
[8];
190 char volume_name
[16];
191 char last_mounted_on
[64];
192 grub_uint32_t compression_info
;
193 grub_uint8_t prealloc_blocks
;
194 grub_uint8_t prealloc_dir_blocks
;
195 grub_uint16_t reserved_gdt_blocks
;
196 grub_uint8_t journal_uuid
[16];
197 grub_uint32_t journal_inum
;
198 grub_uint32_t journal_dev
;
199 grub_uint32_t last_orphan
;
200 grub_uint32_t hash_seed
[4];
201 grub_uint8_t def_hash_version
;
202 grub_uint8_t jnl_backup_type
;
203 grub_uint16_t group_desc_size
;
204 grub_uint32_t default_mount_opts
;
205 grub_uint32_t first_meta_bg
;
206 grub_uint32_t mkfs_time
;
207 grub_uint32_t jnl_blocks
[17];
210 /* The ext2 blockgroup. */
211 struct grub_ext2_block_group
213 grub_uint32_t block_id
;
214 grub_uint32_t inode_id
;
215 grub_uint32_t inode_table_id
;
216 grub_uint16_t free_blocks
;
217 grub_uint16_t free_inodes
;
218 grub_uint16_t used_dirs
;
220 grub_uint32_t reserved
[3];
221 grub_uint32_t block_id_hi
;
222 grub_uint32_t inode_id_hi
;
223 grub_uint32_t inode_table_id_hi
;
224 grub_uint16_t free_blocks_hi
;
225 grub_uint16_t free_inodes_hi
;
226 grub_uint16_t used_dirs_hi
;
228 grub_uint32_t reserved2
[3];
231 /* The ext2 inode. */
232 struct grub_ext2_inode
242 grub_uint16_t nlinks
;
243 grub_uint32_t blockcnt
; /* Blocks of 512 bytes!! */
250 grub_uint32_t dir_blocks
[INDIRECT_BLOCKS
];
251 grub_uint32_t indir_block
;
252 grub_uint32_t double_indir_block
;
253 grub_uint32_t triple_indir_block
;
257 grub_uint32_t version
;
259 grub_uint32_t size_high
;
260 grub_uint32_t fragment_addr
;
261 grub_uint32_t osd2
[3];
264 /* The header of an ext2 directory entry. */
268 grub_uint16_t direntlen
;
269 #define MAX_NAMELEN 255
270 grub_uint8_t namelen
;
271 grub_uint8_t filetype
;
274 struct grub_ext3_journal_header
277 grub_uint32_t block_type
;
278 grub_uint32_t sequence
;
281 struct grub_ext3_journal_revoke_header
283 struct grub_ext3_journal_header header
;
285 grub_uint32_t data
[0];
288 struct grub_ext3_journal_block_tag
294 struct grub_ext3_journal_sblock
296 struct grub_ext3_journal_header header
;
297 grub_uint32_t block_size
;
298 grub_uint32_t maxlen
;
300 grub_uint32_t sequence
;
304 #define EXT4_EXT_MAGIC 0xf30a
306 struct grub_ext4_extent_header
309 grub_uint16_t entries
;
312 grub_uint32_t generation
;
315 struct grub_ext4_extent
319 grub_uint16_t start_hi
;
323 struct grub_ext4_extent_idx
327 grub_uint16_t leaf_hi
;
328 grub_uint16_t unused
;
331 struct grub_fshelp_node
333 struct grub_ext2_data
*data
;
334 struct grub_ext2_inode inode
;
339 /* Information about a "mounted" ext2 filesystem. */
340 struct grub_ext2_data
342 struct grub_ext2_sblock sblock
;
343 int log_group_desc_size
;
345 struct grub_ext2_inode
*inode
;
346 struct grub_fshelp_node diropen
;
349 static grub_dl_t my_mod
;
351 static int g_ventoy_block_count
;
353 /* Check is a = b^x for some x. */
355 is_power_of (grub_uint64_t a
, grub_uint32_t b
)
358 /* Prevent overflow assuming b < 8. */
359 if (a
>= (1LL << 60))
361 for (c
= 1; c
<= a
; c
*= b
);
367 group_has_super_block (struct grub_ext2_data
*data
, grub_uint64_t group
)
369 if (!(data
->sblock
.feature_ro_compat
370 & grub_cpu_to_le32_compile_time(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
)))
372 /* Algorithm looked up in Linux source. */
375 /* Even number is never a power of odd number. */
378 return (is_power_of(group
, 7) || is_power_of(group
, 5) ||
379 is_power_of(group
, 3));
382 /* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
383 the mounted filesystem DATA. */
384 inline static grub_err_t
385 grub_ext2_blockgroup (struct grub_ext2_data
*data
, grub_uint64_t group
,
386 struct grub_ext2_block_group
*blkgrp
)
388 grub_uint64_t full_offset
= (group
<< data
->log_group_desc_size
);
389 grub_uint64_t block
, offset
;
390 block
= (full_offset
>> LOG2_BLOCK_SIZE (data
));
391 offset
= (full_offset
& ((1 << LOG2_BLOCK_SIZE (data
)) - 1));
392 if ((data
->sblock
.feature_incompat
393 & grub_cpu_to_le32_compile_time (EXT2_FEATURE_INCOMPAT_META_BG
))
394 && block
>= grub_le_to_cpu32(data
->sblock
.first_meta_bg
))
396 grub_uint64_t first_block_group
;
397 /* Find the first block group for which a descriptor
398 is stored in given block. */
399 first_block_group
= (block
<< (LOG2_BLOCK_SIZE (data
)
400 - data
->log_group_desc_size
));
402 block
= (first_block_group
403 * grub_le_to_cpu32(data
->sblock
.blocks_per_group
));
405 if (group_has_super_block (data
, first_block_group
))
411 return grub_disk_read (data
->disk
,
412 ((grub_le_to_cpu32 (data
->sblock
.first_data_block
)
414 << LOG2_EXT2_BLOCK_SIZE (data
)), offset
,
415 sizeof (struct grub_ext2_block_group
), blkgrp
);
418 static struct grub_ext4_extent_header
*
419 grub_ext4_find_leaf (struct grub_ext2_data
*data
,
420 struct grub_ext4_extent_header
*ext_block
,
421 grub_uint32_t fileblock
)
423 struct grub_ext4_extent_idx
*index
;
429 grub_disk_addr_t block
;
431 index
= (struct grub_ext4_extent_idx
*) (ext_block
+ 1);
433 if (ext_block
->magic
!= grub_cpu_to_le16_compile_time (EXT4_EXT_MAGIC
))
436 if (ext_block
->depth
== 0)
439 for (i
= 0; i
< grub_le_to_cpu16 (ext_block
->entries
); i
++)
441 if (fileblock
< grub_le_to_cpu32(index
[i
].block
))
448 block
= grub_le_to_cpu16 (index
[i
].leaf_hi
);
449 block
= (block
<< 32) | grub_le_to_cpu32 (index
[i
].leaf
);
451 buf
= grub_malloc (EXT2_BLOCK_SIZE(data
));
454 if (grub_disk_read (data
->disk
,
455 block
<< LOG2_EXT2_BLOCK_SIZE (data
),
456 0, EXT2_BLOCK_SIZE(data
), buf
))
466 static grub_disk_addr_t
467 grub_ext2_read_block (grub_fshelp_node_t node
, grub_disk_addr_t fileblock
)
469 struct grub_ext2_data
*data
= node
->data
;
470 struct grub_ext2_inode
*inode
= &node
->inode
;
471 unsigned int blksz
= EXT2_BLOCK_SIZE (data
);
472 grub_disk_addr_t blksz_quarter
= blksz
/ 4;
473 int log2_blksz
= LOG2_EXT2_BLOCK_SIZE (data
);
474 int log_perblock
= log2_blksz
+ 9 - 2;
478 if (inode
->flags
& grub_cpu_to_le32_compile_time (EXT4_EXTENTS_FLAG
))
480 struct grub_ext4_extent_header
*leaf
;
481 struct grub_ext4_extent
*ext
;
483 grub_disk_addr_t ret
;
485 leaf
= grub_ext4_find_leaf (data
, (struct grub_ext4_extent_header
*) inode
->blocks
.dir_blocks
, fileblock
);
488 grub_error (GRUB_ERR_BAD_FS
, "invalid extent");
492 ext
= (struct grub_ext4_extent
*) (leaf
+ 1);
493 for (i
= 0; i
< grub_le_to_cpu16 (leaf
->entries
); i
++)
495 if (fileblock
< grub_le_to_cpu32 (ext
[i
].block
))
501 fileblock
-= grub_le_to_cpu32 (ext
[i
].block
);
502 if (fileblock
>= grub_le_to_cpu16 (ext
[i
].len
))
506 grub_disk_addr_t start
;
508 start
= grub_le_to_cpu16 (ext
[i
].start_hi
);
509 start
= (start
<< 32) + grub_le_to_cpu32 (ext
[i
].start
);
511 g_ventoy_block_count
= (int)(grub_le_to_cpu16 (ext
[i
].len
) - fileblock
);
512 ret
= fileblock
+ start
;
517 grub_error (GRUB_ERR_BAD_FS
, "something wrong with extent");
521 if (leaf
!= (struct grub_ext4_extent_header
*) inode
->blocks
.dir_blocks
)
528 if (fileblock
< INDIRECT_BLOCKS
)
529 return grub_le_to_cpu32 (inode
->blocks
.dir_blocks
[fileblock
]);
530 fileblock
-= INDIRECT_BLOCKS
;
532 if (fileblock
< blksz_quarter
)
534 indir
= inode
->blocks
.indir_block
;
538 fileblock
-= blksz_quarter
;
539 /* Double indirect. */
540 if (fileblock
< blksz_quarter
* blksz_quarter
)
542 indir
= inode
->blocks
.double_indir_block
;
546 fileblock
-= blksz_quarter
* blksz_quarter
;
547 /* Triple indirect. */
548 if (fileblock
< blksz_quarter
* blksz_quarter
* (blksz_quarter
+ 1))
550 indir
= inode
->blocks
.triple_indir_block
;
554 grub_error (GRUB_ERR_BAD_FS
,
555 "ext2fs doesn't support quadruple indirect blocks");
560 /* If the indirect block is zero, all child blocks are absent
561 (i.e. filled with zeros.) */
564 if (grub_disk_read (data
->disk
,
565 ((grub_disk_addr_t
) grub_le_to_cpu32 (indir
))
567 ((fileblock
>> (log_perblock
* shift
))
568 & ((1 << log_perblock
) - 1))
570 sizeof (indir
), &indir
))
574 return grub_le_to_cpu32 (indir
);
577 /* Read LEN bytes from the file described by DATA starting with byte
578 POS. Return the amount of read bytes in READ. */
580 grub_ext2_read_file (grub_fshelp_node_t node
,
581 grub_disk_read_hook_t read_hook
, void *read_hook_data
,
582 grub_off_t pos
, grub_size_t len
, char *buf
)
584 return grub_fshelp_read_file (node
->data
->disk
, node
,
585 read_hook
, read_hook_data
,
586 pos
, len
, buf
, grub_ext2_read_block
,
587 grub_cpu_to_le32 (node
->inode
.size
)
588 | (((grub_off_t
) grub_cpu_to_le32 (node
->inode
.size_high
)) << 32),
589 LOG2_EXT2_BLOCK_SIZE (node
->data
), 0);
594 /* Read the inode INO for the file described by DATA into INODE. */
596 grub_ext2_read_inode (struct grub_ext2_data
*data
,
597 int ino
, struct grub_ext2_inode
*inode
)
599 struct grub_ext2_block_group blkgrp
;
600 struct grub_ext2_sblock
*sblock
= &data
->sblock
;
601 int inodes_per_block
;
604 grub_disk_addr_t base
;
606 /* It is easier to calculate if the first inode is 0. */
609 grub_ext2_blockgroup (data
,
610 ino
/ grub_le_to_cpu32 (sblock
->inodes_per_group
),
615 inodes_per_block
= EXT2_BLOCK_SIZE (data
) / EXT2_INODE_SIZE (data
);
616 blkno
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
618 blkoff
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
621 base
= grub_le_to_cpu32 (blkgrp
.inode_table_id
);
622 if (data
->log_group_desc_size
>= 6)
623 base
|= (((grub_disk_addr_t
) grub_le_to_cpu32 (blkgrp
.inode_table_id_hi
))
626 /* Read the inode. */
627 if (grub_disk_read (data
->disk
,
628 ((base
+ blkno
) << LOG2_EXT2_BLOCK_SIZE (data
)),
629 EXT2_INODE_SIZE (data
) * blkoff
,
630 sizeof (struct grub_ext2_inode
), inode
))
636 static struct grub_ext2_data
*
637 grub_ext2_mount (grub_disk_t disk
)
639 struct grub_ext2_data
*data
;
641 data
= grub_malloc (sizeof (struct grub_ext2_data
));
645 /* Read the superblock. */
646 grub_disk_read (disk
, 1 * 2, 0, sizeof (struct grub_ext2_sblock
),
651 /* Make sure this is an ext2 filesystem. */
652 if (data
->sblock
.magic
!= grub_cpu_to_le16_compile_time (EXT2_MAGIC
)
653 || grub_le_to_cpu32 (data
->sblock
.log2_block_size
) >= 16
654 || data
->sblock
.inodes_per_group
== 0
655 /* 20 already means 1GiB blocks. We don't want to deal with blocks overflowing int32. */
656 || grub_le_to_cpu32 (data
->sblock
.log2_block_size
) > 20
657 || EXT2_INODE_SIZE (data
) == 0
658 || EXT2_BLOCK_SIZE (data
) / EXT2_INODE_SIZE (data
) == 0)
660 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
664 /* Check the FS doesn't have feature bits enabled that we don't support. */
665 if (data
->sblock
.revision_level
!= grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION
)
666 && (data
->sblock
.feature_incompat
667 & grub_cpu_to_le32_compile_time (~(EXT2_DRIVER_SUPPORTED_INCOMPAT
668 | EXT2_DRIVER_IGNORED_INCOMPAT
))))
670 grub_error (GRUB_ERR_BAD_FS
, "filesystem has unsupported incompatible features");
674 if (data
->sblock
.revision_level
!= grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION
)
675 && (data
->sblock
.feature_incompat
676 & grub_cpu_to_le32_compile_time (EXT4_FEATURE_INCOMPAT_64BIT
))
677 && data
->sblock
.group_desc_size
!= 0
678 && ((data
->sblock
.group_desc_size
& (data
->sblock
.group_desc_size
- 1))
680 && (data
->sblock
.group_desc_size
& grub_cpu_to_le16_compile_time (0x1fe0)))
682 grub_uint16_t b
= grub_le_to_cpu16 (data
->sblock
.group_desc_size
);
683 for (data
->log_group_desc_size
= 0; b
!= (1 << data
->log_group_desc_size
);
684 data
->log_group_desc_size
++);
687 data
->log_group_desc_size
= 5;
691 data
->diropen
.data
= data
;
692 data
->diropen
.ino
= 2;
693 data
->diropen
.inode_read
= 1;
695 data
->inode
= &data
->diropen
.inode
;
697 grub_ext2_read_inode (data
, 2, data
->inode
);
704 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
705 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
712 grub_ext2_read_symlink (grub_fshelp_node_t node
)
715 struct grub_fshelp_node
*diro
= node
;
717 if (! diro
->inode_read
)
719 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
723 if (diro
->inode
.flags
& grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG
))
725 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "symlink is encrypted");
730 symlink
= grub_malloc (grub_le_to_cpu32 (diro
->inode
.size
) + 1);
735 * If the filesize of the symlink is equal to or bigger than 60 the symlink
736 * is stored in a separate block, otherwise it is stored in the inode.
738 if (grub_le_to_cpu32 (diro
->inode
.size
) < sizeof (diro
->inode
.symlink
))
739 grub_memcpy (symlink
,
741 grub_le_to_cpu32 (diro
->inode
.size
));
744 grub_ext2_read_file (diro
, 0, 0, 0,
745 grub_le_to_cpu32 (diro
->inode
.size
),
754 symlink
[grub_le_to_cpu32 (diro
->inode
.size
)] = '\0';
759 grub_ext2_iterate_dir (grub_fshelp_node_t dir
,
760 grub_fshelp_iterate_dir_hook_t hook
, void *hook_data
)
762 unsigned int fpos
= 0;
763 struct grub_fshelp_node
*diro
= (struct grub_fshelp_node
*) dir
;
765 if (! diro
->inode_read
)
767 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
772 if (diro
->inode
.flags
& grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG
))
774 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "directory is encrypted");
778 /* Search the file. */
779 while (fpos
< grub_le_to_cpu32 (diro
->inode
.size
))
781 struct ext2_dirent dirent
;
783 grub_ext2_read_file (diro
, 0, 0, fpos
, sizeof (struct ext2_dirent
),
788 if (dirent
.direntlen
== 0)
791 if (dirent
.inode
!= 0 && dirent
.namelen
!= 0)
793 char filename
[MAX_NAMELEN
+ 1];
794 struct grub_fshelp_node
*fdiro
;
795 enum grub_fshelp_filetype type
= GRUB_FSHELP_UNKNOWN
;
797 grub_ext2_read_file (diro
, 0, 0, fpos
+ sizeof (struct ext2_dirent
),
798 dirent
.namelen
, filename
);
802 fdiro
= grub_malloc (sizeof (struct grub_fshelp_node
));
806 fdiro
->data
= diro
->data
;
807 fdiro
->ino
= grub_le_to_cpu32 (dirent
.inode
);
809 filename
[dirent
.namelen
] = '\0';
811 if (dirent
.filetype
!= FILETYPE_UNKNOWN
)
813 fdiro
->inode_read
= 0;
815 if (dirent
.filetype
== FILETYPE_DIRECTORY
)
816 type
= GRUB_FSHELP_DIR
;
817 else if (dirent
.filetype
== FILETYPE_SYMLINK
)
818 type
= GRUB_FSHELP_SYMLINK
;
819 else if (dirent
.filetype
== FILETYPE_REG
)
820 type
= GRUB_FSHELP_REG
;
824 /* The filetype can not be read from the dirent, read
825 the inode to get more information. */
826 grub_ext2_read_inode (diro
->data
,
827 grub_le_to_cpu32 (dirent
.inode
),
835 fdiro
->inode_read
= 1;
837 if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
838 & FILETYPE_INO_MASK
) == FILETYPE_INO_DIRECTORY
)
839 type
= GRUB_FSHELP_DIR
;
840 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
841 & FILETYPE_INO_MASK
) == FILETYPE_INO_SYMLINK
)
842 type
= GRUB_FSHELP_SYMLINK
;
843 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
844 & FILETYPE_INO_MASK
) == FILETYPE_INO_REG
)
845 type
= GRUB_FSHELP_REG
;
848 if (hook (filename
, type
, fdiro
, hook_data
))
852 fpos
+= grub_le_to_cpu16 (dirent
.direntlen
);
858 /* Open a file named NAME and initialize FILE. */
860 grub_ext2_open (struct grub_file
*file
, const char *name
)
862 struct grub_ext2_data
*data
;
863 struct grub_fshelp_node
*fdiro
= 0;
866 grub_dl_ref (my_mod
);
868 data
= grub_ext2_mount (file
->device
->disk
);
875 err
= grub_fshelp_find_file (name
, &data
->diropen
, &fdiro
,
876 grub_ext2_iterate_dir
,
877 grub_ext2_read_symlink
, GRUB_FSHELP_REG
);
881 if (! fdiro
->inode_read
)
883 err
= grub_ext2_read_inode (data
, fdiro
->ino
, &fdiro
->inode
);
888 if (fdiro
->inode
.flags
& grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG
))
890 err
= grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "file is encrypted");
894 grub_memcpy (data
->inode
, &fdiro
->inode
, sizeof (struct grub_ext2_inode
));
897 file
->size
= grub_le_to_cpu32 (data
->inode
->size
);
898 file
->size
|= ((grub_off_t
) grub_le_to_cpu32 (data
->inode
->size_high
)) << 32;
905 if (fdiro
!= &data
->diropen
)
909 grub_dl_unref (my_mod
);
915 grub_ext2_close (grub_file_t file
)
917 grub_free (file
->data
);
919 grub_dl_unref (my_mod
);
921 return GRUB_ERR_NONE
;
924 /* Read LEN bytes data from FILE into BUF. */
926 grub_ext2_read (grub_file_t file
, char *buf
, grub_size_t len
)
928 struct grub_ext2_data
*data
= (struct grub_ext2_data
*) file
->data
;
930 return grub_ext2_read_file (&data
->diropen
,
931 file
->read_hook
, file
->read_hook_data
,
932 file
->offset
, len
, buf
);
936 /* Context for grub_ext2_dir. */
937 struct grub_ext2_dir_ctx
939 grub_fs_dir_hook_t hook
;
941 struct grub_ext2_data
*data
;
944 /* Helper for grub_ext2_dir. */
946 grub_ext2_dir_iter (const char *filename
, enum grub_fshelp_filetype filetype
,
947 grub_fshelp_node_t node
, void *data
)
949 struct grub_ext2_dir_ctx
*ctx
= data
;
950 struct grub_dirhook_info info
;
952 grub_memset (&info
, 0, sizeof (info
));
953 if (! node
->inode_read
)
955 grub_ext2_read_inode (ctx
->data
, node
->ino
, &node
->inode
);
957 node
->inode_read
= 1;
958 grub_errno
= GRUB_ERR_NONE
;
960 if (node
->inode_read
)
963 info
.mtime
= grub_le_to_cpu32 (node
->inode
.mtime
);
966 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
968 info
.size
= (((grub_off_t
) grub_le_to_cpu32 (node
->inode
.size_high
)) << 32) | grub_le_to_cpu32 (node
->inode
.size
);
970 return ctx
->hook (filename
, &info
, ctx
->hook_data
);
974 grub_ext2_dir (grub_device_t device
, const char *path
, grub_fs_dir_hook_t hook
,
977 struct grub_ext2_dir_ctx ctx
= {
979 .hook_data
= hook_data
981 struct grub_fshelp_node
*fdiro
= 0;
983 grub_dl_ref (my_mod
);
985 ctx
.data
= grub_ext2_mount (device
->disk
);
989 grub_fshelp_find_file (path
, &ctx
.data
->diropen
, &fdiro
,
990 grub_ext2_iterate_dir
, grub_ext2_read_symlink
,
995 grub_ext2_iterate_dir (fdiro
, grub_ext2_dir_iter
, &ctx
);
998 if (fdiro
!= &ctx
.data
->diropen
)
1000 grub_free (ctx
.data
);
1002 grub_dl_unref (my_mod
);
1008 grub_ext2_label (grub_device_t device
, char **label
)
1010 struct grub_ext2_data
*data
;
1011 grub_disk_t disk
= device
->disk
;
1013 grub_dl_ref (my_mod
);
1015 data
= grub_ext2_mount (disk
);
1017 *label
= grub_strndup (data
->sblock
.volume_name
,
1018 sizeof (data
->sblock
.volume_name
));
1022 grub_dl_unref (my_mod
);
1030 grub_ext2_uuid (grub_device_t device
, char **uuid
)
1032 struct grub_ext2_data
*data
;
1033 grub_disk_t disk
= device
->disk
;
1035 grub_dl_ref (my_mod
);
1037 data
= grub_ext2_mount (disk
);
1040 *uuid
= grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
1041 grub_be_to_cpu16 (data
->sblock
.uuid
[0]),
1042 grub_be_to_cpu16 (data
->sblock
.uuid
[1]),
1043 grub_be_to_cpu16 (data
->sblock
.uuid
[2]),
1044 grub_be_to_cpu16 (data
->sblock
.uuid
[3]),
1045 grub_be_to_cpu16 (data
->sblock
.uuid
[4]),
1046 grub_be_to_cpu16 (data
->sblock
.uuid
[5]),
1047 grub_be_to_cpu16 (data
->sblock
.uuid
[6]),
1048 grub_be_to_cpu16 (data
->sblock
.uuid
[7]));
1053 grub_dl_unref (my_mod
);
1062 grub_ext2_mtime (grub_device_t device
, grub_int32_t
*tm
)
1064 struct grub_ext2_data
*data
;
1065 grub_disk_t disk
= device
->disk
;
1067 grub_dl_ref (my_mod
);
1069 data
= grub_ext2_mount (disk
);
1073 *tm
= grub_le_to_cpu32 (data
->sblock
.utime
);
1075 grub_dl_unref (my_mod
);
1083 int grub_ext_get_file_chunk(grub_uint64_t part_start
, grub_file_t file
, ventoy_img_chunk_list
*chunk_list
)
1088 grub_disk_addr_t i
= 0;
1089 grub_disk_addr_t blockcnt
;
1090 grub_disk_addr_t blknr
;
1091 grub_fshelp_node_t node
= NULL
;
1093 disk
= file
->device
->disk
;
1094 node
= &(((struct grub_ext2_data
*)file
->data
)->diropen
);
1096 log2blocksize
= LOG2_EXT2_BLOCK_SIZE (node
->data
);
1097 blocksize
= 1 << (log2blocksize
+ GRUB_DISK_SECTOR_BITS
);
1098 blockcnt
= (file
->size
+ blocksize
- 1) >> (log2blocksize
+ GRUB_DISK_SECTOR_BITS
);
1100 while (i
< blockcnt
)
1102 g_ventoy_block_count
= 1;
1103 blknr
= grub_ext2_read_block(node
, i
);
1109 i
+= g_ventoy_block_count
;
1110 blknr
= blknr
<< log2blocksize
;
1111 grub_disk_blocklist_read(chunk_list
, blknr
, g_ventoy_block_count
* blocksize
, disk
->log_sector_size
);
1114 for (i
= 0; i
< chunk_list
->cur_chunk
; i
++)
1116 chunk_list
->chunk
[i
].disk_start_sector
+= part_start
;
1117 chunk_list
->chunk
[i
].disk_end_sector
+= part_start
;
1123 static struct grub_fs grub_ext2_fs
=
1126 .fs_dir
= grub_ext2_dir
,
1127 .fs_open
= grub_ext2_open
,
1128 .fs_read
= grub_ext2_read
,
1129 .fs_close
= grub_ext2_close
,
1130 .fs_label
= grub_ext2_label
,
1131 .fs_uuid
= grub_ext2_uuid
,
1132 .fs_mtime
= grub_ext2_mtime
,
1134 .reserved_first_sector
= 1,
1135 .blocklist_install
= 1,
1142 grub_fs_register (&grub_ext2_fs
);
1148 grub_fs_unregister (&grub_ext2_fs
);