source: mainline/uspace/app/mkfat/mkfat.c@ 634e020

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 634e020 was ed9bf14, checked in by Jiri Svoboda <jiri@…>, 10 years ago

mkfat can live without the user specifying the FAT type just fine. This fixes FAT creation via fdisk for sizes not corresponding to FAT16 (i.e. too small or too large).

  • Property mode set to 100644
File size: 10.3 KB
Line 
1/*
2 * Copyright (c) 2010 Jiri Svoboda
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/**
34 * @file mkfat.c
35 * @brief Tool for creating new FAT file systems.
36 *
37 * Currently we can create 12/16/32-bit FAT.
38 */
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <block.h>
43#include <mem.h>
44#include <loc.h>
45#include <byteorder.h>
46#include <sys/types.h>
47#include <sys/typefmt.h>
48#include <inttypes.h>
49#include <errno.h>
50#include "fat.h"
51
52#define NAME "mkfat"
53
54/** Divide and round up. */
55#define div_round_up(a, b) (((a) + (b) - 1) / (b))
56
57/** Default file-system parameters */
58enum {
59 default_sector_size = 512,
60 default_sectors_per_cluster = 4,
61 default_fat_count = 2,
62 default_reserved_clusters = 2,
63 default_media_descriptor = 0xF8 /**< fixed disk */
64};
65
66/** Configurable file-system parameters */
67typedef struct fat_cfg {
68 int fat_type; /* FAT12 = 12, FAT16 = 16, FAT32 = 32 */
69 size_t sector_size;
70 uint32_t total_sectors;
71 uint16_t root_ent_max;
72 uint32_t addt_res_sectors;
73 uint8_t sectors_per_cluster;
74
75 uint16_t reserved_sectors;
76 uint32_t rootdir_sectors;
77 uint32_t fat_sectors;
78 uint32_t total_clusters;
79 uint8_t fat_count;
80} fat_cfg_t;
81
82static void syntax_print(void);
83
84static int fat_params_compute(struct fat_cfg *cfg);
85static int fat_blocks_write(struct fat_cfg const *cfg, service_id_t service_id);
86static void fat_bootsec_create(struct fat_cfg const *cfg, struct fat_bs *bs);
87
88int main(int argc, char **argv)
89{
90 struct fat_cfg cfg;
91
92 int rc;
93 char *dev_path;
94 service_id_t service_id;
95 char *endptr;
96 aoff64_t dev_nblocks;
97
98 cfg.sector_size = default_sector_size;
99 cfg.sectors_per_cluster = default_sectors_per_cluster;
100 cfg.fat_count = default_fat_count;
101 cfg.total_sectors = 0;
102 cfg.addt_res_sectors = 0;
103 cfg.root_ent_max = 128;
104 cfg.fat_type = FATAUTO;
105
106 if (argc < 2) {
107 printf(NAME ": Error, argument missing.\n");
108 syntax_print();
109 return 1;
110 }
111
112 --argc; ++argv;
113 if (str_cmp(*argv, "--size") == 0) {
114 --argc; ++argv;
115 if (*argv == NULL) {
116 printf(NAME ": Error, argument missing.\n");
117 syntax_print();
118 return 1;
119 }
120
121 cfg.total_sectors = strtol(*argv, &endptr, 10);
122 if (*endptr != '\0') {
123 printf(NAME ": Error, invalid argument.\n");
124 syntax_print();
125 return 1;
126 }
127
128 --argc; ++argv;
129 }
130
131 if (str_cmp(*argv, "--type") == 0) {
132 --argc; ++argv;
133 if (*argv == NULL) {
134 printf(NAME ": Error, argument missing.\n");
135 syntax_print();
136 return 1;
137 }
138
139 cfg.fat_type = strtol(*argv, &endptr, 10);
140 if (*endptr != '\0') {
141 printf(NAME ": Error, invalid argument.\n");
142 syntax_print();
143 return 1;
144 }
145
146 --argc; ++argv;
147 }
148
149 if (argc != 1) {
150 printf(NAME ": Error, unexpected argument.\n");
151 syntax_print();
152 return 1;
153 }
154
155 dev_path = *argv;
156 printf("Device: %s\n", dev_path);
157
158 rc = loc_service_get_id(dev_path, &service_id, 0);
159 if (rc != EOK) {
160 printf(NAME ": Error resolving device `%s'.\n", dev_path);
161 return 2;
162 }
163
164 rc = block_init(service_id, 2048);
165 if (rc != EOK) {
166 printf(NAME ": Error initializing libblock.\n");
167 return 2;
168 }
169
170 rc = block_get_bsize(service_id, &cfg.sector_size);
171 if (rc != EOK) {
172 printf(NAME ": Error determining device block size.\n");
173 return 2;
174 }
175
176 rc = block_get_nblocks(service_id, &dev_nblocks);
177 if (rc != EOK) {
178 printf(NAME ": Warning, failed to obtain block device size.\n");
179 } else {
180 printf(NAME ": Block device has %" PRIuOFF64 " blocks.\n",
181 dev_nblocks);
182 if (!cfg.total_sectors || dev_nblocks < cfg.total_sectors)
183 cfg.total_sectors = dev_nblocks;
184 }
185
186 if (cfg.total_sectors == 0) {
187 printf(NAME ": Error. You must specify filesystem size.\n");
188 return 1;
189 }
190
191 if (cfg.fat_type != FATAUTO && cfg.fat_type != FAT12 && cfg.fat_type != FAT16 &&
192 cfg.fat_type != FAT32) {
193 printf(NAME ": Error. Unknown FAT type.\n");
194 return 2;
195 }
196
197 printf(NAME ": Creating FAT%d filesystem on device %s.\n", cfg.fat_type, dev_path);
198
199 rc = fat_params_compute(&cfg);
200 if (rc != EOK) {
201 printf(NAME ": Invalid file-system parameters.\n");
202 return 2;
203 }
204
205 rc = fat_blocks_write(&cfg, service_id);
206 if (rc != EOK) {
207 printf(NAME ": Error writing device.\n");
208 return 2;
209 }
210
211 block_fini(service_id);
212 printf("Success.\n");
213
214 return 0;
215}
216
217static void syntax_print(void)
218{
219 printf("syntax: mkfat [--size <sectors>] [--type 12|16|32] <device_name>\n");
220}
221
222/** Derive sizes of different filesystem structures.
223 *
224 * This function concentrates all the different computations of FAT
225 * file system params.
226 */
227static int fat_params_compute(struct fat_cfg *cfg)
228{
229 uint32_t fat_bytes;
230 uint32_t non_data_sectors_lb;
231
232 /*
233 * Make a conservative guess on the FAT size needed for the file
234 * system. The optimum could be potentially smaller since we
235 * do not subtract size of the FAT itself when computing the
236 * size of the data region.
237 */
238
239 cfg->reserved_sectors = 1 + cfg->addt_res_sectors;
240 if (cfg->fat_type != FAT32) {
241 cfg->rootdir_sectors = div_round_up(cfg->root_ent_max * DIRENT_SIZE,
242 cfg->sector_size);
243 } else
244 cfg->rootdir_sectors = 0;
245 non_data_sectors_lb = cfg->reserved_sectors + cfg->rootdir_sectors;
246
247 cfg->total_clusters = div_round_up(cfg->total_sectors - non_data_sectors_lb,
248 cfg->sectors_per_cluster);
249
250 if (cfg->total_clusters <= FAT12_CLST_MAX) {
251 if (cfg->fat_type == FATAUTO)
252 cfg->fat_type = FAT12;
253 else if (cfg->fat_type != FAT12)
254 return EINVAL;
255 } else if (cfg->total_clusters <= FAT16_CLST_MAX) {
256 if (cfg->fat_type == FATAUTO)
257 cfg->fat_type = FAT16;
258 else if (cfg->fat_type != FAT16)
259 return EINVAL;
260 } else {
261 if (cfg->fat_type == FATAUTO)
262 cfg->fat_type = FAT32;
263 else if (cfg->fat_type != FAT32)
264 return EINVAL;
265 }
266
267 fat_bytes = div_round_up((cfg->total_clusters + 2) *
268 FAT_CLUSTER_DOUBLE_SIZE(cfg->fat_type), 2);
269 cfg->fat_sectors = div_round_up(fat_bytes, cfg->sector_size);
270
271 return EOK;
272}
273
274/** Create file system with the given parameters. */
275static int fat_blocks_write(struct fat_cfg const *cfg, service_id_t service_id)
276{
277 aoff64_t addr;
278 uint8_t *buffer;
279 int i;
280 uint32_t j;
281 int rc;
282 struct fat_bs bs;
283
284 fat_bootsec_create(cfg, &bs);
285
286 rc = block_write_direct(service_id, BS_BLOCK, 1, &bs);
287 if (rc != EOK)
288 return EIO;
289
290 addr = BS_BLOCK + 1;
291
292 buffer = calloc(cfg->sector_size, 1);
293 if (buffer == NULL)
294 return ENOMEM;
295 memset(buffer, 0, cfg->sector_size);
296
297 /* Reserved sectors */
298 for (i = 0; i < cfg->reserved_sectors - 1; ++i) {
299 rc = block_write_direct(service_id, addr, 1, buffer);
300 if (rc != EOK)
301 return EIO;
302
303 ++addr;
304 }
305
306 /* File allocation tables */
307 for (i = 0; i < cfg->fat_count; ++i) {
308 printf("Writing allocation table %d.\n", i + 1);
309
310 for (j = 0; j < cfg->fat_sectors; ++j) {
311 memset(buffer, 0, cfg->sector_size);
312 if (j == 0) {
313 buffer[0] = default_media_descriptor;
314 buffer[1] = 0xFF;
315 buffer[2] = 0xFF;
316 if (cfg->fat_type == FAT16) {
317 buffer[3] = 0xFF;
318 } else if (cfg->fat_type == FAT32) {
319 buffer[3] = 0x0F;
320 buffer[4] = 0xFF;
321 buffer[5] = 0xFF;
322 buffer[6] = 0xFF;
323 buffer[7] = 0x0F;
324 buffer[8] = 0xF8;
325 buffer[9] = 0xFF;
326 buffer[10] = 0xFF;
327 buffer[11] = 0x0F;
328 }
329 }
330
331 rc = block_write_direct(service_id, addr, 1, buffer);
332 if (rc != EOK)
333 return EIO;
334
335 ++addr;
336 }
337 }
338
339 /* Root directory */
340 printf("Writing root directory.\n");
341 memset(buffer, 0, cfg->sector_size);
342 if (cfg->fat_type != FAT32) {
343 size_t idx;
344 for (idx = 0; idx < cfg->rootdir_sectors; ++idx) {
345 rc = block_write_direct(service_id, addr, 1, buffer);
346 if (rc != EOK)
347 return EIO;
348
349 ++addr;
350 }
351 } else {
352 for (i = 0; i < cfg->sectors_per_cluster; i++) {
353 rc = block_write_direct(service_id, addr, 1, buffer);
354 if (rc != EOK)
355 return EIO;
356
357 ++addr;
358 }
359 }
360
361 free(buffer);
362
363 return EOK;
364}
365
366/** Construct boot sector with the given parameters. */
367static void fat_bootsec_create(struct fat_cfg const *cfg, struct fat_bs *bs)
368{
369 memset(bs, 0, sizeof(*bs));
370
371 bs->ji[0] = 0xEB;
372 bs->ji[1] = 0x3C;
373 bs->ji[2] = 0x90;
374
375 memcpy(bs->oem_name, "HELENOS ", 8);
376
377 /* BIOS Parameter Block */
378 bs->bps = host2uint16_t_le(cfg->sector_size);
379 bs->spc = cfg->sectors_per_cluster;
380 bs->rscnt = host2uint16_t_le(cfg->reserved_sectors);
381 bs->fatcnt = cfg->fat_count;
382 bs->root_ent_max = host2uint16_t_le(cfg->root_ent_max);
383
384 if (cfg->total_sectors < 0x10000) {
385 bs->totsec16 = host2uint16_t_le(cfg->total_sectors);
386 bs->totsec32 = 0;
387 } else {
388 bs->totsec16 = 0;
389 bs->totsec32 = host2uint32_t_le(cfg->total_sectors);
390 }
391
392 bs->mdesc = default_media_descriptor;
393 bs->sec_per_track = host2uint16_t_le(63);
394 bs->signature = host2uint16_t_be(0x55AA);
395 bs->headcnt = host2uint16_t_le(6);
396 bs->hidden_sec = host2uint32_t_le(0);
397
398 if (cfg->fat_type == FAT32) {
399 bs->sec_per_fat = 0;
400 bs->fat32.sectors_per_fat = host2uint32_t_le(cfg->fat_sectors);
401
402 bs->fat32.pdn = 0x80;
403 bs->fat32.ebs = 0x29;
404 bs->fat32.id = host2uint32_t_be(0x12345678);
405 bs->fat32.root_cluster = 2;
406
407 memcpy(bs->fat32.label, "HELENOS_NEW", 11);
408 memcpy(bs->fat32.type, "FAT32 ", 8);
409 } else {
410 bs->sec_per_fat = host2uint16_t_le(cfg->fat_sectors);
411 bs->pdn = 0x80;
412 bs->ebs = 0x29;
413 bs->id = host2uint32_t_be(0x12345678);
414
415 memcpy(bs->label, "HELENOS_NEW", 11);
416 memcpy(bs->type, "FAT ", 8);
417 }
418}
419
420/**
421 * @}
422 */
Note: See TracBrowser for help on using the repository browser.