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