1 /* vi: set sw=4 ts=4: */
3 * openfs.c --- open an ext2 filesystem
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
8 * This file may be redistributed under the terms of the GNU Public
24 #include <sys/types.h>
33 blk_t
ext2fs_descriptor_block_loc(ext2_filsys fs
, blk_t group_block
, dgrp_t i
)
39 if (!(fs
->super
->s_feature_incompat
& EXT2_FEATURE_INCOMPAT_META_BG
) ||
40 (i
< fs
->super
->s_first_meta_bg
))
41 return (group_block
+ i
+ 1);
43 bg
= (fs
->blocksize
/ sizeof (struct ext2_group_desc
)) * i
;
44 if (ext2fs_bg_has_super(fs
, bg
))
46 ret_blk
= (fs
->super
->s_first_data_block
+ has_super
+
47 (bg
* fs
->super
->s_blocks_per_group
));
49 * If group_block is not the normal value, we're trying to use
50 * the backup group descriptors and superblock --- so use the
51 * alternate location of the second block group in the
52 * metablock group. Ideally we should be testing each bg
53 * descriptor block individually for correctness, but we don't
54 * have the infrastructure in place to do that.
56 if (group_block
!= fs
->super
->s_first_data_block
&&
57 ((ret_blk
+ fs
->super
->s_blocks_per_group
) <
58 fs
->super
->s_blocks_count
))
59 ret_blk
+= fs
->super
->s_blocks_per_group
;
63 errcode_t
ext2fs_open(const char *name
, int flags
, int superblock
,
64 unsigned int block_size
, io_manager manager
,
67 return ext2fs_open2(name
, 0, flags
, superblock
, block_size
,
72 * Note: if superblock is non-zero, block-size must also be non-zero.
73 * Superblock and block_size can be zero to use the default size.
75 * Valid flags for ext2fs_open()
77 * EXT2_FLAG_RW - Open the filesystem for read/write.
78 * EXT2_FLAG_FORCE - Open the filesystem even if some of the
79 * features aren't supported.
80 * EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
82 errcode_t
ext2fs_open2(const char *name
, const char *io_options
,
83 int flags
, int superblock
,
84 unsigned int block_size
, io_manager manager
,
90 int groups_per_block
, blocks_per_group
;
91 blk_t group_block
, blk
;
95 struct ext2_group_desc
*gdp
;
98 EXT2_CHECK_MAGIC(manager
, EXT2_ET_MAGIC_IO_MANAGER
);
100 retval
= ext2fs_get_mem(sizeof(struct struct_ext2_filsys
), &fs
);
104 memset(fs
, 0, sizeof(struct struct_ext2_filsys
));
105 fs
->magic
= EXT2_ET_MAGIC_EXT2FS_FILSYS
;
108 retval
= ext2fs_get_mem(strlen(name
)+1, &fs
->device_name
);
111 strcpy(fs
->device_name
, name
);
112 cp
= strchr(fs
->device_name
, '?');
113 if (!io_options
&& cp
) {
118 retval
= manager
->open(fs
->device_name
,
119 (flags
& EXT2_FLAG_RW
) ? IO_FLAG_RW
: 0,
124 (retval
= io_channel_set_options(fs
->io
, io_options
)))
126 fs
->image_io
= fs
->io
;
127 fs
->io
->app_data
= fs
;
128 retval
= ext2fs_get_mem(SUPERBLOCK_SIZE
, &fs
->super
);
131 if (flags
& EXT2_FLAG_IMAGE_FILE
) {
132 retval
= ext2fs_get_mem(sizeof(struct ext2_image_hdr
),
136 retval
= io_channel_read_blk(fs
->io
, 0,
137 -(int)sizeof(struct ext2_image_hdr
),
141 if (fs
->image_header
->magic_number
!= EXT2_ET_MAGIC_E2IMAGE
)
142 return EXT2_ET_MAGIC_E2IMAGE
;
144 block_size
= fs
->image_header
->fs_blocksize
;
148 * If the user specifies a specific block # for the
149 * superblock, then he/she must also specify the block size!
150 * Otherwise, read the master superblock located at offset
151 * SUPERBLOCK_OFFSET from the start of the partition.
153 * Note: we only save a backup copy of the superblock if we
154 * are reading the superblock from the primary superblock location.
158 retval
= EXT2_ET_INVALID_ARGUMENT
;
161 io_channel_set_blksize(fs
->io
, block_size
);
162 group_block
= superblock
;
165 io_channel_set_blksize(fs
->io
, SUPERBLOCK_OFFSET
);
168 retval
= ext2fs_get_mem(SUPERBLOCK_SIZE
, &fs
->orig_super
);
172 retval
= io_channel_read_blk(fs
->io
, superblock
, -SUPERBLOCK_SIZE
,
177 memcpy(fs
->orig_super
, fs
->super
, SUPERBLOCK_SIZE
);
180 if ((fs
->super
->s_magic
== ext2fs_swab16(EXT2_SUPER_MAGIC
)) ||
181 (fs
->flags
& EXT2_FLAG_SWAP_BYTES
)) {
182 fs
->flags
|= EXT2_FLAG_SWAP_BYTES
;
184 ext2fs_swap_super(fs
->super
);
188 if (fs
->super
->s_magic
!= EXT2_SUPER_MAGIC
) {
189 retval
= EXT2_ET_BAD_MAGIC
;
192 if (fs
->super
->s_rev_level
> EXT2_LIB_CURRENT_REV
) {
193 retval
= EXT2_ET_REV_TOO_HIGH
;
198 * Check for feature set incompatibility
200 if (!(flags
& EXT2_FLAG_FORCE
)) {
201 if (fs
->super
->s_feature_incompat
&
202 ~EXT2_LIB_FEATURE_INCOMPAT_SUPP
) {
203 retval
= EXT2_ET_UNSUPP_FEATURE
;
206 if ((flags
& EXT2_FLAG_RW
) &&
207 (fs
->super
->s_feature_ro_compat
&
208 ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP
)) {
209 retval
= EXT2_ET_RO_UNSUPP_FEATURE
;
212 if (!(flags
& EXT2_FLAG_JOURNAL_DEV_OK
) &&
213 (fs
->super
->s_feature_incompat
&
214 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
)) {
215 retval
= EXT2_ET_UNSUPP_FEATURE
;
220 fs
->blocksize
= EXT2_BLOCK_SIZE(fs
->super
);
221 if (fs
->blocksize
== 0) {
222 retval
= EXT2_ET_CORRUPT_SUPERBLOCK
;
225 fs
->fragsize
= EXT2_FRAG_SIZE(fs
->super
);
226 fs
->inode_blocks_per_group
= ((fs
->super
->s_inodes_per_group
*
227 EXT2_INODE_SIZE(fs
->super
) +
228 EXT2_BLOCK_SIZE(fs
->super
) - 1) /
229 EXT2_BLOCK_SIZE(fs
->super
));
231 if (block_size
!= fs
->blocksize
) {
232 retval
= EXT2_ET_UNEXPECTED_BLOCK_SIZE
;
237 * Set the blocksize to the filesystem's blocksize.
239 io_channel_set_blksize(fs
->io
, fs
->blocksize
);
242 * If this is an external journal device, don't try to read
243 * the group descriptors, because they're not there.
245 if (fs
->super
->s_feature_incompat
&
246 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
) {
247 fs
->group_desc_count
= 0;
253 * Read group descriptors
255 blocks_per_group
= EXT2_BLOCKS_PER_GROUP(fs
->super
);
256 if (blocks_per_group
== 0 ||
257 blocks_per_group
> EXT2_MAX_BLOCKS_PER_GROUP(fs
->super
) ||
258 fs
->inode_blocks_per_group
> EXT2_MAX_INODES_PER_GROUP(fs
->super
)) {
259 retval
= EXT2_ET_CORRUPT_SUPERBLOCK
;
262 fs
->group_desc_count
= (fs
->super
->s_blocks_count
-
263 fs
->super
->s_first_data_block
+
264 blocks_per_group
- 1) / blocks_per_group
;
265 fs
->desc_blocks
= (fs
->group_desc_count
+
266 EXT2_DESC_PER_BLOCK(fs
->super
) - 1)
267 / EXT2_DESC_PER_BLOCK(fs
->super
);
268 retval
= ext2fs_get_mem(fs
->desc_blocks
* fs
->blocksize
,
273 group_block
= fs
->super
->s_first_data_block
;
274 dest
= (char *) fs
->group_desc
;
275 groups_per_block
= fs
->blocksize
/ sizeof(struct ext2_group_desc
);
276 for (i
= 0; i
< fs
->desc_blocks
; i
++) {
277 blk
= ext2fs_descriptor_block_loc(fs
, group_block
, i
);
278 retval
= io_channel_read_blk(fs
->io
, blk
, 1, dest
);
282 if (fs
->flags
& EXT2_FLAG_SWAP_BYTES
) {
283 gdp
= (struct ext2_group_desc
*) dest
;
284 for (j
=0; j
< groups_per_block
; j
++)
285 ext2fs_swap_group_desc(gdp
++);
288 dest
+= fs
->blocksize
;
299 * Set/get the filesystem data I/O channel.
301 * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true.
303 errcode_t
ext2fs_get_data_io(ext2_filsys fs
, io_channel
*old_io
)
305 if ((fs
->flags
& EXT2_FLAG_IMAGE_FILE
) == 0)
306 return EXT2_ET_NOT_IMAGE_FILE
;
308 *old_io
= (fs
->image_io
== fs
->io
) ? 0 : fs
->io
;
313 errcode_t
ext2fs_set_data_io(ext2_filsys fs
, io_channel new_io
)
315 if ((fs
->flags
& EXT2_FLAG_IMAGE_FILE
) == 0)
316 return EXT2_ET_NOT_IMAGE_FILE
;
317 fs
->io
= new_io
? new_io
: fs
->image_io
;
321 errcode_t
ext2fs_rewrite_to_io(ext2_filsys fs
, io_channel new_io
)
323 if ((fs
->flags
& EXT2_FLAG_IMAGE_FILE
) == 0)
324 return EXT2_ET_NOT_IMAGE_FILE
;
325 fs
->io
= fs
->image_io
= new_io
;
326 fs
->flags
|= EXT2_FLAG_DIRTY
| EXT2_FLAG_RW
|
327 EXT2_FLAG_BB_DIRTY
| EXT2_FLAG_IB_DIRTY
;
328 fs
->flags
&= ~EXT2_FLAG_IMAGE_FILE
;