1 /* ext2.c - Second Extended filesystem */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2004,2005,2007,2008 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
24 /* Maximum length of a pathname. */
25 #define EXT2_PATH_MAX 4096
26 /* Maximum nesting of symlinks, used to prevent a loop. */
27 #define EXT2_MAX_SYMLINKCNT 8
29 /* The good old revision and the default inode size. */
30 #define EXT2_GOOD_OLD_REVISION 0
31 #define EXT2_GOOD_OLD_INODE_SIZE 128
33 /* Filetype used in directory entry. */
34 #define FILETYPE_UNKNOWN 0
35 #define FILETYPE_REG 1
36 #define FILETYPE_DIRECTORY 2
37 #define FILETYPE_SYMLINK 7
39 /* Filetype information as used in inodes. */
40 #define FILETYPE_INO_MASK 0170000
41 #define FILETYPE_INO_REG 0100000
42 #define FILETYPE_INO_DIRECTORY 0040000
43 #define FILETYPE_INO_SYMLINK 0120000
46 #include <grub/file.h>
48 #include <grub/misc.h>
49 #include <grub/disk.h>
51 #include <grub/types.h>
52 #include <grub/fshelp.h>
54 /* Log2 size of ext2 block in 512 blocks. */
55 #define LOG2_EXT2_BLOCK_SIZE(data) \
56 (grub_le_to_cpu32 (data->sblock.log2_block_size) + 1)
58 /* Log2 size of ext2 block in bytes. */
59 #define LOG2_BLOCK_SIZE(data) \
60 (grub_le_to_cpu32 (data->sblock.log2_block_size) + 10)
62 /* The size of an ext2 block in bytes. */
63 #define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE (data))
65 /* The revision level. */
66 #define EXT2_REVISION(data) grub_le_to_cpu32 (data->sblock.revision_level)
69 #define EXT2_INODE_SIZE(data) \
70 (EXT2_REVISION (data) == 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_FLEX_BG 0x0200
106 /* The set of back-incompatible features this driver DOES support. Add (OR)
107 * flags here as the related features are implemented into the driver. */
108 #define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
109 | EXT4_FEATURE_INCOMPAT_EXTENTS \
110 | EXT4_FEATURE_INCOMPAT_FLEX_BG )
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 reserved_word_pad
;
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];
204 /* The ext2 inode. */
205 struct grub_ext2_inode
215 grub_uint16_t nlinks
;
216 grub_uint32_t blockcnt
; /* Blocks of 512 bytes!! */
223 grub_uint32_t dir_blocks
[INDIRECT_BLOCKS
];
224 grub_uint32_t indir_block
;
225 grub_uint32_t double_indir_block
;
226 grub_uint32_t triple_indir_block
;
230 grub_uint32_t version
;
232 grub_uint32_t dir_acl
;
233 grub_uint32_t fragment_addr
;
234 grub_uint32_t osd2
[3];
237 /* The header of an ext2 directory entry. */
241 grub_uint16_t direntlen
;
242 grub_uint8_t namelen
;
243 grub_uint8_t filetype
;
246 struct grub_ext3_journal_header
249 grub_uint32_t block_type
;
250 grub_uint32_t sequence
;
253 struct grub_ext3_journal_revoke_header
255 struct grub_ext3_journal_header header
;
257 grub_uint32_t data
[0];
260 struct grub_ext3_journal_block_tag
266 struct grub_ext3_journal_sblock
268 struct grub_ext3_journal_header header
;
269 grub_uint32_t block_size
;
270 grub_uint32_t maxlen
;
272 grub_uint32_t sequence
;
276 #define EXT4_EXT_MAGIC 0xf30a
278 struct grub_ext4_extent_header
281 grub_uint16_t entries
;
284 grub_uint32_t generation
;
287 struct grub_ext4_extent
291 grub_uint16_t start_hi
;
295 struct grub_ext4_extent_idx
299 grub_uint16_t leaf_hi
;
300 grub_uint16_t unused
;
303 struct grub_fshelp_node
305 struct grub_ext2_data
*data
;
306 struct grub_ext2_inode inode
;
311 /* Information about a "mounted" ext2 filesystem. */
312 struct grub_ext2_data
314 struct grub_ext2_sblock sblock
;
316 struct grub_ext2_inode
*inode
;
317 struct grub_fshelp_node diropen
;
320 static grub_dl_t my_mod
;
324 /* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
325 the mounted filesystem DATA. */
326 inline static grub_err_t
327 grub_ext2_blockgroup (struct grub_ext2_data
*data
, int group
,
328 struct grub_ext2_block_group
*blkgrp
)
330 return grub_disk_read (data
->disk
,
331 ((grub_le_to_cpu32 (data
->sblock
.first_data_block
) + 1)
332 << LOG2_EXT2_BLOCK_SIZE (data
)),
333 group
* sizeof (struct grub_ext2_block_group
),
334 sizeof (struct grub_ext2_block_group
), blkgrp
);
337 static struct grub_ext4_extent_header
*
338 grub_ext4_find_leaf (struct grub_ext2_data
*data
, char *buf
,
339 struct grub_ext4_extent_header
*ext_block
,
340 grub_uint32_t fileblock
)
342 struct grub_ext4_extent_idx
*index
;
347 grub_disk_addr_t block
;
349 index
= (struct grub_ext4_extent_idx
*) (ext_block
+ 1);
351 if (grub_le_to_cpu16(ext_block
->magic
) != EXT4_EXT_MAGIC
)
354 if (ext_block
->depth
== 0)
357 for (i
= 0; i
< grub_le_to_cpu16 (ext_block
->entries
); i
++)
359 if (fileblock
< grub_le_to_cpu32(index
[i
].block
))
366 block
= grub_le_to_cpu16 (index
[i
].leaf_hi
);
367 block
= (block
<< 32) + grub_le_to_cpu32 (index
[i
].leaf
);
368 if (grub_disk_read (data
->disk
,
369 block
<< LOG2_EXT2_BLOCK_SIZE (data
),
370 0, EXT2_BLOCK_SIZE(data
), buf
))
373 ext_block
= (struct grub_ext4_extent_header
*) buf
;
377 static grub_disk_addr_t
378 grub_ext2_read_block (grub_fshelp_node_t node
, grub_disk_addr_t fileblock
)
380 struct grub_ext2_data
*data
= node
->data
;
381 struct grub_ext2_inode
*inode
= &node
->inode
;
383 unsigned int blksz
= EXT2_BLOCK_SIZE (data
);
384 int log2_blksz
= LOG2_EXT2_BLOCK_SIZE (data
);
386 if (grub_le_to_cpu32(inode
->flags
) & EXT4_EXTENTS_FLAG
)
388 char buf
[EXT2_BLOCK_SIZE(data
)];
389 struct grub_ext4_extent_header
*leaf
;
390 struct grub_ext4_extent
*ext
;
393 leaf
= grub_ext4_find_leaf (data
, buf
,
394 (struct grub_ext4_extent_header
*) inode
->blocks
.dir_blocks
,
398 grub_error (GRUB_ERR_BAD_FS
, "invalid extent");
402 ext
= (struct grub_ext4_extent
*) (leaf
+ 1);
403 for (i
= 0; i
< grub_le_to_cpu16 (leaf
->entries
); i
++)
405 if (fileblock
< grub_le_to_cpu32 (ext
[i
].block
))
411 fileblock
-= grub_le_to_cpu32 (ext
[i
].block
);
412 if (fileblock
>= grub_le_to_cpu16 (ext
[i
].len
))
416 grub_disk_addr_t start
;
418 start
= grub_le_to_cpu16 (ext
[i
].start_hi
);
419 start
= (start
<< 32) + grub_le_to_cpu32 (ext
[i
].start
);
421 return fileblock
+ start
;
426 grub_error (GRUB_ERR_BAD_FS
, "something wrong with extent");
431 if (fileblock
< INDIRECT_BLOCKS
)
432 blknr
= grub_le_to_cpu32 (inode
->blocks
.dir_blocks
[fileblock
]);
434 else if (fileblock
< INDIRECT_BLOCKS
+ blksz
/ 4)
436 grub_uint32_t indir
[blksz
/ 4];
438 if (grub_disk_read (data
->disk
,
439 grub_le_to_cpu32 (inode
->blocks
.indir_block
)
444 blknr
= grub_le_to_cpu32 (indir
[fileblock
- INDIRECT_BLOCKS
]);
446 /* Double indirect. */
447 else if (fileblock
< INDIRECT_BLOCKS
+ blksz
/ 4 * (blksz
/ 4 + 1))
449 unsigned int perblock
= blksz
/ 4;
450 unsigned int rblock
= fileblock
- (INDIRECT_BLOCKS
452 grub_uint32_t indir
[blksz
/ 4];
454 if (grub_disk_read (data
->disk
,
455 grub_le_to_cpu32 (inode
->blocks
.double_indir_block
)
460 if (grub_disk_read (data
->disk
,
461 grub_le_to_cpu32 (indir
[rblock
/ perblock
])
467 blknr
= grub_le_to_cpu32 (indir
[rblock
% perblock
]);
469 /* triple indirect. */
472 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
473 "ext2fs doesn't support triple indirect blocks");
479 /* Read LEN bytes from the file described by DATA starting with byte
480 POS. Return the amount of read bytes in READ. */
482 grub_ext2_read_file (grub_fshelp_node_t node
,
483 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
484 unsigned offset
, unsigned length
),
485 int pos
, grub_size_t len
, char *buf
)
487 return grub_fshelp_read_file (node
->data
->disk
, node
, read_hook
,
488 pos
, len
, buf
, grub_ext2_read_block
,
490 LOG2_EXT2_BLOCK_SIZE (node
->data
));
495 /* Read the inode INO for the file described by DATA into INODE. */
497 grub_ext2_read_inode (struct grub_ext2_data
*data
,
498 int ino
, struct grub_ext2_inode
*inode
)
500 struct grub_ext2_block_group blkgrp
;
501 struct grub_ext2_sblock
*sblock
= &data
->sblock
;
502 int inodes_per_block
;
506 /* It is easier to calculate if the first inode is 0. */
509 grub_ext2_blockgroup (data
,
510 ino
/ grub_le_to_cpu32 (sblock
->inodes_per_group
),
515 inodes_per_block
= EXT2_BLOCK_SIZE (data
) / EXT2_INODE_SIZE (data
);
516 blkno
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
518 blkoff
= (ino
% grub_le_to_cpu32 (sblock
->inodes_per_group
))
521 /* Read the inode. */
522 if (grub_disk_read (data
->disk
,
523 ((grub_le_to_cpu32 (blkgrp
.inode_table_id
) + blkno
)
524 << LOG2_EXT2_BLOCK_SIZE (data
)),
525 EXT2_INODE_SIZE (data
) * blkoff
,
526 sizeof (struct grub_ext2_inode
), inode
))
532 static struct grub_ext2_data
*
533 grub_ext2_mount (grub_disk_t disk
)
535 struct grub_ext2_data
*data
;
537 data
= grub_malloc (sizeof (struct grub_ext2_data
));
541 /* Read the superblock. */
542 grub_disk_read (disk
, 1 * 2, 0, sizeof (struct grub_ext2_sblock
),
547 /* Make sure this is an ext2 filesystem. */
548 if (grub_le_to_cpu16 (data
->sblock
.magic
) != EXT2_MAGIC
)
550 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
554 /* Check the FS doesn't have feature bits enabled that we don't support. */
555 if (grub_le_to_cpu32 (data
->sblock
.feature_incompat
)
556 & ~(EXT2_DRIVER_SUPPORTED_INCOMPAT
| EXT2_DRIVER_IGNORED_INCOMPAT
))
558 grub_error (GRUB_ERR_BAD_FS
, "filesystem has unsupported incompatible features");
565 data
->diropen
.data
= data
;
566 data
->diropen
.ino
= 2;
567 data
->diropen
.inode_read
= 1;
569 data
->inode
= &data
->diropen
.inode
;
571 grub_ext2_read_inode (data
, 2, data
->inode
);
578 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
579 grub_error (GRUB_ERR_BAD_FS
, "not an ext2 filesystem");
586 grub_ext2_read_symlink (grub_fshelp_node_t node
)
589 struct grub_fshelp_node
*diro
= node
;
591 if (! diro
->inode_read
)
593 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
598 symlink
= grub_malloc (grub_le_to_cpu32 (diro
->inode
.size
) + 1);
602 /* If the filesize of the symlink is bigger than
603 60 the symlink is stored in a separate block,
604 otherwise it is stored in the inode. */
605 if (grub_le_to_cpu32 (diro
->inode
.size
) <= 60)
606 grub_strncpy (symlink
,
608 grub_le_to_cpu32 (diro
->inode
.size
));
611 grub_ext2_read_file (diro
, 0, 0,
612 grub_le_to_cpu32 (diro
->inode
.size
),
621 symlink
[grub_le_to_cpu32 (diro
->inode
.size
)] = '\0';
626 grub_ext2_iterate_dir (grub_fshelp_node_t dir
,
628 (*hook
) (const char *filename
,
629 enum grub_fshelp_filetype filetype
,
630 grub_fshelp_node_t node
))
632 unsigned int fpos
= 0;
633 struct grub_fshelp_node
*diro
= (struct grub_fshelp_node
*) dir
;
635 if (! diro
->inode_read
)
637 grub_ext2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
642 /* Search the file. */
643 while (fpos
< grub_le_to_cpu32 (diro
->inode
.size
))
645 struct ext2_dirent dirent
;
647 grub_ext2_read_file (diro
, 0, fpos
, sizeof (struct ext2_dirent
),
652 if (dirent
.direntlen
== 0)
655 if (dirent
.namelen
!= 0)
657 char filename
[dirent
.namelen
+ 1];
658 struct grub_fshelp_node
*fdiro
;
659 enum grub_fshelp_filetype type
= GRUB_FSHELP_UNKNOWN
;
661 grub_ext2_read_file (diro
, 0, fpos
+ sizeof (struct ext2_dirent
),
662 dirent
.namelen
, filename
);
666 fdiro
= grub_malloc (sizeof (struct grub_fshelp_node
));
670 fdiro
->data
= diro
->data
;
671 fdiro
->ino
= grub_le_to_cpu32 (dirent
.inode
);
673 filename
[dirent
.namelen
] = '\0';
675 if (dirent
.filetype
!= FILETYPE_UNKNOWN
)
677 fdiro
->inode_read
= 0;
679 if (dirent
.filetype
== FILETYPE_DIRECTORY
)
680 type
= GRUB_FSHELP_DIR
;
681 else if (dirent
.filetype
== FILETYPE_SYMLINK
)
682 type
= GRUB_FSHELP_SYMLINK
;
683 else if (dirent
.filetype
== FILETYPE_REG
)
684 type
= GRUB_FSHELP_REG
;
688 /* The filetype can not be read from the dirent, read
689 the inode to get more information. */
690 grub_ext2_read_inode (diro
->data
,
691 grub_le_to_cpu32 (dirent
.inode
),
699 fdiro
->inode_read
= 1;
701 if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
702 & FILETYPE_INO_MASK
) == FILETYPE_INO_DIRECTORY
)
703 type
= GRUB_FSHELP_DIR
;
704 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
705 & FILETYPE_INO_MASK
) == FILETYPE_INO_SYMLINK
)
706 type
= GRUB_FSHELP_SYMLINK
;
707 else if ((grub_le_to_cpu16 (fdiro
->inode
.mode
)
708 & FILETYPE_INO_MASK
) == FILETYPE_INO_REG
)
709 type
= GRUB_FSHELP_REG
;
712 if (hook (filename
, type
, fdiro
))
716 fpos
+= grub_le_to_cpu16 (dirent
.direntlen
);
722 /* Open a file named NAME and initialize FILE. */
724 grub_ext2_open (struct grub_file
*file
, const char *name
)
726 struct grub_ext2_data
*data
;
727 struct grub_fshelp_node
*fdiro
= 0;
729 grub_dl_ref (my_mod
);
731 data
= grub_ext2_mount (file
->device
->disk
);
735 grub_fshelp_find_file (name
, &data
->diropen
, &fdiro
, grub_ext2_iterate_dir
,
736 grub_ext2_read_symlink
, GRUB_FSHELP_REG
);
740 if (! fdiro
->inode_read
)
742 grub_ext2_read_inode (data
, fdiro
->ino
, &fdiro
->inode
);
747 grub_memcpy (data
->inode
, &fdiro
->inode
, sizeof (struct grub_ext2_inode
));
750 file
->size
= grub_le_to_cpu32 (data
->inode
->size
);
757 if (fdiro
!= &data
->diropen
)
761 grub_dl_unref (my_mod
);
767 grub_ext2_close (grub_file_t file
)
769 grub_free (file
->data
);
771 grub_dl_unref (my_mod
);
773 return GRUB_ERR_NONE
;
776 /* Read LEN bytes data from FILE into BUF. */
778 grub_ext2_read (grub_file_t file
, char *buf
, grub_size_t len
)
780 struct grub_ext2_data
*data
= (struct grub_ext2_data
*) file
->data
;
782 return grub_ext2_read_file (&data
->diropen
, file
->read_hook
,
783 file
->offset
, len
, buf
);
788 grub_ext2_dir (grub_device_t device
, const char *path
,
789 int (*hook
) (const char *filename
,
790 const struct grub_dirhook_info
*info
))
792 struct grub_ext2_data
*data
= 0;
793 struct grub_fshelp_node
*fdiro
= 0;
795 auto int NESTED_FUNC_ATTR
iterate (const char *filename
,
796 enum grub_fshelp_filetype filetype
,
797 grub_fshelp_node_t node
);
799 int NESTED_FUNC_ATTR
iterate (const char *filename
,
800 enum grub_fshelp_filetype filetype
,
801 grub_fshelp_node_t node
)
803 struct grub_dirhook_info info
;
804 grub_memset (&info
, 0, sizeof (info
));
805 if (! node
->inode_read
)
807 grub_ext2_read_inode (data
, node
->ino
, &node
->inode
);
809 node
->inode_read
= 1;
810 grub_errno
= GRUB_ERR_NONE
;
812 if (node
->inode_read
)
815 info
.mtime
= grub_le_to_cpu32 (node
->inode
.mtime
);
818 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
820 return hook (filename
, &info
);
823 grub_dl_ref (my_mod
);
825 data
= grub_ext2_mount (device
->disk
);
829 grub_fshelp_find_file (path
, &data
->diropen
, &fdiro
, grub_ext2_iterate_dir
,
830 grub_ext2_read_symlink
, GRUB_FSHELP_DIR
);
834 grub_ext2_iterate_dir (fdiro
, iterate
);
837 if (fdiro
!= &data
->diropen
)
841 grub_dl_unref (my_mod
);
847 grub_ext2_label (grub_device_t device
, char **label
)
849 struct grub_ext2_data
*data
;
850 grub_disk_t disk
= device
->disk
;
852 grub_dl_ref (my_mod
);
854 data
= grub_ext2_mount (disk
);
856 *label
= grub_strndup (data
->sblock
.volume_name
, 14);
860 grub_dl_unref (my_mod
);
868 grub_ext2_uuid (grub_device_t device
, char **uuid
)
870 struct grub_ext2_data
*data
;
871 grub_disk_t disk
= device
->disk
;
873 grub_dl_ref (my_mod
);
875 data
= grub_ext2_mount (disk
);
878 *uuid
= grub_malloc (40 + sizeof ('\0'));
879 grub_sprintf (*uuid
, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
880 grub_be_to_cpu16 (data
->sblock
.uuid
[0]), grub_be_to_cpu16 (data
->sblock
.uuid
[1]),
881 grub_be_to_cpu16 (data
->sblock
.uuid
[2]), grub_be_to_cpu16 (data
->sblock
.uuid
[3]),
882 grub_be_to_cpu16 (data
->sblock
.uuid
[4]), grub_be_to_cpu16 (data
->sblock
.uuid
[5]),
883 grub_be_to_cpu16 (data
->sblock
.uuid
[6]), grub_be_to_cpu16 (data
->sblock
.uuid
[7]));
888 grub_dl_unref (my_mod
);
897 grub_ext2_mtime (grub_device_t device
, grub_int32_t
*tm
)
899 struct grub_ext2_data
*data
;
900 grub_disk_t disk
= device
->disk
;
902 grub_dl_ref (my_mod
);
904 data
= grub_ext2_mount (disk
);
908 *tm
= grub_le_to_cpu32 (data
->sblock
.utime
);
910 grub_dl_unref (my_mod
);
920 static struct grub_fs grub_ext2_fs
=
923 .dir
= grub_ext2_dir
,
924 .open
= grub_ext2_open
,
925 .read
= grub_ext2_read
,
926 .close
= grub_ext2_close
,
927 .label
= grub_ext2_label
,
928 .uuid
= grub_ext2_uuid
,
929 .mtime
= grub_ext2_mtime
,
931 .reserved_first_sector
= 1,
938 grub_fs_register (&grub_ext2_fs
);
944 grub_fs_unregister (&grub_ext2_fs
);