source: mainline/uspace/app/mkexfat/mkexfat.c@ 207ad8bd

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

mkexfat: starts the loop counter from 1, not from zero (the first FAT sector has already been written to disk).

  • 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 = 1; i < cfg->fat_sector_count; ++i) {
207 rc = block_write_direct(service_id,
208 FAT_SECTOR_START + i + 1, 1, pfat);
209 if (rc != EOK)
210 goto error;
211 }
212
213error:
214 free(pfat);
215 return rc;
216}
217
218/** Given a power-of-two number (n), returns the result of log2(n).
219 *
220 * It works only if n is a power of two.
221 */
222static unsigned
223log2(unsigned n)
224{
225 unsigned r;
226
227 for (r = 0;n >> r != 1; ++r);
228
229 return r;
230}
231
232int main (int argc, char **argv)
233{
234 exfat_cfg_t cfg;
235 exfat_bs_t vbr;
236 char *dev_path;
237 service_id_t service_id;
238 int rc;
239
240 if (argc < 2) {
241 printf(NAME ": Error, argument missing\n");
242 usage();
243 return 1;
244 }
245
246 /* TODO: Add parameters */
247
248 ++argv;
249 dev_path = *argv;
250
251 printf(NAME ": Device = %s\n", dev_path);
252
253 rc = loc_service_get_id(dev_path, &service_id, 0);
254 if (rc != EOK) {
255 printf(NAME ": Error resolving device `%s'.\n", dev_path);
256 return 2;
257 }
258
259 rc = block_init(EXCHANGE_SERIALIZE, service_id, 2048);
260 if (rc != EOK) {
261 printf(NAME ": Error initializing libblock.\n");
262 return 2;
263 }
264
265 rc = block_get_bsize(service_id, &cfg.sector_size);
266 if (rc != EOK) {
267 printf(NAME ": Error determining device block size.\n");
268 return 2;
269 }
270
271 if (cfg.sector_size > 4096) {
272 printf(NAME ": Error, sector size can't be greater" \
273 " than 4096 bytes.\n");
274 return 2;
275 }
276
277 rc = block_get_nblocks(service_id, &cfg.volume_count);
278 if (rc != EOK) {
279 printf(NAME ": Warning, failed to obtain" \
280 " device block size.\n");
281 /* FIXME: the user should be able to specify the filesystem size */
282 return 1;
283 } else {
284 printf(NAME ": Block device has %" PRIuOFF64 " blocks.\n",
285 cfg.volume_count);
286 }
287
288 cfg_params_initialize(&cfg);
289 cfg_print_info(&cfg);
290 vbr_initialize(&vbr, &cfg);
291
292 /* Write the VBR on disk */
293 rc = block_write_direct(service_id, 0, 1, &vbr);
294 if (rc != EOK) {
295 printf(NAME ": Error, failed to write the VBR on disk\n");
296 return 2;
297 }
298
299 /* Write the VBR backup on disk */
300 rc = block_write_direct(service_id, 12, 1, &vbr);
301 if (rc != EOK) {
302 printf(NAME ": Error, failed to write the VBR" \
303 " backup on disk\n");
304 return 2;
305 }
306
307 rc = fat_write(service_id, &cfg);
308 if (rc != EOK) {
309 printf(NAME ": Error, failed to write the FAT on disk\n");
310 return 2;
311 }
312
313 return 0;
314}
315
Note: See TracBrowser for help on using the repository browser.