1 /* ext2.c - Second Extended filesystem */
3 * PUPA -- Preliminary Universal Programming Architecture for GRUB
4 * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
6 * This program 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 2 of the License, or
9 * (at your option) any later version.
11 * This program 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 this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* Magic value used to identify an ext2 filesystem. */
22 #define EXT2_MAGIC 0xEF53
23 /* Amount of indirect blocks in an inode. */
24 #define INDIRECT_BLOCKS 12
25 /* Maximum lenght of a pathname. */
26 #define EXT2_PATH_MAX 4096
27 /* Maximum nesting of symlinks, used to prevent a loop. */
28 #define EXT2_MAX_SYMLINKCNT 8
30 /* Filetype used in directory entry. */
31 #define FILETYPE_DIRECTORY 2
32 #define FILETYPE_SYMLINK 7
35 #include <pupa/file.h>
37 #include <pupa/misc.h>
38 #include <pupa/disk.h>
40 #include <pupa/types.h>
42 /* Log2 size of ext2 block in 512 blocks. */
43 #define LOG2_EXT2_BLOCK_SIZE(data) \
44 (pupa_le_to_cpu32 (data->sblock.log2_block_size) + 1)
46 /* Log2 size of ext2 block in bytes. */
47 #define LOG2_BLOCK_SIZE(data) \
48 (pupa_le_to_cpu32 (data->sblock.log2_block_size) + 10)
50 /* The size of an ext2 block in bytes. */
51 #define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE(data))
53 /* The ext2 superblock. */
54 struct pupa_ext_sblock
56 pupa_uint32_t total_inodes
;
57 pupa_uint32_t total_blocks
;
58 pupa_uint32_t reserved_blocks
;
59 pupa_uint32_t free_blocks
;
60 pupa_uint32_t free_inodes
;
61 pupa_uint32_t first_data_block
;
62 pupa_uint32_t log2_block_size
;
63 pupa_uint32_t log2_fragment_size
;
64 pupa_uint32_t blocks_per_group
;
65 pupa_uint32_t fragments_per_group
;
66 pupa_uint32_t inodes_per_group
;
69 pupa_uint16_t mnt_count
;
70 pupa_uint16_t max_mnt_count
;
72 pupa_uint16_t fs_state
;
73 pupa_uint16_t error_handling
;
74 pupa_uint16_t minor_revision_level
;
75 pupa_uint32_t lastcheck
;
76 pupa_uint32_t checkinterval
;
77 pupa_uint32_t creator_os
;
78 pupa_uint32_t revision_level
;
79 pupa_uint16_t uid_reserved
;
80 pupa_uint16_t gid_reserved
;
81 pupa_uint32_t first_inode
;
82 pupa_uint16_t inode_size
;
83 pupa_uint16_t block_group_number
;
84 pupa_uint32_t feature_compatibility
;
85 pupa_uint32_t feature_incompat
;
86 pupa_uint32_t feature_ro_compat
;
87 pupa_uint32_t unique_id
[4];
89 char last_mounted_on
[64];
90 pupa_uint32_t compression_info
;
93 /* The ext2 blockgroup. */
94 struct ext2_block_group
96 pupa_uint32_t block_id
;
97 pupa_uint32_t inode_id
;
98 pupa_uint32_t inode_table_id
;
99 pupa_uint16_t free_blocks
;
100 pupa_uint16_t free_inodes
;
102 pupa_uint32_t reserved
[3];
105 /* The ext2 inode. */
106 struct pupa_ext2_inode
116 pupa_uint16_t nlinks
;
117 pupa_uint32_t blockcnt
; /* Blocks of 512 bytes!! */
124 pupa_uint32_t dir_blocks
[INDIRECT_BLOCKS
];
125 pupa_uint32_t indir_block
;
126 pupa_uint32_t double_indir_block
;
127 pupa_uint32_t tripple_indir_block
;
131 pupa_uint32_t version
;
133 pupa_uint32_t dir_acl
;
134 pupa_uint32_t fragment_addr
;
135 pupa_uint32_t osd2
[3];
138 /* The header of an ext2 directory entry. */
142 pupa_uint16_t direntlen
;
143 pupa_uint8_t namelen
;
144 pupa_uint8_t filetype
;
147 /* Information about a "mounted" ext2 filesystem. */
148 struct pupa_ext2_data
150 struct pupa_ext_sblock sblock
;
152 struct pupa_ext2_inode inode
;
156 static pupa_dl_t my_mod
;
159 /* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
160 the mounted filesystem DATA. */
161 inline static pupa_err_t
162 pupa_ext2_blockgroup (struct pupa_ext2_data
*data
, int group
,
163 struct ext2_block_group
*blkgrp
)
165 return pupa_disk_read (data
->disk
,
166 ((pupa_le_to_cpu32 (data
->sblock
.first_data_block
) + 1)
167 << LOG2_EXT2_BLOCK_SIZE (data
)),
168 group
* sizeof (struct ext2_block_group
),
169 sizeof (struct ext2_block_group
), (char *) blkgrp
);
172 /* Return in BLOCK the on disk block number of block FILEBLOCK in the
173 opened file descibed by DATA. If this block is not stored on disk
174 in case of a sparse file return 0. */
176 pupa_ext2_get_file_block (struct pupa_ext2_data
*data
,
177 int fileblock
, int *block
)
180 struct pupa_ext2_inode
*inode
= &data
->inode
;
183 if (fileblock
< INDIRECT_BLOCKS
)
184 blknr
= pupa_le_to_cpu32 (inode
->blocks
.dir_blocks
[fileblock
]);
186 else if (fileblock
< INDIRECT_BLOCKS
+ EXT2_BLOCK_SIZE (data
) / 4)
188 pupa_uint32_t indir
[EXT2_BLOCK_SIZE (data
) / 4];
190 if (pupa_disk_read (data
->disk
,
191 pupa_le_to_cpu32 (inode
->blocks
.indir_block
)
192 << LOG2_EXT2_BLOCK_SIZE (data
),
193 0, EXT2_BLOCK_SIZE (data
), (char *) indir
))
196 blknr
= pupa_le_to_cpu32 (indir
[fileblock
- INDIRECT_BLOCKS
]);
198 /* Double indirect. */
199 else if (fileblock
< INDIRECT_BLOCKS
+ EXT2_BLOCK_SIZE (data
) / 4
200 * (EXT2_BLOCK_SIZE (data
) / 4 + 1))
202 unsigned int perblock
= EXT2_BLOCK_SIZE (data
) / 4;
203 unsigned int rblock
= fileblock
- (INDIRECT_BLOCKS
204 + EXT2_BLOCK_SIZE (data
) / 4);
205 pupa_uint32_t indir
[EXT2_BLOCK_SIZE (data
) / 4];
207 if (pupa_disk_read (data
->disk
,
208 pupa_le_to_cpu32 (inode
->blocks
.double_indir_block
)
209 << LOG2_EXT2_BLOCK_SIZE (data
),
210 0, EXT2_BLOCK_SIZE (data
), (char *) indir
))
213 if (pupa_disk_read (data
->disk
,
214 pupa_le_to_cpu32 (indir
[rblock
/ perblock
])
215 << LOG2_EXT2_BLOCK_SIZE (data
),
216 0, EXT2_BLOCK_SIZE (data
), (char *) indir
))
220 blknr
= pupa_le_to_cpu32 (indir
[rblock
% perblock
]);
222 /* Tripple indirect. */
225 pupa_error (PUPA_ERR_NOT_IMPLEMENTED_YET
,
226 "ext2fs doesn't support tripple indirect blocks");
235 /* Read LEN bytes from the file described by DATA starting with byte
236 POS. Return the amount of read bytes in READ. */
238 pupa_ext2_read_file (struct pupa_ext2_data
*data
,
239 void (*read_hook
) (unsigned long sector
,
240 unsigned offset
, unsigned length
),
241 int pos
, unsigned int len
, char *buf
)
246 /* Adjust len so it we can't read past the end of the file. */
247 if (len
> pupa_le_to_cpu32 (data
->inode
.size
))
248 len
= pupa_le_to_cpu32 (data
->inode
.size
);
250 blockcnt
= ((len
+ pos
)
251 + EXT2_BLOCK_SIZE (data
) - 1) / EXT2_BLOCK_SIZE (data
);
253 for (i
= pos
/ EXT2_BLOCK_SIZE (data
); i
< blockcnt
; i
++)
256 int blockoff
= pos
% EXT2_BLOCK_SIZE (data
);
257 int blockend
= EXT2_BLOCK_SIZE (data
);
261 pupa_ext2_get_file_block (data
, i
, &blknr
);
265 blknr
= blknr
<< LOG2_EXT2_BLOCK_SIZE (data
);
268 if (i
== blockcnt
- 1)
270 blockend
= (len
+ pos
) % EXT2_BLOCK_SIZE (data
);
272 /* The last portion is exactly EXT2_BLOCK_SIZE (data). */
274 blockend
= EXT2_BLOCK_SIZE (data
);
278 if (i
== pos
/ EXT2_BLOCK_SIZE (data
))
280 skipfirst
= blockoff
;
281 blockend
-= skipfirst
;
284 /* If the block number is 0 this block is not stored on disk but
285 is zero filled instead. */
288 data
->disk
->read_hook
= read_hook
;
289 pupa_disk_read (data
->disk
, blknr
, skipfirst
,
291 data
->disk
->read_hook
= 0;
296 pupa_memset (buf
, EXT2_BLOCK_SIZE (data
) - skipfirst
, 0);
298 buf
+= EXT2_BLOCK_SIZE (data
) - skipfirst
;
305 /* Read the inode INO for the file described by DATA into INODE. */
307 pupa_ext2_read_inode (struct pupa_ext2_data
*data
,
308 int ino
, struct pupa_ext2_inode
*inode
)
310 struct ext2_block_group blkgrp
;
311 struct pupa_ext_sblock
*sblock
= &data
->sblock
;
312 int inodes_per_block
;
317 /* It is easier to calculate if the first inode is 0. */
320 pupa_ext2_blockgroup (data
, ino
/ pupa_le_to_cpu32 (sblock
->inodes_per_group
),
325 inodes_per_block
= EXT2_BLOCK_SIZE (data
) / 128;
326 blkno
= (ino
% pupa_le_to_cpu32 (sblock
->inodes_per_group
))
328 blkoff
= (ino
% pupa_le_to_cpu32 (sblock
->inodes_per_group
))
331 /* Read the inode. */
332 if (pupa_disk_read (data
->disk
,
333 ((pupa_le_to_cpu32 (blkgrp
.inode_table_id
) + blkno
)
334 << LOG2_EXT2_BLOCK_SIZE (data
)),
335 sizeof (struct pupa_ext2_inode
) * blkoff
,
336 sizeof (struct pupa_ext2_inode
), (char *) inode
))
342 static struct pupa_ext2_data
*
343 pupa_ext2_mount (pupa_disk_t disk
)
345 struct pupa_ext2_data
*data
;
347 data
= pupa_malloc (sizeof (struct pupa_ext2_data
));
351 /* Read the superblock. */
352 pupa_disk_read (disk
, 1 * 2, 0, sizeof (struct pupa_ext_sblock
),
353 (char *) &data
->sblock
);
357 /* Make sure this is an ext2 filesystem. */
358 if (pupa_le_to_cpu16 (data
->sblock
.magic
) != EXT2_MAGIC
)
365 pupa_error (PUPA_ERR_BAD_FS
, "not an ext2 filesystem");
370 /* Find the file with the pathname PATH on the filesystem described by
371 DATA. Return its inode number in INO. */
373 pupa_ext2_find_file (struct pupa_ext2_data
*data
, const char *path
, int *ino
)
375 int blocksize
= EXT2_BLOCK_SIZE (data
)
376 << pupa_le_to_cpu32 (data
->sblock
.log2_block_size
);
377 struct pupa_ext2_inode
*inode
= &data
->inode
;
381 char fpath
[EXT2_PATH_MAX
];
384 pupa_strncpy (fpath
, path
, EXT2_PATH_MAX
);
386 if (!name
|| name
[0] != '/')
388 pupa_error (PUPA_ERR_BAD_FILENAME
, "bad filename");
392 /* Skip the first slash. */
400 /* Remove trailing "/". */
401 if (name
[pupa_strlen (name
) - 1] =='/')
402 name
[pupa_strlen (name
) - 1] = '\0';
406 unsigned int fpos
= 0;
410 /* Extract the actual part from the pathname. */
411 next
= pupa_strchr (name
, '/');
418 namesize
= pupa_strlen (name
);
421 pupa_ext2_read_inode (data
, currinode
, inode
);
425 /* Search the file. */
426 while (fpos
< pupa_le_to_cpu32 (inode
->size
))
428 struct ext2_dirent dirent
;
430 /* Read the directory entry. */
431 pupa_ext2_read_file (data
, 0, fpos
, sizeof (struct ext2_dirent
),
436 if (dirent
.namelen
!= 0)
438 char filename
[dirent
.namelen
+ 1];
440 /* Read the filename part of this directory entry. */
441 pupa_ext2_read_file (data
, 0, fpos
442 + sizeof (struct ext2_dirent
),
443 dirent
.namelen
, filename
);
447 filename
[dirent
.namelen
] = '\0';
449 /* Check if the current directory entry described the
450 file we are looking for. */
451 if (dirent
.namelen
== namesize
452 && !pupa_strncmp (name
, filename
, namesize
))
454 /* If this is a symlink, follow it. */
455 if (dirent
.filetype
== FILETYPE_SYMLINK
)
457 /* XXX: Use malloc instead? */
458 char symlink
[blocksize
];
460 if (++symlinkcnt
== EXT2_MAX_SYMLINKCNT
)
462 pupa_error (PUPA_ERR_SYMLINK_LOOP
,
463 "too deep nesting of symlinks");
467 /* Read the symlink. */
468 pupa_ext2_read_inode (data
,
469 pupa_le_to_cpu32 (dirent
.inode
),
472 /* If the filesize of the symlink is bigger than
473 60 the symlink is stored in a separate block,
474 otherwise it is stored in the inode. */
475 if (pupa_le_to_cpu32 (inode
->size
) <= 60)
476 pupa_strncpy (symlink
,
478 pupa_le_to_cpu32 (inode
->size
));
481 pupa_ext2_read_file (data
, 0, 0,
482 pupa_le_to_cpu32 (inode
->size
),
488 symlink
[pupa_le_to_cpu32 (inode
->size
)] = '\0';
490 /* Check if the symlink is absolute or relative. */
491 if (symlink
[0] == '/')
493 pupa_strncpy (fpath
, symlink
, EXT2_PATH_MAX
);
503 bak
= pupa_strdup (next
);
508 /* Relative symlink, construct the new path. */
509 pupa_strcpy (fpath
, symlink
);
514 pupa_strcat (name
, "/");
515 pupa_strcat (name
, bak
);
526 currinode
= pupa_le_to_cpu32 (dirent
.inode
);
529 if (dirent
.filetype
!= FILETYPE_DIRECTORY
)
531 pupa_error (PUPA_ERR_BAD_FILE_TYPE
,
539 *ino
= pupa_le_to_cpu32 (dirent
.inode
);
545 /* Move to next directory entry. */
546 fpos
+= pupa_le_to_cpu16 (dirent
.direntlen
);
549 /* The complete directory was read and no matching file was
551 if (fpos
>= pupa_le_to_cpu32 (inode
->size
))
553 pupa_error (PUPA_ERR_FILE_NOT_FOUND
, "file not found");
562 /* Open a file named NAME and initialize FILE. */
564 pupa_ext2_open (struct pupa_file
*file
, const char *name
)
566 struct pupa_ext2_data
*data
;
570 pupa_dl_ref (my_mod
);
573 data
= pupa_ext2_mount (file
->device
->disk
);
577 pupa_ext2_find_file (data
, name
, &ino
);
581 pupa_ext2_read_inode (data
, ino
, &data
->inode
);
585 if (!(pupa_le_to_cpu16 (data
->inode
.mode
) & 0100000))
587 pupa_error (PUPA_ERR_BAD_FILE_TYPE
, "not a regular file");
591 file
->size
= pupa_le_to_cpu32 (data
->inode
.size
);
602 pupa_dl_unref (my_mod
);
609 pupa_ext2_close (pupa_file_t file
)
611 pupa_free (file
->data
);
614 pupa_dl_unref (my_mod
);
617 return PUPA_ERR_NONE
;
620 /* Read LEN bytes data from FILE into BUF. */
622 pupa_ext2_read (pupa_file_t file
, char *buf
, pupa_ssize_t len
)
624 struct pupa_ext2_data
*data
=
625 (struct pupa_ext2_data
*) file
->data
;
627 return pupa_ext2_read_file (data
, file
->read_hook
, file
->offset
, len
, buf
);
632 pupa_ext2_dir (pupa_device_t device
, const char *path
,
633 int (*hook
) (const char *filename
, int dir
))
635 struct pupa_ext2_data
*data
= 0;;
638 unsigned int fpos
= 0;
641 pupa_dl_ref (my_mod
);
644 data
= pupa_ext2_mount (device
->disk
);
648 pupa_ext2_find_file (data
, (char *) path
, &ino
);
652 pupa_ext2_read_inode (data
, ino
, &data
->inode
);
656 if (!(pupa_le_to_cpu16 (data
->inode
.mode
) & 040000))
658 pupa_error (PUPA_ERR_BAD_FILE_TYPE
, "not a directory");
662 /* Search the file. */
663 while (fpos
< pupa_le_to_cpu32 (data
->inode
.size
))
665 struct ext2_dirent dirent
;
667 pupa_ext2_read_file (data
, 0, fpos
, sizeof (struct ext2_dirent
),
672 if (dirent
.namelen
!= 0)
674 char filename
[dirent
.namelen
+ 1];
676 pupa_ext2_read_file (data
, 0, fpos
+ sizeof (struct ext2_dirent
),
677 dirent
.namelen
, filename
);
681 filename
[dirent
.namelen
] = '\0';
683 hook (filename
, dirent
.filetype
== FILETYPE_DIRECTORY
);
686 fpos
+= pupa_le_to_cpu16 (dirent
.direntlen
);
694 pupa_dl_unref (my_mod
);
701 pupa_ext2_label (pupa_device_t device
, char **label
)
703 struct pupa_ext2_data
*data
;
704 pupa_disk_t disk
= device
->disk
;
707 pupa_dl_ref (my_mod
);
710 data
= pupa_ext2_mount (disk
);
712 *label
= pupa_strndup (data
->sblock
.volume_name
, 14);
717 pupa_dl_unref (my_mod
);
726 static struct pupa_fs pupa_ext2_fs
=
729 .dir
= pupa_ext2_dir
,
730 .open
= pupa_ext2_open
,
731 .read
= pupa_ext2_read
,
732 .close
= pupa_ext2_close
,
733 .label
= pupa_ext2_label
,
739 pupa_ext2_init (void)
741 pupa_fs_register (&pupa_ext2_fs
);
745 pupa_ext2_fini (void)
747 pupa_fs_unregister (&pupa_ext2_fs
);
749 #else /* ! PUPA_UTIL */
752 pupa_fs_register (&pupa_ext2_fs
);
758 pupa_fs_unregister (&pupa_ext2_fs
);
760 #endif /* ! PUPA_UTIL */