]> git.sven.stormbind.net Git - sven/exfatprogs.git/blob - mkfs/mkfs.c
New upstream version 1.0.3
[sven/exfatprogs.git] / mkfs / mkfs.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *   Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdbool.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/ioctl.h>
14 #include <fcntl.h>
15 #include <getopt.h>
16 #include <inttypes.h>
17 #include <errno.h>
18 #include <math.h>
19 #include <locale.h>
20
21 #include "exfat_ondisk.h"
22 #include "libexfat.h"
23 #include "mkfs.h"
24
25 struct exfat_mkfs_info finfo;
26
27 static void exfat_setup_boot_sector(struct pbr *ppbr,
28                 struct exfat_blk_dev *bd, struct exfat_user_input *ui)
29 {
30         struct bpb64 *pbpb = &ppbr->bpb;
31         struct bsx64 *pbsx = &ppbr->bsx;
32
33         /* Fill exfat BIOS paramemter block */
34         pbpb->jmp_boot[0] = 0xeb;
35         pbpb->jmp_boot[1] = 0x76;
36         pbpb->jmp_boot[2] = 0x90;
37         memcpy(pbpb->oem_name, "EXFAT   ", 8);
38         memset(pbpb->res_zero, 0, 53);
39
40         /* Fill exfat extend BIOS paramemter block */
41         pbsx->vol_offset = 0;
42         pbsx->vol_length = cpu_to_le64(bd->size / bd->sector_size);
43         pbsx->fat_offset = cpu_to_le32(finfo.fat_byte_off / bd->sector_size);
44         pbsx->fat_length = cpu_to_le32(finfo.fat_byte_len / bd->sector_size);
45         pbsx->clu_offset = cpu_to_le32(finfo.clu_byte_off / bd->sector_size);
46         pbsx->clu_count = cpu_to_le32(finfo.total_clu_cnt);
47         pbsx->root_cluster = cpu_to_le32(finfo.root_start_clu);
48         pbsx->vol_serial = cpu_to_le32(1234);
49         pbsx->vol_flags = 0;
50         pbsx->sect_size_bits = bd->sector_size_bits;
51         pbsx->sect_per_clus_bits = log2(ui->cluster_size / bd->sector_size);
52         pbsx->num_fats = 1;
53         /* fs_version[0] : minor and fs_version[1] : major */
54         pbsx->fs_version[0] = 0;
55         pbsx->fs_version[1] = 1;
56         memset(pbsx->reserved2, 0, 7);
57
58         memset(ppbr->boot_code, 0, 390);
59         ppbr->signature = cpu_to_le16(PBR_SIGNATURE);
60
61         exfat_debug("Volume Length(sectors) : %" PRIu64 "\n",
62                 le64_to_cpu(pbsx->vol_length));
63         exfat_debug("FAT Offset(sector offset) : %u\n",
64                 le32_to_cpu(pbsx->fat_offset));
65         exfat_debug("FAT Length(sectors) : %u\n",
66                 le32_to_cpu(pbsx->fat_length));
67         exfat_debug("Cluster Heap Offset (sector offset) : %u\n",
68                 le32_to_cpu(pbsx->clu_offset));
69         exfat_debug("Cluster Count (sectors) : %u\n",
70                 le32_to_cpu(pbsx->clu_count));
71         exfat_debug("Root Cluster (cluster offset) : %u\n",
72                 le32_to_cpu(pbsx->root_cluster));
73         exfat_debug("Sector Size Bits : %u\n",
74                 pbsx->sect_size_bits);
75         exfat_debug("Sector per Cluster bits : %u\n",
76                 pbsx->sect_per_clus_bits);
77 }
78
79 static int exfat_write_sector(struct exfat_blk_dev *bd, void *buf,
80                 unsigned int sec_off)
81 {
82         int bytes;
83         unsigned long long offset = sec_off * bd->sector_size;
84
85         lseek(bd->dev_fd, offset, SEEK_SET);
86         bytes = write(bd->dev_fd, buf, bd->sector_size);
87         if (bytes != (int)bd->sector_size) {
88                 exfat_err("write failed, sec_off : %u, bytes : %d\n", sec_off,
89                         bytes);
90                 return -1;
91         }
92         return 0;
93 }
94
95 static int exfat_write_boot_sector(struct exfat_blk_dev *bd,
96                 struct exfat_user_input *ui, unsigned int *checksum,
97                 bool is_backup)
98 {
99         struct pbr *ppbr;
100         unsigned int sec_idx = BOOT_SEC_IDX;
101         int ret = 0;
102
103         if (is_backup)
104                 sec_idx += BACKUP_BOOT_SEC_IDX;
105
106         ppbr = malloc(sizeof(struct pbr));
107         if (!ppbr) {
108                 exfat_err("Cannot allocate pbr: out of memory\n");
109                 return -1;
110         }
111         memset(ppbr, 0, sizeof(struct pbr));
112
113         exfat_setup_boot_sector(ppbr, bd, ui);
114
115         /* write main boot sector */
116         ret = exfat_write_sector(bd, ppbr, sec_idx);
117         if (ret < 0) {
118                 exfat_err("main boot sector write failed\n");
119                 ret = -1;
120                 goto free_ppbr;
121         }
122
123         boot_calc_checksum((unsigned char *)ppbr, sizeof(struct pbr),
124                 true, checksum);
125
126 free_ppbr:
127         free(ppbr);
128         return ret;
129 }
130
131 static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd,
132                 unsigned int *checksum, bool is_backup)
133 {
134         struct exbs eb;
135         int i;
136         unsigned int sec_idx = EXBOOT_SEC_IDX;
137
138         if (is_backup)
139                 sec_idx += BACKUP_BOOT_SEC_IDX;
140
141         memset(&eb, 0, sizeof(struct exbs));
142         eb.signature = cpu_to_le16(PBR_SIGNATURE);
143         for (i = 0; i < EXBOOT_SEC_NUM; i++) {
144                 if (exfat_write_sector(bd, &eb, sec_idx++)) {
145                         exfat_err("extended boot sector write failed\n");
146                         return -1;
147                 }
148
149                 boot_calc_checksum((unsigned char *) &eb, sizeof(struct exbs),
150                         false, checksum);
151         }
152
153         return 0;
154 }
155
156 static int exfat_write_oem_sector(struct exfat_blk_dev *bd,
157                 unsigned int *checksum, bool is_backup)
158 {
159         char *oem;
160         int ret = 0;
161         unsigned int sec_idx = OEM_SEC_IDX;
162
163         oem = malloc(bd->sector_size);
164         if (!oem)
165                 return -1;
166
167         if (is_backup)
168                 sec_idx += BACKUP_BOOT_SEC_IDX;
169
170         memset(oem, 0xFF, bd->sector_size);
171         ret = exfat_write_sector(bd, oem, sec_idx);
172         if (ret) {
173                 exfat_err("oem sector write failed\n");
174                 ret = -1;
175                 goto free_oem;
176         }
177
178         boot_calc_checksum((unsigned char *)oem, bd->sector_size, false,
179                 checksum);
180
181         /* Zero out reserved sector */
182         memset(oem, 0, bd->sector_size);
183         ret = exfat_write_sector(bd, oem, sec_idx + 1);
184         if (ret) {
185                 exfat_err("reserved sector write failed\n");
186                 ret = -1;
187                 goto free_oem;
188         }
189
190         boot_calc_checksum((unsigned char *)oem, bd->sector_size, false,
191                 checksum);
192
193 free_oem:
194         free(oem);
195         return ret;
196 }
197
198 static int exfat_write_checksum_sector(struct exfat_blk_dev *bd,
199                 unsigned int checksum, bool is_backup)
200 {
201         __le32 *checksum_buf;
202         int ret = 0;
203         unsigned int i;
204         unsigned int sec_idx = CHECKSUM_SEC_IDX;
205
206         checksum_buf = malloc(bd->sector_size);
207         if (!checksum_buf)
208                 return -1;
209
210         if (is_backup)
211                 sec_idx += BACKUP_BOOT_SEC_IDX;
212
213         for (i = 0; i < bd->sector_size / sizeof(int); i++)
214                 checksum_buf[i] = cpu_to_le32(checksum);
215
216         ret = exfat_write_sector(bd, checksum_buf, sec_idx);
217         if (ret) {
218                 exfat_err("checksum sector write failed\n");
219                 goto free;
220         }
221
222 free:
223         free(checksum_buf);
224         return ret;
225 }
226
227 static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd,
228                 struct exfat_user_input *ui, bool is_backup)
229 {
230         unsigned int checksum = 0;
231         int ret;
232
233         ret = exfat_write_boot_sector(bd, ui, &checksum, is_backup);
234         if (ret)
235                 return ret;
236         ret = exfat_write_extended_boot_sectors(bd, &checksum, is_backup);
237         if (ret)
238                 return ret;
239         ret = exfat_write_oem_sector(bd, &checksum, is_backup);
240         if (ret)
241                 return ret;
242
243         return exfat_write_checksum_sector(bd, checksum, is_backup);
244 }
245
246 static int write_fat_entry(int fd, __le32 clu,
247                 unsigned long long offset)
248 {
249         int nbyte;
250
251         lseek(fd, finfo.fat_byte_off + (offset * sizeof(__le32)), SEEK_SET);
252         nbyte = write(fd, (__u8 *) &clu, sizeof(__le32));
253         if (nbyte != sizeof(int)) {
254                 exfat_err("write failed, offset : %llu, clu : %x\n",
255                         offset, clu);
256                 return -1;
257         }
258
259         return 0;
260 }
261
262 static int write_fat_entries(struct exfat_user_input *ui, int fd,
263                 unsigned int clu, unsigned int length)
264 {
265         int ret;
266         unsigned int count;
267
268         count = clu + round_up(length, ui->cluster_size) / ui->cluster_size;
269
270         for (; clu < count - 1; clu++) {
271                 ret = write_fat_entry(fd, cpu_to_le32(clu + 1), clu);
272                 if (ret)
273                         return ret;
274         }
275
276         ret = write_fat_entry(fd, cpu_to_le32(EXFAT_EOF_CLUSTER), clu);
277         if (ret)
278                 return ret;
279
280         return clu;
281 }
282
283 static int exfat_create_fat_table(struct exfat_blk_dev *bd,
284                 struct exfat_user_input *ui)
285 {
286         int ret, clu;
287
288         /* fat entry 0 should be media type field(0xF8) */
289         ret = write_fat_entry(bd->dev_fd, cpu_to_le32(0xfffffff8), 0);
290         if (ret) {
291                 exfat_err("fat 0 entry write failed\n");
292                 return ret;
293         }
294
295         /* fat entry 1 is historical precedence(0xFFFFFFFF) */
296         ret = write_fat_entry(bd->dev_fd, cpu_to_le32(0xffffffff), 1);
297         if (ret) {
298                 exfat_err("fat 1 entry write failed\n");
299                 return ret;
300         }
301
302         /* write bitmap entries */
303         clu = write_fat_entries(ui, bd->dev_fd, EXFAT_FIRST_CLUSTER,
304                 finfo.bitmap_byte_len);
305         if (clu < 0)
306                 return ret;
307
308         /* write upcase table entries */
309         clu = write_fat_entries(ui, bd->dev_fd, clu + 1, finfo.ut_byte_len);
310         if (clu < 0)
311                 return ret;
312
313         /* write root directory entries */
314         clu = write_fat_entries(ui, bd->dev_fd, clu + 1, finfo.root_byte_len);
315         if (clu < 0)
316                 return ret;
317
318         finfo.used_clu_cnt = clu + 1;
319         exfat_debug("Total used cluster count : %d\n", finfo.used_clu_cnt);
320
321         return ret;
322 }
323
324 static int exfat_create_bitmap(struct exfat_blk_dev *bd)
325 {
326         char *bitmap;
327         unsigned int i, nbytes;
328
329         bitmap = calloc(finfo.bitmap_byte_len, sizeof(*bitmap));
330         if (!bitmap)
331                 return -1;
332
333         for (i = 0; i < finfo.used_clu_cnt - EXFAT_FIRST_CLUSTER; i++)
334                 exfat_set_bit(bd, bitmap, i);
335
336         lseek(bd->dev_fd, finfo.bitmap_byte_off, SEEK_SET);
337         nbytes = write(bd->dev_fd, bitmap, finfo.bitmap_byte_len);
338         if (nbytes != finfo.bitmap_byte_len) {
339                 exfat_err("write failed, nbytes : %d, bitmap_len : %d\n",
340                         nbytes, finfo.bitmap_byte_len);
341                 free(bitmap);
342                 return -1;
343         }
344
345         free(bitmap);
346         return 0;
347 }
348
349 static int exfat_create_root_dir(struct exfat_blk_dev *bd,
350                 struct exfat_user_input *ui)
351 {
352         struct exfat_dentry ed[3];
353         int dentries_len = sizeof(struct exfat_dentry) * 3;
354         int nbytes;
355
356         /* Set volume label entry */
357         ed[0].type = EXFAT_VOLUME;
358         memset(ed[0].vol_label, 0, 22);
359         memcpy(ed[0].vol_label, ui->volume_label, ui->volume_label_len);
360         ed[0].vol_char_cnt = ui->volume_label_len/2;
361
362         /* Set bitmap entry */
363         ed[1].type = EXFAT_BITMAP;
364         ed[1].bitmap_flags = 0;
365         ed[1].bitmap_start_clu = cpu_to_le32(EXFAT_FIRST_CLUSTER);
366         ed[1].bitmap_size = cpu_to_le64(finfo.bitmap_byte_len);
367
368         /* Set upcase table entry */
369         ed[2].type = EXFAT_UPCASE;
370         ed[2].upcase_checksum = cpu_to_le32(0xe619d30d);
371         ed[2].upcase_start_clu = cpu_to_le32(finfo.ut_start_clu);
372         ed[2].upcase_size = cpu_to_le64(EXFAT_UPCASE_TABLE_SIZE);
373
374         lseek(bd->dev_fd, finfo.root_byte_off, SEEK_SET);
375         nbytes = write(bd->dev_fd, ed, dentries_len);
376         if (nbytes != dentries_len) {
377                 exfat_err("write failed, nbytes : %d, dentries_len : %d\n",
378                         nbytes, dentries_len);
379                 return -1;
380         }
381
382         return 0;
383 }
384
385 static void usage(void)
386 {
387         fprintf(stderr, "Usage: mkfs.exfat\n");
388         fprintf(stderr, "\t-L | --volume-label=label                              Set volume label\n");
389         fprintf(stderr, "\t-c | --cluster-size=size(or suffixed by 'K' or 'M')    Specify cluster size\n");
390         fprintf(stderr, "\t-f | --full-format                                     Full format\n");
391         fprintf(stderr, "\t-V | --version                                         Show version\n");
392         fprintf(stderr, "\t-v | --verbose                                         Print debug\n");
393         fprintf(stderr, "\t-h | --help                                            Show help\n");
394
395         exit(EXIT_FAILURE);
396 }
397
398 static struct option opts[] = {
399         {"volume-label",        required_argument,      NULL,   'L' },
400         {"cluster-size",        required_argument,      NULL,   'c' },
401         {"full-format",         no_argument,            NULL,   'f' },
402         {"version",             no_argument,            NULL,   'V' },
403         {"verbose",             no_argument,            NULL,   'v' },
404         {"help",                no_argument,            NULL,   'h' },
405         {"?",                   no_argument,            NULL,   '?' },
406         {NULL,                  0,                      NULL,    0  }
407 };
408
409 static int exfat_build_mkfs_info(struct exfat_blk_dev *bd,
410                 struct exfat_user_input *ui)
411 {
412         if (ui->cluster_size > DEFAULT_CLUSTER_SIZE)
413                 finfo.fat_byte_off = ui->cluster_size;
414         else
415                 finfo.fat_byte_off = DEFAULT_CLUSTER_SIZE;
416         finfo.fat_byte_len = round_up((bd->num_clusters * sizeof(int)),
417                 ui->cluster_size);
418         finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len,
419                 DEFAULT_CLUSTER_SIZE);
420         finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) /
421                 ui->cluster_size;
422         if (finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) {
423                 exfat_err("cluster size is too small\n");
424                 return -1;
425         }
426
427         finfo.bitmap_byte_off = finfo.clu_byte_off;
428         finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8;
429         finfo.ut_start_clu = round_up(EXFAT_REVERVED_CLUSTERS *
430                 ui->cluster_size + finfo.bitmap_byte_len, ui->cluster_size) /
431                 ui->cluster_size;
432         finfo.ut_byte_off = round_up(finfo.bitmap_byte_off +
433                 finfo.bitmap_byte_len, ui->cluster_size);
434         finfo.ut_byte_len = EXFAT_UPCASE_TABLE_SIZE;
435         finfo.root_start_clu = round_up(finfo.ut_start_clu * ui->cluster_size
436                 + finfo.ut_byte_len, ui->cluster_size) / ui->cluster_size;
437         finfo.root_byte_off = round_up(finfo.ut_byte_off + finfo.ut_byte_len,
438                 ui->cluster_size);
439         finfo.root_byte_len = sizeof(struct exfat_dentry) * 3;
440
441         return 0;
442 }
443
444 static int exfat_zero_out_disk(struct exfat_blk_dev *bd,
445                 struct exfat_user_input *ui)
446 {
447         int nbytes;
448         unsigned long long total_written = 0;
449         char *buf;
450         unsigned int chunk_size = ui->cluster_size;
451         unsigned long long size;
452
453         if (ui->quick)
454                 size = finfo.root_byte_off + chunk_size;
455         else
456                 size = bd->size;
457
458         buf = malloc(chunk_size);
459         if (!buf)
460                 return -1;
461
462         memset(buf, 0, chunk_size);
463         lseek(bd->dev_fd, 0, SEEK_SET);
464         do {
465
466                 nbytes = write(bd->dev_fd, buf, chunk_size);
467                 if (nbytes <= 0) {
468                         if (nbytes < 0)
469                                 exfat_err("write failed(errno : %d)\n", errno);
470                         break;
471                 }
472                 total_written += nbytes;
473         } while (total_written < size);
474
475         free(buf);
476         exfat_debug("zero out written size : %llu, disk size : %llu\n",
477                 total_written, bd->size);
478         return 0;
479 }
480
481 static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui)
482 {
483         int ret;
484
485         exfat_info("Creating exFAT filesystem(%s, cluster size=%u)\n\n",
486                 ui->dev_name, ui->cluster_size);
487
488         exfat_info("Writing volume boot record: ");
489         ret = exfat_create_volume_boot_record(bd, ui, 0);
490         exfat_info("%s\n", ret ? "failed" : "done");
491         if (ret)
492                 return ret;
493
494         exfat_info("Writing backup volume boot record: ");
495         /* backup sector */
496         ret = exfat_create_volume_boot_record(bd, ui, 1);
497         exfat_info("%s\n", ret ? "failed" : "done");
498         if (ret)
499                 return ret;
500
501         exfat_info("Fat table creation: ");
502         ret = exfat_create_fat_table(bd, ui);
503         exfat_info("%s\n", ret ? "failed" : "done");
504         if (ret)
505                 return ret;
506
507         exfat_info("Allocation bitmap creation: ");
508         ret = exfat_create_bitmap(bd);
509         exfat_info("%s\n", ret ? "failed" : "done");
510         if (ret)
511                 return ret;
512
513         exfat_info("Upcase table creation: ");
514         ret = exfat_create_upcase_table(bd);
515         exfat_info("%s\n", ret ? "failed" : "done");
516         if (ret)
517                 return ret;
518
519         exfat_info("Writing root directory entry: ");
520         ret = exfat_create_root_dir(bd, ui);
521         exfat_info("%s\n", ret ? "failed" : "done");
522         if (ret)
523                 return ret;
524
525         return 0;
526 }
527
528 static long long parse_cluster_size(const char *size)
529 {
530         char *data_unit;
531         unsigned long long byte_size = strtoull(size, &data_unit, 0);
532
533         switch (*data_unit) {
534         case 'M':
535         case 'm':
536                 byte_size <<= 20;
537                 break;
538         case 'K':
539         case 'k':
540                 byte_size <<= 10;
541                 break;
542         default:
543                 exfat_err("Wrong unit input('%c') for cluster size\n",
544                                 *data_unit);
545                 return -EINVAL;
546         }
547
548         return byte_size;
549 }
550
551 int main(int argc, char *argv[])
552 {
553         int c;
554         int ret = EXIT_FAILURE;
555         struct exfat_blk_dev bd;
556         struct exfat_user_input ui;
557         bool version_only = false;
558
559         init_user_input(&ui);
560
561         if (!setlocale(LC_CTYPE, ""))
562                 exfat_err("failed to init locale/codeset\n");
563
564         opterr = 0;
565         while ((c = getopt_long(argc, argv, "n:L:c:fVvh", opts, NULL)) != EOF)
566                 switch (c) {
567                 /*
568                  * Make 'n' option fallthrough to 'L' option for for backward
569                  * compatibility with old utils.
570                  */
571                 case 'n':
572                 case 'L':
573                 {
574                         ret = exfat_utf16_enc(optarg,
575                                 ui.volume_label, sizeof(ui.volume_label));
576                         if (ret < 0)
577                                 goto out;
578
579                         ui.volume_label_len = ret;
580                         break;
581                 }
582                 case 'c':
583                         ret = parse_cluster_size(optarg);
584                         if (ret < 0)
585                                 goto out;
586                         else if (ret > EXFAT_MAX_CLUSTER_SIZE) {
587                                 exfat_err("cluster size(%d) exceeds max cluster size(%d)\n",
588                                         ui.cluster_size, EXFAT_MAX_CLUSTER_SIZE);
589                                 goto out;
590                         }
591                         ui.cluster_size = ret;
592                         break;
593                 case 'f':
594                         ui.quick = false;
595                         break;
596                 case 'V':
597                         version_only = true;
598                         break;
599                 case 'v':
600                         print_level = EXFAT_DEBUG;
601                         break;
602                 case '?':
603                 case 'h':
604                 default:
605                         usage();
606         }
607
608         show_version();
609         if (version_only)
610                 exit(EXIT_FAILURE);
611
612         if (argc - optind != 1) {
613                 usage();
614         }
615
616         memset(ui.dev_name, 0, sizeof(ui.dev_name));
617         snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[optind]);
618
619         ret = exfat_get_blk_dev_info(&ui, &bd);
620         if (ret < 0)
621                 goto out;
622
623         ret = exfat_build_mkfs_info(&bd, &ui);
624         if (ret)
625                 goto out;
626
627         ret = exfat_zero_out_disk(&bd, &ui);
628         if (ret)
629                 goto out;
630
631         ret = make_exfat(&bd, &ui);
632         if (ret)
633                 goto out;
634
635         exfat_info("Synchronizing...\n");
636         ret = fsync(bd.dev_fd);
637 out:
638         if (!ret)
639                 exfat_info("\nexFAT format complete!\n");
640         else
641                 exfat_info("\nexFAT format fail!\n");
642         close(bd.dev_fd);
643         return ret;
644 }