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