2009-02-03 Felix Zielcke <fzielcke@z-51.de>
[grub2/phcoder.git] / fs / ext2.c
blob81318f882bed907a21bfc0a1719f8080acfe9b9f
1 /* ext2.c - Second Extended filesystem */
2 /*
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
45 #include <grub/err.h>
46 #include <grub/file.h>
47 #include <grub/mm.h>
48 #include <grub/misc.h>
49 #include <grub/disk.h>
50 #include <grub/dl.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)
68 /* The inode size. */
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 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
76 #define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
78 #define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1
79 #define EXT3_JOURNAL_COMMIT_BLOCK 2
80 #define EXT3_JOURNAL_SUPERBLOCK_V1 3
81 #define EXT3_JOURNAL_SUPERBLOCK_V2 4
82 #define EXT3_JOURNAL_REVOKE_BLOCK 5
84 #define EXT3_JOURNAL_FLAG_ESCAPE 1
85 #define EXT3_JOURNAL_FLAG_SAME_UUID 2
86 #define EXT3_JOURNAL_FLAG_DELETED 4
87 #define EXT3_JOURNAL_FLAG_LAST_TAG 8
89 #define EXT4_EXTENTS_FLAG 0x80000
91 /* The ext2 superblock. */
92 struct grub_ext2_sblock
94 grub_uint32_t total_inodes;
95 grub_uint32_t total_blocks;
96 grub_uint32_t reserved_blocks;
97 grub_uint32_t free_blocks;
98 grub_uint32_t free_inodes;
99 grub_uint32_t first_data_block;
100 grub_uint32_t log2_block_size;
101 grub_uint32_t log2_fragment_size;
102 grub_uint32_t blocks_per_group;
103 grub_uint32_t fragments_per_group;
104 grub_uint32_t inodes_per_group;
105 grub_uint32_t mtime;
106 grub_uint32_t utime;
107 grub_uint16_t mnt_count;
108 grub_uint16_t max_mnt_count;
109 grub_uint16_t magic;
110 grub_uint16_t fs_state;
111 grub_uint16_t error_handling;
112 grub_uint16_t minor_revision_level;
113 grub_uint32_t lastcheck;
114 grub_uint32_t checkinterval;
115 grub_uint32_t creator_os;
116 grub_uint32_t revision_level;
117 grub_uint16_t uid_reserved;
118 grub_uint16_t gid_reserved;
119 grub_uint32_t first_inode;
120 grub_uint16_t inode_size;
121 grub_uint16_t block_group_number;
122 grub_uint32_t feature_compatibility;
123 grub_uint32_t feature_incompat;
124 grub_uint32_t feature_ro_compat;
125 grub_uint16_t uuid[8];
126 char volume_name[16];
127 char last_mounted_on[64];
128 grub_uint32_t compression_info;
129 grub_uint8_t prealloc_blocks;
130 grub_uint8_t prealloc_dir_blocks;
131 grub_uint16_t reserved_gdt_blocks;
132 grub_uint8_t journal_uuid[16];
133 grub_uint32_t journal_inum;
134 grub_uint32_t journal_dev;
135 grub_uint32_t last_orphan;
136 grub_uint32_t hash_seed[4];
137 grub_uint8_t def_hash_version;
138 grub_uint8_t jnl_backup_type;
139 grub_uint16_t reserved_word_pad;
140 grub_uint32_t default_mount_opts;
141 grub_uint32_t first_meta_bg;
142 grub_uint32_t mkfs_time;
143 grub_uint32_t jnl_blocks[17];
146 /* The ext2 blockgroup. */
147 struct grub_ext2_block_group
149 grub_uint32_t block_id;
150 grub_uint32_t inode_id;
151 grub_uint32_t inode_table_id;
152 grub_uint16_t free_blocks;
153 grub_uint16_t free_inodes;
154 grub_uint16_t used_dirs;
155 grub_uint16_t pad;
156 grub_uint32_t reserved[3];
159 /* The ext2 inode. */
160 struct grub_ext2_inode
162 grub_uint16_t mode;
163 grub_uint16_t uid;
164 grub_uint32_t size;
165 grub_uint32_t atime;
166 grub_uint32_t ctime;
167 grub_uint32_t mtime;
168 grub_uint32_t dtime;
169 grub_uint16_t gid;
170 grub_uint16_t nlinks;
171 grub_uint32_t blockcnt; /* Blocks of 512 bytes!! */
172 grub_uint32_t flags;
173 grub_uint32_t osd1;
174 union
176 struct datablocks
178 grub_uint32_t dir_blocks[INDIRECT_BLOCKS];
179 grub_uint32_t indir_block;
180 grub_uint32_t double_indir_block;
181 grub_uint32_t triple_indir_block;
182 } blocks;
183 char symlink[60];
185 grub_uint32_t version;
186 grub_uint32_t acl;
187 grub_uint32_t dir_acl;
188 grub_uint32_t fragment_addr;
189 grub_uint32_t osd2[3];
192 /* The header of an ext2 directory entry. */
193 struct ext2_dirent
195 grub_uint32_t inode;
196 grub_uint16_t direntlen;
197 grub_uint8_t namelen;
198 grub_uint8_t filetype;
201 struct grub_ext3_journal_header
203 grub_uint32_t magic;
204 grub_uint32_t block_type;
205 grub_uint32_t sequence;
208 struct grub_ext3_journal_revoke_header
210 struct grub_ext3_journal_header header;
211 grub_uint32_t count;
212 grub_uint32_t data[0];
215 struct grub_ext3_journal_block_tag
217 grub_uint32_t block;
218 grub_uint32_t flags;
221 struct grub_ext3_journal_sblock
223 struct grub_ext3_journal_header header;
224 grub_uint32_t block_size;
225 grub_uint32_t maxlen;
226 grub_uint32_t first;
227 grub_uint32_t sequence;
228 grub_uint32_t start;
231 #define EXT4_EXT_MAGIC 0xf30a
233 struct grub_ext4_extent_header
235 grub_uint16_t magic;
236 grub_uint16_t entries;
237 grub_uint16_t max;
238 grub_uint16_t depth;
239 grub_uint32_t generation;
242 struct grub_ext4_extent
244 grub_uint32_t block;
245 grub_uint16_t len;
246 grub_uint16_t start_hi;
247 grub_uint32_t start;
250 struct grub_ext4_extent_idx
252 grub_uint32_t block;
253 grub_uint32_t leaf;
254 grub_uint16_t leaf_hi;
255 grub_uint16_t unused;
258 struct grub_fshelp_node
260 struct grub_ext2_data *data;
261 struct grub_ext2_inode inode;
262 int ino;
263 int inode_read;
266 /* Information about a "mounted" ext2 filesystem. */
267 struct grub_ext2_data
269 struct grub_ext2_sblock sblock;
270 grub_disk_t disk;
271 struct grub_ext2_inode *inode;
272 struct grub_fshelp_node diropen;
275 #ifndef GRUB_UTIL
276 static grub_dl_t my_mod;
277 #endif
281 /* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
282 the mounted filesystem DATA. */
283 inline static grub_err_t
284 grub_ext2_blockgroup (struct grub_ext2_data *data, int group,
285 struct grub_ext2_block_group *blkgrp)
287 return grub_disk_read (data->disk,
288 ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1)
289 << LOG2_EXT2_BLOCK_SIZE (data)),
290 group * sizeof (struct grub_ext2_block_group),
291 sizeof (struct grub_ext2_block_group), (char *) blkgrp);
294 static struct grub_ext4_extent_header *
295 grub_ext4_find_leaf (struct grub_ext2_data *data, char *buf,
296 struct grub_ext4_extent_header *ext_block,
297 grub_uint32_t fileblock)
299 struct grub_ext4_extent_idx *index;
301 while (1)
303 int i;
304 grub_disk_addr_t block;
306 index = (struct grub_ext4_extent_idx *) (ext_block + 1);
308 if (grub_le_to_cpu16(ext_block->magic) != EXT4_EXT_MAGIC)
309 return 0;
311 if (ext_block->depth == 0)
312 return ext_block;
314 for (i = 0; i < grub_le_to_cpu16 (ext_block->entries); i++)
316 if (fileblock < grub_le_to_cpu32(index[i].block))
317 break;
320 if (--i < 0)
321 return 0;
323 block = grub_le_to_cpu16 (index[i].leaf_hi);
324 block = (block << 32) + grub_le_to_cpu32 (index[i].leaf);
325 if (grub_disk_read (data->disk,
326 block << LOG2_EXT2_BLOCK_SIZE (data),
327 0, EXT2_BLOCK_SIZE(data), buf))
328 return 0;
330 ext_block = (struct grub_ext4_extent_header *) buf;
334 static grub_disk_addr_t
335 grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
337 struct grub_ext2_data *data = node->data;
338 struct grub_ext2_inode *inode = &node->inode;
339 int blknr = -1;
340 unsigned int blksz = EXT2_BLOCK_SIZE (data);
341 int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
343 if (inode->flags & EXT4_EXTENTS_FLAG)
345 char buf[EXT2_BLOCK_SIZE(data)];
346 struct grub_ext4_extent_header *leaf;
347 struct grub_ext4_extent *ext;
348 int i;
350 leaf = grub_ext4_find_leaf (data, buf,
351 (struct grub_ext4_extent_header *) inode->blocks.dir_blocks,
352 fileblock);
353 if (! leaf)
355 grub_error (GRUB_ERR_BAD_FS, "invalid extent");
356 return -1;
359 ext = (struct grub_ext4_extent *) (leaf + 1);
360 for (i = 0; i < grub_le_to_cpu16 (leaf->entries); i++)
362 if (fileblock < grub_le_to_cpu32 (ext[i].block))
363 break;
366 if (--i >= 0)
368 fileblock -= grub_le_to_cpu32 (ext[i].block);
369 if (fileblock >= grub_le_to_cpu16 (ext[i].len))
370 return 0;
371 else
373 grub_disk_addr_t start;
375 start = grub_le_to_cpu16 (ext[i].start_hi);
376 start = (start << 32) + grub_le_to_cpu32 (ext[i].start);
378 return fileblock + start;
381 else
383 grub_error (GRUB_ERR_BAD_FS, "something wrong with extent");
384 return -1;
387 /* Direct blocks. */
388 if (fileblock < INDIRECT_BLOCKS)
389 blknr = grub_le_to_cpu32 (inode->blocks.dir_blocks[fileblock]);
390 /* Indirect. */
391 else if (fileblock < INDIRECT_BLOCKS + blksz / 4)
393 grub_uint32_t indir[blksz / 4];
395 if (grub_disk_read (data->disk,
396 grub_le_to_cpu32 (inode->blocks.indir_block)
397 << log2_blksz,
398 0, blksz, (char *) indir))
399 return grub_errno;
401 blknr = grub_le_to_cpu32 (indir[fileblock - INDIRECT_BLOCKS]);
403 /* Double indirect. */
404 else if (fileblock < INDIRECT_BLOCKS + blksz / 4 * (blksz / 4 + 1))
406 unsigned int perblock = blksz / 4;
407 unsigned int rblock = fileblock - (INDIRECT_BLOCKS
408 + blksz / 4);
409 grub_uint32_t indir[blksz / 4];
411 if (grub_disk_read (data->disk,
412 grub_le_to_cpu32 (inode->blocks.double_indir_block)
413 << log2_blksz,
414 0, blksz, (char *) indir))
415 return grub_errno;
417 if (grub_disk_read (data->disk,
418 grub_le_to_cpu32 (indir[rblock / perblock])
419 << log2_blksz,
420 0, blksz, (char *) indir))
421 return grub_errno;
424 blknr = grub_le_to_cpu32 (indir[rblock % perblock]);
426 /* triple indirect. */
427 else
429 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
430 "ext2fs doesn't support triple indirect blocks");
433 return blknr;
436 /* Read LEN bytes from the file described by DATA starting with byte
437 POS. Return the amount of read bytes in READ. */
438 static grub_ssize_t
439 grub_ext2_read_file (grub_fshelp_node_t node,
440 void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
441 unsigned offset, unsigned length),
442 int pos, grub_size_t len, char *buf)
444 return grub_fshelp_read_file (node->data->disk, node, read_hook,
445 pos, len, buf, grub_ext2_read_block,
446 node->inode.size,
447 LOG2_EXT2_BLOCK_SIZE (node->data));
452 /* Read the inode INO for the file described by DATA into INODE. */
453 static grub_err_t
454 grub_ext2_read_inode (struct grub_ext2_data *data,
455 int ino, struct grub_ext2_inode *inode)
457 struct grub_ext2_block_group blkgrp;
458 struct grub_ext2_sblock *sblock = &data->sblock;
459 int inodes_per_block;
460 unsigned int blkno;
461 unsigned int blkoff;
463 /* It is easier to calculate if the first inode is 0. */
464 ino--;
466 grub_ext2_blockgroup (data,
467 ino / grub_le_to_cpu32 (sblock->inodes_per_group),
468 &blkgrp);
469 if (grub_errno)
470 return grub_errno;
472 inodes_per_block = EXT2_BLOCK_SIZE (data) / EXT2_INODE_SIZE (data);
473 blkno = (ino % grub_le_to_cpu32 (sblock->inodes_per_group))
474 / inodes_per_block;
475 blkoff = (ino % grub_le_to_cpu32 (sblock->inodes_per_group))
476 % inodes_per_block;
478 /* Read the inode. */
479 if (grub_disk_read (data->disk,
480 ((grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno)
481 << LOG2_EXT2_BLOCK_SIZE (data)),
482 EXT2_INODE_SIZE (data) * blkoff,
483 sizeof (struct grub_ext2_inode), (char *) inode))
484 return grub_errno;
486 return 0;
489 static struct grub_ext2_data *
490 grub_ext2_mount (grub_disk_t disk)
492 struct grub_ext2_data *data;
494 data = grub_malloc (sizeof (struct grub_ext2_data));
495 if (!data)
496 return 0;
498 /* Read the superblock. */
499 grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_ext2_sblock),
500 (char *) &data->sblock);
501 if (grub_errno)
502 goto fail;
504 /* Make sure this is an ext2 filesystem. */
505 if (grub_le_to_cpu16 (data->sblock.magic) != EXT2_MAGIC)
506 goto fail;
508 data->disk = disk;
510 data->diropen.data = data;
511 data->diropen.ino = 2;
512 data->diropen.inode_read = 1;
514 data->inode = &data->diropen.inode;
516 grub_ext2_read_inode (data, 2, data->inode);
517 if (grub_errno)
518 goto fail;
520 return data;
522 fail:
523 grub_error (GRUB_ERR_BAD_FS, "not an ext2 filesystem");
524 grub_free (data);
525 return 0;
528 static char *
529 grub_ext2_read_symlink (grub_fshelp_node_t node)
531 char *symlink;
532 struct grub_fshelp_node *diro = node;
534 if (! diro->inode_read)
536 grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
537 if (grub_errno)
538 return 0;
541 symlink = grub_malloc (grub_le_to_cpu32 (diro->inode.size) + 1);
542 if (! symlink)
543 return 0;
545 /* If the filesize of the symlink is bigger than
546 60 the symlink is stored in a separate block,
547 otherwise it is stored in the inode. */
548 if (grub_le_to_cpu32 (diro->inode.size) <= 60)
549 grub_strncpy (symlink,
550 diro->inode.symlink,
551 grub_le_to_cpu32 (diro->inode.size));
552 else
554 grub_ext2_read_file (diro, 0, 0,
555 grub_le_to_cpu32 (diro->inode.size),
556 symlink);
557 if (grub_errno)
559 grub_free (symlink);
560 return 0;
564 symlink[grub_le_to_cpu32 (diro->inode.size)] = '\0';
565 return symlink;
568 static int
569 grub_ext2_iterate_dir (grub_fshelp_node_t dir,
570 int NESTED_FUNC_ATTR
571 (*hook) (const char *filename,
572 enum grub_fshelp_filetype filetype,
573 grub_fshelp_node_t node))
575 unsigned int fpos = 0;
576 struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
578 if (! diro->inode_read)
580 grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
581 if (grub_errno)
582 return 0;
585 /* Search the file. */
586 while (fpos < grub_le_to_cpu32 (diro->inode.size))
588 struct ext2_dirent dirent;
590 grub_ext2_read_file (diro, 0, fpos, sizeof (struct ext2_dirent),
591 (char *) &dirent);
592 if (grub_errno)
593 return 0;
595 if (dirent.namelen != 0)
597 char filename[dirent.namelen + 1];
598 struct grub_fshelp_node *fdiro;
599 enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
601 grub_ext2_read_file (diro, 0, fpos + sizeof (struct ext2_dirent),
602 dirent.namelen, filename);
603 if (grub_errno)
604 return 0;
606 fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
607 if (! fdiro)
608 return 0;
610 fdiro->data = diro->data;
611 fdiro->ino = grub_le_to_cpu32 (dirent.inode);
613 filename[dirent.namelen] = '\0';
615 if (dirent.filetype != FILETYPE_UNKNOWN)
617 fdiro->inode_read = 0;
619 if (dirent.filetype == FILETYPE_DIRECTORY)
620 type = GRUB_FSHELP_DIR;
621 else if (dirent.filetype == FILETYPE_SYMLINK)
622 type = GRUB_FSHELP_SYMLINK;
623 else if (dirent.filetype == FILETYPE_REG)
624 type = GRUB_FSHELP_REG;
626 else
628 /* The filetype can not be read from the dirent, read
629 the inode to get more information. */
630 grub_ext2_read_inode (diro->data,
631 grub_le_to_cpu32 (dirent.inode),
632 &fdiro->inode);
633 if (grub_errno)
635 grub_free (fdiro);
636 return 0;
639 fdiro->inode_read = 1;
641 if ((grub_le_to_cpu16 (fdiro->inode.mode)
642 & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
643 type = GRUB_FSHELP_DIR;
644 else if ((grub_le_to_cpu16 (fdiro->inode.mode)
645 & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
646 type = GRUB_FSHELP_SYMLINK;
647 else if ((grub_le_to_cpu16 (fdiro->inode.mode)
648 & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
649 type = GRUB_FSHELP_REG;
652 if (hook (filename, type, fdiro))
653 return 1;
656 fpos += grub_le_to_cpu16 (dirent.direntlen);
659 return 0;
662 /* Open a file named NAME and initialize FILE. */
663 static grub_err_t
664 grub_ext2_open (struct grub_file *file, const char *name)
666 struct grub_ext2_data *data;
667 struct grub_fshelp_node *fdiro = 0;
669 #ifndef GRUB_UTIL
670 grub_dl_ref (my_mod);
671 #endif
673 data = grub_ext2_mount (file->device->disk);
674 if (! data)
675 goto fail;
677 grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_ext2_iterate_dir,
678 grub_ext2_read_symlink, GRUB_FSHELP_REG);
679 if (grub_errno)
680 goto fail;
682 if (! fdiro->inode_read)
684 grub_ext2_read_inode (data, fdiro->ino, &fdiro->inode);
685 if (grub_errno)
686 goto fail;
689 grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_ext2_inode));
690 grub_free (fdiro);
692 file->size = grub_le_to_cpu32 (data->inode->size);
693 file->data = data;
694 file->offset = 0;
696 return 0;
698 fail:
699 if (fdiro != &data->diropen)
700 grub_free (fdiro);
701 grub_free (data);
703 #ifndef GRUB_UTIL
704 grub_dl_unref (my_mod);
705 #endif
707 return grub_errno;
710 static grub_err_t
711 grub_ext2_close (grub_file_t file)
713 grub_free (file->data);
715 #ifndef GRUB_UTIL
716 grub_dl_unref (my_mod);
717 #endif
719 return GRUB_ERR_NONE;
722 /* Read LEN bytes data from FILE into BUF. */
723 static grub_ssize_t
724 grub_ext2_read (grub_file_t file, char *buf, grub_size_t len)
726 struct grub_ext2_data *data = (struct grub_ext2_data *) file->data;
728 return grub_ext2_read_file (&data->diropen, file->read_hook,
729 file->offset, len, buf);
733 static grub_err_t
734 grub_ext2_dir (grub_device_t device, const char *path,
735 int (*hook) (const char *filename, int dir))
737 struct grub_ext2_data *data = 0;;
738 struct grub_fshelp_node *fdiro = 0;
740 auto int NESTED_FUNC_ATTR iterate (const char *filename,
741 enum grub_fshelp_filetype filetype,
742 grub_fshelp_node_t node);
744 int NESTED_FUNC_ATTR iterate (const char *filename,
745 enum grub_fshelp_filetype filetype,
746 grub_fshelp_node_t node)
748 grub_free (node);
750 if (filetype == GRUB_FSHELP_DIR)
751 return hook (filename, 1);
752 else
753 return hook (filename, 0);
755 return 0;
758 #ifndef GRUB_UTIL
759 grub_dl_ref (my_mod);
760 #endif
762 data = grub_ext2_mount (device->disk);
763 if (! data)
764 goto fail;
766 grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_ext2_iterate_dir,
767 grub_ext2_read_symlink, GRUB_FSHELP_DIR);
768 if (grub_errno)
769 goto fail;
771 grub_ext2_iterate_dir (fdiro, iterate);
773 fail:
774 if (fdiro != &data->diropen)
775 grub_free (fdiro);
776 grub_free (data);
778 #ifndef GRUB_UTIL
779 grub_dl_unref (my_mod);
780 #endif
782 return grub_errno;
785 static grub_err_t
786 grub_ext2_label (grub_device_t device, char **label)
788 struct grub_ext2_data *data;
789 grub_disk_t disk = device->disk;
791 #ifndef GRUB_UTIL
792 grub_dl_ref (my_mod);
793 #endif
795 data = grub_ext2_mount (disk);
796 if (data)
797 *label = grub_strndup (data->sblock.volume_name, 14);
798 else
799 *label = NULL;
801 #ifndef GRUB_UTIL
802 grub_dl_unref (my_mod);
803 #endif
805 grub_free (data);
807 return grub_errno;
810 static grub_err_t
811 grub_ext2_uuid (grub_device_t device, char **uuid)
813 struct grub_ext2_data *data;
814 grub_disk_t disk = device->disk;
816 #ifndef GRUB_UTIL
817 grub_dl_ref (my_mod);
818 #endif
820 data = grub_ext2_mount (disk);
821 if (data)
823 *uuid = grub_malloc (40 + sizeof ('\0'));
824 grub_sprintf (*uuid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
825 grub_be_to_cpu16 (data->sblock.uuid[0]), grub_be_to_cpu16 (data->sblock.uuid[1]),
826 grub_be_to_cpu16 (data->sblock.uuid[2]), grub_be_to_cpu16 (data->sblock.uuid[3]),
827 grub_be_to_cpu16 (data->sblock.uuid[4]), grub_be_to_cpu16 (data->sblock.uuid[5]),
828 grub_be_to_cpu16 (data->sblock.uuid[6]), grub_be_to_cpu16 (data->sblock.uuid[7]));
830 else
831 *uuid = NULL;
833 #ifndef GRUB_UTIL
834 grub_dl_unref (my_mod);
835 #endif
837 grub_free (data);
839 return grub_errno;
843 static struct grub_fs grub_ext2_fs =
845 .name = "ext2",
846 .dir = grub_ext2_dir,
847 .open = grub_ext2_open,
848 .read = grub_ext2_read,
849 .close = grub_ext2_close,
850 .label = grub_ext2_label,
851 .uuid = grub_ext2_uuid,
852 .next = 0
855 GRUB_MOD_INIT(ext2)
857 grub_fs_register (&grub_ext2_fs);
858 #ifndef GRUB_UTIL
859 my_mod = mod;
860 #endif
863 GRUB_MOD_FINI(ext2)
865 grub_fs_unregister (&grub_ext2_fs);