mkfs_ext2: explain why 0.5G+ images are a bit different
[oweals/busybox.git] / util-linux / mkfs_ext2.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * mkfs_ext2: utility to create EXT2 filesystem
4  * inspired by genext2fs
5  *
6  * Busybox'ed (2009) by Vladimir Dronnikov <dronnikov@gmail.com>
7  *
8  * Licensed under GPLv2, see file LICENSE in this tarball for details.
9  */
10 #include "libbb.h"
11 #include <linux/fs.h>
12 #include <linux/ext2_fs.h>
13 #include <sys/user.h> /* PAGE_SIZE */
14 #ifndef PAGE_SIZE
15 # define PAGE_SIZE 4096
16 #endif
17 #include "volume_id/volume_id_internal.h"
18
19 #define ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT 0
20 #define ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX 1
21
22 // from e2fsprogs
23 #define s_reserved_gdt_blocks s_padding1
24 #define s_mkfs_time           s_reserved[0]
25 #define s_flags               s_reserved[22]
26 #define EXT2_HASH_HALF_MD4     1
27 #define EXT2_FLAGS_SIGNED_HASH 0x0001
28
29 // whiteout: for writable overlays
30 //#define LINUX_S_IFWHT                  0160000
31 //#define EXT2_FEATURE_INCOMPAT_WHITEOUT 0x0020
32
33 // storage helpers
34 char BUG_wrong_field_size(void);
35 #define STORE_LE(field, value) \
36 do { \
37         if (sizeof(field) == 4) \
38                 field = cpu_to_le32(value); \
39         else if (sizeof(field) == 2) \
40                 field = cpu_to_le16(value); \
41         else if (sizeof(field) == 1) \
42                 field = (value); \
43         else \
44                 BUG_wrong_field_size(); \
45 } while (0)
46
47 #define FETCH_LE32(field) \
48         (sizeof(field) == 4 ? cpu_to_le32(field) : BUG_wrong_field_size())
49
50 // All fields are little-endian
51 struct ext2_dir {
52         uint32_t inode1;
53         uint16_t rec_len1;
54         uint8_t  name_len1;
55         uint8_t  file_type1;
56         char     name1[4];
57         uint32_t inode2;
58         uint16_t rec_len2;
59         uint8_t  name_len2;
60         uint8_t  file_type2;
61         char     name2[4];
62         uint32_t inode3;
63         uint16_t rec_len3;
64         uint8_t  name_len3;
65         uint8_t  file_type3;
66         char     name3[12];
67 };
68
69 static unsigned int_log2(unsigned arg)
70 {
71         unsigned r = 0;
72         while ((arg >>= 1) != 0)
73                 r++;
74         return r;
75 }
76
77 // taken from mkfs_minix.c. libbb candidate?
78 // "uint32_t size", since we never use it for anything >32 bits
79 static uint32_t div_roundup(uint32_t size, uint32_t n)
80 {
81         // Overflow-resistant
82         uint32_t res = size / n;
83         if (res * n != size)
84                 res++;
85         return res;
86 }
87
88 static void allocate(uint8_t *bitmap, uint32_t blocksize, uint32_t start, uint32_t end)
89 {
90         uint32_t i;
91
92 //bb_info_msg("ALLOC: [%u][%u][%u]: [%u-%u]:=[%x],[%x]", blocksize, start, end, start/8, blocksize - end/8 - 1, (1 << (start & 7)) - 1, (uint8_t)(0xFF00 >> (end & 7)));
93         memset(bitmap, 0, blocksize);
94         i = start / 8;
95         memset(bitmap, 0xFF, i);
96         bitmap[i] = (1 << (start & 7)) - 1; //0..7 => 00000000..01111111
97         i = end / 8;
98         bitmap[blocksize - i - 1] |= 0x7F00 >> (end & 7); //0..7 => 00000000..11111110
99         memset(bitmap + blocksize - i, 0xFF, i); // N.B. no overflow here!
100 }
101
102 static uint32_t has_super(uint32_t x)
103 {
104         // 0, 1 and powers of 3, 5, 7 up to 2^32 limit
105         static const uint32_t supers[] = {
106                 0, 1, 3, 5, 7, 9, 25, 27, 49, 81, 125, 243, 343, 625, 729,
107                 2187, 2401, 3125, 6561, 15625, 16807, 19683, 59049, 78125,
108                 117649, 177147, 390625, 531441, 823543, 1594323, 1953125,
109                 4782969, 5764801, 9765625, 14348907, 40353607, 43046721,
110                 48828125, 129140163, 244140625, 282475249, 387420489,
111                 1162261467, 1220703125, 1977326743, 3486784401/* >2^31 */,
112         };
113         const uint32_t *sp = supers + ARRAY_SIZE(supers);
114         while (1) {
115                 sp--;
116                 if (x == *sp)
117                         return 1;
118                 if (x > *sp)
119                         return 0;
120         }
121 }
122
123 /* Standard mke2fs 1.41.9:
124  * Usage: mke2fs [-c|-l filename] [-b block-size] [-f fragment-size]
125  *      [-i bytes-per-inode] [-I inode-size] [-J journal-options]
126  *      [-G meta group size] [-N number-of-inodes]
127  *      [-m reserved-blocks-percentage] [-o creator-os]
128  *      [-g blocks-per-group] [-L volume-label] [-M last-mounted-directory]
129  *      [-O feature[,...]] [-r fs-revision] [-E extended-option[,...]]
130  *      [-T fs-type] [-U UUID] [-jnqvFSV] device [blocks-count]
131 */
132 // N.B. not commented below options are taken and silently ignored
133 enum {
134         OPT_c = 1 << 0,
135         OPT_l = 1 << 1,
136         OPT_b = 1 << 2,         // block size, in bytes
137         OPT_f = 1 << 3,
138         OPT_i = 1 << 4,         // bytes per inode
139         OPT_I = 1 << 5,
140         OPT_J = 1 << 6,
141         OPT_G = 1 << 7,
142         OPT_N = 1 << 8,
143         OPT_m = 1 << 9,         // percentage of blocks reserved for superuser
144         OPT_o = 1 << 10,
145         OPT_g = 1 << 11,
146         OPT_L = 1 << 12,        // label
147         OPT_M = 1 << 13,
148         OPT_O = 1 << 14,
149         OPT_r = 1 << 15,
150         OPT_E = 1 << 16,
151         OPT_T = 1 << 17,
152         OPT_U = 1 << 18,
153         OPT_j = 1 << 19,
154         OPT_n = 1 << 20,        // dry run: do not write anything
155         OPT_q = 1 << 21,
156         OPT_v = 1 << 22,
157         OPT_F = 1 << 23,
158         OPT_S = 1 << 24,
159         //OPT_V = 1 << 25,      // -V version. bbox applets don't support that
160 };
161
162 #define fd 3    /* predefined output descriptor */
163
164 static void PUT(uint64_t off, void *buf, uint32_t size)
165 {
166 //      bb_info_msg("PUT[%llu]:[%u]", off, size);
167         xlseek(fd, off, SEEK_SET);
168         xwrite(fd, buf, size);
169 }
170
171 int mkfs_ext2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
172 int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
173 {
174         unsigned i, pos, n;
175         unsigned bs, bpi;
176         unsigned blocksize, blocksize_log2;
177         unsigned reserved_percent = 5;
178         unsigned long long kilobytes;
179         uint32_t nblocks, nblocks_full;
180         uint32_t nreserved;
181         uint32_t ngroups;
182         uint32_t bytes_per_inode;
183         uint32_t first_block;
184         uint32_t inodes_per_group;
185         uint32_t group_desc_blocks;
186         uint32_t inode_table_blocks;
187         uint32_t lost_and_found_blocks;
188         time_t timestamp;
189         unsigned opts;
190         const char *label = "";
191         struct stat st;
192         struct ext2_super_block *sb; // superblock
193         struct ext2_group_desc *gd; // group descriptors
194         struct ext2_inode *inode;
195         struct ext2_dir *dir;
196         uint8_t *buf;
197
198         opt_complementary = "-1:b+:m+:i+";
199         opts = getopt32(argv, "cl:b:f:i:I:J:G:N:m:o:g:L:M:O:r:E:T:U:jnqvFS",
200                 NULL, &bs, NULL, &bpi, NULL, NULL, NULL, NULL,
201                 &reserved_percent, NULL, NULL, &label, NULL, NULL, NULL, NULL, NULL, NULL);
202         argv += optind; // argv[0] -- device
203
204         // check the device is a block device
205         xmove_fd(xopen(argv[0], O_WRONLY), fd);
206         fstat(fd, &st);
207         if (!S_ISBLK(st.st_mode) && !(opts & OPT_F))
208                 bb_error_msg_and_die("not a block device");
209
210         // check if it is mounted
211         // N.B. what if we format a file? find_mount_point will return false negative since
212         // it is loop block device which mounted!
213         if (find_mount_point(argv[0], 0))
214                 bb_error_msg_and_die("can't format mounted filesystem");
215
216         // open the device, get size in kbytes
217         if (argv[1]) {
218                 kilobytes = xatoull(argv[1]);
219         } else {
220                 kilobytes = (uoff_t)xlseek(fd, 0, SEEK_END) / 1024;
221         }
222
223         bytes_per_inode = 16384;
224         if (kilobytes < 512*1024)
225                 bytes_per_inode = 4096;
226         if (kilobytes < 3*1024)
227                 bytes_per_inode = 8192;
228         if (opts & OPT_i)
229                 bytes_per_inode = bpi;
230
231         // Determine block size
232         // block size is a multiple of 1024
233         blocksize = 1024;
234         if (kilobytes >= 512*1024) // mke2fs 1.41.9 compat
235                 blocksize = 4096;
236         if (EXT2_MAX_BLOCK_SIZE > 4096) {
237                 // kilobytes >> 22 == size in 4gigabyte chunks.
238                 // if size >= 16k gigs, blocksize must be increased.
239                 // Try "mke2fs -F image $((16 * 1024*1024*1024))"
240                 while ((kilobytes >> 22) >= blocksize)
241                         blocksize *= 2;
242         }
243         if (opts & OPT_b)
244                 blocksize = bs;
245         if (blocksize < EXT2_MIN_BLOCK_SIZE
246          || blocksize > EXT2_MAX_BLOCK_SIZE
247          || (blocksize & (blocksize - 1)) // not power of 2
248         ) {
249                 bb_error_msg_and_die("blocksize %u is bad", blocksize);
250         }
251         if ((int32_t)bytes_per_inode < blocksize)
252                 bb_error_msg_and_die("-%c is bad", 'i');
253         // number of bits in one block, i.e. 8*blocksize
254 #define blocks_per_group (8 * blocksize)
255         first_block = (EXT2_MIN_BLOCK_SIZE == blocksize);
256         blocksize_log2 = int_log2(blocksize);
257
258         // Determine number of blocks
259         kilobytes >>= (blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
260         nblocks = kilobytes;
261         if (nblocks != kilobytes)
262                 bb_error_msg_and_die("block count doesn't fit in 32 bits");
263 #define kilobytes kilobytes_unused_after_this
264 //compat problem
265 //      if (blocksize < PAGE_SIZE)
266 //              nblocks &= ~((PAGE_SIZE >> blocksize_log2)-1);
267         // Experimentally, standard mke2fs won't work on images smaller than 60k
268         if (nblocks < 60)
269                 bb_error_msg_and_die("need >= 60 blocks");
270
271         // How many reserved blocks?
272         if (reserved_percent > 50)
273                 bb_error_msg_and_die("-%c is bad", 'm');
274         nreserved = (uint64_t)nblocks * reserved_percent / 100;
275
276         // N.B. killing e2fsprogs feature! Unused blocks don't account in calculations
277         nblocks_full = nblocks;
278
279         // If last block group is too small, nblocks may be decreased in order
280         // to discard it, and control returns here to recalculate some
281         // parameters.
282         // Note: blocksize and bytes_per_inode are never recalculated.
283  retry:
284         // N.B. a block group can have no more than blocks_per_group blocks
285         ngroups = div_roundup(nblocks - first_block, blocks_per_group);
286
287         group_desc_blocks = div_roundup(ngroups, blocksize / sizeof(*gd));
288         // TODO: reserved blocks must be marked as such in the bitmaps,
289         // or resulting filesystem is corrupt
290         if (ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT) {
291                 /*
292                  * From e2fsprogs: Calculate the number of GDT blocks to reserve for online
293                  * filesystem growth.
294                  * The absolute maximum number of GDT blocks we can reserve is determined by
295                  * the number of block pointers that can fit into a single block.
296                  * We set it at 1024x the current filesystem size, or
297                  * the upper block count limit (2^32), whichever is lower.
298                  */
299                 uint32_t reserved_group_desc_blocks = 0xFFFFFFFF; // maximum block number
300                 if (nblocks < reserved_group_desc_blocks / 1024)
301                         reserved_group_desc_blocks = nblocks * 1024;
302                 reserved_group_desc_blocks = div_roundup(reserved_group_desc_blocks - first_block, blocks_per_group);
303                 reserved_group_desc_blocks = div_roundup(reserved_group_desc_blocks, blocksize / sizeof(*gd)) - group_desc_blocks;
304                 if (reserved_group_desc_blocks > blocksize / sizeof(uint32_t))
305                         reserved_group_desc_blocks = blocksize / sizeof(uint32_t);
306                 //TODO: STORE_LE(sb->s_reserved_gdt_blocks, reserved_group_desc_blocks);
307                 group_desc_blocks += reserved_group_desc_blocks;
308         }
309
310         {
311                 // N.B. e2fsprogs does as follows!
312                 uint32_t overhead, remainder;
313                 // ninodes is the max number of inodes in this filesystem
314                 uint32_t ninodes = ((uint64_t) nblocks_full * blocksize) / bytes_per_inode;
315                 if (ninodes < EXT2_GOOD_OLD_FIRST_INO+1)
316                         ninodes = EXT2_GOOD_OLD_FIRST_INO+1;
317                 inodes_per_group = div_roundup(ninodes, ngroups);
318                 // minimum number because the first EXT2_GOOD_OLD_FIRST_INO-1 are reserved
319                 if (inodes_per_group < 16)
320                         inodes_per_group = 16;
321                 // a block group can't have more inodes than blocks
322                 if (inodes_per_group > blocks_per_group)
323                         inodes_per_group = blocks_per_group;
324                 // adjust inodes per group so they completely fill the inode table blocks in the descriptor
325 //incompatibility on images >= 0.5GB:
326 //difference in sizeof(*inode) sometimes
327 //results in slightly bigger inodes_per_group here
328 //compared to standard mke2fs:
329                 inodes_per_group = (div_roundup(inodes_per_group * sizeof(*inode), blocksize) * blocksize) / sizeof(*inode);
330                 // make sure the number of inodes per group is a multiple of 8
331                 inodes_per_group &= ~7;
332                 inode_table_blocks = div_roundup(inodes_per_group * sizeof(*inode), blocksize);
333
334                 // to be useful, lost+found should occupy at least 2 blocks (but not exceeding 16*1024 bytes),
335                 // and at most EXT2_NDIR_BLOCKS. So reserve these blocks right now
336                 /* Or e2fsprogs comment verbatim (what does it mean?):
337                  * Ensure that lost+found is at least 2 blocks, so we always
338                  * test large empty blocks for big-block filesystems. */
339                 lost_and_found_blocks = MIN(EXT2_NDIR_BLOCKS, 16 >> (blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE));
340
341                 // the last group needs more attention: isn't it too small for possible overhead?
342                 overhead = (has_super(ngroups - 1) ? (1/*sb*/ + group_desc_blocks) : 0) + 1/*bbmp*/ + 1/*ibmp*/ + inode_table_blocks;
343                 remainder = (nblocks - first_block) % blocks_per_group;
344                 ////can't happen, nblocks >= 60 guarantees this
345                 ////if ((1 == ngroups)
346                 //// && remainder
347                 //// && (remainder < overhead + 1/* "/" */ + lost_and_found_blocks)
348                 ////) {
349                 ////    bb_error_msg_and_die("way small device");
350                 ////}
351
352                 // Standard mke2fs uses 50. Looks like a bug in our calculation
353                 // of "remainder" or "overhead" - we don't match standard mke2fs
354                 // when we transition from one group to two groups
355                 // (a bit after 8M image size), but it works for two->three groups
356                 // transition (at 16M).
357                 if (remainder && (remainder < overhead + 50)) {
358 //bb_info_msg("CHOP[%u]", remainder);
359                         nblocks -= remainder;
360                         goto retry;
361                 }
362         }
363
364         if (nblocks_full - nblocks)
365                 printf("warning: %u blocks unused\n\n", nblocks_full - nblocks);
366         printf(
367                 "Filesystem label=%s\n"
368                 "OS type: Linux\n"
369                 "Block size=%u (log=%u)\n"
370                 "Fragment size=%u (log=%u)\n"
371                 "%u inodes, %u blocks\n"
372                 "%u blocks (%u%%) reserved for the super user\n"
373                 "First data block=%u\n"
374                 "Maximum filesystem blocks=%u\n"
375                 "%u block groups\n"
376                 "%u blocks per group, %u fragments per group\n"
377                 "%u inodes per group"
378                 , label
379                 , blocksize, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE
380                 , blocksize, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE
381                 , inodes_per_group * ngroups, nblocks
382                 , nreserved, reserved_percent
383                 , first_block
384                 , group_desc_blocks * (blocksize / sizeof(*gd)) * blocks_per_group
385                 , ngroups
386                 , blocks_per_group, blocks_per_group
387                 , inodes_per_group
388         );
389         {
390                 const char *fmt = "\nSuperblock backups stored on blocks:\n"
391                         "\t%u";
392                 pos = first_block;
393                 for (i = 1; i < ngroups; i++) {
394                         pos += blocks_per_group;
395                         if (has_super(i)) {
396                                 printf(fmt, (unsigned)pos);
397                                 fmt = ", %u";
398                         }
399                 }
400         }
401         bb_putchar('\n');
402
403         if (opts & OPT_n) {
404                 if (ENABLE_FEATURE_CLEAN_UP)
405                         close(fd);
406                 return EXIT_SUCCESS;
407         }
408
409         // TODO: 3/5 refuse if mounted
410         // TODO: 4/5 compat options
411         // TODO: 1/5 sanity checks
412         // TODO: 0/5 more verbose error messages
413         // TODO: 4/5 bigendianness: recheck, wait for ARM reporters
414         // TODO: 2/5 reserved GDT: how to mark but not allocate?
415         // TODO: 3/5 dir_index?
416
417         // fill the superblock
418         sb = xzalloc(1024);
419         STORE_LE(sb->s_rev_level, 1); // revision 1 filesystem
420         STORE_LE(sb->s_magic, EXT2_SUPER_MAGIC);
421 //incompatibility:
422 //on images > 0.5GB, standard mke2fs uses 256 byte inodes.
423 //we always use 128 byte ones:
424         STORE_LE(sb->s_inode_size, sizeof(*inode));
425         STORE_LE(sb->s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
426         STORE_LE(sb->s_log_block_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
427         STORE_LE(sb->s_log_frag_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
428         // first 1024 bytes of the device are for boot record. If block size is 1024 bytes, then
429         // the first block is 1, otherwise 0
430         STORE_LE(sb->s_first_data_block, first_block);
431         // block and inode bitmaps occupy no more than one block, so maximum number of blocks is
432         STORE_LE(sb->s_blocks_per_group, blocks_per_group);
433         STORE_LE(sb->s_frags_per_group, blocks_per_group);
434         // blocks
435         STORE_LE(sb->s_blocks_count, nblocks);
436         // reserve blocks for superuser
437         STORE_LE(sb->s_r_blocks_count, nreserved);
438         // ninodes
439         STORE_LE(sb->s_inodes_per_group, inodes_per_group);
440         STORE_LE(sb->s_inodes_count, inodes_per_group * ngroups);
441         STORE_LE(sb->s_free_inodes_count, inodes_per_group * ngroups - EXT2_GOOD_OLD_FIRST_INO);
442         // timestamps
443         timestamp = time(NULL);
444         STORE_LE(sb->s_mkfs_time, timestamp);
445         STORE_LE(sb->s_wtime, timestamp);
446         STORE_LE(sb->s_lastcheck, timestamp);
447         // misc
448         STORE_LE(sb->s_state, 1); // TODO: what's 1?
449         STORE_LE(sb->s_creator_os, EXT2_OS_LINUX);
450         STORE_LE(sb->s_checkinterval, 24*60*60 * 180); // 180 days
451         STORE_LE(sb->s_errors, EXT2_ERRORS_DEFAULT);
452         STORE_LE(sb->s_feature_compat, EXT2_FEATURE_COMPAT_SUPP
453                 | (EXT2_FEATURE_COMPAT_RESIZE_INO * ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT)
454                 | (EXT2_FEATURE_COMPAT_DIR_INDEX * ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX)
455         );
456         // e2fsck from 1.41.9 doesn't like EXT2_FEATURE_INCOMPAT_WHITEOUT
457         STORE_LE(sb->s_feature_incompat, EXT2_FEATURE_INCOMPAT_FILETYPE);// | EXT2_FEATURE_INCOMPAT_WHITEOUT;
458         STORE_LE(sb->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER);
459         STORE_LE(sb->s_flags, EXT2_FLAGS_SIGNED_HASH * ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX);
460         generate_uuid(sb->s_uuid);
461         if (ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX) {
462                 STORE_LE(sb->s_def_hash_version, EXT2_HASH_HALF_MD4);
463                 generate_uuid((uint8_t *)sb->s_hash_seed);
464         }
465         /*
466          * From e2fsprogs: add "jitter" to the superblock's check interval so that we
467          * don't check all the filesystems at the same time.  We use a
468          * kludgy hack of using the UUID to derive a random jitter value.
469          */
470         STORE_LE(sb->s_max_mnt_count,
471                 EXT2_DFL_MAX_MNT_COUNT
472                 + (sb->s_uuid[ARRAY_SIZE(sb->s_uuid)-1] % EXT2_DFL_MAX_MNT_COUNT));
473
474         // write the label
475         safe_strncpy((char *)sb->s_volume_name, label, sizeof(sb->s_volume_name));
476
477         // calculate filesystem skeleton structures
478         gd = xzalloc(group_desc_blocks * blocksize);
479         buf = xmalloc(blocksize);
480         sb->s_free_blocks_count = 0;
481         for (i = 0, pos = first_block, n = nblocks - first_block;
482                 i < ngroups;
483                 i++, pos += blocks_per_group, n -= blocks_per_group
484         ) {
485                 uint32_t overhead = pos + (has_super(i) ? (1/*sb*/ + group_desc_blocks) : 0);
486                 uint32_t free_blocks;
487                 // fill group descriptors
488                 STORE_LE(gd[i].bg_block_bitmap, overhead + 0);
489                 STORE_LE(gd[i].bg_inode_bitmap, overhead + 1);
490                 STORE_LE(gd[i].bg_inode_table, overhead + 2);
491                 overhead = overhead - pos + 1/*bbmp*/ + 1/*ibmp*/ + inode_table_blocks;
492                 gd[i].bg_free_inodes_count = inodes_per_group;
493                 //STORE_LE(gd[i].bg_used_dirs_count, 0);
494                 // N.B. both "/" and "/lost+found" are within the first block group
495                 // "/" occupies 1 block, "/lost+found" occupies lost_and_found_blocks...
496                 if (0 == i) {
497                         // ... thus increased overhead for the first block group ...
498                         overhead += 1 + lost_and_found_blocks;
499                         // ... and 2 used directories
500                         STORE_LE(gd[i].bg_used_dirs_count, 2);
501                         // well known reserved inodes belong to the first block too
502                         gd[i].bg_free_inodes_count -= EXT2_GOOD_OLD_FIRST_INO;
503                 }
504
505                 // cache free block count of the group
506                 free_blocks = (n < blocks_per_group ? n : blocks_per_group) - overhead;
507
508                 // mark preallocated blocks as allocated
509 //bb_info_msg("ALLOC: [%u][%u][%u]", blocksize, overhead, blocks_per_group - (free_blocks + overhead));
510                 allocate(buf, blocksize,
511                         // reserve "overhead" blocks
512                         overhead,
513                         // mark unused trailing blocks
514                         blocks_per_group - (free_blocks + overhead)
515                 );
516                 // dump block bitmap
517                 PUT((uint64_t)(FETCH_LE32(gd[i].bg_block_bitmap)) * blocksize, buf, blocksize);
518                 STORE_LE(gd[i].bg_free_blocks_count, free_blocks);
519
520                 // mark preallocated inodes as allocated
521                 allocate(buf, blocksize,
522                         // mark reserved inodes
523                         inodes_per_group - gd[i].bg_free_inodes_count,
524                         // mark unused trailing inodes
525                         blocks_per_group - inodes_per_group
526                 );
527                 // dump inode bitmap
528                 //PUT((uint64_t)(FETCH_LE32(gd[i].bg_block_bitmap)) * blocksize, buf, blocksize);
529                 //but it's right after block bitmap, so we can just:
530                 xwrite(fd, buf, blocksize);
531                 STORE_LE(gd[i].bg_free_inodes_count, gd[i].bg_free_inodes_count);
532
533                 // count overall free blocks
534                 sb->s_free_blocks_count += free_blocks;
535         }
536         STORE_LE(sb->s_free_blocks_count, sb->s_free_blocks_count);
537
538         // dump filesystem skeleton structures
539 //      printf("Writing superblocks and filesystem accounting information: ");
540         for (i = 0, pos = first_block; i < ngroups; i++, pos += blocks_per_group) {
541                 // dump superblock and group descriptors and their backups
542                 if (has_super(i)) {
543                         // N.B. 1024 byte blocks are special
544                         PUT(((uint64_t)pos * blocksize) + ((0 == i && 1024 != blocksize) ? 1024 : 0),
545                                         sb, 1024);
546                         PUT(((uint64_t)pos * blocksize) + blocksize,
547                                         gd, group_desc_blocks * blocksize);
548                 }
549         }
550
551         // zero boot sectors
552         memset(buf, 0, blocksize);
553         PUT(0, buf, 1024); // N.B. 1024 <= blocksize, so buf[0..1023] contains zeros
554         // zero inode tables
555         for (i = 0; i < ngroups; ++i)
556                 for (n = 0; n < inode_table_blocks; ++n)
557                         PUT((uint64_t)(FETCH_LE32(gd[i].bg_inode_table) + n) * blocksize,
558                                 buf, blocksize);
559
560         // prepare directory inode
561         inode = (struct ext2_inode *)buf;
562         STORE_LE(inode->i_mode, S_IFDIR | S_IRWXU | S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH);
563         STORE_LE(inode->i_mtime, timestamp);
564         STORE_LE(inode->i_atime, timestamp);
565         STORE_LE(inode->i_ctime, timestamp);
566         STORE_LE(inode->i_size, blocksize);
567         // inode->i_blocks stores the number of 512 byte data blocks
568         // (512, because it goes directly to struct stat without scaling)
569         STORE_LE(inode->i_blocks, blocksize / 512);
570
571         // dump root dir inode
572         STORE_LE(inode->i_links_count, 3); // "/.", "/..", "/lost+found/.." point to this inode
573         STORE_LE(inode->i_block[0], FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks);
574         PUT(((uint64_t)FETCH_LE32(gd[0].bg_inode_table) * blocksize) + (EXT2_ROOT_INO-1) * sizeof(*inode),
575                                 buf, sizeof(*inode));
576
577         // dump lost+found dir inode
578         STORE_LE(inode->i_links_count, 2); // both "/lost+found" and "/lost+found/." point to this inode
579         STORE_LE(inode->i_size, lost_and_found_blocks * blocksize);
580         STORE_LE(inode->i_blocks, (lost_and_found_blocks * blocksize) / 512);
581         n = FETCH_LE32(inode->i_block[0]) + 1;
582         for (i = 0; i < lost_and_found_blocks; ++i)
583                 STORE_LE(inode->i_block[i], i + n); // use next block
584 //bb_info_msg("LAST BLOCK USED[%u]", i + n);
585         PUT(((uint64_t)FETCH_LE32(gd[0].bg_inode_table) * blocksize) + (EXT2_GOOD_OLD_FIRST_INO-1) * sizeof(*inode),
586                                 buf, sizeof(*inode));
587
588         // zero the blocks for "/lost+found"
589         memset(buf, 0, blocksize);
590         for (i = 1; i < lost_and_found_blocks; ++i)
591                 PUT((uint64_t)(FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks + 1+i) * blocksize,
592                                 buf, blocksize);
593
594         // dump directories
595         dir = (struct ext2_dir *)buf;
596
597         // dump lost+found dir block
598         STORE_LE(dir->inode1, EXT2_GOOD_OLD_FIRST_INO);
599         STORE_LE(dir->rec_len1, 12);
600         STORE_LE(dir->name_len1, 1);
601         STORE_LE(dir->file_type1, EXT2_FT_DIR);
602         dir->name1[0] = '.';
603         STORE_LE(dir->inode2, EXT2_ROOT_INO);
604         STORE_LE(dir->rec_len2, blocksize - 12);
605         STORE_LE(dir->name_len2, 2);
606         STORE_LE(dir->file_type2, EXT2_FT_DIR);
607         dir->name2[0] = '.'; dir->name2[1] = '.';
608         PUT((uint64_t)(FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks + 1) * blocksize, buf, blocksize);
609
610         // dump root dir block
611         STORE_LE(dir->inode1, EXT2_ROOT_INO);
612         STORE_LE(dir->rec_len2, 12);
613         STORE_LE(dir->inode3, EXT2_GOOD_OLD_FIRST_INO);
614         STORE_LE(dir->rec_len3, blocksize - 12 - 12);
615         STORE_LE(dir->name_len3, 10);
616         STORE_LE(dir->file_type3, EXT2_FT_DIR);
617         strcpy(dir->name3, "lost+found");
618         PUT((uint64_t)(FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks + 0) * blocksize, buf, blocksize);
619
620         // cleanup
621         if (ENABLE_FEATURE_CLEAN_UP) {
622                 free(buf);
623                 free(gd);
624                 free(sb);
625         }
626
627         xclose(fd);
628         return EXIT_SUCCESS;
629 }