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>
50 GRUB_MOD_LICENSE ("GPLv3+");
52 /* Log2 size of ext2 block in 512 blocks. */
53 #define LOG2_EXT2_BLOCK_SIZE(data) \
54 (grub_le_to_cpu32 (data->sblock.log2_block_size) + 1)
56 /* Log2 size of ext2 block in bytes. */
57 #define LOG2_BLOCK_SIZE(data) \
58 (grub_le_to_cpu32 (data->sblock.log2_block_size) + 10)
60 /* The size of an ext2 block in bytes. */
61 #define EXT2_BLOCK_SIZE(data) (1U << LOG2_BLOCK_SIZE (data))
63 /* The revision level. */
64 #define EXT2_REVISION(data) grub_le_to_cpu32 (data->sblock.revision_level)
67 #define EXT2_INODE_SIZE(data) \
68 (data->sblock.revision_level \
69 == grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION) \
70 ? EXT2_GOOD_OLD_INODE_SIZE \
71 : grub_le_to_cpu16 (data->sblock.inode_size))
73 /* Superblock filesystem feature flags (RW compatible)
74 * A filesystem with any of these enabled can be read and written by a driver
75 * that does not understand them without causing metadata/data corruption. */
76 #define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
77 #define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
78 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
79 #define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
80 #define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
81 #define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
82 /* Superblock filesystem feature flags (RO compatible)
83 * A filesystem with any of these enabled can be safely read by a driver that
84 * does not understand them, but should not be written to, usually because
85 * additional metadata is required. */
86 #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
87 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
88 #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
89 #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
90 #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
91 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
92 /* Superblock filesystem feature flags (back-incompatible)
93 * A filesystem with any of these enabled should not be attempted to be read
94 * by a driver that does not understand them, since they usually indicate
95 * metadata format changes that might confuse the reader. */
96 #define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
97 #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
98 #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
99 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Volume is journal device */
100 #define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
101 #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* Extents used */
102 #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
103 #define EXT4_FEATURE_INCOMPAT_MMP 0x0100
104 #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
105 #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
107 /* The set of back-incompatible features this driver DOES support. Add (OR)
108 * flags here as the related features are implemented into the driver. */
109 #define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
110 | EXT4_FEATURE_INCOMPAT_EXTENTS \
111 | EXT4_FEATURE_INCOMPAT_FLEX_BG \
112 | EXT2_FEATURE_INCOMPAT_META_BG \
113 | EXT4_FEATURE_INCOMPAT_64BIT \
114 | EXT4_FEATURE_INCOMPAT_ENCRYPT)
115 /* List of rationales for the ignored "incompatible" features:
116 * needs_recovery: Not really back-incompatible - was added as such to forbid
117 * ext2 drivers from mounting an ext3 volume with a dirty
118 * journal because they will ignore the journal, but the next
119 * ext3 driver to mount the volume will find the journal and
120 * replay it, potentially corrupting the metadata written by
121 * the ext2 drivers. Safe to ignore for this RO driver.
122 * mmp: Not really back-incompatible - was added as such to
123 * avoid multiple read-write mounts. Safe to ignore for this
126 #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \
127 | EXT4_FEATURE_INCOMPAT_MMP)
130 #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
138 #define EXT3_JOURNAL_FLAG_ESCAPE 1
139 #define EXT3_JOURNAL_FLAG_SAME_UUID 2
140 #define EXT3_JOURNAL_FLAG_DELETED 4
141 #define EXT3_JOURNAL_FLAG_LAST_TAG 8
143 #define EXT4_ENCRYPT_FLAG 0x800
144 #define EXT4_EXTENTS_FLAG 0x80000
146 /* The ext2 superblock. */
147 struct grub_ext2_sblock
149 grub_uint32_t total_inodes
;
150 grub_uint32_t total_blocks
;
151 grub_uint32_t reserved_blocks
;
152 grub_uint32_t free_blocks
;
153 grub_uint32_t free_inodes
;
154 grub_uint32_t first_data_block
;
155 grub_uint32_t log2_block_size
;
156 grub_uint32_t log2_fragment_size
;
157 grub_uint32_t blocks_per_group
;
158 grub_uint32_t fragments_per_group
;
159 grub_uint32_t inodes_per_group
;
162 grub_uint16_t mnt_count
;
163 grub_uint16_t max_mnt_count
;
165 grub_uint16_t fs_state
;
166 grub_uint16_t error_handling
;
167 grub_uint16_t minor_revision_level
;
168 grub_uint32_t lastcheck
;
169 grub_uint32_t checkinterval
;
170 grub_uint32_t creator_os
;
171 grub_uint32_t revision_level
;
172 grub_uint16_t uid_reserved
;
173 grub_uint16_t gid_reserved
;
174 grub_uint32_t first_inode
;
175 grub_uint16_t inode_size
;
176 grub_uint16_t block_group_number
;
177 grub_uint32_t feature_compatibility
;
178 grub_uint32_t feature_incompat
;
179 grub_uint32_t feature_ro_compat
;
180 grub_uint16_t uuid
[8];
181 char volume_name
[16];
182 char last_mounted_on
[64];
183 grub_uint32_t compression_info
;
184 grub_uint8_t prealloc_blocks
;
185 grub_uint8_t prealloc_dir_blocks
;
186 grub_uint16_t reserved_gdt_blocks
;
187 grub_uint8_t journal_uuid
[16];
188 grub_uint32_t journal_inum
;
189 grub_uint32_t journal_dev
;
190 grub_uint32_t last_orphan
;
191 grub_uint32_t hash_seed
[4];
192 grub_uint8_t def_hash_version
;
193 grub_uint8_t jnl_backup_type
;
194 grub_uint16_t group_desc_size
;
195 grub_uint32_t default_mount_opts
;
196 grub_uint32_t first_meta_bg
;
197 grub_uint32_t mkfs_time
;
198 grub_uint32_t jnl_blocks
[17];
201 /* The ext2 blockgroup. */
202 struct grub_ext2_block_group
204 grub_uint32_t block_id
;
205 grub_uint32_t inode_id
;
206 grub_uint32_t inode_table_id
;
207 grub_uint16_t free_blocks
;
208 grub_uint16_t free_inodes
;
209 grub_uint16_t used_dirs
;
211 grub_uint32_t reserved
[3];
212 grub_uint32_t block_id_hi
;
213 grub_uint32_t inode_id_hi
;
214 grub_uint32_t inode_table_id_hi
;
215 grub_uint16_t free_blocks_hi
;
216 grub_uint16_t free_inodes_hi
;
217 grub_uint16_t used_dirs_hi
;
219 grub_uint32_t reserved2
[3];
222 /* The ext2 inode. */
223 struct grub_ext2_inode
233 grub_uint16_t nlinks
;
234 grub_uint32_t blockcnt
; /* Blocks of 512 bytes!! */
241 grub_uint32_t dir_blocks
[INDIRECT_BLOCKS
];
242 grub_uint32_t indir_block
;
243 grub_uint32_t double_indir_block
;
244 grub_uint32_t triple_indir_block
;
248 grub_uint32_t version
;
250 grub_uint32_t size_high
;
251 grub_uint32_t fragment_addr
;
252 grub_uint32_t osd2
[3];
255 /* The header of an ext2 directory entry. */
259 grub_uint16_t direntlen
;
260 #define MAX_NAMELEN 255
261 grub_uint8_t namelen
;
262 grub_uint8_t filetype
;
265 struct grub_ext3_journal_header
268 grub_uint32_t block_type
;
269 grub_uint32_t sequence
;
272 struct grub_ext3_journal_revoke_header
274 struct grub_ext3_journal_header header
;
276 grub_uint32_t data
[0];
279 struct grub_ext3_journal_block_tag
285 struct grub_ext3_journal_sblock
287 struct grub_ext3_journal_header header
;
288 grub_uint32_t block_size
;
289 grub_uint32_t maxlen
;
291 grub_uint32_t sequence
;
295 #define EXT4_EXT_MAGIC 0xf30a
297 struct grub_ext4_extent_header
300 grub_uint16_t entries
;
303 grub_uint32_t generation
;
306 struct grub_ext4_extent
310 grub_uint16_t start_hi
;
314 struct grub_ext4_extent_idx
318 grub_uint16_t leaf_hi
;
319 grub_uint16_t unused
;
322 struct grub_fshelp_node
324 struct grub_ext2_data
*data
;
325 struct grub_ext2_inode inode
;
330 /* Information about a "mounted" ext2 filesystem. */
331 struct grub_ext2_data
333 struct grub_ext2_sblock sblock
;
334 int log_group_desc_size
;
336 struct grub_ext2_inode
*inode
;
337 struct grub_fshelp_node diropen
;
340 static grub_dl_t my_mod
;
344 /* Check is a = b^x for some x. */
346 is_power_of (grub_uint64_t a
, grub_uint32_t b
)
349 /* Prevent overflow assuming b < 8. */
350 if (a
>= (1LL << 60))
352 for (c
= 1; c
<= a
; c
*= b
);
358 group_has_super_block (struct grub_ext2_data
*data
, grub_uint64_t group
)
360 if (!(data
->sblock
.feature_ro_compat
361 & grub_cpu_to_le32_compile_time(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
)))
363 /* Algorithm looked up in Linux source. */
366 /* Even number is never a power of odd number. */
369 return (is_power_of(group
, 7) || is_power_of(group
, 5) ||
370 is_power_of(group
, 3));
373 /* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
374 the mounted filesystem DATA. */
375 inline static grub_err_t
376 grub_ext2_blockgroup (struct grub_ext2_data
*data
, grub_uint64_t group
,
377 struct grub_ext2_block_group
*blkgrp
)
379 grub_uint64_t full_offset
= (group
<< data
->log_group_desc_size
);
380 grub_uint64_t block
, offset
;
381 block
= (full_offset
>> LOG2_BLOCK_SIZE (data
));
382 offset
= (full_offset
& ((1 << LOG2_BLOCK_SIZE (data
)) - 1));
383 if ((data
->sblock
.feature_incompat
384 & grub_cpu_to_le32_compile_time (EXT2_FEATURE_INCOMPAT_META_BG
))
385 && block
>= grub_le_to_cpu32(data
->sblock
.first_meta_bg
))
387 grub_uint64_t first_block_group
;
388 /* Find the first block group for which a descriptor
389 is stored in given block. */
390 first_block_group
= (block
<< (LOG2_BLOCK_SIZE (data
)
391 - data
->log_group_desc_size
));
393 block
= (first_block_group
394 * grub_le_to_cpu32(data
->sblock
.blocks_per_group
));
396 if (group_has_super_block (data
, first_block_group
))
402 return grub_disk_read (data
->disk
,
403 ((grub_le_to_cpu32 (data
->sblock
.first_data_block
)
405 << LOG2_EXT2_BLOCK_SIZE (data
)), offset
,
406 sizeof (struct grub_ext2_block_group
), blkgrp
);
409 static struct grub_ext4_extent_header
*
410 grub_ext4_find_leaf (struct grub_ext2_data
*data
,
411 struct grub_ext4_extent_header
*ext_block
,
412 grub_uint32_t fileblock
)
414 struct grub_ext4_extent_idx
*index
;
420 grub_disk_addr_t block
;
422 index
= (struct grub_ext4_extent_idx
*) (ext_block
+ 1);
424 if (ext_block
->magic
!= grub_cpu_to_le16_compile_time (EXT4_EXT_MAGIC
))
427 if (ext_block
->depth
== 0)
430 for (i
= 0; i
< grub_le_to_cpu16 (ext_block
->entries
); i
++)
432 if (fileblock
< grub_le_to_cpu32(index
[i
].block
))
439 block
= grub_le_to_cpu16 (index
[i
].leaf_hi
);
440 block
= (block
<< 32) | grub_le_to_cpu32 (index
[i
].leaf
);
442 buf
= grub_malloc (EXT2_BLOCK_SIZE(data
));
445 if (grub_disk_read (data
->disk
,
446 block
<< LOG2_EXT2_BLOCK_SIZE (data
),
447 0, EXT2_BLOCK_SIZE(data
), buf
))
457 static grub_disk_addr_t
458 grub_ext2_read_block (grub_fshelp_node_t node
, grub_disk_addr_t fileblock
)
460 struct grub_ext2_data
*data
= node
->data
;
461 struct grub_ext2_inode
*inode
= &node
->inode
;
462 unsigned int blksz
= EXT2_BLOCK_SIZE (data
);
463 grub_disk_addr_t blksz_quarter
= blksz
/ 4;
464 int log2_blksz
= LOG2_EXT2_BLOCK_SIZE (data
);
465 int log_perblock
= log2_blksz
+ 9 - 2;
469 if (inode
->flags
& grub_cpu_to_le32_compile_time (EXT4_EXTENTS_FLAG
))
471 struct grub_ext4_extent_header
*leaf
;
472 struct grub_ext4_extent
*ext
;
474 grub_disk_addr_t ret
;
476 leaf
= grub_ext4_find_leaf (data
, (struct grub_ext4_extent_header
*) inode
->blocks
.dir_blocks
, fileblock
);
479 grub_error (GRUB_ERR_BAD_FS
, "invalid extent");
483 ext
= (struct grub_ext4_extent
*) (leaf
+ 1);
484 for (i
= 0; i
< grub_le_to_cpu16 (leaf
->entries
); i
++)
486 if (fileblock
< grub_le_to_cpu32 (ext
[i
].block
))
492 fileblock
-= grub_le_to_cpu32 (ext
[i
].block
);
493 if (fileblock
>= grub_le_to_cpu16 (ext
[i
].len
))
497 grub_disk_addr_t start
;
499 start
= grub_le_to_cpu16 (ext
[i
].start_hi
);
500 start
= (start
<< 32) + grub_le_to_cpu32 (ext
[i
].start
);
502 ret
= fileblock
+ start
;
507 grub_error (GRUB_ERR_BAD_FS
, "something wrong with extent");
511 if (leaf
!= (struct grub_ext4_extent_header
*) inode
->blocks
.dir_blocks
)
518 if (fileblock
< INDIRECT_BLOCKS
)
519 return grub_le_to_cpu32 (inode
->blocks
.dir_blocks
[fileblock
]);
520 fileblock
-= INDIRECT_BLOCKS
;
522 if (fileblock
< blksz_quarter
)
524 indir
= inode
->blocks
.indir_block
;
528 fileblock
-= blksz_quarter
;
529 /* Double indirect. */
530 if (fileblock
< blksz_quarter
* blksz_quarter
)
532 indir
= inode
->blocks
.double_indir_block
;
536 fileblock
-= blksz_quarter
* blksz_quarter
;
537 /* Triple indirect. */
538 if (fileblock
< blksz_quarter
* blksz_quarter
* (blksz_quarter
+ 1))
540 indir
= inode
->blocks
.triple_indir_block
;
544 grub_error (GRUB_ERR_BAD_FS
,
545 "ext2fs doesn't support quadruple indirect blocks");
550 /* If the indirect block is zero, all child blocks are absent
551 (i.e. filled with zeros.) */
554 if (grub_disk_read (data
->disk
,
555 ((grub_disk_addr_t
) grub_le_to_cpu32 (indir
))
557 ((fileblock
>> (log_perblock
* shift
))
558 & ((1 << log_perblock
) - 1))
560 sizeof (indir
), &indir
))
564 return grub_le_to_cpu32 (indir
);
567 /* Read LEN bytes from the file described by DATA starting with byte
568 POS. Return the amount of read bytes in READ. */
570 grub_ext2_read_file (grub_fshelp_node_t node
,
571 grub_disk_read_hook_t read_hook
, void *read_hook_data
,
572 grub_off_t pos
, grub_size_t len
, char *buf
)
574 return grub_fshelp_read_file (node
->data
->disk
, node
,
575 read_hook
, read_hook_data
,
576 pos
, len
, buf
, grub_ext2_read_block
,
577 grub_cpu_to_le32 (node
->inode
.size
)
578 | (((grub_off_t
) grub_cpu_to_le32 (node
->inode
.size_high
)) << 32),
579 LOG2_EXT2_BLOCK_SIZE (node
->data
), 0);
584 /* Read the inode INO for the file described by DATA into INODE. */
586 grub_ext2_read_inode (struct grub_ext2_data
*data
,
587 int ino
, struct grub_ext2_inode
*inode
)
589 struct grub_ext2_block_group blkgrp
;
590 struct grub_ext2_sblock
*sblock
= &data
->sblock
;
591 int inodes_per_block
;
594 grub_disk_addr_t base
;
596 /* It is easier to calculate if the first inode is 0. */
599 grub_ext2_blockgroup (data
,
600 ino
/ grub_le_to_cpu32 (sblock
->inodes_per_group
),
605 inodes_per_block
= EXT2_BLOCK_SIZE (data
) / EXT2_INODE_SIZE (data
);
606 blkno
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
608 blkoff
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
611 base
= grub_le_to_cpu32 (blkgrp
.inode_table_id
);
612 if (data
->log_group_desc_size
>= 6)
613 base
|= (((grub_disk_addr_t
) grub_le_to_cpu32 (blkgrp
.inode_table_id_hi
))
616 /* Read the inode. */
617 if (grub_disk_read (data
->disk
,
618 ((base
+ blkno
) << LOG2_EXT2_BLOCK_SIZE (data
)),
619 EXT2_INODE_SIZE (data
) * blkoff
,
620 sizeof (struct grub_ext2_inode
), inode
))
626 static struct grub_ext2_data
*
627 grub_ext2_mount (grub_disk_t disk
)
629 struct grub_ext2_data
*data
;
631 data
= grub_malloc (sizeof (struct grub_ext2_data
));
635 /* Read the superblock. */
636 grub_disk_read (disk
, 1 * 2, 0, sizeof (struct grub_ext2_sblock
),
641 /* Make sure this is an ext2 filesystem. */
642 if (data
->sblock
.magic
!= grub_cpu_to_le16_compile_time (EXT2_MAGIC
)
643 || grub_le_to_cpu32 (data
->sblock
.log2_block_size
) >= 16
644 || data
->sblock
.inodes_per_group
== 0
645 /* 20 already means 1GiB blocks. We don't want to deal with blocks overflowing int32. */
646 || grub_le_to_cpu32 (data
->sblock
.log2_block_size
) > 20
647 || EXT2_INODE_SIZE (data
) == 0
648 || EXT2_BLOCK_SIZE (data
) / EXT2_INODE_SIZE (data
) == 0)
650 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
654 /* Check the FS doesn't have feature bits enabled that we don't support. */
655 if (data
->sblock
.revision_level
!= grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION
)
656 && (data
->sblock
.feature_incompat
657 & grub_cpu_to_le32_compile_time (~(EXT2_DRIVER_SUPPORTED_INCOMPAT
658 | EXT2_DRIVER_IGNORED_INCOMPAT
))))
660 grub_error (GRUB_ERR_BAD_FS
, "filesystem has unsupported incompatible features");
664 if (data
->sblock
.revision_level
!= grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION
)
665 && (data
->sblock
.feature_incompat
666 & grub_cpu_to_le32_compile_time (EXT4_FEATURE_INCOMPAT_64BIT
))
667 && data
->sblock
.group_desc_size
!= 0
668 && ((data
->sblock
.group_desc_size
& (data
->sblock
.group_desc_size
- 1))
670 && (data
->sblock
.group_desc_size
& grub_cpu_to_le16_compile_time (0x1fe0)))
672 grub_uint16_t b
= grub_le_to_cpu16 (data
->sblock
.group_desc_size
);
673 for (data
->log_group_desc_size
= 0; b
!= (1 << data
->log_group_desc_size
);
674 data
->log_group_desc_size
++);
677 data
->log_group_desc_size
= 5;
681 data
->diropen
.data
= data
;
682 data
->diropen
.ino
= 2;
683 data
->diropen
.inode_read
= 1;
685 data
->inode
= &data
->diropen
.inode
;
687 grub_ext2_read_inode (data
, 2, data
->inode
);
694 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
695 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
702 grub_ext2_read_symlink (grub_fshelp_node_t node
)
705 struct grub_fshelp_node
*diro
= node
;
707 if (! diro
->inode_read
)
709 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
713 if (diro
->inode
.flags
& grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG
))
715 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "symlink is encrypted");
720 symlink
= grub_malloc (grub_le_to_cpu32 (diro
->inode
.size
) + 1);
724 /* If the filesize of the symlink is bigger than
725 60 the symlink is stored in a separate block,
726 otherwise it is stored in the inode. */
727 if (grub_le_to_cpu32 (diro
->inode
.size
) <= sizeof (diro
->inode
.symlink
))
728 grub_memcpy (symlink
,
730 grub_le_to_cpu32 (diro
->inode
.size
));
733 grub_ext2_read_file (diro
, 0, 0, 0,
734 grub_le_to_cpu32 (diro
->inode
.size
),
743 symlink
[grub_le_to_cpu32 (diro
->inode
.size
)] = '\0';
748 grub_ext2_iterate_dir (grub_fshelp_node_t dir
,
749 grub_fshelp_iterate_dir_hook_t hook
, void *hook_data
)
751 unsigned int fpos
= 0;
752 struct grub_fshelp_node
*diro
= (struct grub_fshelp_node
*) dir
;
754 if (! diro
->inode_read
)
756 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
761 if (diro
->inode
.flags
& grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG
))
763 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "directory is encrypted");
767 /* Search the file. */
768 while (fpos
< grub_le_to_cpu32 (diro
->inode
.size
))
770 struct ext2_dirent dirent
;
772 grub_ext2_read_file (diro
, 0, 0, fpos
, sizeof (struct ext2_dirent
),
777 if (dirent
.direntlen
== 0)
780 if (dirent
.inode
!= 0 && dirent
.namelen
!= 0)
782 char filename
[MAX_NAMELEN
+ 1];
783 struct grub_fshelp_node
*fdiro
;
784 enum grub_fshelp_filetype type
= GRUB_FSHELP_UNKNOWN
;
786 grub_ext2_read_file (diro
, 0, 0, fpos
+ sizeof (struct ext2_dirent
),
787 dirent
.namelen
, filename
);
791 fdiro
= grub_malloc (sizeof (struct grub_fshelp_node
));
795 fdiro
->data
= diro
->data
;
796 fdiro
->ino
= grub_le_to_cpu32 (dirent
.inode
);
798 filename
[dirent
.namelen
] = '\0';
800 if (dirent
.filetype
!= FILETYPE_UNKNOWN
)
802 fdiro
->inode_read
= 0;
804 if (dirent
.filetype
== FILETYPE_DIRECTORY
)
805 type
= GRUB_FSHELP_DIR
;
806 else if (dirent
.filetype
== FILETYPE_SYMLINK
)
807 type
= GRUB_FSHELP_SYMLINK
;
808 else if (dirent
.filetype
== FILETYPE_REG
)
809 type
= GRUB_FSHELP_REG
;
813 /* The filetype can not be read from the dirent, read
814 the inode to get more information. */
815 grub_ext2_read_inode (diro
->data
,
816 grub_le_to_cpu32 (dirent
.inode
),
824 fdiro
->inode_read
= 1;
826 if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
827 & FILETYPE_INO_MASK
) == FILETYPE_INO_DIRECTORY
)
828 type
= GRUB_FSHELP_DIR
;
829 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
830 & FILETYPE_INO_MASK
) == FILETYPE_INO_SYMLINK
)
831 type
= GRUB_FSHELP_SYMLINK
;
832 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
833 & FILETYPE_INO_MASK
) == FILETYPE_INO_REG
)
834 type
= GRUB_FSHELP_REG
;
837 if (hook (filename
, type
, fdiro
, hook_data
))
841 fpos
+= grub_le_to_cpu16 (dirent
.direntlen
);
847 /* Open a file named NAME and initialize FILE. */
849 grub_ext2_open (struct grub_file
*file
, const char *name
)
851 struct grub_ext2_data
*data
;
852 struct grub_fshelp_node
*fdiro
= 0;
855 grub_dl_ref (my_mod
);
857 data
= grub_ext2_mount (file
->device
->disk
);
864 err
= grub_fshelp_find_file (name
, &data
->diropen
, &fdiro
,
865 grub_ext2_iterate_dir
,
866 grub_ext2_read_symlink
, GRUB_FSHELP_REG
);
870 if (! fdiro
->inode_read
)
872 err
= grub_ext2_read_inode (data
, fdiro
->ino
, &fdiro
->inode
);
877 if (fdiro
->inode
.flags
& grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG
))
879 err
= grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "file is encrypted");
883 grub_memcpy (data
->inode
, &fdiro
->inode
, sizeof (struct grub_ext2_inode
));
886 file
->size
= grub_le_to_cpu32 (data
->inode
->size
);
887 file
->size
|= ((grub_off_t
) grub_le_to_cpu32 (data
->inode
->size_high
)) << 32;
894 if (fdiro
!= &data
->diropen
)
898 grub_dl_unref (my_mod
);
904 grub_ext2_close (grub_file_t file
)
906 grub_free (file
->data
);
908 grub_dl_unref (my_mod
);
910 return GRUB_ERR_NONE
;
913 /* Read LEN bytes data from FILE into BUF. */
915 grub_ext2_read (grub_file_t file
, char *buf
, grub_size_t len
)
917 struct grub_ext2_data
*data
= (struct grub_ext2_data
*) file
->data
;
919 return grub_ext2_read_file (&data
->diropen
,
920 file
->read_hook
, file
->read_hook_data
,
921 file
->offset
, len
, buf
);
925 /* Context for grub_ext2_dir. */
926 struct grub_ext2_dir_ctx
928 grub_fs_dir_hook_t hook
;
930 struct grub_ext2_data
*data
;
933 /* Helper for grub_ext2_dir. */
935 grub_ext2_dir_iter (const char *filename
, enum grub_fshelp_filetype filetype
,
936 grub_fshelp_node_t node
, void *data
)
938 struct grub_ext2_dir_ctx
*ctx
= data
;
939 struct grub_dirhook_info info
;
941 grub_memset (&info
, 0, sizeof (info
));
942 if (! node
->inode_read
)
944 grub_ext2_read_inode (ctx
->data
, node
->ino
, &node
->inode
);
946 node
->inode_read
= 1;
947 grub_errno
= GRUB_ERR_NONE
;
949 if (node
->inode_read
)
952 info
.mtime
= grub_le_to_cpu32 (node
->inode
.mtime
);
955 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
957 info
.size
= (((grub_off_t
) grub_le_to_cpu32 (node
->inode
.size_high
)) << 32) | grub_le_to_cpu32 (node
->inode
.size
);
959 return ctx
->hook (filename
, &info
, ctx
->hook_data
);
963 grub_ext2_dir (grub_device_t device
, const char *path
, grub_fs_dir_hook_t hook
,
966 struct grub_ext2_dir_ctx ctx
= {
968 .hook_data
= hook_data
970 struct grub_fshelp_node
*fdiro
= 0;
972 grub_dl_ref (my_mod
);
974 ctx
.data
= grub_ext2_mount (device
->disk
);
978 grub_fshelp_find_file (path
, &ctx
.data
->diropen
, &fdiro
,
979 grub_ext2_iterate_dir
, grub_ext2_read_symlink
,
984 grub_ext2_iterate_dir (fdiro
, grub_ext2_dir_iter
, &ctx
);
987 if (fdiro
!= &ctx
.data
->diropen
)
989 grub_free (ctx
.data
);
991 grub_dl_unref (my_mod
);
997 grub_ext2_label (grub_device_t device
, char **label
)
999 struct grub_ext2_data
*data
;
1000 grub_disk_t disk
= device
->disk
;
1002 grub_dl_ref (my_mod
);
1004 data
= grub_ext2_mount (disk
);
1006 *label
= grub_strndup (data
->sblock
.volume_name
,
1007 sizeof (data
->sblock
.volume_name
));
1011 grub_dl_unref (my_mod
);
1019 grub_ext2_uuid (grub_device_t device
, char **uuid
)
1021 struct grub_ext2_data
*data
;
1022 grub_disk_t disk
= device
->disk
;
1024 grub_dl_ref (my_mod
);
1026 data
= grub_ext2_mount (disk
);
1029 *uuid
= grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
1030 grub_be_to_cpu16 (data
->sblock
.uuid
[0]),
1031 grub_be_to_cpu16 (data
->sblock
.uuid
[1]),
1032 grub_be_to_cpu16 (data
->sblock
.uuid
[2]),
1033 grub_be_to_cpu16 (data
->sblock
.uuid
[3]),
1034 grub_be_to_cpu16 (data
->sblock
.uuid
[4]),
1035 grub_be_to_cpu16 (data
->sblock
.uuid
[5]),
1036 grub_be_to_cpu16 (data
->sblock
.uuid
[6]),
1037 grub_be_to_cpu16 (data
->sblock
.uuid
[7]));
1042 grub_dl_unref (my_mod
);
1051 grub_ext2_mtime (grub_device_t device
, grub_int32_t
*tm
)
1053 struct grub_ext2_data
*data
;
1054 grub_disk_t disk
= device
->disk
;
1056 grub_dl_ref (my_mod
);
1058 data
= grub_ext2_mount (disk
);
1062 *tm
= grub_le_to_cpu32 (data
->sblock
.utime
);
1064 grub_dl_unref (my_mod
);
1074 static struct grub_fs grub_ext2_fs
=
1077 .fs_dir
= grub_ext2_dir
,
1078 .fs_open
= grub_ext2_open
,
1079 .fs_read
= grub_ext2_read
,
1080 .fs_close
= grub_ext2_close
,
1081 .fs_label
= grub_ext2_label
,
1082 .fs_uuid
= grub_ext2_uuid
,
1083 .fs_mtime
= grub_ext2_mtime
,
1085 .reserved_first_sector
= 1,
1086 .blocklist_install
= 1,
1093 grub_fs_register (&grub_ext2_fs
);
1099 grub_fs_unregister (&grub_ext2_fs
);