aboutsummaryrefslogtreecommitdiff
path: root/util-linux/mkfs_ext2.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-10-20 00:06:03 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-10-20 00:06:03 +0200
commit05647b55512d0fec74fe6d69553a773e852674df (patch)
treee12249ce2de19cfc4280f2850574958202eb8d9c /util-linux/mkfs_ext2.c
parent3ef4f77620a9f5f9a7c1247e29ea9c14e07b8a30 (diff)
downloadbusybox-w32-05647b55512d0fec74fe6d69553a773e852674df.tar.gz
busybox-w32-05647b55512d0fec74fe6d69553a773e852674df.tar.bz2
busybox-w32-05647b55512d0fec74fe6d69553a773e852674df.zip
mkfs_ext2: compat fixes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'util-linux/mkfs_ext2.c')
-rw-r--r--util-linux/mkfs_ext2.c387
1 files changed, 197 insertions, 190 deletions
diff --git a/util-linux/mkfs_ext2.c b/util-linux/mkfs_ext2.c
index 38654ef04..d0ebc1dd9 100644
--- a/util-linux/mkfs_ext2.c
+++ b/util-linux/mkfs_ext2.c
@@ -10,6 +10,10 @@
10#include "libbb.h" 10#include "libbb.h"
11#include <linux/fs.h> 11#include <linux/fs.h>
12#include <linux/ext2_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
13#include "volume_id/volume_id_internal.h" 17#include "volume_id/volume_id_internal.h"
14 18
15#define ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT 0 19#define ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT 0
@@ -26,8 +30,8 @@
26//#define LINUX_S_IFWHT 0160000 30//#define LINUX_S_IFWHT 0160000
27//#define EXT2_FEATURE_INCOMPAT_WHITEOUT 0x0020 31//#define EXT2_FEATURE_INCOMPAT_WHITEOUT 0x0020
28 32
29// storage helper 33// storage helpers
30void BUG_unsupported_field_size(void); 34char BUG_wrong_field_size(void);
31#define STORE_LE(field, value) \ 35#define STORE_LE(field, value) \
32do { \ 36do { \
33 if (sizeof(field) == 4) \ 37 if (sizeof(field) == 4) \
@@ -37,9 +41,12 @@ do { \
37 else if (sizeof(field) == 1) \ 41 else if (sizeof(field) == 1) \
38 field = (value); \ 42 field = (value); \
39 else \ 43 else \
40 BUG_unsupported_field_size(); \ 44 BUG_wrong_field_size(); \
41} while (0) 45} while (0)
42 46
47#define FETCH_LE32(field) \
48 (sizeof(field) == 4 ? cpu_to_le32(field) : BUG_wrong_field_size())
49
43// All fields are little-endian 50// All fields are little-endian
44struct ext2_dir { 51struct ext2_dir {
45 uint32_t inode1; 52 uint32_t inode1;
@@ -68,10 +75,10 @@ static unsigned int_log2(unsigned arg)
68} 75}
69 76
70// taken from mkfs_minix.c. libbb candidate? 77// taken from mkfs_minix.c. libbb candidate?
71static unsigned div_roundup(uint32_t size, uint32_t n) 78static unsigned div_roundup(uint64_t size, uint32_t n)
72{ 79{
73 // Overflow-resistant 80 // Overflow-resistant
74 uint32_t res = size / n; 81 uint64_t res = size / n;
75 if (res * n != size) 82 if (res * n != size)
76 res++; 83 res++;
77 return res; 84 return res;
@@ -83,8 +90,8 @@ static void allocate(uint8_t *bitmap, uint32_t blocksize, uint32_t start, uint32
83 memset(bitmap, 0, blocksize); 90 memset(bitmap, 0, blocksize);
84 i = start / 8; 91 i = start / 8;
85 memset(bitmap, 0xFF, i); 92 memset(bitmap, 0xFF, i);
86 bitmap[i] = 0xFF >> (8-(start&7)); 93 bitmap[i] = 0xFF >> (8 - (start & 7));
87//bb_info_msg("ALLOC: [%u][%u][%u]: [%u]:=[%x]", blocksize, start, end, blocksize - end/8 - 1, (uint8_t)(0xFF << (8-(end&7)))); 94//bb_info_msg("ALLOC: [%u][%u][%u]: [%u-%u]:=[%x],[%x]", blocksize, start, end, start/8, blocksize - end/8 - 1, 0xFF >> (8 - (start & 7)), (uint8_t)(0xFF << (8-(end&7))));
88 i = end / 8; 95 i = end / 8;
89 bitmap[blocksize - i - 1] = 0xFF << (8 - (end & 7)); 96 bitmap[blocksize - i - 1] = 0xFF << (8 - (end & 7));
90 memset(bitmap + blocksize - i, 0xFF, i); // N.B. no overflow here! 97 memset(bitmap + blocksize - i, 0xFF, i); // N.B. no overflow here!
@@ -167,15 +174,15 @@ int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
167 unsigned blocksize, blocksize_log2; 174 unsigned blocksize, blocksize_log2;
168 unsigned nreserved = 5; 175 unsigned nreserved = 5;
169 unsigned long long kilobytes; 176 unsigned long long kilobytes;
170 uint32_t nblocks; 177 uint32_t nblocks, nblocks_full;
171 uint32_t ngroups; 178 uint32_t ngroups;
172 uint32_t bytes_per_inode; 179 uint32_t bytes_per_inode;
173 uint32_t first_data_block; 180 uint32_t first_data_block;
174 uint32_t ninodes_per_group; 181 uint32_t inodes_per_group;
175 uint32_t gdtsz, itsz; 182 uint32_t gdtsz, itsz;
176 time_t timestamp; 183 time_t timestamp;
177 unsigned opts; 184 unsigned opts;
178 const char *label; 185 const char *label = "";
179 struct stat st; 186 struct stat st;
180 struct ext2_super_block *sb; // superblock 187 struct ext2_super_block *sb; // superblock
181 struct ext2_group_desc *gd; // group descriptors 188 struct ext2_group_desc *gd; // group descriptors
@@ -245,145 +252,85 @@ int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
245 nblocks = kilobytes; 252 nblocks = kilobytes;
246 if (nblocks != kilobytes) 253 if (nblocks != kilobytes)
247 bb_error_msg_and_die("block count doesn't fit in 32 bits"); 254 bb_error_msg_and_die("block count doesn't fit in 32 bits");
255#define kilobytes kilobytes_unused_after_this
256
257 if (blocksize < PAGE_SIZE)
258 nblocks &= ~((PAGE_SIZE / blocksize)-1);
259
260 // N.B. killing e2fsprogs feature! Unused blocks don't account in calculations
261 nblocks_full = nblocks;
262 retry:
248 if (nblocks < 8) 263 if (nblocks < 8)
249 bb_error_msg_and_die("need >= 8 blocks"); 264 bb_error_msg_and_die("need >= 8 blocks");
250#define kilobytes kilobytes_unused_after_this
251 265
252 // number of bits in one block, i.e. 8*blocksize 266 // number of bits in one block, i.e. 8*blocksize
253#define blocks_per_group (8 * blocksize) 267#define blocks_per_group (8 * blocksize)
254 268
255/* e2fsprogs-1.41.9
256 overhead = 2 + fs->inode_blocks_per_group;
257 if (has_super(fs->group_desc_count - 1))
258 overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;
259 rem = (nblocks - first_data_block) % blocks_per_group);
260 if ((fs->group_desc_count == 1) && rem && (rem < overhead)) {
261 retval = EXT2_ET_TOOSMALL;
262 goto cleanup;
263 }
264 if (rem && (rem < overhead+50)) {
265 nblocks -= rem;
266 goto retry;
267 }
268*/
269
270 // N.B. a block group can have no more than blocks_per_group blocks 269 // N.B. a block group can have no more than blocks_per_group blocks
271 first_data_block = (EXT2_MIN_BLOCK_SIZE == blocksize); 270 first_data_block = (EXT2_MIN_BLOCK_SIZE == blocksize);
272 ngroups = div_roundup(nblocks - first_data_block, blocks_per_group); 271 ngroups = div_roundup(nblocks - first_data_block, blocks_per_group);
273 if (0 == ngroups) 272 if (0 == ngroups)
274 bb_error_msg_and_die("ngroups"); 273 bb_error_msg_and_die("ngroups");
275 274
276 { 275 gdtsz = div_roundup(ngroups, blocksize / sizeof(*gd));
277 // ninodes is the total number of inodes (files) in the file system 276 // TODO: reserved blocks must be marked as such in the bitmaps,
278 uint32_t ninodes = nblocks / (bytes_per_inode >> blocksize_log2); 277 // or resulting filesystem is corrupt
279 if (ninodes < EXT2_GOOD_OLD_FIRST_INO+1)
280 ninodes = EXT2_GOOD_OLD_FIRST_INO+1;
281 ninodes_per_group = div_roundup(ninodes, ngroups);
282 // minimum number because the first EXT2_GOOD_OLD_FIRST_INO-1 are reserved
283 if (ninodes_per_group < 16)
284 ninodes_per_group = 16;
285 }
286
287 // TODO: 5?/5 WE MUST NOT DEPEND ON WHETHER DEVICE IS /dev/zero 'ed OR NOT
288 // TODO: 3/5 refuse if mounted
289 // TODO: 4/5 compat options
290 // TODO: 1/5 sanity checks
291 // TODO: 0/5 more verbose error messages
292 // TODO: 0/5 info printing
293 // TODO: 2/5 bigendianness! Spot where it comes to play! sb->, gd->
294 // TODO: 2/5 reserved GDT: how to mark but not allocate?
295 // TODO: 3/5 dir_index?
296
297 // fill the superblock
298 sb = xzalloc(blocksize);
299 sb->s_rev_level = 1; // revision 1 filesystem
300 sb->s_magic = EXT2_SUPER_MAGIC;
301 sb->s_inode_size = sizeof(*inode);
302 sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
303 sb->s_log_block_size = sb->s_log_frag_size = blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE;
304 // first 1024 bytes of the device are for boot record. If block size is 1024 bytes, then
305 // the first block available for data is 1, otherwise 0
306 sb->s_first_data_block = first_data_block; // 0 or 1
307 // block and inode bitmaps occupy no more than one block, so maximum number of blocks is
308 sb->s_blocks_per_group = sb->s_frags_per_group = blocks_per_group;
309 timestamp = time(NULL);
310 sb->s_mkfs_time = sb->s_wtime = sb->s_lastcheck = timestamp;
311 sb->s_state = 1;
312 sb->s_creator_os = EXT2_OS_LINUX;
313 sb->s_checkinterval = 24*60*60 * 180; // 180 days
314 sb->s_errors = EXT2_ERRORS_DEFAULT;
315 sb->s_feature_compat = EXT2_FEATURE_COMPAT_SUPP
316 | (EXT2_FEATURE_COMPAT_RESIZE_INO * ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT)
317 | (EXT2_FEATURE_COMPAT_DIR_INDEX * ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX)
318 ;
319 // e2fsprogs-1.41.9 doesn't like EXT2_FEATURE_INCOMPAT_WHITEOUT
320 sb->s_feature_incompat = EXT2_FEATURE_INCOMPAT_FILETYPE;// | EXT2_FEATURE_INCOMPAT_WHITEOUT;
321 sb->s_feature_ro_compat = EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
322 sb->s_flags = EXT2_FLAGS_SIGNED_HASH * ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX;
323 generate_uuid(sb->s_uuid);
324 if (ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX) {
325 sb->s_def_hash_version = EXT2_HASH_HALF_MD4;
326 generate_uuid((uint8_t *)sb->s_hash_seed);
327 }
328 /*
329 * From e2fsprogs: add "jitter" to the superblock's check interval so that we
330 * don't check all the filesystems at the same time. We use a
331 * kludgy hack of using the UUID to derive a random jitter value.
332 */
333 sb->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT
334 + (sb->s_uuid[ARRAY_SIZE(sb->s_uuid)-1] % EXT2_DFL_MAX_MNT_COUNT);
335
336 sb->s_blocks_count = nblocks;
337
338 // reserve blocks for superuser
339 sb->s_r_blocks_count = ((uint64_t) nblocks * nreserved) / 100;
340
341 gdtsz = div_roundup(ngroups, EXT2_DESC_PER_BLOCK(sb));
342 /*
343 * From e2fsprogs: Calculate the number of GDT blocks to reserve for online
344 * filesystem growth.
345 * The absolute maximum number of GDT blocks we can reserve is determined by
346 * the number of block pointers that can fit into a single block.
347 */
348 /* We set it at 1024x the current filesystem size, or
349 * the upper block count limit (2^32), whichever is lower.
350 */
351 if (ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT) { 278 if (ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT) {
279 /*
280 * From e2fsprogs: Calculate the number of GDT blocks to reserve for online
281 * filesystem growth.
282 * The absolute maximum number of GDT blocks we can reserve is determined by
283 * the number of block pointers that can fit into a single block.
284 * We set it at 1024x the current filesystem size, or
285 * the upper block count limit (2^32), whichever is lower.
286 */
352 uint32_t rgdtsz = 0xFFFFFFFF; // maximum block number 287 uint32_t rgdtsz = 0xFFFFFFFF; // maximum block number
353 if (nblocks < rgdtsz / 1024) 288 if (nblocks < rgdtsz / 1024)
354 rgdtsz = nblocks * 1024; 289 rgdtsz = nblocks * 1024;
355 rgdtsz = div_roundup(rgdtsz - first_data_block, blocks_per_group); 290 rgdtsz = div_roundup(rgdtsz - first_data_block, blocks_per_group);
356 rgdtsz = div_roundup(rgdtsz, EXT2_DESC_PER_BLOCK(sb)) - gdtsz; 291 rgdtsz = div_roundup(rgdtsz, blocksize / sizeof(*gd)) - gdtsz;
357 if (rgdtsz > EXT2_ADDR_PER_BLOCK(sb)) 292 if (rgdtsz > blocksize / sizeof(uint32_t))
358 rgdtsz = EXT2_ADDR_PER_BLOCK(sb); 293 rgdtsz = blocksize / sizeof(uint32_t);
359 STORE_LE(sb->s_reserved_gdt_blocks, rgdtsz); 294 //TODO: STORE_LE(sb->s_reserved_gdt_blocks, rgdtsz);
360 gdtsz += rgdtsz; 295 gdtsz += rgdtsz;
361 } 296 }
362 297
363 // N.B. a block group can have no more than 8*blocksize inodes 298 {
364 if (ninodes_per_group > blocks_per_group) 299 // N.B. e2fsprogs does as follows!
365 ninodes_per_group = blocks_per_group; 300 // ninodes is the total number of inodes (files) in the file system
366 // adjust inodes per group so they completely fill the inode table blocks in the descriptor 301 uint32_t ninodes = nblocks_full / (blocksize >= 4096 ? 1 : 4096 / blocksize);
367 ninodes_per_group = (div_roundup(ninodes_per_group * EXT2_INODE_SIZE(sb), blocksize) << blocksize_log2) / EXT2_INODE_SIZE(sb); 302 uint32_t overhead, remainder;
368 // make sure the number of inodes per group is a multiple of 8 303 if (ninodes < EXT2_GOOD_OLD_FIRST_INO+1)
369 ninodes_per_group &= ~7; 304 ninodes = EXT2_GOOD_OLD_FIRST_INO+1;
370 sb->s_inodes_per_group = ninodes_per_group;// = div_roundup(ninodes_per_group * sb->s_inode_size, blocksize); 305 inodes_per_group = div_roundup(ninodes, ngroups);
371 // total ninodes 306 // minimum number because the first EXT2_GOOD_OLD_FIRST_INO-1 are reserved
372 sb->s_inodes_count = ninodes_per_group * ngroups; 307 if (inodes_per_group < 16)
373 308 inodes_per_group = 16;
374 itsz = ninodes_per_group * sb->s_inode_size / blocksize; 309
375 sb->s_free_inodes_count = sb->s_inodes_count - EXT2_GOOD_OLD_FIRST_INO; 310 // N.B. a block group can have no more than 8*blocksize inodes
376 311 if (inodes_per_group > blocks_per_group)
377 // write the label, if any 312 inodes_per_group = blocks_per_group;
378 if (opts & OPT_L) 313 // adjust inodes per group so they completely fill the inode table blocks in the descriptor
379 safe_strncpy((char *)sb->s_volume_name, label, sizeof(sb->s_volume_name)); 314 inodes_per_group = (div_roundup(inodes_per_group * sizeof(*inode), blocksize) << blocksize_log2) / sizeof(*inode);
380 315 // make sure the number of inodes per group is a multiple of 8
381#if 1 316 inodes_per_group &= ~7;
382/* if (fs_param.s_blocks_count != s->s_blocks_count) 317 itsz = div_roundup(inodes_per_group * sizeof(*inode), blocksize);
383 fprintf(stderr, _("warning: %u blocks unused.\n\n"), 318
384 fs_param.s_blocks_count - s->s_blocks_count); 319 // the last block needs more attention: doesn't it too small for possible overhead?
385*/ 320 overhead = (has_super(ngroups - 1) ? (1/*sb*/ + gdtsz) : 0) + 1/*bbmp*/ + 1/*ibmp*/ + itsz;
321 remainder = (nblocks - first_data_block) % blocks_per_group;
322 if ((1 == ngroups) && remainder && (remainder < overhead))
323 bb_error_msg_and_die("way small device");
324 if (remainder && (remainder < overhead + 50)) {
325//bb_info_msg("CHOP[%u]", remainder);
326 nblocks -= remainder;
327 goto retry;
328 }
329 }
386 330
331 // print info
332 if (nblocks_full - nblocks)
333 printf("warning: %u blocks unused\n\n", nblocks_full - nblocks);
387 printf( 334 printf(
388 "Filesystem label=%s\n" 335 "Filesystem label=%s\n"
389 "OS type: Linux\n" 336 "OS type: Linux\n"
@@ -396,16 +343,17 @@ int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
396 "%u block groups\n" 343 "%u block groups\n"
397 "%u blocks per group, %u fragments per group\n" 344 "%u blocks per group, %u fragments per group\n"
398 "%u inodes per group" 345 "%u inodes per group"
399 , (char *)sb->s_volume_name 346 , label
400 , blocksize, sb->s_log_block_size 347 , blocksize, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE
401 , blocksize, sb->s_log_block_size 348 , blocksize, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE
402 , sb->s_inodes_count, sb->s_blocks_count 349 , inodes_per_group * ngroups, nblocks
403 , sb->s_r_blocks_count, nreserved 350 //, div_roundup((uint64_t) nblocks * nreserved, 100), nreserved
351 , (unsigned)((uint64_t) nblocks_full * nreserved / 100), nreserved
404 , first_data_block 352 , first_data_block
405 , gdtsz * EXT2_DESC_PER_BLOCK(sb) * blocks_per_group 353 , gdtsz * (blocksize / sizeof(*gd)) * blocks_per_group
406 , ngroups 354 , ngroups
407 , blocks_per_group, blocks_per_group 355 , blocks_per_group, blocks_per_group
408 , ninodes_per_group 356 , inodes_per_group
409 ); 357 );
410 { 358 {
411 const char *fmt = "\nSuperblock backups stored on blocks:\n" 359 const char *fmt = "\nSuperblock backups stored on blocks:\n"
@@ -420,84 +368,149 @@ int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
420 } 368 }
421 } 369 }
422 bb_putchar('\n'); 370 bb_putchar('\n');
423#endif
424 371
372 // dry run? -> we are done
425 if (opts & OPT_n) 373 if (opts & OPT_n)
426 goto done; 374 goto done;
427 375
376 // TODO: 3/5 refuse if mounted
377 // TODO: 4/5 compat options
378 // TODO: 1/5 sanity checks
379 // TODO: 0/5 more verbose error messages
380 // TODO: 4/5 bigendianness: recheck, wait for ARM reporters
381 // TODO: 2/5 reserved GDT: how to mark but not allocate?
382 // TODO: 3/5 dir_index?
383
384 // fill the superblock
385 sb = xzalloc(blocksize);
386 STORE_LE(sb->s_rev_level, 1); // revision 1 filesystem
387 STORE_LE(sb->s_magic, EXT2_SUPER_MAGIC);
388 STORE_LE(sb->s_inode_size, sizeof(*inode));
389 STORE_LE(sb->s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
390 STORE_LE(sb->s_log_block_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
391 STORE_LE(sb->s_log_frag_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
392 // first 1024 bytes of the device are for boot record. If block size is 1024 bytes, then
393 // the first block available for data is 1, otherwise 0
394 STORE_LE(sb->s_first_data_block, first_data_block); // 0 or 1
395 // block and inode bitmaps occupy no more than one block, so maximum number of blocks is
396 STORE_LE(sb->s_blocks_per_group, blocks_per_group);
397 STORE_LE(sb->s_frags_per_group, blocks_per_group);
398 // blocks
399 STORE_LE(sb->s_blocks_count, nblocks);
400 // reserve blocks for superuser
401 STORE_LE(sb->s_r_blocks_count, (uint32_t)((uint64_t) nblocks_full * nreserved / 100));
402 // ninodes
403 STORE_LE(sb->s_inodes_per_group, inodes_per_group);
404 STORE_LE(sb->s_inodes_count, inodes_per_group * ngroups);
405 STORE_LE(sb->s_free_inodes_count, inodes_per_group * ngroups - EXT2_GOOD_OLD_FIRST_INO);
406 // timestamps
407 timestamp = time(NULL);
408 STORE_LE(sb->s_mkfs_time, timestamp);
409 STORE_LE(sb->s_wtime, timestamp);
410 STORE_LE(sb->s_lastcheck, timestamp);
411 // misc
412 STORE_LE(sb->s_state, 1); // TODO: what's 1?
413 STORE_LE(sb->s_creator_os, EXT2_OS_LINUX);
414 STORE_LE(sb->s_checkinterval, 24*60*60 * 180); // 180 days
415 STORE_LE(sb->s_errors, EXT2_ERRORS_DEFAULT);
416 STORE_LE(sb->s_feature_compat, EXT2_FEATURE_COMPAT_SUPP
417 | (EXT2_FEATURE_COMPAT_RESIZE_INO * ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT)
418 | (EXT2_FEATURE_COMPAT_DIR_INDEX * ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX)
419 );
420 // e2fsprogs-1.41.9 doesn't like EXT2_FEATURE_INCOMPAT_WHITEOUT
421 STORE_LE(sb->s_feature_incompat, EXT2_FEATURE_INCOMPAT_FILETYPE);// | EXT2_FEATURE_INCOMPAT_WHITEOUT;
422 STORE_LE(sb->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER);
423 STORE_LE(sb->s_flags, EXT2_FLAGS_SIGNED_HASH * ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX);
424 generate_uuid(sb->s_uuid);
425 if (ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX) {
426 STORE_LE(sb->s_def_hash_version, EXT2_HASH_HALF_MD4);
427 generate_uuid((uint8_t *)sb->s_hash_seed);
428 }
429 /*
430 * From e2fsprogs: add "jitter" to the superblock's check interval so that we
431 * don't check all the filesystems at the same time. We use a
432 * kludgy hack of using the UUID to derive a random jitter value.
433 */
434 STORE_LE(sb->s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT
435 + (sb->s_uuid[ARRAY_SIZE(sb->s_uuid)-1] % EXT2_DFL_MAX_MNT_COUNT));
436
437 // write the label, if any
438 if (label) //opts & OPT_L)
439 safe_strncpy((char *)sb->s_volume_name, label, sizeof(sb->s_volume_name));
440
428 // fill group descriptors 441 // fill group descriptors
429 gd = xzalloc(gdtsz * blocksize); 442 gd = xzalloc(gdtsz * blocksize);
443 buf = xmalloc(blocksize);
430 sb->s_free_blocks_count = 0; 444 sb->s_free_blocks_count = 0;
431 for (i = 0, pos = first_data_block, n = nblocks; 445 for (i = 0, pos = first_data_block, n = nblocks - first_data_block;
432 i < ngroups; 446 i < ngroups;
433 i++, pos += blocks_per_group, n -= blocks_per_group 447 i++, pos += blocks_per_group, n -= blocks_per_group
434 ) { 448 ) {
435 uint32_t overhead = pos + (has_super(i) ? (1/*sb*/ + gdtsz) : 0); 449 uint32_t overhead = pos + (has_super(i) ? (1/*sb*/ + gdtsz) : 0);
436 gd[i].bg_block_bitmap = overhead + 0; 450 uint32_t fb;
437 gd[i].bg_inode_bitmap = overhead + 1; 451 STORE_LE(gd[i].bg_block_bitmap, overhead + 0);
438 gd[i].bg_inode_table = overhead + 2; 452 STORE_LE(gd[i].bg_inode_bitmap, overhead + 1);
453 STORE_LE(gd[i].bg_inode_table, overhead + 2);
439 overhead = overhead - pos + 1/*bbmp*/ + 1/*ibmp*/ + itsz; 454 overhead = overhead - pos + 1/*bbmp*/ + 1/*ibmp*/ + itsz;
440 gd[i].bg_free_inodes_count = ninodes_per_group; 455 gd[i].bg_free_inodes_count = inodes_per_group;
441 //gd[i].bg_used_dirs_count = 0; 456 //STORE_LE(gd[i].bg_used_dirs_count, 0);
442 // N.B. both root and lost+found dirs are within the first block group, thus +2 457 // N.B. both root and lost+found dirs are within the first block group, thus +2
443 if (0 == i) { 458 if (0 == i) {
444 overhead += 2; 459 overhead += 2;
445 gd[i].bg_used_dirs_count = 2; 460 STORE_LE(gd[i].bg_used_dirs_count, 2);
446 gd[i].bg_free_inodes_count -= EXT2_GOOD_OLD_FIRST_INO; 461 gd[i].bg_free_inodes_count -= EXT2_GOOD_OLD_FIRST_INO;
447 } 462 }
448 // N.B. the following is pure heuristics! 463// // N.B. the following is pure heuristics!
449 // Likely to cope with 1024-byte blocks, when first block is for boot sectors 464// // Likely to cope with 1024-byte blocks, when first block is for boot sectors
450 if (ngroups-1 == i) { 465// if (ngroups-1 == i) {
451 overhead += first_data_block; 466// n -= first_data_block;
452 } 467// }
453 gd[i].bg_free_blocks_count = (n < blocks_per_group ? n : blocks_per_group) - overhead; 468
454 sb->s_free_blocks_count += gd[i].bg_free_blocks_count; 469 // mark preallocated blocks as allocated
470 fb = (n < blocks_per_group ? n : blocks_per_group) - overhead;
471//bb_info_msg("ALLOC: [%u][%u][%u]", blocksize, overhead, blocks_per_group - (fb + overhead));
472 allocate(buf, blocksize,
473 overhead,
474 blocks_per_group - (fb + overhead)
475 );
476 // dump block bitmap
477 PUT((uint64_t)(FETCH_LE32(gd[i].bg_block_bitmap)) * blocksize, buf, blocksize);
478 STORE_LE(gd[i].bg_free_blocks_count, fb);
479
480 // mark preallocated inodes as allocated
481 allocate(buf, blocksize,
482 inodes_per_group - gd[i].bg_free_inodes_count,
483 blocks_per_group - inodes_per_group
484 );
485 // dump inode bitmap
486 //PUT((uint64_t)(FETCH_LE32(gd[i].bg_block_bitmap)) * blocksize, buf, blocksize);
487 //but it's right after block bitmap, so we can just:
488 xwrite(fd, buf, blocksize);
489 STORE_LE(gd[i].bg_free_inodes_count, gd[i].bg_free_inodes_count);
490
491 // count overall free blocks
492 sb->s_free_blocks_count += fb;
455 } 493 }
456 STORE_LE(sb->s_free_blocks_count, sb->s_free_blocks_count); 494 STORE_LE(sb->s_free_blocks_count, sb->s_free_blocks_count);
457 495
458 // dump filesystem skeleton structures 496 // dump filesystem skeleton structures
459// printf("Writing superblocks and filesystem accounting information: "); 497// printf("Writing superblocks and filesystem accounting information: ");
460 buf = xmalloc(blocksize);
461 for (i = 0, pos = first_data_block; i < ngroups; i++, pos += blocks_per_group) { 498 for (i = 0, pos = first_data_block; i < ngroups; i++, pos += blocks_per_group) {
462 uint32_t overhead = has_super(i) ? (1/*sb*/ + gdtsz) : 0;
463 uint32_t start;
464 uint32_t end;
465
466 // dump superblock and group descriptors and their backups 499 // dump superblock and group descriptors and their backups
467 if (overhead) { // N.B. in fact, we want (has_super(i)) condition, but it is equal to (overhead != 0) and is cheaper 500 if (has_super(i)) {
468 // N.B. 1024 byte blocks are special 501 // N.B. 1024 byte blocks are special
469 PUT(((uint64_t)pos << blocksize_log2) + ((0 == i && 0 == first_data_block) ? 1024 : 0), sb, 1024);//blocksize); 502 PUT(((uint64_t)pos << blocksize_log2) + ((0 == i && 0 == first_data_block) ? 1024 : 0), sb, 1024);//blocksize);
470 PUT(((uint64_t)pos << blocksize_log2) + blocksize, gd, gdtsz * blocksize); 503 PUT(((uint64_t)pos << blocksize_log2) + blocksize, gd, gdtsz * blocksize);
471 } 504 }
472
473 start = overhead + 1/*bbmp*/ + 1/*ibmp*/ + itsz;
474 if (i == 0)
475 start += 2; // for "/" and "/lost+found"
476 end = blocks_per_group - (start + gd[i].bg_free_blocks_count);
477
478 // mark preallocated blocks as allocated
479 allocate(buf, blocksize, start, end);
480 // dump block bitmap
481 PUT((uint64_t)(pos + overhead) * blocksize, buf, blocksize);
482
483 // mark preallocated inodes as allocated
484 allocate(buf, blocksize,
485 ninodes_per_group - gd[i].bg_free_inodes_count,
486 blocks_per_group - ninodes_per_group
487 );
488 // dump inode bitmap
489 //PUT((uint64_t)(pos + overhead + 1) * blocksize, buf, blocksize);
490 //but it's right after block bitmap, so we can just:
491 xwrite(fd, buf, blocksize);
492 } 505 }
493 506
494 // zero boot sectors 507 // zero boot sectors
495 memset(buf, 0, blocksize); 508 memset(buf, 0, blocksize);
496 PUT(0, buf, 1024); // N.B. 1024 <= blocksize 509 PUT(0, buf, 1024); // N.B. 1024 <= blocksize, so buf[0..1023] contains zeros
497 // zero inode tables 510 // zero inode tables
498 for (i = 0; i < ngroups; ++i) 511 for (i = 0; i < ngroups; ++i)
499 for (n = 0; n < itsz; ++n) 512 for (n = 0; n < itsz; ++n)
500 PUT((uint64_t)(gd[i].bg_inode_table + n) * blocksize, buf, blocksize); 513 PUT((uint64_t)(FETCH_LE32(gd[i].bg_inode_table) + n) * blocksize, buf, blocksize);
501 514
502 // prepare directory inode 515 // prepare directory inode
503 inode = (struct ext2_inode *)buf; 516 inode = (struct ext2_inode *)buf;
@@ -511,13 +524,13 @@ int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
511 524
512 // dump root dir inode 525 // dump root dir inode
513 STORE_LE(inode->i_links_count, 3); // "/.", "/..", "/lost+found/.." point to this inode 526 STORE_LE(inode->i_links_count, 3); // "/.", "/..", "/lost+found/.." point to this inode
514 STORE_LE(inode->i_block[0], gd[0].bg_inode_table + itsz); 527 STORE_LE(inode->i_block[0], FETCH_LE32(gd[0].bg_inode_table) + itsz);
515 PUT(((uint64_t)gd[0].bg_inode_table << blocksize_log2) + (EXT2_ROOT_INO-1) * sizeof(*inode), buf, sizeof(*inode)); 528 PUT(((uint64_t)FETCH_LE32(gd[0].bg_inode_table) << blocksize_log2) + (EXT2_ROOT_INO-1) * sizeof(*inode), buf, sizeof(*inode));
516 529
517 // dump lost+found dir inode 530 // dump lost+found dir inode
518 STORE_LE(inode->i_links_count, 2); // both "/lost+found" and "/lost+found/." point to this inode 531 STORE_LE(inode->i_links_count, 2); // both "/lost+found" and "/lost+found/." point to this inode
519 STORE_LE(inode->i_block[0], inode->i_block[0]+1); // use next block //= gd[0].bg_inode_table + itsz + 1; 532 STORE_LE(inode->i_block[0], inode->i_block[0]+1); // use next block
520 PUT(((uint64_t)gd[0].bg_inode_table << blocksize_log2) + (EXT2_GOOD_OLD_FIRST_INO-1) * sizeof(*inode), buf, sizeof(*inode)); 533 PUT(((uint64_t)FETCH_LE32(gd[0].bg_inode_table) << blocksize_log2) + (EXT2_GOOD_OLD_FIRST_INO-1) * sizeof(*inode), buf, sizeof(*inode));
521 534
522 // dump directories 535 // dump directories
523 memset(buf, 0, blocksize); 536 memset(buf, 0, blocksize);
@@ -534,7 +547,7 @@ int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
534 STORE_LE(dir->name_len2, 2); 547 STORE_LE(dir->name_len2, 2);
535 STORE_LE(dir->file_type2, EXT2_FT_DIR); 548 STORE_LE(dir->file_type2, EXT2_FT_DIR);
536 dir->name2[0] = '.'; dir->name2[1] = '.'; 549 dir->name2[0] = '.'; dir->name2[1] = '.';
537 PUT((uint64_t)(gd[0].bg_inode_table + itsz + 1) * blocksize, buf, blocksize); 550 PUT((uint64_t)(FETCH_LE32(gd[0].bg_inode_table) + itsz + 1) * blocksize, buf, blocksize);
538 551
539 // dump root dir block 552 // dump root dir block
540 STORE_LE(dir->inode1, EXT2_ROOT_INO); 553 STORE_LE(dir->inode1, EXT2_ROOT_INO);
@@ -544,13 +557,7 @@ int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
544 STORE_LE(dir->name_len3, 10); 557 STORE_LE(dir->name_len3, 10);
545 STORE_LE(dir->file_type3, EXT2_FT_DIR); 558 STORE_LE(dir->file_type3, EXT2_FT_DIR);
546 strcpy(dir->name3, "lost+found"); 559 strcpy(dir->name3, "lost+found");
547 PUT((uint64_t)(gd[0].bg_inode_table + itsz + 0) * blocksize, buf, blocksize); 560 PUT((uint64_t)(FETCH_LE32(gd[0].bg_inode_table) + itsz + 0) * blocksize, buf, blocksize);
548
549// bb_info_msg("done\n"
550// "This filesystem will be automatically checked every %u mounts or\n"
551// "180 days, whichever comes first. Use tune2fs -c or -i to override.",
552// sb->s_max_mnt_count
553// );
554 561
555 done: 562 done:
556 // cleanup 563 // cleanup