source: mainline/uspace/app/mkexfat/mkexfat.c@ 3f6d4ea

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

mkexfat: write the VBR and the VBR-backup on disk.

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