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) (1 << 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 (EXT2_REVISION (data) == EXT2_GOOD_OLD_REVISION \
69 ? EXT2_GOOD_OLD_INODE_SIZE \
70 : grub_le_to_cpu16 (data->sblock.inode_size))
72 /* Superblock filesystem feature flags (RW compatible)
73 * A filesystem with any of these enabled can be read and written by a driver
74 * that does not understand them without causing metadata/data corruption. */
75 #define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
76 #define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
77 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
78 #define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
79 #define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
80 #define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
81 /* Superblock filesystem feature flags (RO compatible)
82 * A filesystem with any of these enabled can be safely read by a driver that
83 * does not understand them, but should not be written to, usually because
84 * additional metadata is required. */
85 #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
86 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
87 #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
88 #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
89 #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
90 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
91 /* Superblock filesystem feature flags (back-incompatible)
92 * A filesystem with any of these enabled should not be attempted to be read
93 * by a driver that does not understand them, since they usually indicate
94 * metadata format changes that might confuse the reader. */
95 #define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
96 #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
97 #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
98 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Volume is journal device */
99 #define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
100 #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* Extents used */
101 #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
102 #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
104 /* The set of back-incompatible features this driver DOES support. Add (OR)
105 * flags here as the related features are implemented into the driver. */
106 #define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
107 | EXT4_FEATURE_INCOMPAT_EXTENTS \
108 | EXT4_FEATURE_INCOMPAT_FLEX_BG )
109 /* List of rationales for the ignored "incompatible" features:
110 * needs_recovery: Not really back-incompatible - was added as such to forbid
111 * ext2 drivers from mounting an ext3 volume with a dirty
112 * journal because they will ignore the journal, but the next
113 * ext3 driver to mount the volume will find the journal and
114 * replay it, potentially corrupting the metadata written by
115 * the ext2 drivers. Safe to ignore for this RO driver. */
116 #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER )
119 #define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
121 #define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1
122 #define EXT3_JOURNAL_COMMIT_BLOCK 2
123 #define EXT3_JOURNAL_SUPERBLOCK_V1 3
124 #define EXT3_JOURNAL_SUPERBLOCK_V2 4
125 #define EXT3_JOURNAL_REVOKE_BLOCK 5
127 #define EXT3_JOURNAL_FLAG_ESCAPE 1
128 #define EXT3_JOURNAL_FLAG_SAME_UUID 2
129 #define EXT3_JOURNAL_FLAG_DELETED 4
130 #define EXT3_JOURNAL_FLAG_LAST_TAG 8
132 #define EXT4_EXTENTS_FLAG 0x80000
134 /* The ext2 superblock. */
135 struct grub_ext2_sblock
137 grub_uint32_t total_inodes
;
138 grub_uint32_t total_blocks
;
139 grub_uint32_t reserved_blocks
;
140 grub_uint32_t free_blocks
;
141 grub_uint32_t free_inodes
;
142 grub_uint32_t first_data_block
;
143 grub_uint32_t log2_block_size
;
144 grub_uint32_t log2_fragment_size
;
145 grub_uint32_t blocks_per_group
;
146 grub_uint32_t fragments_per_group
;
147 grub_uint32_t inodes_per_group
;
150 grub_uint16_t mnt_count
;
151 grub_uint16_t max_mnt_count
;
153 grub_uint16_t fs_state
;
154 grub_uint16_t error_handling
;
155 grub_uint16_t minor_revision_level
;
156 grub_uint32_t lastcheck
;
157 grub_uint32_t checkinterval
;
158 grub_uint32_t creator_os
;
159 grub_uint32_t revision_level
;
160 grub_uint16_t uid_reserved
;
161 grub_uint16_t gid_reserved
;
162 grub_uint32_t first_inode
;
163 grub_uint16_t inode_size
;
164 grub_uint16_t block_group_number
;
165 grub_uint32_t feature_compatibility
;
166 grub_uint32_t feature_incompat
;
167 grub_uint32_t feature_ro_compat
;
168 grub_uint16_t uuid
[8];
169 char volume_name
[16];
170 char last_mounted_on
[64];
171 grub_uint32_t compression_info
;
172 grub_uint8_t prealloc_blocks
;
173 grub_uint8_t prealloc_dir_blocks
;
174 grub_uint16_t reserved_gdt_blocks
;
175 grub_uint8_t journal_uuid
[16];
176 grub_uint32_t journal_inum
;
177 grub_uint32_t journal_dev
;
178 grub_uint32_t last_orphan
;
179 grub_uint32_t hash_seed
[4];
180 grub_uint8_t def_hash_version
;
181 grub_uint8_t jnl_backup_type
;
182 grub_uint16_t reserved_word_pad
;
183 grub_uint32_t default_mount_opts
;
184 grub_uint32_t first_meta_bg
;
185 grub_uint32_t mkfs_time
;
186 grub_uint32_t jnl_blocks
[17];
189 /* The ext2 blockgroup. */
190 struct grub_ext2_block_group
192 grub_uint32_t block_id
;
193 grub_uint32_t inode_id
;
194 grub_uint32_t inode_table_id
;
195 grub_uint16_t free_blocks
;
196 grub_uint16_t free_inodes
;
197 grub_uint16_t used_dirs
;
199 grub_uint32_t reserved
[3];
202 /* The ext2 inode. */
203 struct grub_ext2_inode
213 grub_uint16_t nlinks
;
214 grub_uint32_t blockcnt
; /* Blocks of 512 bytes!! */
221 grub_uint32_t dir_blocks
[INDIRECT_BLOCKS
];
222 grub_uint32_t indir_block
;
223 grub_uint32_t double_indir_block
;
224 grub_uint32_t triple_indir_block
;
228 grub_uint32_t version
;
230 grub_uint32_t size_high
;
231 grub_uint32_t fragment_addr
;
232 grub_uint32_t osd2
[3];
235 /* The header of an ext2 directory entry. */
239 grub_uint16_t direntlen
;
240 grub_uint8_t namelen
;
241 grub_uint8_t filetype
;
244 struct grub_ext3_journal_header
247 grub_uint32_t block_type
;
248 grub_uint32_t sequence
;
251 struct grub_ext3_journal_revoke_header
253 struct grub_ext3_journal_header header
;
255 grub_uint32_t data
[0];
258 struct grub_ext3_journal_block_tag
264 struct grub_ext3_journal_sblock
266 struct grub_ext3_journal_header header
;
267 grub_uint32_t block_size
;
268 grub_uint32_t maxlen
;
270 grub_uint32_t sequence
;
274 #define EXT4_EXT_MAGIC 0xf30a
276 struct grub_ext4_extent_header
279 grub_uint16_t entries
;
282 grub_uint32_t generation
;
285 struct grub_ext4_extent
289 grub_uint16_t start_hi
;
293 struct grub_ext4_extent_idx
297 grub_uint16_t leaf_hi
;
298 grub_uint16_t unused
;
301 struct grub_fshelp_node
303 struct grub_ext2_data
*data
;
304 struct grub_ext2_inode inode
;
309 /* Information about a "mounted" ext2 filesystem. */
310 struct grub_ext2_data
312 struct grub_ext2_sblock sblock
;
314 struct grub_ext2_inode
*inode
;
315 struct grub_fshelp_node diropen
;
318 static grub_dl_t my_mod
;
322 /* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
323 the mounted filesystem DATA. */
324 inline static grub_err_t
325 grub_ext2_blockgroup (struct grub_ext2_data
*data
, int group
,
326 struct grub_ext2_block_group
*blkgrp
)
328 return grub_disk_read (data
->disk
,
329 ((grub_le_to_cpu32 (data
->sblock
.first_data_block
) + 1)
330 << LOG2_EXT2_BLOCK_SIZE (data
)),
331 group
* sizeof (struct grub_ext2_block_group
),
332 sizeof (struct grub_ext2_block_group
), blkgrp
);
335 static struct grub_ext4_extent_header
*
336 grub_ext4_find_leaf (struct grub_ext2_data
*data
, grub_properly_aligned_t
*buf
,
337 struct grub_ext4_extent_header
*ext_block
,
338 grub_uint32_t fileblock
)
340 struct grub_ext4_extent_idx
*index
;
345 grub_disk_addr_t block
;
347 index
= (struct grub_ext4_extent_idx
*) (ext_block
+ 1);
349 if (grub_le_to_cpu16(ext_block
->magic
) != EXT4_EXT_MAGIC
)
352 if (ext_block
->depth
== 0)
355 for (i
= 0; i
< grub_le_to_cpu16 (ext_block
->entries
); i
++)
357 if (fileblock
< grub_le_to_cpu32(index
[i
].block
))
364 block
= grub_le_to_cpu16 (index
[i
].leaf_hi
);
365 block
= (block
<< 32) + grub_le_to_cpu32 (index
[i
].leaf
);
366 if (grub_disk_read (data
->disk
,
367 block
<< LOG2_EXT2_BLOCK_SIZE (data
),
368 0, EXT2_BLOCK_SIZE(data
), buf
))
371 ext_block
= (struct grub_ext4_extent_header
*) buf
;
375 static grub_disk_addr_t
376 grub_ext2_read_block (grub_fshelp_node_t node
, grub_disk_addr_t fileblock
)
378 struct grub_ext2_data
*data
= node
->data
;
379 struct grub_ext2_inode
*inode
= &node
->inode
;
381 unsigned int blksz
= EXT2_BLOCK_SIZE (data
);
382 int log2_blksz
= LOG2_EXT2_BLOCK_SIZE (data
);
384 if (grub_le_to_cpu32(inode
->flags
) & EXT4_EXTENTS_FLAG
)
386 GRUB_PROPERLY_ALIGNED_ARRAY (buf
, EXT2_BLOCK_SIZE(data
));
387 struct grub_ext4_extent_header
*leaf
;
388 struct grub_ext4_extent
*ext
;
391 leaf
= grub_ext4_find_leaf (data
, buf
,
392 (struct grub_ext4_extent_header
*) inode
->blocks
.dir_blocks
,
396 grub_error (GRUB_ERR_BAD_FS
, "invalid extent");
400 ext
= (struct grub_ext4_extent
*) (leaf
+ 1);
401 for (i
= 0; i
< grub_le_to_cpu16 (leaf
->entries
); i
++)
403 if (fileblock
< grub_le_to_cpu32 (ext
[i
].block
))
409 fileblock
-= grub_le_to_cpu32 (ext
[i
].block
);
410 if (fileblock
>= grub_le_to_cpu16 (ext
[i
].len
))
414 grub_disk_addr_t start
;
416 start
= grub_le_to_cpu16 (ext
[i
].start_hi
);
417 start
= (start
<< 32) + grub_le_to_cpu32 (ext
[i
].start
);
419 return fileblock
+ start
;
424 grub_error (GRUB_ERR_BAD_FS
, "something wrong with extent");
429 if (fileblock
< INDIRECT_BLOCKS
)
430 blknr
= grub_le_to_cpu32 (inode
->blocks
.dir_blocks
[fileblock
]);
432 else if (fileblock
< INDIRECT_BLOCKS
+ blksz
/ 4)
434 grub_uint32_t indir
[blksz
/ 4];
436 if (grub_disk_read (data
->disk
,
438 grub_le_to_cpu32 (inode
->blocks
.indir_block
))
443 blknr
= grub_le_to_cpu32 (indir
[fileblock
- INDIRECT_BLOCKS
]);
445 /* Double indirect. */
446 else if (fileblock
< INDIRECT_BLOCKS
+ blksz
/ 4 * (blksz
/ 4 + 1))
448 unsigned int perblock
= blksz
/ 4;
449 unsigned int rblock
= fileblock
- (INDIRECT_BLOCKS
451 grub_uint32_t indir
[blksz
/ 4];
453 if (grub_disk_read (data
->disk
,
455 grub_le_to_cpu32 (inode
->blocks
.double_indir_block
))
460 if (grub_disk_read (data
->disk
,
462 grub_le_to_cpu32 (indir
[rblock
/ perblock
]))
468 blknr
= grub_le_to_cpu32 (indir
[rblock
% perblock
]);
470 /* triple indirect. */
471 else if (fileblock
< INDIRECT_BLOCKS
+ blksz
/ 4 * (blksz
/ 4 + 1)
472 + (blksz
/ 4) * (blksz
/ 4) * (blksz
/ 4 + 1))
474 unsigned int perblock
= blksz
/ 4;
475 unsigned int rblock
= fileblock
- (INDIRECT_BLOCKS
+ blksz
/ 4
477 grub_uint32_t indir
[blksz
/ 4];
479 if (grub_disk_read (data
->disk
,
481 grub_le_to_cpu32 (inode
->blocks
.triple_indir_block
))
486 if (grub_disk_read (data
->disk
,
488 grub_le_to_cpu32 (indir
[(rblock
/ perblock
) / perblock
]))
493 if (grub_disk_read (data
->disk
,
495 grub_le_to_cpu32 (indir
[(rblock
/ perblock
) % perblock
]))
500 blknr
= grub_le_to_cpu32 (indir
[rblock
% perblock
]);
504 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
505 "ext2fs doesn't support quadruple indirect blocks");
511 /* Read LEN bytes from the file described by DATA starting with byte
512 POS. Return the amount of read bytes in READ. */
514 grub_ext2_read_file (grub_fshelp_node_t node
,
515 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
516 unsigned offset
, unsigned length
),
517 grub_off_t pos
, grub_size_t len
, char *buf
)
519 return grub_fshelp_read_file (node
->data
->disk
, node
, read_hook
,
520 pos
, len
, buf
, grub_ext2_read_block
,
521 grub_cpu_to_le32 (node
->inode
.size
)
522 | (((grub_off_t
) grub_cpu_to_le32 (node
->inode
.size_high
)) << 32),
523 LOG2_EXT2_BLOCK_SIZE (node
->data
), 0);
528 /* Read the inode INO for the file described by DATA into INODE. */
530 grub_ext2_read_inode (struct grub_ext2_data
*data
,
531 int ino
, struct grub_ext2_inode
*inode
)
533 struct grub_ext2_block_group blkgrp
;
534 struct grub_ext2_sblock
*sblock
= &data
->sblock
;
535 int inodes_per_block
;
539 /* It is easier to calculate if the first inode is 0. */
542 grub_ext2_blockgroup (data
,
543 ino
/ grub_le_to_cpu32 (sblock
->inodes_per_group
),
548 inodes_per_block
= EXT2_BLOCK_SIZE (data
) / EXT2_INODE_SIZE (data
);
549 blkno
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
551 blkoff
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
554 /* Read the inode. */
555 if (grub_disk_read (data
->disk
,
556 (((grub_disk_addr_t
) grub_le_to_cpu32 (blkgrp
.inode_table_id
) + blkno
)
557 << LOG2_EXT2_BLOCK_SIZE (data
)),
558 EXT2_INODE_SIZE (data
) * blkoff
,
559 sizeof (struct grub_ext2_inode
), inode
))
565 static struct grub_ext2_data
*
566 grub_ext2_mount (grub_disk_t disk
)
568 struct grub_ext2_data
*data
;
570 data
= grub_malloc (sizeof (struct grub_ext2_data
));
574 /* Read the superblock. */
575 grub_disk_read (disk
, 1 * 2, 0, sizeof (struct grub_ext2_sblock
),
580 /* Make sure this is an ext2 filesystem. */
581 if (grub_le_to_cpu16 (data
->sblock
.magic
) != EXT2_MAGIC
582 || grub_le_to_cpu32 (data
->sblock
.log2_block_size
) >= 16)
584 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
588 /* Check the FS doesn't have feature bits enabled that we don't support. */
589 if (grub_le_to_cpu32 (data
->sblock
.feature_incompat
)
590 & ~(EXT2_DRIVER_SUPPORTED_INCOMPAT
| EXT2_DRIVER_IGNORED_INCOMPAT
))
592 grub_error (GRUB_ERR_BAD_FS
, "filesystem has unsupported incompatible features");
599 data
->diropen
.data
= data
;
600 data
->diropen
.ino
= 2;
601 data
->diropen
.inode_read
= 1;
603 data
->inode
= &data
->diropen
.inode
;
605 grub_ext2_read_inode (data
, 2, data
->inode
);
612 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
613 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
620 grub_ext2_read_symlink (grub_fshelp_node_t node
)
623 struct grub_fshelp_node
*diro
= node
;
625 if (! diro
->inode_read
)
627 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
632 symlink
= grub_malloc (grub_le_to_cpu32 (diro
->inode
.size
) + 1);
636 /* If the filesize of the symlink is bigger than
637 60 the symlink is stored in a separate block,
638 otherwise it is stored in the inode. */
639 if (grub_le_to_cpu32 (diro
->inode
.size
) <= 60)
640 grub_strncpy (symlink
,
642 grub_le_to_cpu32 (diro
->inode
.size
));
645 grub_ext2_read_file (diro
, 0, 0,
646 grub_le_to_cpu32 (diro
->inode
.size
),
655 symlink
[grub_le_to_cpu32 (diro
->inode
.size
)] = '\0';
660 grub_ext2_iterate_dir (grub_fshelp_node_t dir
,
662 (*hook
) (const char *filename
,
663 enum grub_fshelp_filetype filetype
,
664 grub_fshelp_node_t node
))
666 unsigned int fpos
= 0;
667 struct grub_fshelp_node
*diro
= (struct grub_fshelp_node
*) dir
;
669 if (! diro
->inode_read
)
671 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
676 /* Search the file. */
677 while (fpos
< grub_le_to_cpu32 (diro
->inode
.size
))
679 struct ext2_dirent dirent
;
681 grub_ext2_read_file (diro
, 0, fpos
, sizeof (struct ext2_dirent
),
686 if (dirent
.direntlen
== 0)
689 if (dirent
.inode
!= 0 && dirent
.namelen
!= 0)
691 char filename
[dirent
.namelen
+ 1];
692 struct grub_fshelp_node
*fdiro
;
693 enum grub_fshelp_filetype type
= GRUB_FSHELP_UNKNOWN
;
695 grub_ext2_read_file (diro
, 0, fpos
+ sizeof (struct ext2_dirent
),
696 dirent
.namelen
, filename
);
700 fdiro
= grub_malloc (sizeof (struct grub_fshelp_node
));
704 fdiro
->data
= diro
->data
;
705 fdiro
->ino
= grub_le_to_cpu32 (dirent
.inode
);
707 filename
[dirent
.namelen
] = '\0';
709 if (dirent
.filetype
!= FILETYPE_UNKNOWN
)
711 fdiro
->inode_read
= 0;
713 if (dirent
.filetype
== FILETYPE_DIRECTORY
)
714 type
= GRUB_FSHELP_DIR
;
715 else if (dirent
.filetype
== FILETYPE_SYMLINK
)
716 type
= GRUB_FSHELP_SYMLINK
;
717 else if (dirent
.filetype
== FILETYPE_REG
)
718 type
= GRUB_FSHELP_REG
;
722 /* The filetype can not be read from the dirent, read
723 the inode to get more information. */
724 grub_ext2_read_inode (diro
->data
,
725 grub_le_to_cpu32 (dirent
.inode
),
733 fdiro
->inode_read
= 1;
735 if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
736 & FILETYPE_INO_MASK
) == FILETYPE_INO_DIRECTORY
)
737 type
= GRUB_FSHELP_DIR
;
738 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
739 & FILETYPE_INO_MASK
) == FILETYPE_INO_SYMLINK
)
740 type
= GRUB_FSHELP_SYMLINK
;
741 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
742 & FILETYPE_INO_MASK
) == FILETYPE_INO_REG
)
743 type
= GRUB_FSHELP_REG
;
746 if (hook (filename
, type
, fdiro
))
750 fpos
+= grub_le_to_cpu16 (dirent
.direntlen
);
756 /* Open a file named NAME and initialize FILE. */
758 grub_ext2_open (struct grub_file
*file
, const char *name
)
760 struct grub_ext2_data
*data
;
761 struct grub_fshelp_node
*fdiro
= 0;
764 grub_dl_ref (my_mod
);
766 data
= grub_ext2_mount (file
->device
->disk
);
773 err
= grub_fshelp_find_file (name
, &data
->diropen
, &fdiro
,
774 grub_ext2_iterate_dir
,
775 grub_ext2_read_symlink
, GRUB_FSHELP_REG
);
779 if (! fdiro
->inode_read
)
781 err
= grub_ext2_read_inode (data
, fdiro
->ino
, &fdiro
->inode
);
786 grub_memcpy (data
->inode
, &fdiro
->inode
, sizeof (struct grub_ext2_inode
));
789 file
->size
= grub_le_to_cpu32 (data
->inode
->size
);
790 file
->size
|= ((grub_off_t
) grub_le_to_cpu32 (data
->inode
->size_high
)) << 32;
797 if (fdiro
!= &data
->diropen
)
801 grub_dl_unref (my_mod
);
807 grub_ext2_close (grub_file_t file
)
809 grub_free (file
->data
);
811 grub_dl_unref (my_mod
);
813 return GRUB_ERR_NONE
;
816 /* Read LEN bytes data from FILE into BUF. */
818 grub_ext2_read (grub_file_t file
, char *buf
, grub_size_t len
)
820 struct grub_ext2_data
*data
= (struct grub_ext2_data
*) file
->data
;
822 return grub_ext2_read_file (&data
->diropen
, file
->read_hook
,
823 file
->offset
, len
, buf
);
828 grub_ext2_dir (grub_device_t device
, const char *path
,
829 int (*hook
) (const char *filename
,
830 const struct grub_dirhook_info
*info
))
832 struct grub_ext2_data
*data
= 0;
833 struct grub_fshelp_node
*fdiro
= 0;
835 auto int NESTED_FUNC_ATTR
iterate (const char *filename
,
836 enum grub_fshelp_filetype filetype
,
837 grub_fshelp_node_t node
);
839 int NESTED_FUNC_ATTR
iterate (const char *filename
,
840 enum grub_fshelp_filetype filetype
,
841 grub_fshelp_node_t node
)
843 struct grub_dirhook_info info
;
844 grub_memset (&info
, 0, sizeof (info
));
845 if (! node
->inode_read
)
847 grub_ext2_read_inode (data
, node
->ino
, &node
->inode
);
849 node
->inode_read
= 1;
850 grub_errno
= GRUB_ERR_NONE
;
852 if (node
->inode_read
)
855 info
.mtime
= grub_le_to_cpu32 (node
->inode
.mtime
);
858 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
860 return hook (filename
, &info
);
863 grub_dl_ref (my_mod
);
865 data
= grub_ext2_mount (device
->disk
);
869 grub_fshelp_find_file (path
, &data
->diropen
, &fdiro
, grub_ext2_iterate_dir
,
870 grub_ext2_read_symlink
, GRUB_FSHELP_DIR
);
874 grub_ext2_iterate_dir (fdiro
, iterate
);
877 if (fdiro
!= &data
->diropen
)
881 grub_dl_unref (my_mod
);
887 grub_ext2_label (grub_device_t device
, char **label
)
889 struct grub_ext2_data
*data
;
890 grub_disk_t disk
= device
->disk
;
892 grub_dl_ref (my_mod
);
894 data
= grub_ext2_mount (disk
);
896 *label
= grub_strndup (data
->sblock
.volume_name
,
897 sizeof (data
->sblock
.volume_name
));
901 grub_dl_unref (my_mod
);
909 grub_ext2_uuid (grub_device_t device
, char **uuid
)
911 struct grub_ext2_data
*data
;
912 grub_disk_t disk
= device
->disk
;
914 grub_dl_ref (my_mod
);
916 data
= grub_ext2_mount (disk
);
919 *uuid
= grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
920 grub_be_to_cpu16 (data
->sblock
.uuid
[0]),
921 grub_be_to_cpu16 (data
->sblock
.uuid
[1]),
922 grub_be_to_cpu16 (data
->sblock
.uuid
[2]),
923 grub_be_to_cpu16 (data
->sblock
.uuid
[3]),
924 grub_be_to_cpu16 (data
->sblock
.uuid
[4]),
925 grub_be_to_cpu16 (data
->sblock
.uuid
[5]),
926 grub_be_to_cpu16 (data
->sblock
.uuid
[6]),
927 grub_be_to_cpu16 (data
->sblock
.uuid
[7]));
932 grub_dl_unref (my_mod
);
941 grub_ext2_mtime (grub_device_t device
, grub_int32_t
*tm
)
943 struct grub_ext2_data
*data
;
944 grub_disk_t disk
= device
->disk
;
946 grub_dl_ref (my_mod
);
948 data
= grub_ext2_mount (disk
);
952 *tm
= grub_le_to_cpu32 (data
->sblock
.utime
);
954 grub_dl_unref (my_mod
);
964 static struct grub_fs grub_ext2_fs
=
967 .dir
= grub_ext2_dir
,
968 .open
= grub_ext2_open
,
969 .read
= grub_ext2_read
,
970 .close
= grub_ext2_close
,
971 .label
= grub_ext2_label
,
972 .uuid
= grub_ext2_uuid
,
973 .mtime
= grub_ext2_mtime
,
975 .reserved_first_sector
= 1,
976 .blocklist_install
= 1,
983 grub_fs_register (&grub_ext2_fs
);
989 grub_fs_unregister (&grub_ext2_fs
);