comparison toys/mke2fs.c @ 112:aadd28817955

Next iteration of mke2fs development.
author Rob Landley <rob@landley.net>
date Wed, 18 Apr 2007 21:39:46 -0400
parents c5b6fb1fe3a4
children 9cbb323f297f
comparison
equal deleted inserted replaced
111:a3b8838c3908 112:aadd28817955
7 7
8 #include "toys.h" 8 #include "toys.h"
9 9
10 #define TT toy.mke2fs 10 #define TT toy.mke2fs
11 11
12 // b - block size (1024, 2048, 4096)
13 // F - force (run on mounted device or non-block device)
14 // i - bytes per inode
15 // N - number of inodes
16 // m - reserved blocks percentage
17 // n - Don't write
18 // q - quiet
19
20 // L - volume label
21 // M - last mounted path
22 // o - creator os
23
24 // j - create journal
25 // J - journal options (size=1024-102400 blocks,device=)
26 // device=/dev/blah or LABEL=label UUID=uuid
27
28 // E - extended options (stride=stripe-size blocks)
29 // O - none,dir_index,filetype,has_journal,journal_dev,sparse_super
30
31 #define INODES_RESERVED 10 12 #define INODES_RESERVED 10
32 13
14 static uint32_t div_round_up(uint32_t a, uint32_t b)
15 {
16 uint32_t c = a/b;
17
18 if (a%b) c++;
19 return c;
20 }
21
33 // Calculate data blocks plus index blocks needed to hold a file. 22 // Calculate data blocks plus index blocks needed to hold a file.
34 23
35 static uint32_t count_blocks_used(uint64_t size) 24 static uint32_t file_blocks_used(uint64_t size, uint32_t *blocklist)
36 { 25 {
37 uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize); 26 uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize);
38 uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0; 27 uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0;
28
29 // Fill out index blocks.
30
31 if (blocklist) {
32 int i;
33
34 for (i=0; i<13 && i<dblocks; i++) blocklist[i] = i;
35 if (dblocks > 13+idx) blocklist[13] = 13+idx;
36 idx = 13 + idx + (idx*idx);
37 if (dblocks > idx) blocklist[14] = idx;
38
39 return 0;
40 }
39 41
40 // Account for direct, singly, doubly, and triply indirect index blocks 42 // Account for direct, singly, doubly, and triply indirect index blocks
41 43
42 if (dblocks > 12) { 44 if (dblocks > 12) {
43 iblocks = ((dblocks-13)/idx)+1; 45 iblocks = ((dblocks-13)/idx)+1;
49 } 51 }
50 52
51 return dblocks + iblocks + diblocks + tiblocks; 53 return dblocks + iblocks + diblocks + tiblocks;
52 } 54 }
53 55
54 // Calculate the number of blocks used by each inode. Returns blocks used, 56 // Use the parent pointer to iterate through the tree non-recursively.
55 // assigns bytes used to *size. Writes total block count to TT.treeblocks 57 static struct dirtree *treenext(struct dirtree *this)
56 // and inode count to TT.treeinodes. 58 {
59 while (this && !this->next) this = this->parent;
60 if (this) this = this->next;
61
62 return this;
63 }
64
65 // Recursively calculate the number of blocks used by each inode in the tree.
66 // Returns blocks used by this directory, assigns bytes used to *size.
67 // Writes total block count to TT.treeblocks and inode count to TT.treeinodes.
57 68
58 static long check_treesize(struct dirtree *this, off_t *size) 69 static long check_treesize(struct dirtree *this, off_t *size)
59 { 70 {
60 long blocks; 71 long blocks;
61 72
63 *size += sizeof(struct ext2_dentry) + strlen(this->name); 74 *size += sizeof(struct ext2_dentry) + strlen(this->name);
64 75
65 if (this->child) 76 if (this->child)
66 this->st.st_blocks = check_treesize(this->child, &this->st.st_size); 77 this->st.st_blocks = check_treesize(this->child, &this->st.st_size);
67 else if (S_ISREG(this->st.st_mode)) { 78 else if (S_ISREG(this->st.st_mode)) {
68 this->st.st_blocks = count_blocks_used(this->st.st_size); 79 this->st.st_blocks = file_blocks_used(this->st.st_size, 0);
69 TT.treeblocks += this->st.st_blocks; 80 TT.treeblocks += this->st.st_blocks;
70 } 81 }
71 this = this->next; 82 this = this->next;
72 } 83 }
73 TT.treeblocks += blocks = count_blocks_used(*size); 84 TT.treeblocks += blocks = file_blocks_used(*size, 0);
74 TT.treeinodes++; 85 TT.treeinodes++;
75 86
76 return blocks; 87 return blocks;
77 } 88 }
78 89
79 // Use the parent pointer to iterate through the tree non-recursively. 90 // Calculate inode numbers and link counts.
80 static struct dirtree *treenext(struct dirtree *this) 91 //
81 {
82 while (this && !this->next) this = this->parent;
83 if (this) this = this->next;
84
85 return this;
86 }
87
88 // To do this right I need to copy the tree and sort it, but here's a really 92 // To do this right I need to copy the tree and sort it, but here's a really
89 // ugly n^2 way of dealing with the problem that doesn't scale well to large 93 // ugly n^2 way of dealing with the problem that doesn't scale well to large
90 // numbers of files but can be done in very little code. 94 // numbers of files (> 100,000) but can be done in very little code.
91 95 // This rewrites inode numbers to their final values, allocating depth first.
92 static void check_treelinks(void) 96
93 { 97 static void check_treelinks(struct dirtree *tree)
94 struct dirtree *this, *that; 98 {
95 99 struct dirtree *this=tree, *that;
96 for (this = TT.dt; this; this = treenext(this)) { 100 long inode = INODES_RESERVED;
101
102 while (this) {
103 ++inode;
97 // Since we can't hardlink to directories, we know their link count. 104 // Since we can't hardlink to directories, we know their link count.
98 if (S_ISDIR(this->st.st_mode)) this->st.st_nlink = 2; 105 if (S_ISDIR(this->st.st_mode)) this->st.st_nlink = 2;
99 else { 106 else {
107 dev_t new = this->st.st_dev;
108
109 if (!new) continue;
110
100 this->st.st_nlink = 0; 111 this->st.st_nlink = 0;
101 for (that = TT.dt; that; that = treenext(that)) 112 for (that = tree; that; that = treenext(that)) {
102 if (this->st.st_ino == that->st.st_ino) 113 if (this->st.st_ino == that->st.st_ino &&
103 if (this->st.st_dev == that->st.st_dev) 114 this->st.st_dev == that->st.st_dev)
104 this->st.st_nlink++; 115 {
105 } 116 this->st.st_nlink++;
117 this->st.st_ino = inode;
118 }
119 }
120 }
121 this->st.st_ino = inode;
122 this = treenext(this);
106 } 123 }
107 } 124 }
108 125
109 // According to http://www.opengroup.org/onlinepubs/9629399/apdxa.htm 126 // According to http://www.opengroup.org/onlinepubs/9629399/apdxa.htm
110 // we should generate a uuid structure by reading a clock with 100 nanosecond 127 // we should generate a uuid structure by reading a clock with 100 nanosecond
112 // and looking up our eth0 mac address. 129 // and looking up our eth0 mac address.
113 // 130 //
114 // On the other hand, we have 128 bits to come up with a unique identifier, of 131 // On the other hand, we have 128 bits to come up with a unique identifier, of
115 // which 6 have a defined value. /dev/urandom it is. 132 // which 6 have a defined value. /dev/urandom it is.
116 133
117 static void create_uuid(char *uuid) 134 static void fake_uuid(char *uuid)
118 { 135 {
119 // Read 128 random bits 136 // Read 128 random bits
120 int fd = xopen("/dev/urandom", O_RDONLY); 137 int fd = xopen("/dev/urandom", O_RDONLY);
121 xreadall(fd, uuid, 16); 138 xreadall(fd, uuid, 16);
122 close(fd); 139 close(fd);
129 // set bit 1 of the node ID, which is the mac multicast bit. This means we 146 // set bit 1 of the node ID, which is the mac multicast bit. This means we
130 // should never collide with anybody actually using a macaddr. 147 // should never collide with anybody actually using a macaddr.
131 uuid[11] = uuid[11] | 128; 148 uuid[11] = uuid[11] | 128;
132 } 149 }
133 150
134 // Figure out inodes per group, rounded up to fill complete inode blocks. 151 // Calculate inodes per group from total inodes.
135 static uint32_t get_inodespg(uint32_t inodes) 152 static uint32_t get_inodespg(uint32_t inodes)
136 { 153 {
137 uint32_t temp; 154 uint32_t temp;
138 155
156 // Round up to fill complete inode blocks.
139 temp = (inodes + TT.groups - 1) / TT.groups; 157 temp = (inodes + TT.groups - 1) / TT.groups;
140 inodes = TT.blocksize/sizeof(struct ext2_inode); 158 inodes = TT.blocksize/sizeof(struct ext2_inode);
141 return ((temp + inodes - 1)/inodes)*inodes; 159 return ((temp + inodes - 1)/inodes)*inodes;
142 } 160 }
143 161
144 // Fill out superblock and TT 162 // Fill out superblock and TT structures.
145 163
146 static void init_superblock(struct ext2_superblock *sb) 164 static void init_superblock(struct ext2_superblock *sb)
147 { 165 {
148 uint32_t temp; 166 uint32_t temp;
149 167
154 sb->log_block_size = sb->log_frag_size = SWAP_LE32(temp); 172 sb->log_block_size = sb->log_frag_size = SWAP_LE32(temp);
155 173
156 // Fill out blocks_count, r_blocks_count, first_data_block 174 // Fill out blocks_count, r_blocks_count, first_data_block
157 175
158 sb->blocks_count = SWAP_LE32(TT.blocks); 176 sb->blocks_count = SWAP_LE32(TT.blocks);
177 sb->free_blocks_count = SWAP_LE32(TT.freeblocks);
159 temp = (TT.blocks * (uint64_t)TT.reserved_percent) / 100; 178 temp = (TT.blocks * (uint64_t)TT.reserved_percent) / 100;
160 sb->r_blocks_count = SWAP_LE32(temp); 179 sb->r_blocks_count = SWAP_LE32(temp);
161 180
162 sb->first_data_block = SWAP_LE32(TT.blocksize == 1024 ? 1 : 0); 181 sb->first_data_block = SWAP_LE32(TT.blocksize == 1024 ? 1 : 0);
163 182
164 // Set blocks_per_group and frags_per_group, which is the size of an 183 // Set blocks_per_group and frags_per_group, which is the size of an
165 // allocation bitmap that fits in one block (I.E. how many bits per block)? 184 // allocation bitmap that fits in one block (I.E. how many bits per block)?
166 185
167 sb->blocks_per_group = sb->frags_per_group = SWAP_LE32(TT.blockbits); 186 sb->blocks_per_group = sb->frags_per_group = SWAP_LE32(TT.blockbits);
168
169 // How many block groups do we need? (Round up avoiding integer overflow.)
170
171 TT.groups = (TT.blocks)/TT.blockbits;
172 if (TT.blocks & (TT.blockbits-1)) TT.groups++;
173
174 // Figure out inodes per group, rounded up to block size.
175
176 TT.inodespg = get_inodespg(TT.inodespg);
177 187
178 // Set inodes_per_group and total inodes_count 188 // Set inodes_per_group and total inodes_count
179 sb->inodes_per_group = SWAP_LE32(TT.inodespg); 189 sb->inodes_per_group = SWAP_LE32(TT.inodespg);
180 sb->inodes_count = SWAP_LE32(TT.inodespg * TT.groups); 190 sb->inodes_count = SWAP_LE32(TT.inodespg * TT.groups);
191
192 // Determine free inodes.
193 temp = TT.inodespg*TT.groups - INODES_RESERVED;
194 if (temp < TT.treeinodes) error_exit("Not enough inodes.\n");
195 sb->free_inodes_count = SWAP_LE32(temp - TT.treeinodes);
181 196
182 // Fill out the rest of the superblock. 197 // Fill out the rest of the superblock.
183 sb->max_mnt_count=0xFFFF; 198 sb->max_mnt_count=0xFFFF;
184 sb->wtime = sb->lastcheck = sb->mkfs_time = SWAP_LE32(time(NULL)); 199 sb->wtime = sb->lastcheck = sb->mkfs_time = SWAP_LE32(time(NULL));
185 sb->magic = SWAP_LE32(0xEF53); 200 sb->magic = SWAP_LE32(0xEF53);
189 sb->first_ino = SWAP_LE32(INODES_RESERVED+1); 204 sb->first_ino = SWAP_LE32(INODES_RESERVED+1);
190 sb->inode_size = SWAP_LE16(sizeof(struct ext2_inode)); 205 sb->inode_size = SWAP_LE16(sizeof(struct ext2_inode));
191 sb->feature_incompat = SWAP_LE32(EXT2_FEATURE_INCOMPAT_FILETYPE); 206 sb->feature_incompat = SWAP_LE32(EXT2_FEATURE_INCOMPAT_FILETYPE);
192 sb->feature_ro_compat = SWAP_LE32(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER); 207 sb->feature_ro_compat = SWAP_LE32(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER);
193 208
194 create_uuid(sb->uuid); 209 fake_uuid(sb->uuid);
195 210
196 // TODO If we're called as mke3fs or mkfs.ext3, do a journal. 211 // TODO If we're called as mke3fs or mkfs.ext3, do a journal.
197 212
198 //if (strchr(toys.which->name,'3')) 213 //if (strchr(toys.which->name,'3'))
199 // sb->feature_compat |= SWAP_LE32(EXT3_FEATURE_COMPAT_HAS_JOURNAL); 214 // sb->feature_compat |= SWAP_LE32(EXT3_FEATURE_COMPAT_HAS_JOURNAL);
200 } 215 }
213 } 228 }
214 return 0; 229 return 0;
215 } 230 }
216 231
217 232
218 // Number of blocks used in this group by superblock/group list backup. 233 // Number of blocks used in group by optional superblock/group list backup.
219 static int group_superblock_used(uint32_t group) 234 static int group_superblock_overhead(uint32_t group)
220 { 235 {
221 int used; 236 int used;
222 237
223 if (!is_sb_group(group)) return 0; 238 if (!is_sb_group(group)) return 0;
224 239
225 // How blocks does the group table take up? 240 // How many blocks does the group descriptor table take up?
226 used = TT.groups * sizeof(struct ext2_group); 241 used = TT.groups * sizeof(struct ext2_group);
227 used += TT.blocksize - 1; 242 used += TT.blocksize - 1;
228 used /= TT.blocksize; 243 used /= TT.blocksize;
229 // Plus the superblock itself. 244 // Plus the superblock itself.
230 used++; 245 used++;
232 if (!group && TT.blocksize == 1024) used++; 247 if (!group && TT.blocksize == 1024) used++;
233 248
234 return used; 249 return used;
235 } 250 }
236 251
237 static uint32_t get_all_group_blocks(void) 252 // Number of blocks used in group to store superblock/group/inode list
238 { 253 static int group_overhead(uint32_t group)
239 uint32_t i, blocks, inodeblks; 254 {
240 255 // Return superblock backup overhead (if any), plus block/inode
241 inodeblks = get_inodespg(TT.inodespg); 256 // allocation bitmaps, plus inode tables.
242 inodeblks /= TT.blocksize/sizeof(struct ext2_inode); 257 return group_superblock_overhead(group) + 2 + get_inodespg(TT.inodespg)
243 for (i = blocks = 0; i<TT.groups; i++) 258 / (TT.blocksize/sizeof(struct ext2_inode));
244 blocks += group_superblock_used(i) + 2 + inodeblks; 259 }
245 260
246 return blocks; 261 // In bitmap "array" set "len" bits starting at position "start" (from 0).
247 }
248
249 static void bits_set(char *array, int start, int len) 262 static void bits_set(char *array, int start, int len)
250 { 263 {
251 while(len) { 264 while(len) {
252 if ((start&7) || len<8) { 265 if ((start&7) || len<8) {
253 array[start/8]|=(1<<(start&7)); 266 array[start/8]|=(1<<(start&7));
263 276
264 // Seek past len bytes (to maintain sparse file), or write zeroes if output 277 // Seek past len bytes (to maintain sparse file), or write zeroes if output
265 // not seekable 278 // not seekable
266 static void put_zeroes(int len) 279 static void put_zeroes(int len)
267 { 280 {
268 if(TT.noseek || -1 == lseek(TT.fsfd, len, SEEK_SET)) { 281 if(-1 == lseek(TT.fsfd, len, SEEK_SET)) {
269
270 TT.noseek=1;
271 memset(toybuf, 0, sizeof(toybuf)); 282 memset(toybuf, 0, sizeof(toybuf));
272 while (len) { 283 while (len) {
273 int out = len > sizeof(toybuf) ? sizeof(toybuf) : len; 284 int out = len > sizeof(toybuf) ? sizeof(toybuf) : len;
274 xwrite(TT.fsfd, toybuf, out); 285 xwrite(TT.fsfd, toybuf, out);
275 len -= out; 286 len -= out;
276 } 287 }
277 } 288 }
278 } 289 }
279 290
291 // Fill out an inode structure from struct stat info in dirtree.
280 static void fill_inode(struct ext2_inode *in, struct dirtree *this) 292 static void fill_inode(struct ext2_inode *in, struct dirtree *this)
281 { 293 {
282 memset(in,0,sizeof(struct ext2_inode)); 294 uint32_t fbu[15];
283 295 int temp;
284 // This works on Linux. S_ISREG/DIR/CHR/BLK/FIFO/LNK/SOCK(m) 296
285 in->mode = this->st.st_mode; 297 file_blocks_used(this->st.st_size, fbu);
286 298
287 in->uid = this->st.st_uid & 0xFFFF; 299 // If this inode needs data blocks allocated to it.
288 in->uid_high = this->st.st_uid >> 16; 300 if (this->st.st_size) {
289 in->gid = this->st.st_gid & 0xFFFF; 301 int i, group = TT.nextblock/TT.blockbits;
290 in->gid_high = this->st.st_gid >> 16; 302
291 in->size = this->st.st_size & 0xFFFFFFFF; 303 // TODO: teach this about indirect blocks.
292 304 for (i=0; i<15; i++) {
293 in->atime = this->st.st_atime; 305 // If we just jumped into a new group, skip group overhead blocks.
294 in->ctime = this->st.st_ctime; 306 while (group >= TT.nextgroup)
295 in->mtime = this->st.st_mtime; 307 TT.nextblock += group_overhead(TT.nextgroup++);
296 308 }
297 in->links_count = this->st.st_nlink; 309 }
298 in->blocks = this->st.st_blocks; 310 // TODO : S_ISREG/DIR/CHR/BLK/FIFO/LNK/SOCK(m)
311 in->mode = SWAP_LE32(this->st.st_mode);
312
313 in->uid = SWAP_LE16(this->st.st_uid & 0xFFFF);
314 in->uid_high = SWAP_LE16(this->st.st_uid >> 16);
315 in->gid = SWAP_LE16(this->st.st_gid & 0xFFFF);
316 in->gid_high = SWAP_LE16(this->st.st_gid >> 16);
317 in->size = SWAP_LE32(this->st.st_size & 0xFFFFFFFF);
318
319 // Contortions to make the compiler not generate a warning for x>>32
320 // when x is 32 bits. The optimizer should clean this up.
321 if (sizeof(this->st.st_size) > 4) temp = 32;
322 else temp = 0;
323 if (temp) in->dir_acl = SWAP_LE32(this->st.st_size >> temp);
324
325 in->atime = SWAP_LE32(this->st.st_atime);
326 in->ctime = SWAP_LE32(this->st.st_ctime);
327 in->mtime = SWAP_LE32(this->st.st_mtime);
328
329 in->links_count = SWAP_LE16(this->st.st_nlink);
330 in->blocks = SWAP_LE32(this->st.st_blocks);
331 // in->faddr
299 } 332 }
300 333
301 int mke2fs_main(void) 334 int mke2fs_main(void)
302 { 335 {
303 int i, temp; 336 int i, temp;
304 off_t length; 337 off_t length;
305 uint32_t usedblocks, usedinodes; 338 uint32_t usedblocks, usedinodes, dtiblk, dtbblk;
306 339 struct dirtree *dti, *dtb;
340
307 // Handle command line arguments. 341 // Handle command line arguments.
308 342
309 if (toys.optargs[1]) { 343 if (toys.optargs[1]) {
310 sscanf(toys.optargs[1], "%u", &TT.blocks); 344 sscanf(toys.optargs[1], "%u", &TT.blocks);
311 temp = O_RDWR|O_CREAT; 345 temp = O_RDWR|O_CREAT;
323 length = fdlength(TT.fsfd); 357 length = fdlength(TT.fsfd);
324 if (!TT.blocksize) TT.blocksize = (length && length < 1<<29) ? 1024 : 4096; 358 if (!TT.blocksize) TT.blocksize = (length && length < 1<<29) ? 1024 : 4096;
325 TT.blockbits = 8*TT.blocksize; 359 TT.blockbits = 8*TT.blocksize;
326 if (!TT.blocks) TT.blocks = length/TT.blocksize; 360 if (!TT.blocks) TT.blocks = length/TT.blocksize;
327 361
328 // Figure out how many total inodes we need.
329
330 if (!TT.inodespg) {
331 if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192;
332 TT.inodespg = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode;
333 }
334
335 // Collect gene2fs list or lost+found, calculate requirements. 362 // Collect gene2fs list or lost+found, calculate requirements.
336 363
337 if (TT.gendir) { 364 if (TT.gendir) {
338 strncpy(toybuf, TT.gendir, sizeof(toybuf)); 365 strncpy(toybuf, TT.gendir, sizeof(toybuf));
339 TT.dt = read_dirtree(toybuf, NULL); 366 dti = read_dirtree(toybuf, NULL);
340 } else { 367 } else {
341 TT.dt = xzalloc(sizeof(struct dirtree)+11); 368 dti = xzalloc(sizeof(struct dirtree)+11);
342 strcpy(TT.dt->name, "lost+found"); 369 strcpy(dti->name, "lost+found");
343 TT.dt->st.st_mode = S_IFDIR|0755; 370 dti->st.st_mode = S_IFDIR|0755;
344 TT.dt->st.st_ctime = TT.dt->st.st_mtime = time(NULL); 371 dti->st.st_ctime = dti->st.st_mtime = time(NULL);
345 } 372 }
346 373
374 // Add root directory inode. This is iterated through for when finding
375 // blocks, but not when finding inodes. The tree's parent pointers don't
376 // point back into this.
377
378 dtb = xzalloc(sizeof(struct dirtree)+1);
379 dtb->st.st_mode = S_IFDIR|0755;
380 dtb->st.st_ctime = dtb->st.st_mtime = time(NULL);
381 dtb->child = dti;
382
347 // Figure out how much space is used by preset files 383 // Figure out how much space is used by preset files
348 length = 0; 384 length = check_treesize(dtb, &(dtb->st.st_size));
349 length = check_treesize(TT.dt, &length); 385 check_treelinks(dtb);
350 check_treelinks(); // Calculate st_nlink for each node in tree. 386
351 387 // Figure out how many total inodes we need.
352 if (TT.gendir && !TT.blocks) { 388
353 // Figure out how many blocks of overhead superblock backups and 389 if (!TT.inodes) {
354 // group descriptor tables impose. Start with a minimal guess, 390 if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192;
355 // find the overhead for that many groups, and loop until this 391 TT.inodes = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode;
356 // is enough groups to store this many blocks. 392 }
357 TT.groups = (TT.treeblocks/TT.blockbits)+1; 393
358 for (;;) { 394 // If we're generating a filesystem and have no idea how many blocks it
359 TT.blocks = TT.treeblocks + get_all_group_blocks(); 395 // needs, start with a minimal guess, find the overhead of that many
360 if (TT.blocks <= TT.groups * TT.blockbits) break; 396 // groups, and loop until this is enough groups to store this many blocks.
361 TT.groups++; 397 if (!TT.blocks) TT.groups = (TT.treeblocks/TT.blockbits)+1;
362 } 398 else TT.groups = div_round_up(TT.blocks, TT.blockbits);
363 } 399
364 400 for (;;) {
365 // TT.blocks is now big enough to initialize superblock structure 401 temp = TT.treeblocks;
402
403 for (i = 0; i<TT.groups; i++) temp += group_overhead(i);
404
405 if (TT.blocks) {
406 if (TT.blocks < temp) error_exit("Not enough space.\n");
407 break;
408 }
409 if (temp <= TT.groups * TT.blockbits) {
410 TT.blocks = temp;
411 break;
412 }
413 TT.groups++;
414 }
415 TT.freeblocks = TT.blocks - temp;
416
417 // Now we know all the TT data, initialize superblock structure.
366 418
367 init_superblock(&TT.sb); 419 init_superblock(&TT.sb);
368 temp = get_all_group_blocks(); 420
369 if (TT.blocks < TT.treeblocks + temp) error_exit("Not enough space.\n"); 421 // Start writing. Skip the first 1k to avoid the boot sector (if any).
370 TT.sb.free_blocks_count = SWAP_LE32(TT.blocks - TT.treeblocks - temp);
371
372 temp = TT.inodespg*TT.groups - INODES_RESERVED;
373 if (temp < TT.treeinodes) error_exit("Not enough inodes.\n");
374 TT.sb.free_inodes_count = SWAP_LE32(temp - TT.treeinodes);
375
376 // Skip the first 1k to avoid the boot sector (if any)
377 put_zeroes(1024); 422 put_zeroes(1024);
378 423
379 // Loop through block groups, write out each one. 424 // Loop through block groups, write out each one.
380 usedblocks = 0; 425 dtiblk = dtbblk = usedblocks = usedinodes = 0;
381 usedinodes = 0;
382 for (i=0; i<TT.groups; i++) { 426 for (i=0; i<TT.groups; i++) {
383 struct ext2_inode *in = (struct ext2_inode *)toybuf; 427 struct ext2_inode *in = (struct ext2_inode *)toybuf;
384 uint32_t start, itable, used, end; 428 uint32_t start, itable, used, end;
385 int j, slot; 429 int j, slot;
386 430
390 434
391 // Blocks used by inode table 435 // Blocks used by inode table
392 itable = (TT.inodespg*sizeof(struct ext2_inode))/TT.blocksize; 436 itable = (TT.inodespg*sizeof(struct ext2_inode))/TT.blocksize;
393 437
394 // If a superblock goes here, write it out. 438 // If a superblock goes here, write it out.
395 start = group_superblock_used(i); 439 start = group_superblock_overhead(i);
396 if (start) { 440 if (start) {
397 struct ext2_group *bg = (struct ext2_group *)toybuf; 441 struct ext2_group *bg = (struct ext2_group *)toybuf;
398 int treeblocks = TT.treeblocks, treeinodes = TT.treeinodes; 442 int treeblocks = TT.treeblocks, treeinodes = TT.treeinodes;
399 443
400 TT.sb.block_group_nr = SWAP_LE16(i); 444 TT.sb.block_group_nr = SWAP_LE16(i);
408 452
409 // Loop through groups to write group descriptor table. 453 // Loop through groups to write group descriptor table.
410 for(j=0; j<TT.groups; j++) { 454 for(j=0; j<TT.groups; j++) {
411 455
412 // Figure out what sector this group starts in. 456 // Figure out what sector this group starts in.
413 used = group_superblock_used(j); 457 used = group_superblock_overhead(j);
414 458
415 // Find next array slot in this block (flush block if full). 459 // Find next array slot in this block (flush block if full).
416 slot = j % (TT.blocksize/sizeof(struct ext2_group)); 460 slot = j % (TT.blocksize/sizeof(struct ext2_group));
417 if (!slot) { 461 if (!slot) {
418 if (j) xwrite(TT.fsfd, bg, TT.blocksize); 462 if (j) xwrite(TT.fsfd, bg, TT.blocksize);
485 slot = j % (TT.blocksize/sizeof(struct ext2_inode)); 529 slot = j % (TT.blocksize/sizeof(struct ext2_inode));
486 if (!slot) { 530 if (!slot) {
487 if (j) xwrite(TT.fsfd, in, TT.blocksize); 531 if (j) xwrite(TT.fsfd, in, TT.blocksize);
488 memset(in, 0, TT.blocksize); 532 memset(in, 0, TT.blocksize);
489 } 533 }
534 if (!i && j<INODES_RESERVED) {
535 // Write root inode
536 if (j == 2) fill_inode(in+slot, dtb);
537 } else if (dti) {
538 fill_inode(in+slot, dti);
539 dti = treenext(dti);
540 }
490 } 541 }
491 xwrite(TT.fsfd, in, TT.blocksize); 542 xwrite(TT.fsfd, in, TT.blocksize);
492 543
493 // Write empty data blocks 544 while (dtb) {
545 // TODO write index data block
546 // TODO write root directory data block
547 // TODO write directory data block
548 // TODO write file data block
549 put_zeroes(TT.blocksize);
550 start++;
551 if (start == end) break;
552 }
553 // Write data blocks (TODO)
494 put_zeroes((end-start) * TT.blocksize); 554 put_zeroes((end-start) * TT.blocksize);
495 } 555 }
496 556
497 return 0; 557 return 0;
498 } 558 }
559
560 // Scratch pad:
561 // b - block size (1024, 2048, 4096)
562 // F - force (run on mounted device or non-block device)
563 // i - bytes per inode
564 // N - number of inodes
565 // m - reserved blocks percentage
566 // n - Don't write
567 // q - quiet
568
569 // L - volume label
570 // M - last mounted path
571 // o - creator os
572
573 // j - create journal
574 // J - journal options (size=1024-102400 blocks,device=)
575 // device=/dev/blah or LABEL=label UUID=uuid
576
577 // E - extended options (stride=stripe-size blocks)
578 // O - none,dir_index,filetype,has_journal,journal_dev,sparse_super
579
580