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