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_FLEX_BG 0x0200
105 /* The set of back-incompatible features this driver DOES support. Add (OR)
106 * flags here as the related features are implemented into the driver. */
107 #define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
108 | EXT4_FEATURE_INCOMPAT_EXTENTS \
109 | EXT4_FEATURE_INCOMPAT_FLEX_BG \
110 | EXT4_FEATURE_INCOMPAT_64BIT)
111 /* List of rationales for the ignored "incompatible" features:
112 * needs_recovery: Not really back-incompatible - was added as such to forbid
113 * ext2 drivers from mounting an ext3 volume with a dirty
114 * journal because they will ignore the journal, but the next
115 * ext3 driver to mount the volume will find the journal and
116 * replay it, potentially corrupting the metadata written by
117 * the ext2 drivers. Safe to ignore for this RO driver. */
118 #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER )
121 #define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
123 #define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1
124 #define EXT3_JOURNAL_COMMIT_BLOCK 2
125 #define EXT3_JOURNAL_SUPERBLOCK_V1 3
126 #define EXT3_JOURNAL_SUPERBLOCK_V2 4
127 #define EXT3_JOURNAL_REVOKE_BLOCK 5
129 #define EXT3_JOURNAL_FLAG_ESCAPE 1
130 #define EXT3_JOURNAL_FLAG_SAME_UUID 2
131 #define EXT3_JOURNAL_FLAG_DELETED 4
132 #define EXT3_JOURNAL_FLAG_LAST_TAG 8
134 #define EXT4_EXTENTS_FLAG 0x80000
136 /* The ext2 superblock. */
137 struct grub_ext2_sblock
139 grub_uint32_t total_inodes
;
140 grub_uint32_t total_blocks
;
141 grub_uint32_t reserved_blocks
;
142 grub_uint32_t free_blocks
;
143 grub_uint32_t free_inodes
;
144 grub_uint32_t first_data_block
;
145 grub_uint32_t log2_block_size
;
146 grub_uint32_t log2_fragment_size
;
147 grub_uint32_t blocks_per_group
;
148 grub_uint32_t fragments_per_group
;
149 grub_uint32_t inodes_per_group
;
152 grub_uint16_t mnt_count
;
153 grub_uint16_t max_mnt_count
;
155 grub_uint16_t fs_state
;
156 grub_uint16_t error_handling
;
157 grub_uint16_t minor_revision_level
;
158 grub_uint32_t lastcheck
;
159 grub_uint32_t checkinterval
;
160 grub_uint32_t creator_os
;
161 grub_uint32_t revision_level
;
162 grub_uint16_t uid_reserved
;
163 grub_uint16_t gid_reserved
;
164 grub_uint32_t first_inode
;
165 grub_uint16_t inode_size
;
166 grub_uint16_t block_group_number
;
167 grub_uint32_t feature_compatibility
;
168 grub_uint32_t feature_incompat
;
169 grub_uint32_t feature_ro_compat
;
170 grub_uint16_t uuid
[8];
171 char volume_name
[16];
172 char last_mounted_on
[64];
173 grub_uint32_t compression_info
;
174 grub_uint8_t prealloc_blocks
;
175 grub_uint8_t prealloc_dir_blocks
;
176 grub_uint16_t reserved_gdt_blocks
;
177 grub_uint8_t journal_uuid
[16];
178 grub_uint32_t journal_inum
;
179 grub_uint32_t journal_dev
;
180 grub_uint32_t last_orphan
;
181 grub_uint32_t hash_seed
[4];
182 grub_uint8_t def_hash_version
;
183 grub_uint8_t jnl_backup_type
;
184 grub_uint16_t group_desc_size
;
185 grub_uint32_t default_mount_opts
;
186 grub_uint32_t first_meta_bg
;
187 grub_uint32_t mkfs_time
;
188 grub_uint32_t jnl_blocks
[17];
191 /* The ext2 blockgroup. */
192 struct grub_ext2_block_group
194 grub_uint32_t block_id
;
195 grub_uint32_t inode_id
;
196 grub_uint32_t inode_table_id
;
197 grub_uint16_t free_blocks
;
198 grub_uint16_t free_inodes
;
199 grub_uint16_t used_dirs
;
201 grub_uint32_t reserved
[3];
202 grub_uint32_t block_id_hi
;
203 grub_uint32_t inode_id_hi
;
204 grub_uint32_t inode_table_id_hi
;
205 grub_uint16_t free_blocks_hi
;
206 grub_uint16_t free_inodes_hi
;
207 grub_uint16_t used_dirs_hi
;
209 grub_uint32_t reserved2
[3];
212 /* The ext2 inode. */
213 struct grub_ext2_inode
223 grub_uint16_t nlinks
;
224 grub_uint32_t blockcnt
; /* Blocks of 512 bytes!! */
231 grub_uint32_t dir_blocks
[INDIRECT_BLOCKS
];
232 grub_uint32_t indir_block
;
233 grub_uint32_t double_indir_block
;
234 grub_uint32_t triple_indir_block
;
238 grub_uint32_t version
;
240 grub_uint32_t size_high
;
241 grub_uint32_t fragment_addr
;
242 grub_uint32_t osd2
[3];
245 /* The header of an ext2 directory entry. */
249 grub_uint16_t direntlen
;
250 #define MAX_NAMELEN 255
251 grub_uint8_t namelen
;
252 grub_uint8_t filetype
;
255 struct grub_ext3_journal_header
258 grub_uint32_t block_type
;
259 grub_uint32_t sequence
;
262 struct grub_ext3_journal_revoke_header
264 struct grub_ext3_journal_header header
;
266 grub_uint32_t data
[0];
269 struct grub_ext3_journal_block_tag
275 struct grub_ext3_journal_sblock
277 struct grub_ext3_journal_header header
;
278 grub_uint32_t block_size
;
279 grub_uint32_t maxlen
;
281 grub_uint32_t sequence
;
285 #define EXT4_EXT_MAGIC 0xf30a
287 struct grub_ext4_extent_header
290 grub_uint16_t entries
;
293 grub_uint32_t generation
;
296 struct grub_ext4_extent
300 grub_uint16_t start_hi
;
304 struct grub_ext4_extent_idx
308 grub_uint16_t leaf_hi
;
309 grub_uint16_t unused
;
312 struct grub_fshelp_node
314 struct grub_ext2_data
*data
;
315 struct grub_ext2_inode inode
;
320 /* Information about a "mounted" ext2 filesystem. */
321 struct grub_ext2_data
323 struct grub_ext2_sblock sblock
;
324 int log_group_desc_size
;
326 struct grub_ext2_inode
*inode
;
327 struct grub_fshelp_node diropen
;
330 static grub_dl_t my_mod
;
334 /* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
335 the mounted filesystem DATA. */
336 inline static grub_err_t
337 grub_ext2_blockgroup (struct grub_ext2_data
*data
, int group
,
338 struct grub_ext2_block_group
*blkgrp
)
340 return grub_disk_read (data
->disk
,
341 ((grub_le_to_cpu32 (data
->sblock
.first_data_block
) + 1)
342 << LOG2_EXT2_BLOCK_SIZE (data
)),
343 group
<< data
->log_group_desc_size
,
344 sizeof (struct grub_ext2_block_group
), blkgrp
);
347 static struct grub_ext4_extent_header
*
348 grub_ext4_find_leaf (struct grub_ext2_data
*data
,
349 struct grub_ext4_extent_header
*ext_block
,
350 grub_uint32_t fileblock
)
352 struct grub_ext4_extent_idx
*index
;
358 grub_disk_addr_t block
;
360 index
= (struct grub_ext4_extent_idx
*) (ext_block
+ 1);
362 if (ext_block
->magic
!= grub_cpu_to_le16_compile_time (EXT4_EXT_MAGIC
))
365 if (ext_block
->depth
== 0)
368 for (i
= 0; i
< grub_le_to_cpu16 (ext_block
->entries
); i
++)
370 if (fileblock
< grub_le_to_cpu32(index
[i
].block
))
377 block
= grub_le_to_cpu16 (index
[i
].leaf_hi
);
378 block
= (block
<< 32) | grub_le_to_cpu32 (index
[i
].leaf
);
380 buf
= grub_malloc (EXT2_BLOCK_SIZE(data
));
383 if (grub_disk_read (data
->disk
,
384 block
<< LOG2_EXT2_BLOCK_SIZE (data
),
385 0, EXT2_BLOCK_SIZE(data
), buf
))
395 static grub_disk_addr_t
396 grub_ext2_read_block (grub_fshelp_node_t node
, grub_disk_addr_t fileblock
)
398 struct grub_ext2_data
*data
= node
->data
;
399 struct grub_ext2_inode
*inode
= &node
->inode
;
400 unsigned int blksz
= EXT2_BLOCK_SIZE (data
);
401 grub_disk_addr_t blksz_quarter
= blksz
/ 4;
402 int log2_blksz
= LOG2_EXT2_BLOCK_SIZE (data
);
403 int log_perblock
= log2_blksz
+ 9 - 2;
407 if (inode
->flags
& grub_cpu_to_le32_compile_time (EXT4_EXTENTS_FLAG
))
409 struct grub_ext4_extent_header
*leaf
;
410 struct grub_ext4_extent
*ext
;
412 grub_disk_addr_t ret
;
414 leaf
= grub_ext4_find_leaf (data
, (struct grub_ext4_extent_header
*) inode
->blocks
.dir_blocks
, fileblock
);
417 grub_error (GRUB_ERR_BAD_FS
, "invalid extent");
421 ext
= (struct grub_ext4_extent
*) (leaf
+ 1);
422 for (i
= 0; i
< grub_le_to_cpu16 (leaf
->entries
); i
++)
424 if (fileblock
< grub_le_to_cpu32 (ext
[i
].block
))
430 fileblock
-= grub_le_to_cpu32 (ext
[i
].block
);
431 if (fileblock
>= grub_le_to_cpu16 (ext
[i
].len
))
435 grub_disk_addr_t start
;
437 start
= grub_le_to_cpu16 (ext
[i
].start_hi
);
438 start
= (start
<< 32) + grub_le_to_cpu32 (ext
[i
].start
);
440 ret
= fileblock
+ start
;
445 grub_error (GRUB_ERR_BAD_FS
, "something wrong with extent");
449 if (leaf
!= (struct grub_ext4_extent_header
*) inode
->blocks
.dir_blocks
)
456 if (fileblock
< INDIRECT_BLOCKS
)
457 return grub_le_to_cpu32 (inode
->blocks
.dir_blocks
[fileblock
]);
458 fileblock
-= INDIRECT_BLOCKS
;
460 if (fileblock
< blksz_quarter
)
462 indir
= inode
->blocks
.indir_block
;
466 fileblock
-= blksz_quarter
;
467 /* Double indirect. */
468 if (fileblock
< blksz_quarter
* blksz_quarter
)
470 indir
= inode
->blocks
.double_indir_block
;
474 fileblock
-= blksz_quarter
* blksz_quarter
;
475 /* Triple indirect. */
476 if (fileblock
< blksz_quarter
* blksz_quarter
* (blksz_quarter
+ 1))
478 indir
= inode
->blocks
.triple_indir_block
;
482 return grub_error (GRUB_ERR_BAD_FS
,
483 "ext2fs doesn't support quadruple indirect blocks");
487 /* If the indirect block is zero, all child blocks are absent
488 (i.e. filled with zeros.) */
491 if (grub_disk_read (data
->disk
,
492 ((grub_disk_addr_t
) grub_le_to_cpu32 (indir
))
494 ((fileblock
>> (log_perblock
* shift
))
495 & ((1 << log_perblock
) - 1))
497 sizeof (indir
), &indir
))
501 return grub_le_to_cpu32 (indir
);
504 /* Read LEN bytes from the file described by DATA starting with byte
505 POS. Return the amount of read bytes in READ. */
507 grub_ext2_read_file (grub_fshelp_node_t node
,
508 grub_disk_read_hook_t read_hook
, void *read_hook_data
,
509 grub_off_t pos
, grub_size_t len
, char *buf
)
511 return grub_fshelp_read_file (node
->data
->disk
, node
,
512 read_hook
, read_hook_data
,
513 pos
, len
, buf
, grub_ext2_read_block
,
514 grub_cpu_to_le32 (node
->inode
.size
)
515 | (((grub_off_t
) grub_cpu_to_le32 (node
->inode
.size_high
)) << 32),
516 LOG2_EXT2_BLOCK_SIZE (node
->data
), 0);
521 /* Read the inode INO for the file described by DATA into INODE. */
523 grub_ext2_read_inode (struct grub_ext2_data
*data
,
524 int ino
, struct grub_ext2_inode
*inode
)
526 struct grub_ext2_block_group blkgrp
;
527 struct grub_ext2_sblock
*sblock
= &data
->sblock
;
528 int inodes_per_block
;
531 grub_disk_addr_t base
;
533 /* It is easier to calculate if the first inode is 0. */
536 grub_ext2_blockgroup (data
,
537 ino
/ grub_le_to_cpu32 (sblock
->inodes_per_group
),
542 inodes_per_block
= EXT2_BLOCK_SIZE (data
) / EXT2_INODE_SIZE (data
);
543 blkno
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
545 blkoff
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
548 base
= grub_le_to_cpu32 (blkgrp
.inode_table_id
);
549 if (data
->log_group_desc_size
>= 6)
550 base
|= (((grub_disk_addr_t
) grub_le_to_cpu32 (blkgrp
.inode_table_id_hi
))
553 /* Read the inode. */
554 if (grub_disk_read (data
->disk
,
555 ((base
+ blkno
) << LOG2_EXT2_BLOCK_SIZE (data
)),
556 EXT2_INODE_SIZE (data
) * blkoff
,
557 sizeof (struct grub_ext2_inode
), inode
))
563 static struct grub_ext2_data
*
564 grub_ext2_mount (grub_disk_t disk
)
566 struct grub_ext2_data
*data
;
568 data
= grub_malloc (sizeof (struct grub_ext2_data
));
572 /* Read the superblock. */
573 grub_disk_read (disk
, 1 * 2, 0, sizeof (struct grub_ext2_sblock
),
578 /* Make sure this is an ext2 filesystem. */
579 if (data
->sblock
.magic
!= grub_cpu_to_le16_compile_time (EXT2_MAGIC
)
580 || grub_le_to_cpu32 (data
->sblock
.log2_block_size
) >= 16
581 || data
->sblock
.inodes_per_group
== 0
582 /* 20 already means 1GiB blocks. We don't want to deal with blocks overflowing int32. */
583 || grub_le_to_cpu32 (data
->sblock
.log2_block_size
) > 20
584 || EXT2_INODE_SIZE (data
) == 0
585 || EXT2_BLOCK_SIZE (data
) / EXT2_INODE_SIZE (data
) == 0)
587 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
591 /* Check the FS doesn't have feature bits enabled that we don't support. */
592 if (data
->sblock
.revision_level
!= grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION
)
593 && (data
->sblock
.feature_incompat
594 & grub_cpu_to_le32_compile_time (~(EXT2_DRIVER_SUPPORTED_INCOMPAT
595 | EXT2_DRIVER_IGNORED_INCOMPAT
))))
597 grub_error (GRUB_ERR_BAD_FS
, "filesystem has unsupported incompatible features");
601 if (data
->sblock
.revision_level
!= grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION
)
602 && (data
->sblock
.feature_incompat
603 & grub_cpu_to_le32_compile_time (EXT4_FEATURE_INCOMPAT_64BIT
))
604 && data
->sblock
.group_desc_size
!= 0
605 && ((data
->sblock
.group_desc_size
& (data
->sblock
.group_desc_size
- 1))
607 && (data
->sblock
.group_desc_size
& grub_cpu_to_le16_compile_time (0x1fe0)))
609 grub_uint16_t b
= grub_le_to_cpu16 (data
->sblock
.group_desc_size
);
610 for (data
->log_group_desc_size
= 0; b
!= (1 << data
->log_group_desc_size
);
611 data
->log_group_desc_size
++);
614 data
->log_group_desc_size
= 5;
618 data
->diropen
.data
= data
;
619 data
->diropen
.ino
= 2;
620 data
->diropen
.inode_read
= 1;
622 data
->inode
= &data
->diropen
.inode
;
624 grub_ext2_read_inode (data
, 2, data
->inode
);
631 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
632 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
639 grub_ext2_read_symlink (grub_fshelp_node_t node
)
642 struct grub_fshelp_node
*diro
= node
;
644 if (! diro
->inode_read
)
646 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
651 symlink
= grub_malloc (grub_le_to_cpu32 (diro
->inode
.size
) + 1);
655 /* If the filesize of the symlink is bigger than
656 60 the symlink is stored in a separate block,
657 otherwise it is stored in the inode. */
658 if (grub_le_to_cpu32 (diro
->inode
.size
) <= sizeof (diro
->inode
.symlink
))
659 grub_memcpy (symlink
,
661 grub_le_to_cpu32 (diro
->inode
.size
));
664 grub_ext2_read_file (diro
, 0, 0, 0,
665 grub_le_to_cpu32 (diro
->inode
.size
),
674 symlink
[grub_le_to_cpu32 (diro
->inode
.size
)] = '\0';
679 grub_ext2_iterate_dir (grub_fshelp_node_t dir
,
680 grub_fshelp_iterate_dir_hook_t hook
, void *hook_data
)
682 unsigned int fpos
= 0;
683 struct grub_fshelp_node
*diro
= (struct grub_fshelp_node
*) dir
;
685 if (! diro
->inode_read
)
687 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
692 /* Search the file. */
693 while (fpos
< grub_le_to_cpu32 (diro
->inode
.size
))
695 struct ext2_dirent dirent
;
697 grub_ext2_read_file (diro
, 0, 0, fpos
, sizeof (struct ext2_dirent
),
702 if (dirent
.direntlen
== 0)
705 if (dirent
.inode
!= 0 && dirent
.namelen
!= 0)
707 char filename
[MAX_NAMELEN
+ 1];
708 struct grub_fshelp_node
*fdiro
;
709 enum grub_fshelp_filetype type
= GRUB_FSHELP_UNKNOWN
;
711 grub_ext2_read_file (diro
, 0, 0, fpos
+ sizeof (struct ext2_dirent
),
712 dirent
.namelen
, filename
);
716 fdiro
= grub_malloc (sizeof (struct grub_fshelp_node
));
720 fdiro
->data
= diro
->data
;
721 fdiro
->ino
= grub_le_to_cpu32 (dirent
.inode
);
723 filename
[dirent
.namelen
] = '\0';
725 if (dirent
.filetype
!= FILETYPE_UNKNOWN
)
727 fdiro
->inode_read
= 0;
729 if (dirent
.filetype
== FILETYPE_DIRECTORY
)
730 type
= GRUB_FSHELP_DIR
;
731 else if (dirent
.filetype
== FILETYPE_SYMLINK
)
732 type
= GRUB_FSHELP_SYMLINK
;
733 else if (dirent
.filetype
== FILETYPE_REG
)
734 type
= GRUB_FSHELP_REG
;
738 /* The filetype can not be read from the dirent, read
739 the inode to get more information. */
740 grub_ext2_read_inode (diro
->data
,
741 grub_le_to_cpu32 (dirent
.inode
),
749 fdiro
->inode_read
= 1;
751 if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
752 & FILETYPE_INO_MASK
) == FILETYPE_INO_DIRECTORY
)
753 type
= GRUB_FSHELP_DIR
;
754 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
755 & FILETYPE_INO_MASK
) == FILETYPE_INO_SYMLINK
)
756 type
= GRUB_FSHELP_SYMLINK
;
757 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
758 & FILETYPE_INO_MASK
) == FILETYPE_INO_REG
)
759 type
= GRUB_FSHELP_REG
;
762 if (hook (filename
, type
, fdiro
, hook_data
))
766 fpos
+= grub_le_to_cpu16 (dirent
.direntlen
);
772 /* Open a file named NAME and initialize FILE. */
774 grub_ext2_open (struct grub_file
*file
, const char *name
)
776 struct grub_ext2_data
*data
;
777 struct grub_fshelp_node
*fdiro
= 0;
780 grub_dl_ref (my_mod
);
782 data
= grub_ext2_mount (file
->device
->disk
);
789 err
= grub_fshelp_find_file (name
, &data
->diropen
, &fdiro
,
790 grub_ext2_iterate_dir
,
791 grub_ext2_read_symlink
, GRUB_FSHELP_REG
);
795 if (! fdiro
->inode_read
)
797 err
= grub_ext2_read_inode (data
, fdiro
->ino
, &fdiro
->inode
);
802 grub_memcpy (data
->inode
, &fdiro
->inode
, sizeof (struct grub_ext2_inode
));
805 file
->size
= grub_le_to_cpu32 (data
->inode
->size
);
806 file
->size
|= ((grub_off_t
) grub_le_to_cpu32 (data
->inode
->size_high
)) << 32;
813 if (fdiro
!= &data
->diropen
)
817 grub_dl_unref (my_mod
);
823 grub_ext2_close (grub_file_t file
)
825 grub_free (file
->data
);
827 grub_dl_unref (my_mod
);
829 return GRUB_ERR_NONE
;
832 /* Read LEN bytes data from FILE into BUF. */
834 grub_ext2_read (grub_file_t file
, char *buf
, grub_size_t len
)
836 struct grub_ext2_data
*data
= (struct grub_ext2_data
*) file
->data
;
838 return grub_ext2_read_file (&data
->diropen
,
839 file
->read_hook
, file
->read_hook_data
,
840 file
->offset
, len
, buf
);
844 /* Context for grub_ext2_dir. */
845 struct grub_ext2_dir_ctx
847 grub_fs_dir_hook_t hook
;
849 struct grub_ext2_data
*data
;
852 /* Helper for grub_ext2_dir. */
854 grub_ext2_dir_iter (const char *filename
, enum grub_fshelp_filetype filetype
,
855 grub_fshelp_node_t node
, void *data
)
857 struct grub_ext2_dir_ctx
*ctx
= data
;
858 struct grub_dirhook_info info
;
860 grub_memset (&info
, 0, sizeof (info
));
861 if (! node
->inode_read
)
863 grub_ext2_read_inode (ctx
->data
, node
->ino
, &node
->inode
);
865 node
->inode_read
= 1;
866 grub_errno
= GRUB_ERR_NONE
;
868 if (node
->inode_read
)
871 info
.mtime
= grub_le_to_cpu32 (node
->inode
.mtime
);
874 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
876 return ctx
->hook (filename
, &info
, ctx
->hook_data
);
880 grub_ext2_dir (grub_device_t device
, const char *path
, grub_fs_dir_hook_t hook
,
883 struct grub_ext2_dir_ctx ctx
= {
885 .hook_data
= hook_data
887 struct grub_fshelp_node
*fdiro
= 0;
889 grub_dl_ref (my_mod
);
891 ctx
.data
= grub_ext2_mount (device
->disk
);
895 grub_fshelp_find_file (path
, &ctx
.data
->diropen
, &fdiro
,
896 grub_ext2_iterate_dir
, grub_ext2_read_symlink
,
901 grub_ext2_iterate_dir (fdiro
, grub_ext2_dir_iter
, &ctx
);
904 if (fdiro
!= &ctx
.data
->diropen
)
906 grub_free (ctx
.data
);
908 grub_dl_unref (my_mod
);
914 grub_ext2_label (grub_device_t device
, char **label
)
916 struct grub_ext2_data
*data
;
917 grub_disk_t disk
= device
->disk
;
919 grub_dl_ref (my_mod
);
921 data
= grub_ext2_mount (disk
);
923 *label
= grub_strndup (data
->sblock
.volume_name
,
924 sizeof (data
->sblock
.volume_name
));
928 grub_dl_unref (my_mod
);
936 grub_ext2_uuid (grub_device_t device
, char **uuid
)
938 struct grub_ext2_data
*data
;
939 grub_disk_t disk
= device
->disk
;
941 grub_dl_ref (my_mod
);
943 data
= grub_ext2_mount (disk
);
946 *uuid
= grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
947 grub_be_to_cpu16 (data
->sblock
.uuid
[0]),
948 grub_be_to_cpu16 (data
->sblock
.uuid
[1]),
949 grub_be_to_cpu16 (data
->sblock
.uuid
[2]),
950 grub_be_to_cpu16 (data
->sblock
.uuid
[3]),
951 grub_be_to_cpu16 (data
->sblock
.uuid
[4]),
952 grub_be_to_cpu16 (data
->sblock
.uuid
[5]),
953 grub_be_to_cpu16 (data
->sblock
.uuid
[6]),
954 grub_be_to_cpu16 (data
->sblock
.uuid
[7]));
959 grub_dl_unref (my_mod
);
968 grub_ext2_mtime (grub_device_t device
, grub_int32_t
*tm
)
970 struct grub_ext2_data
*data
;
971 grub_disk_t disk
= device
->disk
;
973 grub_dl_ref (my_mod
);
975 data
= grub_ext2_mount (disk
);
979 *tm
= grub_le_to_cpu32 (data
->sblock
.utime
);
981 grub_dl_unref (my_mod
);
991 static struct grub_fs grub_ext2_fs
=
994 .dir
= grub_ext2_dir
,
995 .open
= grub_ext2_open
,
996 .read
= grub_ext2_read
,
997 .close
= grub_ext2_close
,
998 .label
= grub_ext2_label
,
999 .uuid
= grub_ext2_uuid
,
1000 .mtime
= grub_ext2_mtime
,
1002 .reserved_first_sector
= 1,
1003 .blocklist_install
= 1,
1010 grub_fs_register (&grub_ext2_fs
);
1016 grub_fs_unregister (&grub_ext2_fs
);