]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - lib/ext2fs/initialize.c
Many files:
[thirdparty/e2fsprogs.git] / lib / ext2fs / initialize.c
1 /*
2 * initialize.c --- initialize a filesystem handle given superblock
3 * parameters. Used by mke2fs when initializing a filesystem.
4 */
5
6 #include <stdio.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <fcntl.h>
11 #include <time.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14
15 #include <linux/ext2_fs.h>
16
17 #include "ext2fs.h"
18
19 errcode_t ext2fs_initialize(const char *name, int flags,
20 struct ext2_super_block *param,
21 io_manager manager, ext2_filsys *ret_fs)
22 {
23 ext2_filsys fs;
24 errcode_t retval;
25 struct ext2_super_block *super;
26 int frags_per_block;
27 int rem;
28 int overhead = 0;
29 blk_t group_block;
30 int i, j;
31 int numblocks;
32 char *buf;
33
34 if (!param || !param->s_blocks_count)
35 return EINVAL;
36
37 fs = (ext2_filsys) malloc(sizeof(struct struct_ext2_filsys));
38 if (!fs)
39 return ENOMEM;
40
41 memset(fs, 0, sizeof(struct struct_ext2_filsys));
42 fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
43 fs->flags = flags | EXT2_FLAG_RW;
44 retval = manager->open(name, IO_FLAG_RW, &fs->io);
45 if (retval)
46 goto cleanup;
47 fs->device_name = malloc(strlen(name)+1);
48 if (!fs->device_name) {
49 retval = ENOMEM;
50 goto cleanup;
51 }
52 strcpy(fs->device_name, name);
53 fs->super = super = malloc(SUPERBLOCK_SIZE);
54 if (!super) {
55 retval = ENOMEM;
56 goto cleanup;
57 }
58 memset(super, 0, SUPERBLOCK_SIZE);
59
60 #define set_field(field, default) (super->field = param->field ? \
61 param->field : (default))
62
63 super->s_magic = EXT2_SUPER_MAGIC;
64 super->s_state = EXT2_VALID_FS;
65
66 set_field(s_log_block_size, 0); /* default blocksize: 1024 bytes */
67 set_field(s_log_frag_size, 0); /* default fragsize: 1024 bytes */
68 set_field(s_first_data_block, super->s_log_block_size ? 0 : 1);
69 set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT);
70 set_field(s_errors, EXT2_ERRORS_DEFAULT);
71
72 set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL);
73 super->s_lastcheck = time(NULL);
74
75 #ifdef EXT2_OS_LINUX
76 super->s_creator_os = EXT2_OS_LINUX;
77 #endif
78
79 fs->blocksize = EXT2_BLOCK_SIZE(super);
80 fs->fragsize = EXT2_FRAG_SIZE(super);
81 frags_per_block = fs->blocksize / fs->fragsize;
82
83 set_field(s_blocks_per_group, 8192); /* default: 8192 blocks/group */
84 super->s_frags_per_group = super->s_blocks_per_group * frags_per_block;
85
86 super->s_blocks_count = param->s_blocks_count;
87 super->s_r_blocks_count = param->s_r_blocks_count;
88 if (super->s_r_blocks_count >= param->s_blocks_count) {
89 retval = EINVAL;
90 goto cleanup;
91 }
92
93 retry:
94 fs->group_desc_count = (super->s_blocks_count -
95 super->s_first_data_block +
96 EXT2_BLOCKS_PER_GROUP(super) - 1)
97 / EXT2_BLOCKS_PER_GROUP(super);
98 fs->desc_blocks = (fs->group_desc_count +
99 EXT2_DESC_PER_BLOCK(super) - 1)
100 / EXT2_DESC_PER_BLOCK(super);
101
102 set_field(s_inodes_count, (super->s_blocks_count*fs->blocksize)/4096);
103
104 /*
105 * There should be at least as many inodes as the user
106 * requested. Figure out how many inodes per group that
107 * should be.
108 */
109 super->s_inodes_per_group = (super->s_inodes_count +
110 fs->group_desc_count - 1) /
111 fs->group_desc_count;
112
113 /*
114 * Make sure the number of inodes per group completely fills
115 * the inode table blocks in the descriptor. If not, add some
116 * additional inodes/group. Waste not, want not...
117 */
118 fs->inode_blocks_per_group = (super->s_inodes_per_group +
119 EXT2_INODES_PER_BLOCK(super) - 1) /
120 EXT2_INODES_PER_BLOCK(super);
121 super->s_inodes_per_group = fs->inode_blocks_per_group *
122 EXT2_INODES_PER_BLOCK(super);
123
124 /*
125 * adjust inode count to reflect the adjusted inodes_per_group
126 */
127 super->s_inodes_count = super->s_inodes_per_group *
128 fs->group_desc_count;
129 super->s_free_inodes_count = super->s_inodes_count;
130
131 /*
132 * Overhead is the number of bookkeeping blocks per group. It
133 * includes the superblock backup, the group descriptor
134 * backups, the inode bitmap, the block bitmap, and the inode
135 * table.
136 */
137 overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
138 super->s_free_blocks_count = super->s_blocks_count -
139 super->s_first_data_block - (overhead*fs->group_desc_count);
140
141 /*
142 * See if the last group is big enough to support the
143 * necessary data structures. If not, we need to get rid of
144 * it.
145 */
146 rem = (super->s_blocks_count - super->s_first_data_block) %
147 super->s_blocks_per_group;
148 if ((fs->group_desc_count == 1) && rem && (rem < overhead))
149 return EXT2_ET_TOOSMALL;
150 if (rem && (rem < overhead+50)) {
151 super->s_blocks_count -= rem;
152 goto retry;
153 }
154
155 /*
156 * At this point we know how big the filesystem will be. So
157 * we can do any and all allocations that depend on the block
158 * count.
159 */
160
161 buf = malloc(strlen(fs->device_name) + 80);
162 if (!buf) {
163 retval = ENOMEM;
164 goto cleanup;
165 }
166
167 sprintf(buf, "block bitmap for %s", fs->device_name);
168 retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
169 if (retval)
170 goto cleanup;
171
172 sprintf(buf, "inode bitmap for %s", fs->device_name);
173 retval = ext2fs_allocate_inode_bitmap(fs, 0, &fs->inode_map);
174 if (retval)
175 goto cleanup;
176
177 free(buf);
178
179 fs->group_desc = malloc(fs->desc_blocks * fs->blocksize);
180 if (!fs->group_desc) {
181 retval = ENOMEM;
182 goto cleanup;
183 }
184 memset(fs->group_desc, 0, fs->desc_blocks * fs->blocksize);
185
186 /*
187 * Reserve the superblock and group descriptors for each
188 * group, and fill in the correct group statistics for group.
189 * Note that although the block bitmap, inode bitmap, and
190 * inode table have not been allocated (and in fact won't be
191 * by this routine), they are accounted for nevertheless.
192 */
193 group_block = super->s_first_data_block;
194 for (i = 0; i < fs->group_desc_count; i++) {
195 for (j=0; j < fs->desc_blocks+1; j++)
196 ext2fs_mark_block_bitmap(fs->block_map,
197 group_block + j);
198
199 if (i == fs->group_desc_count-1) {
200 numblocks = (fs->super->s_blocks_count -
201 fs->super->s_first_data_block) %
202 fs->super->s_blocks_per_group;
203 if (!numblocks)
204 numblocks = fs->super->s_blocks_per_group;
205 } else
206 numblocks = fs->super->s_blocks_per_group;
207 numblocks -= 3 + fs->desc_blocks + fs->inode_blocks_per_group;
208
209 fs->group_desc[i].bg_free_blocks_count = numblocks;
210 fs->group_desc[i].bg_free_inodes_count =
211 fs->super->s_inodes_per_group;
212 fs->group_desc[i].bg_used_dirs_count = 0;
213
214 group_block += super->s_blocks_per_group;
215 }
216
217 ext2fs_mark_super_dirty(fs);
218 ext2fs_mark_bb_dirty(fs);
219 ext2fs_mark_ib_dirty(fs);
220
221 io_channel_set_blksize(fs->io, fs->blocksize);
222
223 *ret_fs = fs;
224 return 0;
225 cleanup:
226 ext2fs_free(fs);
227 return retval;
228 }
229
230
231