1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69#include "libbb.h"
70#include <linux/fs.h>
71#include "bb_e2fs_defs.h"
72
73#define ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT 0
74#define ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX 1
75
76#define EXT2_HASH_HALF_MD4 1
77#define EXT2_FLAGS_SIGNED_HASH 0x0001
78#define EXT2_FLAGS_UNSIGNED_HASH 0x0002
79
80
81char BUG_wrong_field_size(void);
82#define STORE_LE(field, value) \
83do { \
84 if (sizeof(field) == 4) \
85 field = SWAP_LE32(value); \
86 else if (sizeof(field) == 2) \
87 field = SWAP_LE16(value); \
88 else if (sizeof(field) == 1) \
89 field = (value); \
90 else \
91 BUG_wrong_field_size(); \
92} while (0)
93
94#define FETCH_LE32(field) \
95 (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size())
96
97
98struct ext2_dir {
99 uint32_t inode1;
100 uint16_t rec_len1;
101 uint8_t name_len1;
102 uint8_t file_type1;
103 char name1[4];
104 uint32_t inode2;
105 uint16_t rec_len2;
106 uint8_t name_len2;
107 uint8_t file_type2;
108 char name2[4];
109 uint32_t inode3;
110 uint16_t rec_len3;
111 uint8_t name_len3;
112 uint8_t file_type3;
113 char name3[12];
114};
115
116static unsigned int_log2(unsigned arg)
117{
118 unsigned r = 0;
119 while ((arg >>= 1) != 0)
120 r++;
121 return r;
122}
123
124
125
126static uint32_t div_roundup(uint32_t size, uint32_t n)
127{
128
129 uint32_t res = size / n;
130 if (res * n != size)
131 res++;
132 return res;
133}
134
135static void allocate(uint8_t *bitmap, uint32_t blocksize, uint32_t start, uint32_t end)
136{
137 uint32_t i;
138
139
140 memset(bitmap, 0, blocksize);
141 i = start / 8;
142 memset(bitmap, 0xFF, i);
143 bitmap[i] = (1 << (start & 7)) - 1;
144 i = end / 8;
145 bitmap[blocksize - i - 1] |= 0x7F00 >> (end & 7);
146 memset(bitmap + blocksize - i, 0xFF, i);
147}
148
149static uint32_t has_super(uint32_t x)
150{
151
152 static const uint32_t supers[] = {
153 0, 1, 3, 5, 7, 9, 25, 27, 49, 81, 125, 243, 343, 625, 729,
154 2187, 2401, 3125, 6561, 15625, 16807, 19683, 59049, 78125,
155 117649, 177147, 390625, 531441, 823543, 1594323, 1953125,
156 4782969, 5764801, 9765625, 14348907, 40353607, 43046721,
157 48828125, 129140163, 244140625, 282475249, 387420489,
158 1162261467, 1220703125, 1977326743, 3486784401,
159 };
160 const uint32_t *sp = supers + ARRAY_SIZE(supers);
161 while (1) {
162 sp--;
163 if (x == *sp)
164 return 1;
165 if (x > *sp)
166 return 0;
167 }
168}
169
170#define fd 3
171
172static void PUT(uint64_t off, void *buf, uint32_t size)
173{
174
175 xlseek(fd, off, SEEK_SET);
176 xwrite(fd, buf, size);
177}
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209enum {
210 OPT_c = 1 << 0,
211 OPT_l = 1 << 1,
212 OPT_b = 1 << 2,
213 OPT_f = 1 << 3,
214 OPT_i = 1 << 4,
215 OPT_I = 1 << 5,
216 OPT_J = 1 << 6,
217 OPT_G = 1 << 7,
218 OPT_N = 1 << 8,
219 OPT_m = 1 << 9,
220 OPT_o = 1 << 10,
221 OPT_g = 1 << 11,
222 OPT_L = 1 << 12,
223 OPT_M = 1 << 13,
224 OPT_O = 1 << 14,
225 OPT_r = 1 << 15,
226 OPT_E = 1 << 16,
227 OPT_T = 1 << 17,
228 OPT_U = 1 << 18,
229 OPT_j = 1 << 19,
230 OPT_n = 1 << 20,
231 OPT_q = 1 << 21,
232 OPT_v = 1 << 22,
233 OPT_F = 1 << 23,
234 OPT_S = 1 << 24,
235
236};
237
238int mkfs_ext2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
239int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
240{
241 unsigned i, pos, n;
242 unsigned bs, bpi;
243 unsigned blocksize, blocksize_log2;
244 unsigned inodesize, user_inodesize;
245 unsigned reserved_percent = 5;
246 unsigned long long kilobytes;
247 uint32_t nblocks, nblocks_full;
248 uint32_t nreserved;
249 uint32_t ngroups;
250 uint32_t bytes_per_inode;
251 uint32_t first_block;
252 uint32_t inodes_per_group;
253 uint32_t group_desc_blocks;
254 uint32_t inode_table_blocks;
255 uint32_t lost_and_found_blocks;
256 time_t timestamp;
257 const char *label = "";
258 struct stat st;
259 struct ext2_super_block *sb;
260 struct ext2_group_desc *gd;
261 struct ext2_inode *inode;
262 struct ext2_dir *dir;
263 uint8_t *buf;
264
265
266
267 getopt32(argv, "cl:b:+f:i:+I:+J:G:N:m:+o:g:L:M:O:r:E:T:U:jnqvFS",
268 NULL, &bs, NULL, &bpi,
269 &user_inodesize, NULL, NULL, NULL,
270 &reserved_percent, NULL, NULL, &label,
271 NULL, NULL, NULL, NULL,
272 NULL, NULL);
273 argv += optind;
274
275
276 xmove_fd(xopen(argv[0], O_WRONLY), fd);
277 xfstat(fd, &st, argv[0]);
278 if (!S_ISBLK(st.st_mode) && !(option_mask32 & OPT_F))
279 bb_error_msg_and_die("%s: not a block device", argv[0]);
280
281
282
283
284 if (find_mount_point(argv[0], 0))
285 bb_error_msg_and_die("can't format mounted filesystem");
286
287
288 kilobytes = get_volume_size_in_bytes(fd, argv[1], 1024, !(option_mask32 & OPT_n)) / 1024;
289
290 bytes_per_inode = 16384;
291 if (kilobytes < 512*1024)
292 bytes_per_inode = 4096;
293 if (kilobytes < 3*1024)
294 bytes_per_inode = 8192;
295 if (option_mask32 & OPT_i)
296 bytes_per_inode = bpi;
297
298
299
300
301 blocksize = 1024;
302 inodesize = sizeof(struct ext2_inode);
303 if (kilobytes >= 512*1024) {
304 blocksize = 4096;
305 inodesize = 256;
306 }
307 if (EXT2_MAX_BLOCK_SIZE > 4096) {
308
309
310
311 while ((kilobytes >> 22) >= blocksize)
312 blocksize *= 2;
313 }
314 if (option_mask32 & OPT_b)
315 blocksize = bs;
316 if (blocksize < EXT2_MIN_BLOCK_SIZE
317 || blocksize > EXT2_MAX_BLOCK_SIZE
318 || (blocksize & (blocksize - 1))
319 ) {
320 bb_error_msg_and_die("blocksize %u is bad", blocksize);
321 }
322
323 if (option_mask32 & OPT_I) {
324 if (user_inodesize < sizeof(*inode)
325 || user_inodesize > blocksize
326 || (user_inodesize & (user_inodesize - 1))
327 ) {
328 bb_error_msg("-%c is bad", 'I');
329 } else {
330 inodesize = user_inodesize;
331 }
332 }
333
334 if ((int32_t)bytes_per_inode < blocksize)
335 bb_error_msg_and_die("-%c is bad", 'i');
336
337#define blocks_per_group (8 * blocksize)
338 first_block = (EXT2_MIN_BLOCK_SIZE == blocksize);
339 blocksize_log2 = int_log2(blocksize);
340
341
342 kilobytes >>= (blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
343 nblocks = kilobytes;
344 if (nblocks != kilobytes)
345 bb_error_msg_and_die("block count doesn't fit in 32 bits");
346#define kilobytes kilobytes_unused_after_this
347
348 if (nblocks < 60)
349 bb_error_msg_and_die("need >= 60 blocks");
350
351
352 if (reserved_percent > 50)
353 bb_error_msg_and_die("-%c is bad", 'm');
354 nreserved = (uint64_t)nblocks * reserved_percent / 100;
355
356
357 nblocks_full = nblocks;
358
359
360
361
362
363 retry:
364
365 ngroups = div_roundup(nblocks - first_block, blocks_per_group);
366
367 group_desc_blocks = div_roundup(ngroups, blocksize / sizeof(*gd));
368
369
370 if (ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT) {
371
372
373
374
375
376
377
378
379 uint32_t reserved_group_desc_blocks = 0xFFFFFFFF;
380 if (nblocks < reserved_group_desc_blocks / 1024)
381 reserved_group_desc_blocks = nblocks * 1024;
382 reserved_group_desc_blocks = div_roundup(reserved_group_desc_blocks - first_block, blocks_per_group);
383 reserved_group_desc_blocks = div_roundup(reserved_group_desc_blocks, blocksize / sizeof(*gd)) - group_desc_blocks;
384 if (reserved_group_desc_blocks > blocksize / sizeof(uint32_t))
385 reserved_group_desc_blocks = blocksize / sizeof(uint32_t);
386
387 group_desc_blocks += reserved_group_desc_blocks;
388 }
389
390 {
391
392 uint32_t overhead, remainder;
393
394 uint32_t ninodes = ((uint64_t) nblocks_full * blocksize) / bytes_per_inode;
395 if (ninodes < EXT2_GOOD_OLD_FIRST_INO+1)
396 ninodes = EXT2_GOOD_OLD_FIRST_INO+1;
397 inodes_per_group = div_roundup(ninodes, ngroups);
398
399 if (inodes_per_group < 16)
400 inodes_per_group = 16;
401
402 if (inodes_per_group > blocks_per_group)
403 inodes_per_group = blocks_per_group;
404
405 inodes_per_group = (div_roundup(inodes_per_group * inodesize, blocksize) * blocksize) / inodesize;
406
407 inodes_per_group &= ~7;
408 inode_table_blocks = div_roundup(inodes_per_group * inodesize, blocksize);
409
410
411
412
413
414
415 lost_and_found_blocks = MIN(EXT2_NDIR_BLOCKS, 16 >> (blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE));
416
417
418 overhead = (has_super(ngroups - 1) ? (1 + group_desc_blocks) : 0) + 1 + 1 + inode_table_blocks;
419 remainder = (nblocks - first_block) % blocks_per_group;
420
421
422
423
424
425
426
427
428
429
430
431
432
433 if (remainder && (remainder < overhead + 50)) {
434
435 nblocks -= remainder;
436 goto retry;
437 }
438 }
439
440 if (nblocks_full - nblocks)
441 printf("warning: %u blocks unused\n\n", nblocks_full - nblocks);
442 printf(
443 "Filesystem label=%s\n"
444 "OS type: Linux\n"
445 "Block size=%u (log=%u)\n"
446 "Fragment size=%u (log=%u)\n"
447 "%u inodes, %u blocks\n"
448 "%u blocks (%u%%) reserved for the super user\n"
449 "First data block=%u\n"
450 "Maximum filesystem blocks=%u\n"
451 "%u block groups\n"
452 "%u blocks per group, %u fragments per group\n"
453 "%u inodes per group"
454 , label
455 , blocksize, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE
456 , blocksize, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE
457 , inodes_per_group * ngroups, nblocks
458 , nreserved, reserved_percent
459 , first_block
460 , group_desc_blocks * (blocksize / (unsigned)sizeof(*gd)) * blocks_per_group
461 , ngroups
462 , blocks_per_group, blocks_per_group
463 , inodes_per_group
464 );
465 {
466 const char *fmt = "\nSuperblock backups stored on blocks:\n"
467 "\t%u";
468 pos = first_block;
469 for (i = 1; i < ngroups; i++) {
470 pos += blocks_per_group;
471 if (has_super(i)) {
472 printf(fmt, (unsigned)pos);
473 fmt = ", %u";
474 }
475 }
476 }
477 bb_putchar('\n');
478
479 if (option_mask32 & OPT_n) {
480 if (ENABLE_FEATURE_CLEAN_UP)
481 close(fd);
482 return EXIT_SUCCESS;
483 }
484
485
486
487
488
489
490
491
492
493
494 sb = xzalloc(1024);
495 STORE_LE(sb->s_rev_level, EXT2_DYNAMIC_REV);
496 STORE_LE(sb->s_magic, EXT2_SUPER_MAGIC);
497 STORE_LE(sb->s_inode_size, inodesize);
498
499 if (inodesize != sizeof(*inode)) {
500 STORE_LE(sb->s_min_extra_isize, 0x001c);
501 STORE_LE(sb->s_want_extra_isize, 0x001c);
502 }
503 STORE_LE(sb->s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
504 STORE_LE(sb->s_log_block_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
505 STORE_LE(sb->s_log_frag_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
506
507
508 STORE_LE(sb->s_first_data_block, first_block);
509
510 STORE_LE(sb->s_blocks_per_group, blocks_per_group);
511 STORE_LE(sb->s_frags_per_group, blocks_per_group);
512
513 STORE_LE(sb->s_blocks_count, nblocks);
514
515 STORE_LE(sb->s_r_blocks_count, nreserved);
516
517 STORE_LE(sb->s_inodes_per_group, inodes_per_group);
518 STORE_LE(sb->s_inodes_count, inodes_per_group * ngroups);
519 STORE_LE(sb->s_free_inodes_count, inodes_per_group * ngroups - EXT2_GOOD_OLD_FIRST_INO);
520
521 timestamp = time(NULL);
522 STORE_LE(sb->s_mkfs_time, timestamp);
523 STORE_LE(sb->s_wtime, timestamp);
524 STORE_LE(sb->s_lastcheck, timestamp);
525
526 STORE_LE(sb->s_state, 1);
527 STORE_LE(sb->s_creator_os, EXT2_OS_LINUX);
528 STORE_LE(sb->s_checkinterval, 24*60*60 * 180);
529 STORE_LE(sb->s_errors, EXT2_ERRORS_DEFAULT);
530
531
532
533
534 STORE_LE(sb->s_feature_compat, EXT2_FEATURE_COMPAT_SUPP
535 | (EXT2_FEATURE_COMPAT_RESIZE_INO * ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT)
536 | (EXT2_FEATURE_COMPAT_DIR_INDEX * ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX)
537 );
538 STORE_LE(sb->s_feature_incompat, EXT2_FEATURE_INCOMPAT_FILETYPE);
539 STORE_LE(sb->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER);
540 STORE_LE(sb->s_flags, EXT2_FLAGS_UNSIGNED_HASH * ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX);
541 generate_uuid(sb->s_uuid);
542 if (ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX) {
543 STORE_LE(sb->s_def_hash_version, EXT2_HASH_HALF_MD4);
544 generate_uuid((uint8_t *)sb->s_hash_seed);
545 }
546
547
548
549
550
551 STORE_LE(sb->s_max_mnt_count,
552 EXT2_DFL_MAX_MNT_COUNT
553 + (sb->s_uuid[ARRAY_SIZE(sb->s_uuid)-1] % EXT2_DFL_MAX_MNT_COUNT));
554
555
556 safe_strncpy((char *)sb->s_volume_name, label, sizeof(sb->s_volume_name));
557
558
559 gd = xzalloc(group_desc_blocks * blocksize);
560 buf = xmalloc(blocksize);
561 sb->s_free_blocks_count = 0;
562 for (i = 0, pos = first_block, n = nblocks - first_block;
563 i < ngroups;
564 i++, pos += blocks_per_group, n -= blocks_per_group
565 ) {
566 uint32_t overhead = pos + (has_super(i) ? (1 + group_desc_blocks) : 0);
567 uint32_t free_blocks;
568
569 STORE_LE(gd[i].bg_block_bitmap, overhead + 0);
570 STORE_LE(gd[i].bg_inode_bitmap, overhead + 1);
571 STORE_LE(gd[i].bg_inode_table, overhead + 2);
572 overhead = overhead - pos + 1 + 1 + inode_table_blocks;
573 gd[i].bg_free_inodes_count = inodes_per_group;
574
575
576
577 if (0 == i) {
578
579 overhead += 1 + lost_and_found_blocks;
580
581 STORE_LE(gd[i].bg_used_dirs_count, 2);
582
583 gd[i].bg_free_inodes_count -= EXT2_GOOD_OLD_FIRST_INO;
584 }
585
586
587 free_blocks = (n < blocks_per_group ? n : blocks_per_group) - overhead;
588
589
590
591 allocate(buf, blocksize,
592
593 overhead,
594
595 blocks_per_group - (free_blocks + overhead)
596 );
597
598 PUT((uint64_t)(FETCH_LE32(gd[i].bg_block_bitmap)) * blocksize, buf, blocksize);
599 STORE_LE(gd[i].bg_free_blocks_count, free_blocks);
600
601
602 allocate(buf, blocksize,
603
604 inodes_per_group - gd[i].bg_free_inodes_count,
605
606 blocks_per_group - inodes_per_group
607 );
608
609
610
611 xwrite(fd, buf, blocksize);
612 STORE_LE(gd[i].bg_free_inodes_count, gd[i].bg_free_inodes_count);
613
614
615 sb->s_free_blocks_count += free_blocks;
616 }
617 STORE_LE(sb->s_free_blocks_count, sb->s_free_blocks_count);
618
619
620
621 for (i = 0, pos = first_block; i < ngroups; i++, pos += blocks_per_group) {
622
623 if (has_super(i)) {
624
625 PUT(((uint64_t)pos * blocksize) + ((0 == i && 1024 != blocksize) ? 1024 : 0),
626 sb, 1024);
627 PUT(((uint64_t)pos * blocksize) + blocksize,
628 gd, group_desc_blocks * blocksize);
629 }
630 }
631
632
633 memset(buf, 0, blocksize);
634
635
636
637
638
639
640 for (i = 0; i < ngroups; ++i)
641 for (n = 0; n < inode_table_blocks; ++n)
642 PUT((uint64_t)(FETCH_LE32(gd[i].bg_inode_table) + n) * blocksize,
643 buf, blocksize);
644
645
646 inode = (struct ext2_inode *)buf;
647 STORE_LE(inode->i_mode, S_IFDIR | S_IRWXU | S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH);
648 STORE_LE(inode->i_mtime, timestamp);
649 STORE_LE(inode->i_atime, timestamp);
650 STORE_LE(inode->i_ctime, timestamp);
651 STORE_LE(inode->i_size, blocksize);
652
653
654 STORE_LE(inode->i_blocks, blocksize / 512);
655
656
657 STORE_LE(inode->i_links_count, 3);
658 STORE_LE(inode->i_block[0], FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks);
659 PUT(((uint64_t)FETCH_LE32(gd[0].bg_inode_table) * blocksize) + (EXT2_ROOT_INO-1) * inodesize,
660 buf, inodesize);
661
662
663 STORE_LE(inode->i_links_count, 2);
664 STORE_LE(inode->i_size, lost_and_found_blocks * blocksize);
665 STORE_LE(inode->i_blocks, (lost_and_found_blocks * blocksize) / 512);
666 n = FETCH_LE32(inode->i_block[0]) + 1;
667 for (i = 0; i < lost_and_found_blocks; ++i)
668 STORE_LE(inode->i_block[i], i + n);
669
670 PUT(((uint64_t)FETCH_LE32(gd[0].bg_inode_table) * blocksize) + (EXT2_GOOD_OLD_FIRST_INO-1) * inodesize,
671 buf, inodesize);
672
673
674 memset(buf, 0, blocksize);
675 dir = (struct ext2_dir *)buf;
676
677
678 STORE_LE(dir->rec_len1, blocksize);
679 for (i = 1; i < lost_and_found_blocks; ++i)
680 PUT((uint64_t)(FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks + 1+i) * blocksize,
681 buf, blocksize);
682
683
684 STORE_LE(dir->inode1, EXT2_GOOD_OLD_FIRST_INO);
685 STORE_LE(dir->rec_len1, 12);
686 STORE_LE(dir->name_len1, 1);
687 STORE_LE(dir->file_type1, EXT2_FT_DIR);
688 dir->name1[0] = '.';
689 STORE_LE(dir->inode2, EXT2_ROOT_INO);
690 STORE_LE(dir->rec_len2, blocksize - 12);
691 STORE_LE(dir->name_len2, 2);
692 STORE_LE(dir->file_type2, EXT2_FT_DIR);
693 dir->name2[0] = '.'; dir->name2[1] = '.';
694 PUT((uint64_t)(FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks + 1) * blocksize, buf, blocksize);
695
696
697 STORE_LE(dir->inode1, EXT2_ROOT_INO);
698 STORE_LE(dir->rec_len2, 12);
699 STORE_LE(dir->inode3, EXT2_GOOD_OLD_FIRST_INO);
700 STORE_LE(dir->rec_len3, blocksize - 12 - 12);
701 STORE_LE(dir->name_len3, 10);
702 STORE_LE(dir->file_type3, EXT2_FT_DIR);
703 strcpy(dir->name3, "lost+found");
704 PUT((uint64_t)(FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks + 0) * blocksize, buf, blocksize);
705
706
707 if (ENABLE_FEATURE_CLEAN_UP) {
708 free(buf);
709 free(gd);
710 free(sb);
711 }
712
713 xclose(fd);
714 return EXIT_SUCCESS;
715}
716