Mercurial > hg > toybox
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 } |