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_ENCRYPT 0x10000
108 /* The set of back-incompatible features this driver DOES support. Add (OR)
109 * flags here as the related features are implemented into the driver. */
110 #define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
111 | EXT4_FEATURE_INCOMPAT_EXTENTS \
112 | EXT4_FEATURE_INCOMPAT_FLEX_BG \
113 | EXT2_FEATURE_INCOMPAT_META_BG \
114 | EXT4_FEATURE_INCOMPAT_64BIT \
115 | EXT4_FEATURE_INCOMPAT_ENCRYPT)
116 /* List of rationales for the ignored "incompatible" features:
117 * needs_recovery: Not really back-incompatible - was added as such to forbid
118 * ext2 drivers from mounting an ext3 volume with a dirty
119 * journal because they will ignore the journal, but the next
120 * ext3 driver to mount the volume will find the journal and
121 * replay it, potentially corrupting the metadata written by
122 * the ext2 drivers. Safe to ignore for this RO driver.
123 * mmp: Not really back-incompatible - was added as such to
124 * avoid multiple read-write mounts. Safe to ignore for this
127 #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \
128 | EXT4_FEATURE_INCOMPAT_MMP)
131 #define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
133 #define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1
134 #define EXT3_JOURNAL_COMMIT_BLOCK 2
135 #define EXT3_JOURNAL_SUPERBLOCK_V1 3
136 #define EXT3_JOURNAL_SUPERBLOCK_V2 4
137 #define EXT3_JOURNAL_REVOKE_BLOCK 5
139 #define EXT3_JOURNAL_FLAG_ESCAPE 1
140 #define EXT3_JOURNAL_FLAG_SAME_UUID 2
141 #define EXT3_JOURNAL_FLAG_DELETED 4
142 #define EXT3_JOURNAL_FLAG_LAST_TAG 8
144 #define EXT4_ENCRYPT_FLAG 0x800
145 #define EXT4_EXTENTS_FLAG 0x80000
147 /* The ext2 superblock. */
148 struct grub_ext2_sblock
150 grub_uint32_t total_inodes
;
151 grub_uint32_t total_blocks
;
152 grub_uint32_t reserved_blocks
;
153 grub_uint32_t free_blocks
;
154 grub_uint32_t free_inodes
;
155 grub_uint32_t first_data_block
;
156 grub_uint32_t log2_block_size
;
157 grub_uint32_t log2_fragment_size
;
158 grub_uint32_t blocks_per_group
;
159 grub_uint32_t fragments_per_group
;
160 grub_uint32_t inodes_per_group
;
163 grub_uint16_t mnt_count
;
164 grub_uint16_t max_mnt_count
;
166 grub_uint16_t fs_state
;
167 grub_uint16_t error_handling
;
168 grub_uint16_t minor_revision_level
;
169 grub_uint32_t lastcheck
;
170 grub_uint32_t checkinterval
;
171 grub_uint32_t creator_os
;
172 grub_uint32_t revision_level
;
173 grub_uint16_t uid_reserved
;
174 grub_uint16_t gid_reserved
;
175 grub_uint32_t first_inode
;
176 grub_uint16_t inode_size
;
177 grub_uint16_t block_group_number
;
178 grub_uint32_t feature_compatibility
;
179 grub_uint32_t feature_incompat
;
180 grub_uint32_t feature_ro_compat
;
181 grub_uint16_t uuid
[8];
182 char volume_name
[16];
183 char last_mounted_on
[64];
184 grub_uint32_t compression_info
;
185 grub_uint8_t prealloc_blocks
;
186 grub_uint8_t prealloc_dir_blocks
;
187 grub_uint16_t reserved_gdt_blocks
;
188 grub_uint8_t journal_uuid
[16];
189 grub_uint32_t journal_inum
;
190 grub_uint32_t journal_dev
;
191 grub_uint32_t last_orphan
;
192 grub_uint32_t hash_seed
[4];
193 grub_uint8_t def_hash_version
;
194 grub_uint8_t jnl_backup_type
;
195 grub_uint16_t group_desc_size
;
196 grub_uint32_t default_mount_opts
;
197 grub_uint32_t first_meta_bg
;
198 grub_uint32_t mkfs_time
;
199 grub_uint32_t jnl_blocks
[17];
202 /* The ext2 blockgroup. */
203 struct grub_ext2_block_group
205 grub_uint32_t block_id
;
206 grub_uint32_t inode_id
;
207 grub_uint32_t inode_table_id
;
208 grub_uint16_t free_blocks
;
209 grub_uint16_t free_inodes
;
210 grub_uint16_t used_dirs
;
212 grub_uint32_t reserved
[3];
213 grub_uint32_t block_id_hi
;
214 grub_uint32_t inode_id_hi
;
215 grub_uint32_t inode_table_id_hi
;
216 grub_uint16_t free_blocks_hi
;
217 grub_uint16_t free_inodes_hi
;
218 grub_uint16_t used_dirs_hi
;
220 grub_uint32_t reserved2
[3];
223 /* The ext2 inode. */
224 struct grub_ext2_inode
234 grub_uint16_t nlinks
;
235 grub_uint32_t blockcnt
; /* Blocks of 512 bytes!! */
242 grub_uint32_t dir_blocks
[INDIRECT_BLOCKS
];
243 grub_uint32_t indir_block
;
244 grub_uint32_t double_indir_block
;
245 grub_uint32_t triple_indir_block
;
249 grub_uint32_t version
;
251 grub_uint32_t size_high
;
252 grub_uint32_t fragment_addr
;
253 grub_uint32_t osd2
[3];
256 /* The header of an ext2 directory entry. */
260 grub_uint16_t direntlen
;
261 #define MAX_NAMELEN 255
262 grub_uint8_t namelen
;
263 grub_uint8_t filetype
;
266 struct grub_ext3_journal_header
269 grub_uint32_t block_type
;
270 grub_uint32_t sequence
;
273 struct grub_ext3_journal_revoke_header
275 struct grub_ext3_journal_header header
;
277 grub_uint32_t data
[0];
280 struct grub_ext3_journal_block_tag
286 struct grub_ext3_journal_sblock
288 struct grub_ext3_journal_header header
;
289 grub_uint32_t block_size
;
290 grub_uint32_t maxlen
;
292 grub_uint32_t sequence
;
296 #define EXT4_EXT_MAGIC 0xf30a
298 struct grub_ext4_extent_header
301 grub_uint16_t entries
;
304 grub_uint32_t generation
;
307 struct grub_ext4_extent
311 grub_uint16_t start_hi
;
315 struct grub_ext4_extent_idx
319 grub_uint16_t leaf_hi
;
320 grub_uint16_t unused
;
323 struct grub_fshelp_node
325 struct grub_ext2_data
*data
;
326 struct grub_ext2_inode inode
;
331 /* Information about a "mounted" ext2 filesystem. */
332 struct grub_ext2_data
334 struct grub_ext2_sblock sblock
;
335 int log_group_desc_size
;
337 struct grub_ext2_inode
*inode
;
338 struct grub_fshelp_node diropen
;
341 static grub_dl_t my_mod
;
343 static int g_ventoy_block_count
;
345 /* Check is a = b^x for some x. */
347 is_power_of (grub_uint64_t a
, grub_uint32_t b
)
350 /* Prevent overflow assuming b < 8. */
351 if (a
>= (1LL << 60))
353 for (c
= 1; c
<= a
; c
*= b
);
359 group_has_super_block (struct grub_ext2_data
*data
, grub_uint64_t group
)
361 if (!(data
->sblock
.feature_ro_compat
362 & grub_cpu_to_le32_compile_time(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
)))
364 /* Algorithm looked up in Linux source. */
367 /* Even number is never a power of odd number. */
370 return (is_power_of(group
, 7) || is_power_of(group
, 5) ||
371 is_power_of(group
, 3));
374 /* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
375 the mounted filesystem DATA. */
376 inline static grub_err_t
377 grub_ext2_blockgroup (struct grub_ext2_data
*data
, grub_uint64_t group
,
378 struct grub_ext2_block_group
*blkgrp
)
380 grub_uint64_t full_offset
= (group
<< data
->log_group_desc_size
);
381 grub_uint64_t block
, offset
;
382 block
= (full_offset
>> LOG2_BLOCK_SIZE (data
));
383 offset
= (full_offset
& ((1 << LOG2_BLOCK_SIZE (data
)) - 1));
384 if ((data
->sblock
.feature_incompat
385 & grub_cpu_to_le32_compile_time (EXT2_FEATURE_INCOMPAT_META_BG
))
386 && block
>= grub_le_to_cpu32(data
->sblock
.first_meta_bg
))
388 grub_uint64_t first_block_group
;
389 /* Find the first block group for which a descriptor
390 is stored in given block. */
391 first_block_group
= (block
<< (LOG2_BLOCK_SIZE (data
)
392 - data
->log_group_desc_size
));
394 block
= (first_block_group
395 * grub_le_to_cpu32(data
->sblock
.blocks_per_group
));
397 if (group_has_super_block (data
, first_block_group
))
403 return grub_disk_read (data
->disk
,
404 ((grub_le_to_cpu32 (data
->sblock
.first_data_block
)
406 << LOG2_EXT2_BLOCK_SIZE (data
)), offset
,
407 sizeof (struct grub_ext2_block_group
), blkgrp
);
410 static struct grub_ext4_extent_header
*
411 grub_ext4_find_leaf (struct grub_ext2_data
*data
,
412 struct grub_ext4_extent_header
*ext_block
,
413 grub_uint32_t fileblock
)
415 struct grub_ext4_extent_idx
*index
;
421 grub_disk_addr_t block
;
423 index
= (struct grub_ext4_extent_idx
*) (ext_block
+ 1);
425 if (ext_block
->magic
!= grub_cpu_to_le16_compile_time (EXT4_EXT_MAGIC
))
428 if (ext_block
->depth
== 0)
431 for (i
= 0; i
< grub_le_to_cpu16 (ext_block
->entries
); i
++)
433 if (fileblock
< grub_le_to_cpu32(index
[i
].block
))
440 block
= grub_le_to_cpu16 (index
[i
].leaf_hi
);
441 block
= (block
<< 32) | grub_le_to_cpu32 (index
[i
].leaf
);
443 buf
= grub_malloc (EXT2_BLOCK_SIZE(data
));
446 if (grub_disk_read (data
->disk
,
447 block
<< LOG2_EXT2_BLOCK_SIZE (data
),
448 0, EXT2_BLOCK_SIZE(data
), buf
))
458 static grub_disk_addr_t
459 grub_ext2_read_block (grub_fshelp_node_t node
, grub_disk_addr_t fileblock
)
461 struct grub_ext2_data
*data
= node
->data
;
462 struct grub_ext2_inode
*inode
= &node
->inode
;
463 unsigned int blksz
= EXT2_BLOCK_SIZE (data
);
464 grub_disk_addr_t blksz_quarter
= blksz
/ 4;
465 int log2_blksz
= LOG2_EXT2_BLOCK_SIZE (data
);
466 int log_perblock
= log2_blksz
+ 9 - 2;
470 if (inode
->flags
& grub_cpu_to_le32_compile_time (EXT4_EXTENTS_FLAG
))
472 struct grub_ext4_extent_header
*leaf
;
473 struct grub_ext4_extent
*ext
;
475 grub_disk_addr_t ret
;
477 leaf
= grub_ext4_find_leaf (data
, (struct grub_ext4_extent_header
*) inode
->blocks
.dir_blocks
, fileblock
);
480 grub_error (GRUB_ERR_BAD_FS
, "invalid extent");
484 ext
= (struct grub_ext4_extent
*) (leaf
+ 1);
485 for (i
= 0; i
< grub_le_to_cpu16 (leaf
->entries
); i
++)
487 if (fileblock
< grub_le_to_cpu32 (ext
[i
].block
))
493 fileblock
-= grub_le_to_cpu32 (ext
[i
].block
);
494 if (fileblock
>= grub_le_to_cpu16 (ext
[i
].len
))
498 grub_disk_addr_t start
;
500 start
= grub_le_to_cpu16 (ext
[i
].start_hi
);
501 start
= (start
<< 32) + grub_le_to_cpu32 (ext
[i
].start
);
503 g_ventoy_block_count
= (int)(grub_le_to_cpu16 (ext
[i
].len
) - fileblock
);
504 ret
= fileblock
+ start
;
509 grub_error (GRUB_ERR_BAD_FS
, "something wrong with extent");
513 if (leaf
!= (struct grub_ext4_extent_header
*) inode
->blocks
.dir_blocks
)
520 if (fileblock
< INDIRECT_BLOCKS
)
521 return grub_le_to_cpu32 (inode
->blocks
.dir_blocks
[fileblock
]);
522 fileblock
-= INDIRECT_BLOCKS
;
524 if (fileblock
< blksz_quarter
)
526 indir
= inode
->blocks
.indir_block
;
530 fileblock
-= blksz_quarter
;
531 /* Double indirect. */
532 if (fileblock
< blksz_quarter
* blksz_quarter
)
534 indir
= inode
->blocks
.double_indir_block
;
538 fileblock
-= blksz_quarter
* blksz_quarter
;
539 /* Triple indirect. */
540 if (fileblock
< blksz_quarter
* blksz_quarter
* (blksz_quarter
+ 1))
542 indir
= inode
->blocks
.triple_indir_block
;
546 grub_error (GRUB_ERR_BAD_FS
,
547 "ext2fs doesn't support quadruple indirect blocks");
552 /* If the indirect block is zero, all child blocks are absent
553 (i.e. filled with zeros.) */
556 if (grub_disk_read (data
->disk
,
557 ((grub_disk_addr_t
) grub_le_to_cpu32 (indir
))
559 ((fileblock
>> (log_perblock
* shift
))
560 & ((1 << log_perblock
) - 1))
562 sizeof (indir
), &indir
))
566 return grub_le_to_cpu32 (indir
);
569 /* Read LEN bytes from the file described by DATA starting with byte
570 POS. Return the amount of read bytes in READ. */
572 grub_ext2_read_file (grub_fshelp_node_t node
,
573 grub_disk_read_hook_t read_hook
, void *read_hook_data
,
574 grub_off_t pos
, grub_size_t len
, char *buf
)
576 return grub_fshelp_read_file (node
->data
->disk
, node
,
577 read_hook
, read_hook_data
,
578 pos
, len
, buf
, grub_ext2_read_block
,
579 grub_cpu_to_le32 (node
->inode
.size
)
580 | (((grub_off_t
) grub_cpu_to_le32 (node
->inode
.size_high
)) << 32),
581 LOG2_EXT2_BLOCK_SIZE (node
->data
), 0);
586 /* Read the inode INO for the file described by DATA into INODE. */
588 grub_ext2_read_inode (struct grub_ext2_data
*data
,
589 int ino
, struct grub_ext2_inode
*inode
)
591 struct grub_ext2_block_group blkgrp
;
592 struct grub_ext2_sblock
*sblock
= &data
->sblock
;
593 int inodes_per_block
;
596 grub_disk_addr_t base
;
598 /* It is easier to calculate if the first inode is 0. */
601 grub_ext2_blockgroup (data
,
602 ino
/ grub_le_to_cpu32 (sblock
->inodes_per_group
),
607 inodes_per_block
= EXT2_BLOCK_SIZE (data
) / EXT2_INODE_SIZE (data
);
608 blkno
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
610 blkoff
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
613 base
= grub_le_to_cpu32 (blkgrp
.inode_table_id
);
614 if (data
->log_group_desc_size
>= 6)
615 base
|= (((grub_disk_addr_t
) grub_le_to_cpu32 (blkgrp
.inode_table_id_hi
))
618 /* Read the inode. */
619 if (grub_disk_read (data
->disk
,
620 ((base
+ blkno
) << LOG2_EXT2_BLOCK_SIZE (data
)),
621 EXT2_INODE_SIZE (data
) * blkoff
,
622 sizeof (struct grub_ext2_inode
), inode
))
628 static struct grub_ext2_data
*
629 grub_ext2_mount (grub_disk_t disk
)
631 struct grub_ext2_data
*data
;
633 data
= grub_malloc (sizeof (struct grub_ext2_data
));
637 /* Read the superblock. */
638 grub_disk_read (disk
, 1 * 2, 0, sizeof (struct grub_ext2_sblock
),
643 /* Make sure this is an ext2 filesystem. */
644 if (data
->sblock
.magic
!= grub_cpu_to_le16_compile_time (EXT2_MAGIC
)
645 || grub_le_to_cpu32 (data
->sblock
.log2_block_size
) >= 16
646 || data
->sblock
.inodes_per_group
== 0
647 /* 20 already means 1GiB blocks. We don't want to deal with blocks overflowing int32. */
648 || grub_le_to_cpu32 (data
->sblock
.log2_block_size
) > 20
649 || EXT2_INODE_SIZE (data
) == 0
650 || EXT2_BLOCK_SIZE (data
) / EXT2_INODE_SIZE (data
) == 0)
652 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
656 /* Check the FS doesn't have feature bits enabled that we don't support. */
657 if (data
->sblock
.revision_level
!= grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION
)
658 && (data
->sblock
.feature_incompat
659 & grub_cpu_to_le32_compile_time (~(EXT2_DRIVER_SUPPORTED_INCOMPAT
660 | EXT2_DRIVER_IGNORED_INCOMPAT
))))
662 grub_error (GRUB_ERR_BAD_FS
, "filesystem has unsupported incompatible features");
666 if (data
->sblock
.revision_level
!= grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION
)
667 && (data
->sblock
.feature_incompat
668 & grub_cpu_to_le32_compile_time (EXT4_FEATURE_INCOMPAT_64BIT
))
669 && data
->sblock
.group_desc_size
!= 0
670 && ((data
->sblock
.group_desc_size
& (data
->sblock
.group_desc_size
- 1))
672 && (data
->sblock
.group_desc_size
& grub_cpu_to_le16_compile_time (0x1fe0)))
674 grub_uint16_t b
= grub_le_to_cpu16 (data
->sblock
.group_desc_size
);
675 for (data
->log_group_desc_size
= 0; b
!= (1 << data
->log_group_desc_size
);
676 data
->log_group_desc_size
++);
679 data
->log_group_desc_size
= 5;
683 data
->diropen
.data
= data
;
684 data
->diropen
.ino
= 2;
685 data
->diropen
.inode_read
= 1;
687 data
->inode
= &data
->diropen
.inode
;
689 grub_ext2_read_inode (data
, 2, data
->inode
);
696 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
697 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
704 grub_ext2_read_symlink (grub_fshelp_node_t node
)
707 struct grub_fshelp_node
*diro
= node
;
709 if (! diro
->inode_read
)
711 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
715 if (diro
->inode
.flags
& grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG
))
717 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "symlink is encrypted");
722 symlink
= grub_malloc (grub_le_to_cpu32 (diro
->inode
.size
) + 1);
726 /* If the filesize of the symlink is bigger than
727 60 the symlink is stored in a separate block,
728 otherwise it is stored in the inode. */
729 if (grub_le_to_cpu32 (diro
->inode
.size
) <= sizeof (diro
->inode
.symlink
))
730 grub_memcpy (symlink
,
732 grub_le_to_cpu32 (diro
->inode
.size
));
735 grub_ext2_read_file (diro
, 0, 0, 0,
736 grub_le_to_cpu32 (diro
->inode
.size
),
745 symlink
[grub_le_to_cpu32 (diro
->inode
.size
)] = '\0';
750 grub_ext2_iterate_dir (grub_fshelp_node_t dir
,
751 grub_fshelp_iterate_dir_hook_t hook
, void *hook_data
)
753 unsigned int fpos
= 0;
754 struct grub_fshelp_node
*diro
= (struct grub_fshelp_node
*) dir
;
756 if (! diro
->inode_read
)
758 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
763 if (diro
->inode
.flags
& grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG
))
765 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "directory is encrypted");
769 /* Search the file. */
770 while (fpos
< grub_le_to_cpu32 (diro
->inode
.size
))
772 struct ext2_dirent dirent
;
774 grub_ext2_read_file (diro
, 0, 0, fpos
, sizeof (struct ext2_dirent
),
779 if (dirent
.direntlen
== 0)
782 if (dirent
.inode
!= 0 && dirent
.namelen
!= 0)
784 char filename
[MAX_NAMELEN
+ 1];
785 struct grub_fshelp_node
*fdiro
;
786 enum grub_fshelp_filetype type
= GRUB_FSHELP_UNKNOWN
;
788 grub_ext2_read_file (diro
, 0, 0, fpos
+ sizeof (struct ext2_dirent
),
789 dirent
.namelen
, filename
);
793 fdiro
= grub_malloc (sizeof (struct grub_fshelp_node
));
797 fdiro
->data
= diro
->data
;
798 fdiro
->ino
= grub_le_to_cpu32 (dirent
.inode
);
800 filename
[dirent
.namelen
] = '\0';
802 if (dirent
.filetype
!= FILETYPE_UNKNOWN
)
804 fdiro
->inode_read
= 0;
806 if (dirent
.filetype
== FILETYPE_DIRECTORY
)
807 type
= GRUB_FSHELP_DIR
;
808 else if (dirent
.filetype
== FILETYPE_SYMLINK
)
809 type
= GRUB_FSHELP_SYMLINK
;
810 else if (dirent
.filetype
== FILETYPE_REG
)
811 type
= GRUB_FSHELP_REG
;
815 /* The filetype can not be read from the dirent, read
816 the inode to get more information. */
817 grub_ext2_read_inode (diro
->data
,
818 grub_le_to_cpu32 (dirent
.inode
),
826 fdiro
->inode_read
= 1;
828 if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
829 & FILETYPE_INO_MASK
) == FILETYPE_INO_DIRECTORY
)
830 type
= GRUB_FSHELP_DIR
;
831 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
832 & FILETYPE_INO_MASK
) == FILETYPE_INO_SYMLINK
)
833 type
= GRUB_FSHELP_SYMLINK
;
834 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
835 & FILETYPE_INO_MASK
) == FILETYPE_INO_REG
)
836 type
= GRUB_FSHELP_REG
;
839 if (hook (filename
, type
, fdiro
, hook_data
))
843 fpos
+= grub_le_to_cpu16 (dirent
.direntlen
);
849 /* Open a file named NAME and initialize FILE. */
851 grub_ext2_open (struct grub_file
*file
, const char *name
)
853 struct grub_ext2_data
*data
;
854 struct grub_fshelp_node
*fdiro
= 0;
857 grub_dl_ref (my_mod
);
859 data
= grub_ext2_mount (file
->device
->disk
);
866 err
= grub_fshelp_find_file (name
, &data
->diropen
, &fdiro
,
867 grub_ext2_iterate_dir
,
868 grub_ext2_read_symlink
, GRUB_FSHELP_REG
);
872 if (! fdiro
->inode_read
)
874 err
= grub_ext2_read_inode (data
, fdiro
->ino
, &fdiro
->inode
);
879 if (fdiro
->inode
.flags
& grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG
))
881 err
= grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "file is encrypted");
885 grub_memcpy (data
->inode
, &fdiro
->inode
, sizeof (struct grub_ext2_inode
));
888 file
->size
= grub_le_to_cpu32 (data
->inode
->size
);
889 file
->size
|= ((grub_off_t
) grub_le_to_cpu32 (data
->inode
->size_high
)) << 32;
896 if (fdiro
!= &data
->diropen
)
900 grub_dl_unref (my_mod
);
906 grub_ext2_close (grub_file_t file
)
908 grub_free (file
->data
);
910 grub_dl_unref (my_mod
);
912 return GRUB_ERR_NONE
;
915 /* Read LEN bytes data from FILE into BUF. */
917 grub_ext2_read (grub_file_t file
, char *buf
, grub_size_t len
)
919 struct grub_ext2_data
*data
= (struct grub_ext2_data
*) file
->data
;
921 return grub_ext2_read_file (&data
->diropen
,
922 file
->read_hook
, file
->read_hook_data
,
923 file
->offset
, len
, buf
);
927 /* Context for grub_ext2_dir. */
928 struct grub_ext2_dir_ctx
930 grub_fs_dir_hook_t hook
;
932 struct grub_ext2_data
*data
;
935 /* Helper for grub_ext2_dir. */
937 grub_ext2_dir_iter (const char *filename
, enum grub_fshelp_filetype filetype
,
938 grub_fshelp_node_t node
, void *data
)
940 struct grub_ext2_dir_ctx
*ctx
= data
;
941 struct grub_dirhook_info info
;
943 grub_memset (&info
, 0, sizeof (info
));
944 if (! node
->inode_read
)
946 grub_ext2_read_inode (ctx
->data
, node
->ino
, &node
->inode
);
948 node
->inode_read
= 1;
949 grub_errno
= GRUB_ERR_NONE
;
951 if (node
->inode_read
)
954 info
.mtime
= grub_le_to_cpu32 (node
->inode
.mtime
);
957 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
959 info
.size
= (((grub_off_t
) grub_le_to_cpu32 (node
->inode
.size_high
)) << 32) | grub_le_to_cpu32 (node
->inode
.size
);
961 return ctx
->hook (filename
, &info
, ctx
->hook_data
);
965 grub_ext2_dir (grub_device_t device
, const char *path
, grub_fs_dir_hook_t hook
,
968 struct grub_ext2_dir_ctx ctx
= {
970 .hook_data
= hook_data
972 struct grub_fshelp_node
*fdiro
= 0;
974 grub_dl_ref (my_mod
);
976 ctx
.data
= grub_ext2_mount (device
->disk
);
980 grub_fshelp_find_file (path
, &ctx
.data
->diropen
, &fdiro
,
981 grub_ext2_iterate_dir
, grub_ext2_read_symlink
,
986 grub_ext2_iterate_dir (fdiro
, grub_ext2_dir_iter
, &ctx
);
989 if (fdiro
!= &ctx
.data
->diropen
)
991 grub_free (ctx
.data
);
993 grub_dl_unref (my_mod
);
999 grub_ext2_label (grub_device_t device
, char **label
)
1001 struct grub_ext2_data
*data
;
1002 grub_disk_t disk
= device
->disk
;
1004 grub_dl_ref (my_mod
);
1006 data
= grub_ext2_mount (disk
);
1008 *label
= grub_strndup (data
->sblock
.volume_name
,
1009 sizeof (data
->sblock
.volume_name
));
1013 grub_dl_unref (my_mod
);
1021 grub_ext2_uuid (grub_device_t device
, char **uuid
)
1023 struct grub_ext2_data
*data
;
1024 grub_disk_t disk
= device
->disk
;
1026 grub_dl_ref (my_mod
);
1028 data
= grub_ext2_mount (disk
);
1031 *uuid
= grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
1032 grub_be_to_cpu16 (data
->sblock
.uuid
[0]),
1033 grub_be_to_cpu16 (data
->sblock
.uuid
[1]),
1034 grub_be_to_cpu16 (data
->sblock
.uuid
[2]),
1035 grub_be_to_cpu16 (data
->sblock
.uuid
[3]),
1036 grub_be_to_cpu16 (data
->sblock
.uuid
[4]),
1037 grub_be_to_cpu16 (data
->sblock
.uuid
[5]),
1038 grub_be_to_cpu16 (data
->sblock
.uuid
[6]),
1039 grub_be_to_cpu16 (data
->sblock
.uuid
[7]));
1044 grub_dl_unref (my_mod
);
1053 grub_ext2_mtime (grub_device_t device
, grub_int32_t
*tm
)
1055 struct grub_ext2_data
*data
;
1056 grub_disk_t disk
= device
->disk
;
1058 grub_dl_ref (my_mod
);
1060 data
= grub_ext2_mount (disk
);
1064 *tm
= grub_le_to_cpu32 (data
->sblock
.utime
);
1066 grub_dl_unref (my_mod
);
1074 int grub_ext_get_file_chunk(grub_uint64_t part_start
, grub_file_t file
, ventoy_img_chunk_list
*chunk_list
)
1079 grub_disk_addr_t i
= 0;
1080 grub_disk_addr_t blockcnt
;
1081 grub_disk_addr_t blknr
;
1082 grub_fshelp_node_t node
= NULL
;
1084 disk
= file
->device
->disk
;
1085 node
= &(((struct grub_ext2_data
*)file
->data
)->diropen
);
1087 log2blocksize
= LOG2_EXT2_BLOCK_SIZE (node
->data
);
1088 blocksize
= 1 << (log2blocksize
+ GRUB_DISK_SECTOR_BITS
);
1089 blockcnt
= (file
->size
+ blocksize
- 1) >> (log2blocksize
+ GRUB_DISK_SECTOR_BITS
);
1091 while (i
< blockcnt
)
1093 g_ventoy_block_count
= 1;
1094 blknr
= grub_ext2_read_block(node
, i
);
1100 i
+= g_ventoy_block_count
;
1101 blknr
= blknr
<< log2blocksize
;
1102 grub_disk_blocklist_read(chunk_list
, blknr
, g_ventoy_block_count
* blocksize
, disk
->log_sector_size
);
1105 for (i
= 0; i
< chunk_list
->cur_chunk
; i
++)
1107 chunk_list
->chunk
[i
].disk_start_sector
+= part_start
;
1108 chunk_list
->chunk
[i
].disk_end_sector
+= part_start
;
1114 static struct grub_fs grub_ext2_fs
=
1117 .fs_dir
= grub_ext2_dir
,
1118 .fs_open
= grub_ext2_open
,
1119 .fs_read
= grub_ext2_read
,
1120 .fs_close
= grub_ext2_close
,
1121 .fs_label
= grub_ext2_label
,
1122 .fs_uuid
= grub_ext2_uuid
,
1123 .fs_mtime
= grub_ext2_mtime
,
1125 .reserved_first_sector
= 1,
1126 .blocklist_install
= 1,
1133 grub_fs_register (&grub_ext2_fs
);
1139 grub_fs_unregister (&grub_ext2_fs
);