comparison toys/mke2fs.c @ 99:97d717829ff0

More work on mke2fs.c. Random in-progress snapshot...
author Rob Landley <rob@landley.net>
date Mon, 12 Feb 2007 20:03:01 -0500
parents 4c81e6375719
children ff85a83e7d7e
comparison
equal deleted inserted replaced
98:5174f1459c91 99:97d717829ff0
29 // O - none,dir_index,filetype,has_journal,journal_dev,sparse_super 29 // O - none,dir_index,filetype,has_journal,journal_dev,sparse_super
30 30
31 #define INODES_RESERVED 10 31 #define INODES_RESERVED 10
32 32
33 // Calculate data blocks plus index blocks needed to hold a file. 33 // Calculate data blocks plus index blocks needed to hold a file.
34 uint32_t blocks_used(uint64_t size) 34
35 static uint32_t count_blocks_used(uint64_t size)
35 { 36 {
36 uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize); 37 uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize);
37 uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0; 38 uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0;
38 39
39 // Account for direct, singly, doubly, and triply indiret index blocks 40 // Account for direct, singly, doubly, and triply indirect index blocks
40 41
41 if (dblocks > 12) { 42 if (dblocks > 12) {
42 iblocks = ((dblocks-13)/idx)+1; 43 iblocks = ((dblocks-13)/idx)+1;
43 if (iblocks > 1) { 44 if (iblocks > 1) {
44 diblocks = ((iblocks-2)/idx)+1; 45 diblocks = ((iblocks-2)/idx)+1;
45 if (diblocks > 1) 46 if (diblocks > 1)
46 tiblocks = ((diblocks-2)/idx)+1; 47 tiblocks = ((diblocks-2)/idx)+1;
47 } 48 }
48 } 49 }
49 50
50 return dblocks + iblocks + diblocks + tiblocks; 51 return dblocks + iblocks + diblocks + tiblocks;
52 }
53
54 // Calculate the number of blocks used by each inode. Returns blocks used,
55 // assigns bytes used to *size. Writes total block count to TT.treeblocks
56 // and inode count to TT.treeinodes.
57
58 long check_treesize(struct dirtree *this, off_t *size)
59 {
60 long blocks;
61
62 while (this) {
63 *size += sizeof(struct ext2_dentry) + strlen(this->name);
64
65 if (this->child)
66 this->st.st_blocks = check_treesize(this->child, &this->st.st_size);
67 else if (S_ISREG(this->st.st_mode)) {
68 this->st.st_blocks = count_blocks_used(this->st.st_size);
69 TT.treeblocks += this->st.st_blocks;
70 }
71 this = this->next;
72 }
73 TT.treeblocks += blocks = count_blocks_used(*size);
74 TT.treeinodes++;
75
76 return blocks;
51 } 77 }
52 78
53 // According to http://www.opengroup.org/onlinepubs/9629399/apdxa.htm 79 // According to http://www.opengroup.org/onlinepubs/9629399/apdxa.htm
54 // we should generate a uuid structure by reading a clock with 100 nanosecond 80 // we should generate a uuid structure by reading a clock with 100 nanosecond
55 // precision, normalizing it to the start of the gregorian calendar in 1582, 81 // precision, normalizing it to the start of the gregorian calendar in 1582,
58 // On the other hand, we have 128 bits to come up with a unique identifier, of 84 // On the other hand, we have 128 bits to come up with a unique identifier, of
59 // which 6 have a defined value. /dev/urandom it is. 85 // which 6 have a defined value. /dev/urandom it is.
60 86
61 static void create_uuid(char *uuid) 87 static void create_uuid(char *uuid)
62 { 88 {
63 // Read 128 random bytes 89 // Read 128 random bits
64 int fd = xopen("/dev/urandom", O_RDONLY); 90 int fd = xopen("/dev/urandom", O_RDONLY);
65 xreadall(fd, uuid, 16); 91 xreadall(fd, uuid, 16);
66 close(fd); 92 close(fd);
67 93
68 // Claim to be a DCE format UUID. 94 // Claim to be a DCE format UUID.
88 sb->log_block_size = sb->log_frag_size = SWAP_LE32(temp); 114 sb->log_block_size = sb->log_frag_size = SWAP_LE32(temp);
89 115
90 // Fill out blocks_count, r_blocks_count, first_data_block 116 // Fill out blocks_count, r_blocks_count, first_data_block
91 117
92 sb->blocks_count = SWAP_LE32(TT.blocks); 118 sb->blocks_count = SWAP_LE32(TT.blocks);
93
94 if (!TT.reserved_percent) TT.reserved_percent = 5; 119 if (!TT.reserved_percent) TT.reserved_percent = 5;
95 temp = (TT.blocks * (uint64_t)TT.reserved_percent) /100; 120 temp = (TT.blocks * (uint64_t)TT.reserved_percent) /100;
96 sb->r_blocks_count = SWAP_LE32(temp); 121 sb->r_blocks_count = SWAP_LE32(temp);
97 122
98 sb->first_data_block = SWAP_LE32(TT.blocksize == 1024 ? 1 : 0); 123 sb->first_data_block = SWAP_LE32(TT.blocksize == 1024 ? 1 : 0);
106 // How many block groups do we need? (Round up avoiding integer overflow.) 131 // How many block groups do we need? (Round up avoiding integer overflow.)
107 132
108 TT.groups = (TT.blocks)/temp; 133 TT.groups = (TT.blocks)/temp;
109 if (TT.blocks & (temp-1)) TT.groups++; 134 if (TT.blocks & (temp-1)) TT.groups++;
110 135
111 // Figure out how many inodes we need. 136 // Figure out how many total inodes we need.
112 137
113 if (!TT.inodes) { 138 if (!TT.inodespg) {
114 if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192; 139 if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192;
115 TT.inodes = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode; 140 TT.inodespg = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode;
116 } 141 }
117 142
118 // Figure out inodes per group, rounded up to block size. 143 // Figure out inodes per group, rounded up to block size.
119 144
120 // How many blocks of inodes total, rounded up 145 // How many blocks of inodes total, rounded up
121 temp = TT.inodes / (TT.blocksize/sizeof(struct ext2_inode)); 146 temp = TT.inodespg / (TT.blocksize/sizeof(struct ext2_inode));
122 if (temp * (TT.blocksize/sizeof(struct ext2_inode)) != TT.inodes) temp++; 147 if (temp * (TT.blocksize/sizeof(struct ext2_inode)) != TT.inodespg) temp++;
123 // How many blocks of inodes per group, again rounded up 148 // How many blocks of inodes per group, again rounded up
124 TT.inodes = temp / TT.groups; 149 TT.inodespg = temp / TT.groups;
125 if (temp & (TT.groups-1)) TT.inodes++; 150 if (temp & (TT.groups-1)) TT.inodespg++;
126 // How many inodes per group is that? 151 // How many inodes per group is that?
127 TT.inodes *= (TT.blocksize/sizeof(struct ext2_inode)); 152 TT.inodespg *= (TT.blocksize/sizeof(struct ext2_inode));
128 153
129 // Set inodes_per_group and total inodes_count 154 // Set inodes_per_group and total inodes_count
130 sb->inodes_per_group = SWAP_LE32(TT.inodes); 155 sb->inodes_per_group = SWAP_LE32(TT.inodespg);
131 sb->inodes_count = SWAP_LE32(TT.inodes *= TT.groups); 156 sb->inodes_count = SWAP_LE32(TT.inodespg * TT.groups);
132 157
133 // Fill out the rest of the superblock. 158 // Fill out the rest of the superblock.
134 sb->max_mnt_count=0xFFFF; 159 sb->max_mnt_count=0xFFFF;
135 sb->wtime = sb->lastcheck = sb->mkfs_time = SWAP_LE32(time(NULL)); 160 sb->wtime = sb->lastcheck = sb->mkfs_time = SWAP_LE32(time(NULL));
136 sb->magic = SWAP_LE32(0xEF53); 161 sb->magic = SWAP_LE32(0xEF53);
193 len-=8; 218 len-=8;
194 } 219 }
195 } 220 }
196 } 221 }
197 222
223 // Seek past len bytes (to maintain sparse file), or write zeroes if output
224 // not seekable
225 static void put_zeroes(int len)
226 {
227 if(TT.noseek || -1 == lseek(TT.fsfd, len, SEEK_SET)) {
228
229 TT.noseek=1;
230 memset(toybuf, 0, sizeof(toybuf));
231 while (len) {
232 int out = len > sizeof(toybuf) ? sizeof(toybuf) : len;
233 xwrite(TT.fsfd, toybuf, out);
234 len -= out;
235 }
236 }
237 }
238
239 static void fill_inode(struct ext2_inode *in, struct dirtree *this)
240 {
241 memset(in,0,sizeof(struct ext2_inode));
242
243 // This works on Linux. S_ISREG/DIR/CHR/BLK/FIFO/LNK/SOCK(m)
244 in->mode = this->st.st_mode;
245
246 in->uid = this->st.st_uid & 0xFFFF;
247 in->uid_high = this->st.st_uid >> 16;
248 in->gid = this->st.st_gid & 0xFFFF;
249 in->gid_high = this->st.st_gid >> 16;
250 in->size = this->st.st_size & 0xFFFFFFFF;
251
252 in->atime = this->st.st_atime;
253 in->ctime = this->st.st_ctime;
254 in->mtime = this->st.st_mtime;
255
256 in->links_count = this->st.st_nlink; // TODO
257 in->blocks = this->st.st_blocks;
258 }
259
198 int mke2fs_main(void) 260 int mke2fs_main(void)
199 { 261 {
200 int i, temp, blockbits; 262 int i, temp, blockbits;
201 off_t length; 263 off_t length;
202 264
217 strcpy(TT.dt->name, "lost+found"); 279 strcpy(TT.dt->name, "lost+found");
218 TT.dt->st.st_mode = S_IFDIR|0755; 280 TT.dt->st.st_mode = S_IFDIR|0755;
219 TT.dt->st.st_ctime = TT.dt->st.st_mtime = time(NULL); 281 TT.dt->st.st_ctime = TT.dt->st.st_mtime = time(NULL);
220 } 282 }
221 283
222 // Calculate st_nlink for each node in tree. 284 // TODO: Calculate st_nlink for each node in tree.
223 285
224 // TODO: Check if filesystem is mounted here 286 // TODO: Check if filesystem is mounted here
225 287
226 // For mke?fs, open file. For gene?fs, create file. 288 // For mke?fs, open file. For gene?fs, create file.
227 TT.fsfd = xcreate(*toys.optargs, temp, 0777); 289 TT.fsfd = xcreate(*toys.optargs, temp, 0777);
231 length = fdlength(TT.fsfd); 293 length = fdlength(TT.fsfd);
232 if (!TT.blocksize) TT.blocksize = (length && length < 1<<29) ? 1024 : 4096; 294 if (!TT.blocksize) TT.blocksize = (length && length < 1<<29) ? 1024 : 4096;
233 if (!TT.blocks) TT.blocks = length/TT.blocksize; 295 if (!TT.blocks) TT.blocks = length/TT.blocksize;
234 if (!TT.blocks) error_exit("gene2fs is a TODO item"); 296 if (!TT.blocks) error_exit("gene2fs is a TODO item");
235 297
236 // Skip the first 1k to avoid the boot sector (if any). Use this to 298 // Skip the first 1k to avoid the boot sector (if any), then
237 // figure out if this file is seekable. 299 // initialize superblock structure
238 if(-1 == lseek(TT.fsfd, 1024, SEEK_SET)) { 300
239 TT.noseek=1; 301 put_zeroes(1024);
240 xwrite(TT.fsfd, &TT.sb, 1024);
241 }
242
243 // Initialize superblock structure
244
245 init_superblock(&TT.sb); 302 init_superblock(&TT.sb);
246 blockbits = 8*TT.blocksize; 303 blockbits = 8*TT.blocksize;
304
305 // Figure out how much space is used
306 length = 0;
307 length = check_treesize(TT.dt, &length);
308 for (temp=i=0; i<TT.groups; i++) {
309 temp += group_superblock_used(i) + 2;
310 temp += TT.inodespg/(TT.blocksize/sizeof(struct ext2_inode));
311 }
312 TT.sb.free_blocks_count = SWAP_LE32(TT.blocks - TT.treeblocks - temp);
313 TT.sb.free_inodes_count = SWAP_LE32(TT.inodespg*TT.groups - INODES_RESERVED
314 - TT.treeinodes);
315
316 // Figure out how many inodes are used
247 317
248 // Loop through block groups. 318 // Loop through block groups.
249 319
250 for (i=0; i<TT.groups; i++) { 320 for (i=0; i<TT.groups; i++) {
251 struct ext2_inode *in = (struct ext2_inode *)toybuf; 321 struct ext2_inode *in = (struct ext2_inode *)toybuf;
255 // Where does this group end? 325 // Where does this group end?
256 end = blockbits; 326 end = blockbits;
257 if ((i+1)*blockbits > TT.blocks) end = TT.blocks & (blockbits-1); 327 if ((i+1)*blockbits > TT.blocks) end = TT.blocks & (blockbits-1);
258 328
259 // Blocks used by inode table 329 // Blocks used by inode table
260 itable = ((TT.inodes/TT.groups)*sizeof(struct ext2_inode))/TT.blocksize; 330 itable = (TT.inodespg*sizeof(struct ext2_inode))/TT.blocksize;
261 331
262 // If a superblock goes here, write it out. 332 // If a superblock goes here, write it out.
263 start = group_superblock_used(i); 333 start = group_superblock_used(i);
264 if (start) { 334 if (start) {
265 struct ext2_group *bg = (struct ext2_group *)toybuf; 335 struct ext2_group *bg = (struct ext2_group *)toybuf;
284 if (!slot) { 354 if (!slot) {
285 if (j) xwrite(TT.fsfd, bg, TT.blocksize); 355 if (j) xwrite(TT.fsfd, bg, TT.blocksize);
286 memset(bg, 0, TT.blocksize); 356 memset(bg, 0, TT.blocksize);
287 } 357 }
288 358
289 // sb.inodes_per_group is uint32_t, but group.free_inodes_count 359 // How many free inodes in this group? (TODO)
290 // is uint16_t. Add in endianness conversion and this little 360 temp = TT.inodespg;
291 // dance is called for.
292 temp = SWAP_LE32(TT.sb.inodes_per_group);
293 if (!i) temp -= INODES_RESERVED; 361 if (!i) temp -= INODES_RESERVED;
294 bg[slot].free_inodes_count = SWAP_LE16(temp); 362 bg[slot].free_inodes_count = SWAP_LE16(temp);
295 363
296 // How many blocks will the inode table use? 364 // How many free blocks in this group? (TODO)
297 temp *= sizeof(struct ext2_inode); 365 temp = TT.inodespg/(TT.blocksize/sizeof(struct ext2_inode)) + 2;
298 temp /= TT.blocksize;
299
300 // How many does that leave? (TODO: fill it up)
301 temp = end-used-temp; 366 temp = end-used-temp;
302 bg[slot].free_blocks_count = SWAP_LE32(temp); 367 bg[slot].free_blocks_count = SWAP_LE32(temp);
303 368
304 // Fill out rest of group structure (TODO: gene2fs allocation) 369 // Fill out rest of group structure (TODO: gene2fs allocation)
305 used += j*blockbits; 370 used += j*blockbits;
319 bits_set(toybuf, 0, start+itable); 384 bits_set(toybuf, 0, start+itable);
320 if (end!=blockbits) bits_set(toybuf, end, blockbits-end); 385 if (end!=blockbits) bits_set(toybuf, end, blockbits-end);
321 xwrite(TT.fsfd, toybuf, TT.blocksize); 386 xwrite(TT.fsfd, toybuf, TT.blocksize);
322 387
323 // Write inode bitmap (TODO) 388 // Write inode bitmap (TODO)
324 temp = TT.inodes/TT.groups;
325 memset(toybuf, 0, TT.blocksize); 389 memset(toybuf, 0, TT.blocksize);
326 if (!i) bits_set(toybuf, 0, INODES_RESERVED); 390 if (!i) bits_set(toybuf, 0, INODES_RESERVED);
327 bits_set(toybuf, temp, blockbits-temp); 391 bits_set(toybuf, TT.inodespg, blockbits-TT.inodespg);
328 xwrite(TT.fsfd, toybuf, TT.blocksize); 392 xwrite(TT.fsfd, toybuf, TT.blocksize);
329 393
394 start += 3;
395
330 // Write inode table for this group 396 // Write inode table for this group
331 for (j = 0; j<temp; j++) { 397 for (j = 0; j<TT.inodespg; j++) {
332 slot = j % (TT.blocksize/sizeof(struct ext2_inode)); 398 slot = j % (TT.blocksize/sizeof(struct ext2_inode));
333 if (!slot) { 399 if (!slot) {
334 if (j) xwrite(TT.fsfd, in, TT.blocksize); 400 if (j) {
401 xwrite(TT.fsfd, in, TT.blocksize);
402 start++;
403 }
335 memset(in, 0, TT.blocksize); 404 memset(in, 0, TT.blocksize);
336 } 405 }
337 } 406 }
338 xwrite(TT.fsfd, in, TT.blocksize); 407 xwrite(TT.fsfd, in, TT.blocksize);
339 408
340 // Write empty data blocks 409 // Write empty data blocks
341 memset(toybuf, 0, TT.blocksize); 410 put_zeroes((end-start) * TT.blocksize);
342 for (j = start; j < end; j++)
343 xwrite(TT.fsfd, toybuf, TT.blocksize);
344 } 411 }
345 412
346 return 0; 413 return 0;
347 } 414 }