source: mainline/uspace/app/mkmfs/mkmfs.c@ b8dbe2f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b8dbe2f was 0395a7b, checked in by Maurizio Lombardi <m.lombardi85@…>, 12 years ago

mkmfs: fix zone bitmap initialization.

  • Property mode set to 100644
File size: 19.0 KB
RevLine 
[954bf385]1/*
2 * Copyright (c) 2011 Maurizio Lombardi
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup fs
30 * @{
31 */
32
33/**
[7a46bfe]34 * @file mkmfs.c
[954bf385]35 * @brief Tool for creating new Minix file systems.
36 *
37 */
38
39#include <stdio.h>
40#include <stdlib.h>
[f73b291]41#include <block.h>
[954bf385]42#include <unistd.h>
43#include <errno.h>
44#include <sys/typefmt.h>
45#include <inttypes.h>
46#include <getopt.h>
47#include <mem.h>
[fd282ad]48#include <str.h>
[4727a97a]49#include <time.h>
[86d0b4b3]50#include <minix.h>
[954bf385]51
[7a46bfe]52#define NAME "mkmfs"
[954bf385]53
[e6aaa59]54#define FREE 0
55#define USED 1
56
[8367d1d]57#define UPPER(n, size) (((n) / (size)) + (((n) % (size)) != 0))
58#define NEXT_DENTRY(p, dirsize) (p += (dirsize))
[ae1ae27]59
[954bf385]60typedef enum {
61 HELP_SHORT,
62 HELP_LONG
63} help_level_t;
64
[8367d1d]65/* Generic MFS superblock */
[59e670e]66struct mfs_sb_info {
67 uint64_t n_inodes;
68 uint64_t n_zones;
69 aoff64_t dev_nblocks;
70 unsigned long ibmap_blocks;
71 unsigned long zbmap_blocks;
72 unsigned long first_data_zone;
[410a065]73 unsigned long itable_size;
[59e670e]74 int log2_zone_size;
75 int ino_per_block;
[fd282ad]76 int dirsize;
[59e670e]77 uint32_t max_file_size;
78 uint16_t magic;
79 uint32_t block_size;
80 int fs_version;
81 bool longnames;
82};
[19a057f9]83
[7a46bfe]84static void help_cmd_mkmfs(help_level_t level);
[5726a1a3]85static bool is_power_of_two(uint32_t n);
[0b07acd]86static int init_superblock(struct mfs_sb_info *sb);
[197b671]87static int write_superblock(const struct mfs_sb_info *sbi);
88static int write_superblock3(const struct mfs_sb_info *sbi);
89static int init_bitmaps(const struct mfs_sb_info *sb);
90static int init_inode_table(const struct mfs_sb_info *sb);
91static int make_root_ino(const struct mfs_sb_info *sb);
[bed0356]92static int make_root_ino2(const struct mfs_sb_info *sb);
[59e670e]93static void mark_bmap(uint32_t *bmap, int idx, int v);
[197b671]94static int insert_dentries(const struct mfs_sb_info *sb);
95
[f66d903]96static inline int write_block(aoff64_t off, size_t size, const void *data);
[b84175a]97
[03bc76a]98static service_id_t service_id;
[f66d903]99static int shift;
[954bf385]100
101static struct option const long_options[] = {
[e91b898]102 { "help", no_argument, 0, 'h' },
103 { "long-names", no_argument, 0, 'l' },
104 { "block-size", required_argument, 0, 'b' },
105 { "inodes", required_argument, 0, 'i' },
106 { NULL, no_argument, 0, '1' },
107 { NULL, no_argument, 0, '2' },
108 { 0, 0, 0, 0 }
[954bf385]109};
110
111int main (int argc, char **argv)
112{
113 int rc, c, opt_ind;
114 char *device_name;
[16cc9a6]115 size_t devblock_size;
[954bf385]116
[59e670e]117 struct mfs_sb_info sb;
[954bf385]118
[8367d1d]119 /* Default is MinixFS V3 */
[59e670e]120 sb.magic = MFS_MAGIC_V3;
[6cda025]121 sb.fs_version = 3;
[eee8007]122
[8367d1d]123 /* Default block size is 4Kb */
[59e670e]124 sb.block_size = MFS_MAX_BLOCKSIZE;
[c4c7f5a]125 sb.dirsize = MFS3_DIRSIZE;
[59e670e]126 sb.n_inodes = 0;
127 sb.longnames = false;
128 sb.ino_per_block = V3_INODES_PER_BLOCK(MFS_MAX_BLOCKSIZE);
[eaf9794]129
[954bf385]130 if (argc == 1) {
[7a46bfe]131 help_cmd_mkmfs(HELP_SHORT);
132 printf("Incorrect number of arguments, try `mkmfs --help'\n");
[954bf385]133 exit(0);
134 }
135
136 for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
[8367d1d]137 c = getopt_long(argc, argv, "lh12b:i:",
138 long_options, &opt_ind);
[954bf385]139 switch (c) {
140 case 'h':
[7a46bfe]141 help_cmd_mkmfs(HELP_LONG);
[954bf385]142 exit(0);
143 case '1':
[59e670e]144 sb.magic = MFS_MAGIC_V1;
145 sb.block_size = MFS_BLOCKSIZE;
146 sb.fs_version = 1;
147 sb.ino_per_block = V1_INODES_PER_BLOCK;
[fd282ad]148 sb.dirsize = MFS_DIRSIZE;
[954bf385]149 break;
150 case '2':
[59e670e]151 sb.magic = MFS_MAGIC_V2;
152 sb.block_size = MFS_BLOCKSIZE;
153 sb.fs_version = 2;
154 sb.ino_per_block = V2_INODES_PER_BLOCK;
[fd282ad]155 sb.dirsize = MFS_DIRSIZE;
[954bf385]156 break;
157 case 'b':
[59e670e]158 sb.block_size = (uint32_t) strtol(optarg, NULL, 10);
[954bf385]159 break;
160 case 'i':
[c64506b]161 sb.n_inodes = (uint64_t) strtol(optarg, NULL, 10);
[eee8007]162 break;
163 case 'l':
[59e670e]164 sb.longnames = true;
[fd282ad]165 sb.dirsize = MFSL_DIRSIZE;
[954bf385]166 break;
167 }
168 }
169
[59e670e]170 if (sb.block_size < MFS_MIN_BLOCKSIZE ||
[8367d1d]171 sb.block_size > MFS_MAX_BLOCKSIZE) {
[954bf385]172 printf(NAME ":Error! Invalid block size.\n");
173 exit(0);
[5726a1a3]174 } else if (!is_power_of_two(sb.block_size)) {
[8367d1d]175 /* Block size must be a power of 2. */
[954bf385]176 printf(NAME ":Error! Invalid block size.\n");
177 exit(0);
[59e670e]178 } else if (sb.block_size > MFS_BLOCKSIZE &&
[8367d1d]179 sb.fs_version != 3) {
180 printf(NAME ":Error! Block size > 1024 is "
181 "supported by V3 filesystem only.\n");
[eee8007]182 exit(0);
[59e670e]183 } else if (sb.fs_version == 3 && sb.longnames) {
[8367d1d]184 printf(NAME ":Error! Long filenames are supported "
185 "by V1/V2 filesystem only.\n");
[954bf385]186 exit(0);
187 }
188
[f66d903]189 if (sb.block_size == MFS_MIN_BLOCKSIZE)
190 shift = 1;
191 else if (sb.block_size == MFS_MAX_BLOCKSIZE)
192 shift = 3;
193 else
194 shift = 2;
195
[954bf385]196 argv += optind;
197
198 device_name = argv[0];
199
200 if (!device_name) {
[7a46bfe]201 help_cmd_mkmfs(HELP_LONG);
[954bf385]202 exit(0);
203 }
204
[03bc76a]205 rc = loc_service_get_id(device_name, &service_id, 0);
[954bf385]206 if (rc != EOK) {
207 printf(NAME ": Error resolving device `%s'.\n", device_name);
208 return 2;
209 }
210
[03bc76a]211 rc = block_init(EXCHANGE_SERIALIZE, service_id, 2048);
[954bf385]212 if (rc != EOK) {
213 printf(NAME ": Error initializing libblock.\n");
214 return 2;
215 }
216
[03bc76a]217 rc = block_get_bsize(service_id, &devblock_size);
[954bf385]218 if (rc != EOK) {
219 printf(NAME ": Error determining device block size.\n");
220 return 2;
221 }
222
[03bc76a]223 rc = block_get_nblocks(service_id, &sb.dev_nblocks);
[954bf385]224 if (rc != EOK) {
[8367d1d]225 printf(NAME ": Warning, failed to obtain "
226 "block device size.\n");
[954bf385]227 } else {
228 printf(NAME ": Block device has %" PRIuOFF64 " blocks.\n",
[8367d1d]229 sb.dev_nblocks);
[954bf385]230 }
231
[197b671]232 if (devblock_size != 512) {
[954bf385]233 printf(NAME ": Error. Device block size is not 512 bytes.\n");
234 return 2;
235 }
236
[8367d1d]237 /* Minimum block size is 1 Kb */
[59e670e]238 sb.dev_nblocks /= 2;
[68ed0fb]239
240 printf(NAME ": Creating Minix file system on device\n");
[5726a1a3]241 printf(NAME ": Writing superblock\n");
[954bf385]242
[8367d1d]243 /* Initialize superblock */
[0b07acd]244 if (init_superblock(&sb) != EOK) {
245 printf(NAME ": Error. Superblock initialization failed\n");
246 return 2;
247 }
[eaf9794]248
[5726a1a3]249 printf(NAME ": Initializing bitmaps\n");
250
[8367d1d]251 /* Initialize bitmaps */
[0b07acd]252 if (init_bitmaps(&sb) != EOK) {
253 printf(NAME ": Error. Bitmaps initialization failed\n");
254 return 2;
255 }
[eee8007]256
[5726a1a3]257 printf(NAME ": Initializing the inode table\n");
258
[8367d1d]259 /* Init inode table */
[0b07acd]260 if (init_inode_table(&sb) != EOK) {
261 printf(NAME ": Error. Inode table initialization failed\n");
262 return 2;
263 }
[410a065]264
[5726a1a3]265 printf(NAME ": Creating the root directory inode\n");
266
[8367d1d]267 /* Make the root inode */
[bed0356]268 if (sb.fs_version == 1)
[0b07acd]269 rc = make_root_ino(&sb);
[bed0356]270 else
271 rc = make_root_ino2(&sb);
[0b07acd]272
273 if (rc != EOK) {
274 printf(NAME ": Error. Root inode initialization failed\n");
275 return 2;
276 }
[f0ceb1d]277
[8367d1d]278 /* Insert directory entries . and .. */
[0b07acd]279 if (insert_dentries(&sb) != EOK) {
280 printf(NAME ": Error. Root directory initialization failed\n");
281 return 2;
282 }
[fd282ad]283
[03bc76a]284 block_fini(service_id);
285
[954bf385]286 return 0;
287}
288
[2eaf655]289/**Inserts the '.' and '..' directory entries in the root directory.
290 *
291 * @param sb Pointer to the superblock structure.
292 *
293 * @return EOK on success or a negative error code.
294 */
[197b671]295static int insert_dentries(const struct mfs_sb_info *sb)
[fd282ad]296{
297 void *root_block;
[fcce9e1]298 uint8_t *dentry_ptr;
[0b07acd]299 int rc;
[f66d903]300 const long root_dblock = sb->first_data_zone;
[fd282ad]301
[b438804]302 root_block = malloc(sb->block_size);
[f66d903]303 memset(root_block, 0x00, sb->block_size);
[0b07acd]304
305 if (!root_block)
306 return ENOMEM;
[fcce9e1]307
308 dentry_ptr = root_block;
[e91b898]309
[fd282ad]310 if (sb->fs_version != 3) {
[8367d1d]311 /* Directory entries for V1/V2 filesystem */
[fd282ad]312 struct mfs_dentry *dentry = root_block;
313
314 dentry->d_inum = MFS_ROOT_INO;
[14c29ba]315 memcpy(dentry->d_name, ".\0", 2);
[fd282ad]316
[fcce9e1]317 dentry = (struct mfs_dentry *) NEXT_DENTRY(dentry_ptr,
[8367d1d]318 sb->dirsize);
[fd282ad]319
320 dentry->d_inum = MFS_ROOT_INO;
[14c29ba]321 memcpy(dentry->d_name, "..\0", 3);
[fd282ad]322 } else {
[8367d1d]323 /* Directory entries for V3 filesystem */
[fd282ad]324 struct mfs3_dentry *dentry = root_block;
325
326 dentry->d_inum = MFS_ROOT_INO;
[14c29ba]327 memcpy(dentry->d_name, ".\0", 2);
[fd282ad]328
[fcce9e1]329 dentry = (struct mfs3_dentry *) NEXT_DENTRY(dentry_ptr,
[8367d1d]330 sb->dirsize);
[fd282ad]331
332 dentry->d_inum = MFS_ROOT_INO;
[14c29ba]333 memcpy(dentry->d_name, "..\0", 3);
[fd282ad]334 }
335
[f66d903]336 rc = write_block(root_dblock, 1, root_block);
[fd282ad]337
338 free(root_block);
[0b07acd]339 return rc;
[fd282ad]340}
341
[2eaf655]342/**Initialize the inode table.
343 *
344 * @param sb Pointer to the superblock structure.
345 *
346 * @return EOK on success or a negative error code.
347 */
[197b671]348static int init_inode_table(const struct mfs_sb_info *sb)
[410a065]349{
350 unsigned int i;
351 uint8_t *itable_buf;
[0b07acd]352 int rc;
[340b5690]353
[f66d903]354 long itable_off = sb->zbmap_blocks + sb->ibmap_blocks + 2;
355 unsigned long itable_size = sb->itable_size;
[340b5690]356
[f66d903]357 itable_buf = malloc(sb->block_size);
[0b07acd]358
359 if (!itable_buf)
360 return ENOMEM;
361
[f66d903]362 memset(itable_buf, 0x00, sb->block_size);
[410a065]363
[8ceba1e]364 for (i = 0; i < itable_size; ++i, ++itable_off) {
[f66d903]365 rc = write_block(itable_off, 1, itable_buf);
[0b07acd]366
367 if (rc != EOK)
368 break;
369 }
[410a065]370
371 free(itable_buf);
[0b07acd]372 return rc;
[410a065]373}
374
[2eaf655]375/**Initialize a V1 root inode.
376 *
377 * @param sb Ponter to the superblock structure.
378 *
379 * @return EOK on success or a negative error code.
380 */
[197b671]381static int make_root_ino(const struct mfs_sb_info *sb)
[410a065]382{
383 struct mfs_inode *ino_buf;
[0b07acd]384 int rc;
[410a065]385
[f66d903]386 const long itable_off = sb->zbmap_blocks + sb->ibmap_blocks + 2;
[340b5690]387
[4727a97a]388 const time_t sec = time(NULL);
389
[b438804]390 ino_buf = malloc(MFS_BLOCKSIZE);
[0b07acd]391
392 if (!ino_buf)
393 return ENOMEM;
394
[4727a97a]395 memset(ino_buf, 0x00, MFS_BLOCKSIZE);
[410a065]396
[e33100c]397 ino_buf[MFS_ROOT_INO - 1].i_mode = S_IFDIR;
398 ino_buf[MFS_ROOT_INO - 1].i_uid = 0;
399 ino_buf[MFS_ROOT_INO - 1].i_gid = 0;
400 ino_buf[MFS_ROOT_INO - 1].i_size = (sb->longnames ? MFSL_DIRSIZE :
[8367d1d]401 MFS_DIRSIZE) * 2;
[e33100c]402 ino_buf[MFS_ROOT_INO - 1].i_mtime = sec;
403 ino_buf[MFS_ROOT_INO - 1].i_nlinks = 2;
404 ino_buf[MFS_ROOT_INO - 1].i_dzone[0] = sb->first_data_zone;
[410a065]405
[f66d903]406 rc = write_block(itable_off, 1, ino_buf);
[410a065]407
408 free(ino_buf);
[0b07acd]409 return rc;
[410a065]410}
411
[2eaf655]412/**Initialize a Minix V2 root inode on disk, also valid for V3 filesystem.
413 *
414 * @param sb Pointer to the superblock structure.
415 *
416 * @return EOK on success or a negative error code.
417 */
[bed0356]418static int make_root_ino2(const struct mfs_sb_info *sb)
[410a065]419{
420 struct mfs2_inode *ino_buf;
[0b07acd]421 int rc;
[410a065]422
[8367d1d]423 /* Compute offset of the first inode table block */
[f66d903]424 const long itable_off = sb->zbmap_blocks + sb->ibmap_blocks + 2;
[340b5690]425
[4727a97a]426 const time_t sec = time(NULL);
427
[b438804]428 ino_buf = malloc(sb->block_size);
[0b07acd]429
430 if (!ino_buf)
431 return ENOMEM;
432
[f66d903]433 memset(ino_buf, 0x00, sb->block_size);
[410a065]434
[e33100c]435 ino_buf[MFS_ROOT_INO - 1].i_mode = S_IFDIR;
436 ino_buf[MFS_ROOT_INO - 1].i_uid = 0;
437 ino_buf[MFS_ROOT_INO - 1].i_gid = 0;
438 ino_buf[MFS_ROOT_INO - 1].i_size = MFS3_DIRSIZE * 2;
439 ino_buf[MFS_ROOT_INO - 1].i_mtime = sec;
440 ino_buf[MFS_ROOT_INO - 1].i_atime = sec;
441 ino_buf[MFS_ROOT_INO - 1].i_ctime = sec;
442 ino_buf[MFS_ROOT_INO - 1].i_nlinks = 2;
443 ino_buf[MFS_ROOT_INO - 1].i_dzone[0] = sb->first_data_zone;
[410a065]444
[f66d903]445 rc = write_block(itable_off, 1, ino_buf);
[410a065]446
447 free(ino_buf);
[0b07acd]448 return rc;
[410a065]449}
450
[2eaf655]451/**Initialize the superblock structure on disk.
452 *
453 * @param sb Pointer to the superblock structure.
454 *
455 * @return EOK on success or a negative error code.
456 */
[0b07acd]457static int init_superblock(struct mfs_sb_info *sb)
[eee8007]458{
[e2267e82]459 aoff64_t inodes;
[99f043e]460 unsigned long ind;
461 unsigned long ind2;
462 unsigned long zones;
[0b07acd]463 int rc;
[68ed0fb]464
[59e670e]465 if (sb->longnames)
[8367d1d]466 sb->magic = sb->fs_version == 1 ? MFS_MAGIC_V1L :
467 MFS_MAGIC_V2L;
[939b7d2]468
[8367d1d]469 /* Compute the number of zones on disk */
[e03a733]470
[59e670e]471 if (sb->fs_version == 1) {
[8367d1d]472 /* Valid only for MFS V1 */
[59e670e]473 sb->n_zones = sb->dev_nblocks > UINT16_MAX ?
[8367d1d]474 UINT16_MAX : sb->dev_nblocks;
[99f043e]475 ind = MFS_BLOCKSIZE / sizeof(uint16_t);
476 ind2 = ind * ind;
[8367d1d]477 sb->max_file_size = (V1_NR_DIRECT_ZONES + ind + ind2) *
478 MFS_BLOCKSIZE;
[59e670e]479 } else {
480 /*Valid for MFS V2/V3*/
[99f043e]481 size_t ptrsize;
482 if (sb->fs_version == 2)
483 ptrsize = sizeof(uint16_t);
484 else
485 ptrsize = sizeof(uint32_t);
[8367d1d]486
[99f043e]487 ind = sb->block_size / ptrsize;
488 ind2 = ind * ind;
489 zones = V2_NR_DIRECT_ZONES + ind + ind2;
490 sb->max_file_size = zones * sb->block_size;
[59e670e]491 sb->n_zones = sb->dev_nblocks > UINT32_MAX ?
[8367d1d]492 UINT32_MAX : sb->dev_nblocks;
[19a057f9]493
[59e670e]494 if (sb->fs_version == 3) {
[99f043e]495 if(INT32_MAX / sb->block_size < zones)
496 sb->max_file_size = INT32_MAX;
[59e670e]497 sb->ino_per_block = V3_INODES_PER_BLOCK(sb->block_size);
498 sb->n_zones /= (sb->block_size / MFS_MIN_BLOCKSIZE);
499 }
500 }
[19a057f9]501
[8367d1d]502 /* Round up the number of inodes to fill block size */
[59e670e]503 if (sb->n_inodes == 0)
504 inodes = sb->dev_nblocks / 3;
[c64506b]505 else
506 inodes = sb->n_inodes;
[68ed0fb]507
[59e670e]508 if (inodes % sb->ino_per_block)
[8367d1d]509 inodes = ((inodes / sb->ino_per_block) + 1) *
510 sb->ino_per_block;
[e91b898]511
[59e670e]512 if (sb->fs_version < 3)
513 sb->n_inodes = inodes > UINT16_MAX ? UINT16_MAX : inodes;
514 else
515 sb->n_inodes = inodes > UINT32_MAX ? UINT32_MAX : inodes;
[68ed0fb]516
[8367d1d]517 /* Compute inode bitmap size in blocks */
[59e670e]518 sb->ibmap_blocks = UPPER(sb->n_inodes, sb->block_size * 8);
[68ed0fb]519
[8367d1d]520 /* Compute inode table size */
[410a065]521 sb->itable_size = sb->n_inodes / sb->ino_per_block;
[e03a733]522
[8367d1d]523 /* Compute zone bitmap size in blocks */
[340b5690]524 sb->zbmap_blocks = UPPER(sb->n_zones, sb->block_size * 8);
525
[8367d1d]526 /* Compute first data zone position */
[92dd5c8]527 sb->first_data_zone = 2 + sb->itable_size +
[8367d1d]528 sb->zbmap_blocks + sb->ibmap_blocks;
[ae1ae27]529
[8367d1d]530 /* Set log2 of zone to block ratio to zero */
[59e670e]531 sb->log2_zone_size = 0;
[ae1ae27]532
[8367d1d]533 /* Check for errors */
[0b07acd]534 if (sb->first_data_zone >= sb->n_zones) {
535 printf(NAME ": Error! Insufficient disk space");
536 return ENOMEM;
537 }
538
[8367d1d]539 /* Superblock is now ready to be written on disk */
[86c03ba]540 printf(NAME ": %d block size\n", sb->block_size);
[59e670e]541 printf(NAME ": %d inodes\n", (uint32_t) sb->n_inodes);
542 printf(NAME ": %d zones\n", (uint32_t) sb->n_zones);
[410a065]543 printf(NAME ": inode table blocks = %ld\n", sb->itable_size);
544 printf(NAME ": inode bitmap blocks = %ld\n", sb->ibmap_blocks);
545 printf(NAME ": zone bitmap blocks = %ld\n", sb->zbmap_blocks);
[8367d1d]546 printf(NAME ": first data zone = %d\n", (uint32_t)sb->first_data_zone);
[99f043e]547 printf(NAME ": max file size = %u\n", sb->max_file_size);
[59e670e]548 printf(NAME ": long fnames = %s\n", sb->longnames ? "Yes" : "No");
[bc99ed6]549
[59e670e]550 if (sb->fs_version == 3)
[0b07acd]551 rc = write_superblock3(sb);
[59e670e]552 else
[0b07acd]553 rc = write_superblock(sb);
554
555 return rc;
[eee8007]556}
557
[2eaf655]558/**Write the V1/V2 superblock on disk.
559 *
560 * @param sbi Pointer to the superblock structure to write on disk.
561 *
562 * @return EOK on success or a negative error code.
563 */
[197b671]564static int write_superblock(const struct mfs_sb_info *sbi)
[eee8007]565{
[59e670e]566 struct mfs_superblock *sb;
[0b07acd]567 int rc;
[e03a733]568
[b438804]569 sb = malloc(MFS_SUPERBLOCK_SIZE);;
[e03a733]570
[0b07acd]571 if (!sb)
572 return ENOMEM;
573
[59e670e]574 sb->s_ninodes = (uint16_t) sbi->n_inodes;
575 sb->s_nzones = (uint16_t) sbi->n_zones;
576 sb->s_nzones2 = (uint32_t) sbi->n_zones;
577 sb->s_ibmap_blocks = (uint16_t) sbi->ibmap_blocks;
578 sb->s_zbmap_blocks = (uint16_t) sbi->zbmap_blocks;
579 sb->s_first_data_zone = (uint16_t) sbi->first_data_zone;
580 sb->s_log2_zone_size = sbi->log2_zone_size;
[99f043e]581 sb->s_max_file_size = sbi->max_file_size;
[59e670e]582 sb->s_magic = sbi->magic;
583 sb->s_state = MFS_VALID_FS;
[e03a733]584
[f66d903]585 rc = write_block(MFS_SUPERBLOCK, 1, sb);
[8e41994]586 free(sb);
[0b07acd]587
588 return rc;
[59e670e]589}
[e03a733]590
[2eaf655]591/**Write the V3s superblock on disk.
592 *
593 * @param sbi Pointer to the superblock structure to write on disk.
594 *
595 * @return EOK on success or a negative error code.
596 */
[197b671]597static int write_superblock3(const struct mfs_sb_info *sbi)
[59e670e]598{
599 struct mfs3_superblock *sb;
[0b07acd]600 int rc;
[59e670e]601
[b438804]602 sb = malloc(MFS_SUPERBLOCK_SIZE);
[59e670e]603
[0b07acd]604 if (!sb)
605 return ENOMEM;
606
[59e670e]607 sb->s_ninodes = (uint32_t) sbi->n_inodes;
608 sb->s_nzones = (uint32_t) sbi->n_zones;
609 sb->s_ibmap_blocks = (uint16_t) sbi->ibmap_blocks;
610 sb->s_zbmap_blocks = (uint16_t) sbi->zbmap_blocks;
611 sb->s_first_data_zone = (uint16_t) sbi->first_data_zone;
612 sb->s_log2_zone_size = sbi->log2_zone_size;
[99f043e]613 sb->s_max_file_size = sbi->max_file_size;
[59e670e]614 sb->s_magic = sbi->magic;
615 sb->s_block_size = sbi->block_size;
[e03a733]616 sb->s_disk_version = 3;
[bc99ed6]617
[03bc76a]618 rc = block_write_direct(service_id, MFS_SUPERBLOCK << 1, 1 << 1, sb);
[410a065]619 free(sb);
[0b07acd]620
621 return rc;
[eee8007]622}
623
[2eaf655]624/**Initialize the inode and block bitmaps on disk.
625 *
626 * @param sb Pointer to the superblock structure.
627 *
628 * @return EOK on success or a negative error code.
629 */
[197b671]630static int init_bitmaps(const struct mfs_sb_info *sb)
[e6aaa59]631{
[bb0db564]632 uint32_t *ibmap_buf, *zbmap_buf;
633 uint8_t *ibmap_buf8, *zbmap_buf8;
[f66d903]634 const unsigned int ibmap_nblocks = sb->ibmap_blocks;
635 const unsigned int zbmap_nblocks = sb->zbmap_blocks;
[e6aaa59]636 unsigned int i;
[0b07acd]637 int rc;
[e6aaa59]638
[b438804]639 ibmap_buf = malloc(ibmap_nblocks * sb->block_size);
640 zbmap_buf = malloc(zbmap_nblocks * sb->block_size);
[e6aaa59]641
[0b07acd]642 if (!ibmap_buf || !zbmap_buf)
643 return ENOMEM;
644
[59e670e]645 memset(ibmap_buf, 0xFF, ibmap_nblocks * sb->block_size);
646 memset(zbmap_buf, 0xFF, zbmap_nblocks * sb->block_size);
[e6aaa59]647
[e33100c]648 for (i = 2; i < sb->n_inodes + 1; ++i)
[bb0db564]649 mark_bmap(ibmap_buf, i, FREE);
[f5cbd4f]650
[0395a7b]651 for (i = 2; i < sb->n_zones - sb->first_data_zone; ++i)
[bb0db564]652 mark_bmap(zbmap_buf, i, FREE);
[e6aaa59]653
[bb0db564]654 ibmap_buf8 = (uint8_t *) ibmap_buf;
655 zbmap_buf8 = (uint8_t *) zbmap_buf;
656
[f66d903]657 int start_block = 2;
[8ceba1e]658
[7df022e5]659 for (i = 0; i < ibmap_nblocks; ++i) {
[f66d903]660 if ((rc = write_block(start_block + i,
[8367d1d]661 1, (ibmap_buf8 + i * sb->block_size))) != EOK)
[7df022e5]662 return rc;
663 }
664
[f66d903]665 start_block = 2 + ibmap_nblocks;
[8ceba1e]666
[7df022e5]667 for (i = 0; i < zbmap_nblocks; ++i) {
[f66d903]668 if ((rc = write_block(start_block + i,
[8367d1d]669 1, (zbmap_buf8 + i * sb->block_size))) != EOK)
[7df022e5]670 return rc;
671 }
672
[c4c7f5a]673 free(ibmap_buf);
674 free(zbmap_buf);
675
[0b07acd]676 return rc;
[e6aaa59]677}
678
[2eaf655]679/**Mark a bitmap entry as used or free.
680 *
681 * @param bmap 32-bit pointer to the bitmap in memory.
682 * @param idx The index in the bitmap of the bit to set at 1 or 0.
683 * @param v FREE to clear the bit, USED to set the bit.
684 */
[59e670e]685static void mark_bmap(uint32_t *bmap, int idx, int v)
[e6aaa59]686{
687 if (v == FREE)
[59e670e]688 bmap[idx / 32] &= ~(1 << (idx % 32));
[e6aaa59]689 else
[59e670e]690 bmap[idx / 32] |= 1 << (idx % 32);
[e6aaa59]691}
692
[2eaf655]693/**Write a block on disk.
694 *
695 * @param off 64-bit block offset on disk.
696 * @param size size of the block.
697 * @param data Pointer to the block content.
698 *
699 * @return EOK on success or a negative error number.
700 */
[f66d903]701static inline int write_block(aoff64_t off, size_t size, const void *data)
[b84175a]702{
[f66d903]703 if (shift == 3) {
704 int rc;
705 aoff64_t tmp_off = off << 1;
706 uint8_t *data_ptr = (uint8_t *) data;
707
[8367d1d]708 rc = block_write_direct(service_id, tmp_off << 2,
709 size << 2, data_ptr);
[f66d903]710
711 if (rc != EOK)
712 return rc;
713
714 data_ptr += 2048;
715 tmp_off++;
716
[8367d1d]717 return block_write_direct(service_id, tmp_off << 2,
718 size << 2, data_ptr);
[f66d903]719 }
[8367d1d]720 return block_write_direct(service_id, off << shift,
721 size << shift, data);
[b84175a]722}
723
[7a46bfe]724static void help_cmd_mkmfs(help_level_t level)
[954bf385]725{
726 if (level == HELP_SHORT) {
727 printf(NAME": tool to create new Minix file systems\n");
728 } else {
[e91b898]729 printf("Usage: [options] device\n"
[8367d1d]730 "-1 Make a Minix version 1 filesystem\n"
731 "-2 Make a Minix version 2 filesystem\n"
732 "-b ## Specify the block size in bytes (V3 only),\n"
733 " valid block size values are 1024, 2048 and"
734 " 4096 bytes per block\n"
735 "-i ## Specify the number of inodes"
736 " for the filesystem\n"
737 "-l Use 30-char long filenames (V1/V2 only)\n");
[954bf385]738 }
739}
740
[8367d1d]741/** Check if a given number is a power of two.
742 *
743 * @param n The number to check.
744 *
745 * @return true if it is a power of two, false otherwise.
746 */
[5726a1a3]747static bool is_power_of_two(uint32_t n)
[954bf385]748{
[5726a1a3]749 if (n == 0)
750 return false;
751
752 return (n & (n - 1)) == 0;
[954bf385]753}
754
755
756/**
757 * @}
758 */
Note: See TracBrowser for help on using the repository browser.