1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44#include "libbb.h"
45
46#include <linux/hdreg.h>
47#include <linux/fd.h>
48#include <sys/mount.h>
49#if !defined(BLKSSZGET)
50# define BLKSSZGET _IO(0x12, 104)
51#endif
52
53
54#define SECTOR_SIZE 512
55
56#define SECTORS_PER_BLOCK (BLOCK_SIZE / SECTOR_SIZE)
57
58
59#define EOF_FAT32 0x0FFFFFF8
60#define BAD_FAT32 0x0FFFFFF7
61#define MAX_CLUST_32 0x0FFFFFF0
62
63#define ATTR_VOLUME 8
64
65#define NUM_FATS 2
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90enum {
91
92 info_sector_number = 1,
93
94
95 backup_boot_sector = 3,
96 reserved_sect = 6,
97};
98
99
100#define TEST_BUFFER_BLOCKS 16
101
102struct msdos_dir_entry {
103 char name[11];
104 uint8_t attr;
105 uint8_t lcase;
106 uint8_t ctime_cs;
107 uint16_t ctime;
108 uint16_t cdate;
109 uint16_t adate;
110 uint16_t starthi;
111 uint16_t time;
112 uint16_t date;
113 uint16_t start;
114 uint32_t size;
115} PACKED;
116
117
118
119
120
121
122
123
124
125struct msdos_volume_info {
126 uint8_t drive_number;
127 uint8_t reserved;
128 uint8_t ext_boot_sign;
129 uint32_t volume_id32;
130 char volume_label[11];
131 char fs_type[8];
132} PACKED;
133
134struct msdos_boot_sector {
135
136 char boot_jump_and_sys_id[3+8];
137
138 uint16_t bytes_per_sect;
139 uint8_t sect_per_clust;
140 uint16_t reserved_sect;
141 uint8_t fats;
142 uint16_t dir_entries;
143 uint16_t volume_size_sect;
144 uint8_t media_byte;
145 uint16_t sect_per_fat;
146 uint16_t sect_per_track;
147 uint16_t heads;
148 uint32_t hidden;
149 uint32_t fat32_volume_size_sect;
150 uint32_t fat32_sect_per_fat;
151 uint16_t fat32_flags;
152 uint8_t fat32_version[2];
153 uint32_t fat32_root_cluster;
154 uint16_t fat32_info_sector;
155 uint16_t fat32_backup_boot;
156 uint32_t reserved2[3];
157 struct msdos_volume_info vi;
158 char boot_code[0x200 - 0x5a - 2];
159#define BOOT_SIGN 0xAA55
160 uint16_t boot_sign;
161} PACKED;
162
163#define FAT_FSINFO_SIG1 0x41615252
164#define FAT_FSINFO_SIG2 0x61417272
165struct fat32_fsinfo {
166 uint32_t signature1;
167 uint32_t reserved1[128 - 8];
168 uint32_t signature2;
169 uint32_t free_clusters;
170 uint32_t next_cluster;
171 uint32_t reserved2[3];
172 uint16_t reserved3;
173 uint16_t boot_sign;
174} PACKED;
175
176struct bug_check {
177 char BUG1[sizeof(struct msdos_dir_entry ) == 0x20 ? 1 : -1];
178 char BUG2[sizeof(struct msdos_volume_info) == 0x1a ? 1 : -1];
179 char BUG3[sizeof(struct msdos_boot_sector) == 0x200 ? 1 : -1];
180 char BUG4[sizeof(struct fat32_fsinfo ) == 0x200 ? 1 : -1];
181};
182
183static const char boot_code[] ALIGN1 =
184 "\x0e"
185 "\x1f"
186 "\xbe\x77\x7c"
187 "\xac"
188 "\x22\xc0"
189 "\x74\x0b"
190 "\x56"
191 "\xb4\x0e"
192 "\xbb\x07\x00"
193 "\xcd\x10"
194 "\x5e"
195 "\xeb\xf0"
196 "\x32\xe4"
197 "\xcd\x16"
198 "\xcd\x19"
199 "\xeb\xfe"
200
201 "This is not a bootable disk\r\n";
202
203
204#define MARK_CLUSTER(cluster, value) \
205 ((uint32_t *)fat)[cluster] = SWAP_LE32(value)
206
207
208
209
210
211
212
213
214
215
216
217
218int mkfs_vfat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
219int mkfs_vfat_main(int argc UNUSED_PARAM, char **argv)
220{
221 struct stat st;
222 const char *volume_label = "";
223 char *buf;
224 char *device_name;
225 uoff_t volume_size_bytes;
226 uoff_t volume_size_sect;
227 uint32_t total_clust;
228 uint32_t volume_id;
229 int dev;
230 unsigned bytes_per_sect;
231 unsigned sect_per_fat;
232 unsigned opts;
233 uint16_t sect_per_track;
234 uint8_t media_byte;
235 uint8_t sect_per_clust;
236 uint8_t heads;
237 enum {
238 OPT_A = 1 << 0,
239 OPT_b = 1 << 1,
240 OPT_c = 1 << 2,
241 OPT_C = 1 << 3,
242 OPT_f = 1 << 4,
243 OPT_F = 1 << 5,
244 OPT_h = 1 << 6,
245 OPT_I = 1 << 7,
246 OPT_i = 1 << 8,
247 OPT_l = 1 << 9,
248 OPT_m = 1 << 10,
249 OPT_n = 1 << 11,
250 OPT_r = 1 << 12,
251 OPT_R = 1 << 13,
252 OPT_s = 1 << 14,
253 OPT_S = 1 << 15,
254 OPT_v = 1 << 16,
255 };
256
257 opts = getopt32(argv, "^"
258 "Ab:cCf:F:h:Ii:l:m:n:r:R:s:S:v"
259 "\0" "-1",
260 NULL, NULL, NULL, NULL, NULL,
261 NULL, NULL, &volume_label, NULL, NULL, NULL, NULL);
262 argv += optind;
263
264
265 device_name = argv[0];
266
267 volume_id = time(NULL);
268
269 dev = xopen(device_name, O_RDWR);
270 xfstat(dev, &st, device_name);
271
272
273
274
275 bytes_per_sect = SECTOR_SIZE;
276 if (!S_ISBLK(st.st_mode)) {
277 if (!S_ISREG(st.st_mode)) {
278 if (!argv[1])
279 bb_simple_error_msg_and_die("image size must be specified");
280 }
281
282 opts &= ~OPT_c;
283 } else {
284 int min_bytes_per_sect;
285#if 0
286 unsigned device_num;
287
288 device_num = st.st_rdev & 0xff3f;
289
290 if (!(opts & OPT_I) && (
291 device_num == 0x0300 ||
292 (device_num & 0xff0f) == 0x0800 ||
293 device_num == 0x0d00 ||
294 device_num == 0x1600 )
295 )
296 bb_error_msg_and_die("will not try to make filesystem on full-disk device (use -I if wanted)");
297
298 if (find_mount_point(device_name, 0))
299 bb_error_msg_and_die("can't format mounted filesystem");
300#endif
301
302
303 xioctl(dev, BLKSSZGET, &min_bytes_per_sect);
304 if (min_bytes_per_sect > SECTOR_SIZE) {
305 bytes_per_sect = min_bytes_per_sect;
306 bb_error_msg("for this device sector size is %u", min_bytes_per_sect);
307 }
308 }
309 volume_size_bytes = get_volume_size_in_bytes(dev, argv[1], 1024, 1);
310 volume_size_sect = volume_size_bytes / bytes_per_sect;
311
312
313
314
315 media_byte = 0xf8;
316 heads = 255;
317 sect_per_track = 63;
318 sect_per_clust = 1;
319 {
320 struct hd_geometry geometry;
321
322 struct floppy_struct param;
323
324
325 if (ioctl(dev, HDIO_GETGEO, &geometry) == 0
326 && geometry.sectors
327 && geometry.heads
328 ) {
329
330 sect_per_track = geometry.sectors;
331 heads = geometry.heads;
332
333 set_cluster_size:
334
335
336
337
338
339
340
341 sect_per_clust = 1;
342 if (volume_size_bytes >= 260*1024*1024) {
343 sect_per_clust = 8;
344
345
346
347 if (sizeof(off_t) > 4) {
348 unsigned t = (volume_size_bytes >> 31 >> 1);
349 if (t >= 8/4)
350 sect_per_clust = 16;
351 if (t >= 16/4)
352 sect_per_clust = 32;
353 }
354 }
355 } else {
356
357 int not_floppy = ioctl(dev, FDGETPRM, ¶m);
358 if (not_floppy == 0) {
359
360 sect_per_track = param.sect;
361 heads = param.head;
362 volume_size_sect = param.size;
363 volume_size_bytes = param.size * SECTOR_SIZE;
364 }
365
366 switch (volume_size_sect) {
367 case 2*360:
368 media_byte = 0xfd;
369 break;
370 case 2*720:
371 case 2*1200:
372 media_byte = 0xf9;
373 break;
374 default:
375 if (not_floppy)
376 goto set_cluster_size;
377 case 2*1440:
378 case 2*2880:
379 media_byte = 0xf0;
380 break;
381 }
382
383
384
385
386 heads = 2;
387 sect_per_track = (unsigned)volume_size_sect / 160;
388 if (sect_per_track < 9)
389 sect_per_track = 9;
390 }
391 }
392
393
394
395
396
397
398
399 if ((off_t)(volume_size_sect - reserved_sect) < 4)
400 bb_simple_error_msg_and_die("the image is too small for FAT32");
401 sect_per_fat = 1;
402 while (1) {
403 while (1) {
404 int spf_adj;
405 uoff_t tcl = (volume_size_sect - reserved_sect - NUM_FATS * sect_per_fat) / sect_per_clust;
406
407
408
409
410
411 if (tcl > 0x80ffffff)
412 goto next;
413 total_clust = tcl;
414
415
416
417
418
419
420 spf_adj = ((total_clust+2) + (bytes_per_sect/4)-1) / (bytes_per_sect/4) - sect_per_fat;
421#if 0
422 bb_error_msg("sect_per_clust:%u sect_per_fat:%u total_clust:%u",
423 sect_per_clust, sect_per_fat, (int)tcl);
424 bb_error_msg("adjust to sect_per_fat:%d", spf_adj);
425#endif
426 if (spf_adj <= 0) {
427
428
429 if (total_clust <= MAX_CLUST_32)
430 goto found_total_clust;
431
432 goto next;
433 }
434
435
436 sect_per_fat += ((unsigned)spf_adj / 2) | 1;
437 }
438 next:
439 if (sect_per_clust == 128)
440 bb_simple_error_msg_and_die("can't make FAT32 with >128 sectors/cluster");
441 sect_per_clust *= 2;
442 sect_per_fat = (sect_per_fat / 2) | 1;
443 }
444 found_total_clust:
445
446
447
448
449 if (opts & OPT_v) {
450 fprintf(stderr,
451 "Device '%s':\n"
452 "heads:%u, sectors/track:%u, bytes/sector:%u\n"
453 "media descriptor:%02x\n"
454 "total sectors:%"OFF_FMT"u, clusters:%u, sectors/cluster:%u\n"
455 "FATs:2, sectors/FAT:%u\n"
456 "volumeID:%08x, label:'%s'\n",
457 device_name,
458 heads, sect_per_track, bytes_per_sect,
459 (int)media_byte,
460 volume_size_sect, (int)total_clust, (int)sect_per_clust,
461 sect_per_fat,
462 (int)volume_id, volume_label
463 );
464 }
465
466
467
468
469 {
470
471 unsigned bufsize = reserved_sect;
472
473 bufsize |= 2;
474 bufsize |= sect_per_clust;
475 buf = xzalloc(bufsize * bytes_per_sect);
476 }
477
478 {
479 struct msdos_boot_sector *boot_blk = (void*)buf;
480 struct fat32_fsinfo *info = (void*)(buf + bytes_per_sect);
481
482 strcpy(boot_blk->boot_jump_and_sys_id, "\xeb\x58\x90" "mkdosfs");
483 STORE_LE(boot_blk->bytes_per_sect, bytes_per_sect);
484 STORE_LE(boot_blk->sect_per_clust, sect_per_clust);
485
486 STORE_LE(boot_blk->reserved_sect, (uint16_t)reserved_sect);
487 STORE_LE(boot_blk->fats, 2);
488
489 if (volume_size_sect <= 0xffff)
490 STORE_LE(boot_blk->volume_size_sect, volume_size_sect);
491 STORE_LE(boot_blk->media_byte, media_byte);
492
493
494
495
496
497 STORE_LE(boot_blk->sect_per_track, sect_per_track);
498 STORE_LE(boot_blk->heads, heads);
499
500 STORE_LE(boot_blk->fat32_volume_size_sect, volume_size_sect);
501 STORE_LE(boot_blk->fat32_sect_per_fat, sect_per_fat);
502
503
504 STORE_LE(boot_blk->fat32_root_cluster, 2);
505 STORE_LE(boot_blk->fat32_info_sector, info_sector_number);
506 STORE_LE(boot_blk->fat32_backup_boot, backup_boot_sector);
507
508 STORE_LE(boot_blk->vi.ext_boot_sign, 0x29);
509 STORE_LE(boot_blk->vi.volume_id32, volume_id);
510 memcpy(boot_blk->vi.fs_type, "FAT32 ", sizeof(boot_blk->vi.fs_type));
511 strncpy(boot_blk->vi.volume_label, volume_label, sizeof(boot_blk->vi.volume_label));
512 memcpy(boot_blk->boot_code, boot_code, sizeof(boot_code));
513 STORE_LE(boot_blk->boot_sign, BOOT_SIGN);
514
515 STORE_LE(info->signature1, FAT_FSINFO_SIG1);
516 STORE_LE(info->signature2, FAT_FSINFO_SIG2);
517
518 STORE_LE(info->free_clusters, (total_clust - 1));
519 STORE_LE(info->next_cluster, 2);
520 STORE_LE(info->boot_sign, BOOT_SIGN);
521
522
523 xwrite(dev, buf, bytes_per_sect * backup_boot_sector);
524
525 xwrite(dev, buf, bytes_per_sect * (reserved_sect - backup_boot_sector));
526 }
527
528 {
529 unsigned i,j;
530 unsigned char *fat = (void*)buf;
531
532 memset(buf, 0, bytes_per_sect * 2);
533
534 MARK_CLUSTER(0, 0x0fffff00 | media_byte);
535 MARK_CLUSTER(1, 0xffffffff);
536
537 MARK_CLUSTER(2, EOF_FAT32);
538 for (i = 0; i < NUM_FATS; i++) {
539 xwrite(dev, buf, bytes_per_sect);
540 for (j = 1; j < sect_per_fat; j++)
541 xwrite(dev, buf + bytes_per_sect, bytes_per_sect);
542 }
543 }
544
545
546
547 memset(buf, 0, sect_per_clust * bytes_per_sect);
548 if (volume_label[0]) {
549
550 struct msdos_dir_entry *de;
551#if 0
552 struct tm tm_time;
553 uint16_t t, d;
554#endif
555 de = (void*)buf;
556 strncpy(de->name, volume_label, sizeof(de->name));
557 STORE_LE(de->attr, ATTR_VOLUME);
558#if 0
559 localtime_r(&create_time, &tm_time);
560 t = (tm_time.tm_sec >> 1) + (tm_time.tm_min << 5) + (tm_time.tm_hour << 11);
561 d = tm_time.tm_mday + ((tm_time.tm_mon+1) << 5) + ((tm_time.tm_year-80) << 9);
562 STORE_LE(de->time, t);
563 STORE_LE(de->date, d);
564
565 de->ctime = de->time;
566 de->cdate = de->date;
567 de->adate = de->date;
568#endif
569 }
570 xwrite(dev, buf, sect_per_clust * bytes_per_sect);
571
572#if 0
573 if (opts & OPT_c) {
574 uoff_t volume_size_blocks;
575 unsigned start_data_sector;
576 unsigned start_data_block;
577 unsigned badblocks = 0;
578 int try, got;
579 off_t currently_testing;
580 char *blkbuf = xmalloc(BLOCK_SIZE * TEST_BUFFER_BLOCKS);
581
582 volume_size_blocks = (volume_size_bytes >> BLOCK_SIZE_BITS);
583
584 start_data_sector = (reserved_sect + NUM_FATS * sect_per_fat) * (bytes_per_sect / SECTOR_SIZE);
585 start_data_block = (start_data_sector + SECTORS_PER_BLOCK - 1) / SECTORS_PER_BLOCK;
586
587 bb_error_msg("searching for bad blocks");
588 currently_testing = 0;
589 try = TEST_BUFFER_BLOCKS;
590 while (currently_testing < volume_size_blocks) {
591 if (currently_testing + try > volume_size_blocks)
592 try = volume_size_blocks - currently_testing;
593
594
595
596 xlseek(dev, currently_testing * BLOCK_SIZE, SEEK_SET);
597
598 got = read(dev, blkbuf, try * BLOCK_SIZE);
599 if (got < 0)
600 got = 0;
601 if (got & (BLOCK_SIZE - 1))
602 bb_error_msg("unexpected values in do_check: probably bugs");
603 got /= BLOCK_SIZE;
604 currently_testing += got;
605 if (got == try) {
606 try = TEST_BUFFER_BLOCKS;
607 continue;
608 }
609 try = 1;
610 if (currently_testing < start_data_block)
611 bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
612
613
614 for (i = 0; i < SECTORS_PER_BLOCK; i++) {
615 int cluster = (currently_testing * SECTORS_PER_BLOCK + i - start_data_sector) / (int) (sect_per_clust) / (bytes_per_sect / SECTOR_SIZE);
616 if (cluster < 0)
617 bb_error_msg_and_die("invalid cluster number in mark_sector: probably bug!");
618 MARK_CLUSTER(cluster, BAD_FAT32);
619 }
620 badblocks++;
621 currently_testing++;
622 }
623 free(blkbuf);
624 if (badblocks)
625 bb_error_msg("%d bad block(s)", badblocks);
626 }
627#endif
628
629
630 if (ENABLE_FEATURE_CLEAN_UP) {
631 free(buf);
632 close(dev);
633 }
634
635 return 0;
636}
637