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