source: mainline/uspace/app/mkexfat/mkexfat.c@ 50e754e

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

mkexfat: Initialize the FAT vector, vbr-backup starts at sector 12.

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/*
2 * Copyright (c) 2012 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/**
34 * @file mkexfat.c
35 * @brief Tool for creating new exFAT file systems.
36 *
37 */
38
39#include <stdio.h>
40#include <libblock.h>
41#include <assert.h>
42#include <errno.h>
43#include <malloc.h>
44#include <byteorder.h>
45#include <align.h>
46#include <sys/types.h>
47#include <sys/typefmt.h>
48#include "exfat.h"
49
50#define NAME "mkexfat"
51
52/** First sector of the FAT */
53#define FAT_SECTOR_START 128
54
55/** Divide and round up. */
56#define div_round_up(a, b) (((a) + (b) - 1) / (b))
57
58/** The default size of each cluster is 4096 byte */
59#define DEFAULT_CLUSTER_SIZE 4096
60
61static unsigned log2(unsigned n);
62
63typedef struct exfat_cfg {
64 aoff64_t volume_start;
65 aoff64_t volume_count;
66 unsigned long fat_sector_count;
67 unsigned long data_start_sector;
68 unsigned long rootdir_cluster;
69 unsigned long total_clusters;
70 size_t sector_size;
71 size_t cluster_size;
72} exfat_cfg_t;
73
74static void usage(void)
75{
76 printf("Usage: mkexfat <device>\n");
77}
78
79/** Initialize the exFAT params structure.
80 *
81 * @param cfg Pointer to the exFAT params structure to initialize.
82 */
83static void
84cfg_params_initialize(exfat_cfg_t *cfg)
85{
86 unsigned long fat_bytes;
87 aoff64_t const volume_bytes = (cfg->volume_count - FAT_SECTOR_START) *
88 cfg->sector_size;
89
90 /** Number of clusters required to index the entire device, it must
91 * be less then UINT32_MAX.
92 */
93 aoff64_t n_req_clusters = volume_bytes / DEFAULT_CLUSTER_SIZE;
94 cfg->cluster_size = DEFAULT_CLUSTER_SIZE;
95
96 /* Compute the required cluster size to index
97 * the entire storage device.
98 */
99 while (n_req_clusters > 4000000 &&
100 (cfg->cluster_size < 32 * 1024 * 1024)) {
101
102 cfg->cluster_size <<= 1;
103 n_req_clusters = volume_bytes / cfg->cluster_size;
104 }
105
106 cfg->total_clusters = n_req_clusters + 2;
107
108 /* Compute the FAT size in sectors */
109 fat_bytes = (cfg->total_clusters + 1) * 4;
110 cfg->fat_sector_count = div_round_up(fat_bytes, cfg->sector_size);
111
112 /* Compute the number of the first data sector */
113 cfg->data_start_sector = ROUND_UP(FAT_SECTOR_START +
114 cfg->fat_sector_count, cfg->cluster_size / cfg->sector_size);
115
116 cfg->rootdir_cluster = 0;
117
118 /* The first sector of the partition is zero */
119 cfg->volume_start = 0;
120}
121
122/** Prints the exFAT structure values
123 *
124 * @param cfg Pointer to the exfat_cfg_t structure.
125 */
126static void
127cfg_print_info(exfat_cfg_t *cfg)
128{
129 printf(NAME ": Sector size: %lu\n", cfg->sector_size);
130 printf(NAME ": Cluster size: %lu\n", cfg->cluster_size);
131 printf(NAME ": FAT size in sectors: %lu\n", cfg->fat_sector_count);
132 printf(NAME ": Data start sector: %lu\n", cfg->data_start_sector);
133 printf(NAME ": Total num of clusters: %lu\n", cfg->total_clusters);
134}
135
136/** Initialize the Volume Boot Record fields.
137 *
138 * @param vbr Pointer to the Volume Boot Record structure.
139 * @param cfg Pointer to the exFAT configuration structure.
140 */
141static void
142vbr_initialize(exfat_bs_t *vbr, exfat_cfg_t *cfg)
143{
144 /* Fill the structure with zeroes */
145 memset(vbr, 0, sizeof(exfat_bs_t));
146
147 /* Init Jump Boot section */
148 vbr->jump[0] = 0xEB;
149 vbr->jump[1] = 0x76;
150 vbr->jump[2] = 0x90;
151
152 /* Set the filesystem name */
153 memcpy(vbr->oem_name, "EXFAT ", sizeof(vbr->oem_name));
154
155 vbr->volume_start = host2uint64_t_le(cfg->volume_start);
156 vbr->volume_count = host2uint64_t_le(cfg->volume_count);
157 vbr->fat_sector_start = host2uint32_t_le(FAT_SECTOR_START);
158 vbr->fat_sector_count = host2uint32_t_le(cfg->fat_sector_count);
159 vbr->data_start_sector = host2uint32_t_le(cfg->data_start_sector);
160
161 vbr->data_clusters = host2uint32_t_le(cfg->total_clusters -
162 div_round_up(cfg->data_start_sector, cfg->cluster_size));
163
164 vbr->rootdir_cluster = 0;
165 vbr->volume_serial = 0;
166 vbr->version.major = 1;
167 vbr->version.minor = 0;
168 vbr->volume_flags = host2uint16_t_le(0);
169 vbr->bytes_per_sector = log2(cfg->sector_size);
170 vbr->sec_per_cluster = log2(cfg->cluster_size / cfg->sector_size);
171
172 /* Maximum cluster size is 32 Mb */
173 assert((vbr->bytes_per_sector + vbr->sec_per_cluster) <= 25);
174
175 vbr->fat_count = 1;
176 vbr->drive_no = 0x80;
177 vbr->allocated_percent = 0;
178 vbr->signature = host2uint16_t_le(0xAA55);
179}
180
181/** Writes the FAT on disk.
182 *
183 * @param cfg Pointer to the exfat_cfg structure.
184 * @return EOK on success or a negative error code.
185 */
186static int
187fat_write(service_id_t service_id, exfat_cfg_t *cfg)
188{
189 unsigned long i;
190 uint32_t *pfat;
191 int rc;
192
193 pfat = calloc(cfg->fat_sector_count, cfg->sector_size);
194 if (!pfat)
195 return ENOMEM;
196
197 pfat[0] = host2uint32_t_le(0xFFFFFFF8);
198 pfat[1] = host2uint32_t_le(0xFFFFFFFF);
199
200 rc = block_write_direct(service_id, FAT_SECTOR_START, 1, pfat);
201 if (rc != EOK)
202 goto error;
203
204 pfat[0] = pfat[1] = 0x00000000;
205
206 for (i = FAT_SECTOR_START + 1; i < cfg->fat_sector_count; ++i) {
207 rc = block_write_direct(service_id, i, 1, pfat);
208 if (rc != EOK)
209 goto error;
210 }
211
212error:
213 free(pfat);
214 return rc;
215}
216
217/** Given a power-of-two number (n), returns the result of log2(n).
218 *
219 * It works only if n is a power of two.
220 */
221static unsigned
222log2(unsigned n)
223{
224 unsigned r;
225
226 for (r = 0;n >> r != 1; ++r);
227
228 return r;
229}
230
231int main (int argc, char **argv)
232{
233 exfat_cfg_t cfg;
234 exfat_bs_t vbr;
235 char *dev_path;
236 service_id_t service_id;
237 int rc;
238
239 if (argc < 2) {
240 printf(NAME ": Error, argument missing\n");
241 usage();
242 return 1;
243 }
244
245 /* TODO: Add parameters */
246
247 ++argv;
248 dev_path = *argv;
249
250 printf(NAME ": Device = %s\n", dev_path);
251
252 rc = loc_service_get_id(dev_path, &service_id, 0);
253 if (rc != EOK) {
254 printf(NAME ": Error resolving device `%s'.\n", dev_path);
255 return 2;
256 }
257
258 rc = block_init(EXCHANGE_SERIALIZE, service_id, 2048);
259 if (rc != EOK) {
260 printf(NAME ": Error initializing libblock.\n");
261 return 2;
262 }
263
264 rc = block_get_bsize(service_id, &cfg.sector_size);
265 if (rc != EOK) {
266 printf(NAME ": Error determining device block size.\n");
267 return 2;
268 }
269
270 if (cfg.sector_size > 4096) {
271 printf(NAME ": Error, sector size can't be greater" \
272 " than 4096 bytes.\n");
273 return 2;
274 }
275
276 rc = block_get_nblocks(service_id, &cfg.volume_count);
277 if (rc != EOK) {
278 printf(NAME ": Warning, failed to obtain" \
279 " device block size.\n");
280 /* FIXME: the user should be able to specify the filesystem size */
281 return 1;
282 } else {
283 printf(NAME ": Block device has %" PRIuOFF64 " blocks.\n",
284 cfg.volume_count);
285 }
286
287 cfg_params_initialize(&cfg);
288 cfg_print_info(&cfg);
289 vbr_initialize(&vbr, &cfg);
290
291 /* Write the VBR on disk */
292 rc = block_write_direct(service_id, 0, 1, &vbr);
293 if (rc != EOK) {
294 printf(NAME ": Error, failed to write the VBR on disk\n");
295 return 2;
296 }
297
298 /* Write the VBR backup on disk */
299 rc = block_write_direct(service_id, 12, 1, &vbr);
300 if (rc != EOK) {
301 printf(NAME ": Error, failed to write the VBR" \
302 " backup on disk\n");
303 return 2;
304 }
305
306 rc = fat_write(service_id, &cfg);
307 if (rc != EOK) {
308 printf(NAME ": Error, failed to write the FAT on disk\n");
309 return 2;
310 }
311
312 return 0;
313}
314
Note: See TracBrowser for help on using the repository browser.