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

Last change on this file was 7ae01d5, checked in by Jiri Svoboda <jiri@…>, 14 months ago

Remove unused comm_size parameter of block_init()

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