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 static const char NO_NAME_11[] = "NO NAME ";
222
223 struct stat st;
224 const char *arg_volume_label = NO_NAME_11;
225 char volume_label11[12];
226 char *buf;
227 char *device_name;
228 uoff_t volume_size_bytes;
229 uoff_t volume_size_sect;
230 uint32_t total_clust;
231 uint32_t volume_id;
232 int dev;
233 unsigned bytes_per_sect;
234 unsigned sect_per_fat;
235 unsigned opts;
236 uint16_t sect_per_track;
237 uint8_t media_byte;
238 uint8_t sect_per_clust;
239 uint8_t heads;
240 enum {
241 OPT_A = 1 << 0,
242 OPT_b = 1 << 1,
243 OPT_c = 1 << 2,
244 OPT_C = 1 << 3,
245 OPT_f = 1 << 4,
246 OPT_F = 1 << 5,
247 OPT_h = 1 << 6,
248 OPT_I = 1 << 7,
249 OPT_i = 1 << 8,
250 OPT_l = 1 << 9,
251 OPT_m = 1 << 10,
252 OPT_n = 1 << 11,
253 OPT_r = 1 << 12,
254 OPT_R = 1 << 13,
255 OPT_s = 1 << 14,
256 OPT_S = 1 << 15,
257 OPT_v = 1 << 16,
258 };
259
260 opts = getopt32(argv, "^"
261 "Ab:cCf:F:h:Ii:l:m:n:r:R:s:S:v"
262 "\0" "-1",
263 NULL, NULL, NULL, NULL, NULL,
264 NULL, NULL, &arg_volume_label,
265 NULL, NULL, NULL, NULL);
266 argv += optind;
267
268
269 device_name = argv[0];
270
271 volume_id = time(NULL);
272
273 sprintf(volume_label11, "%-11.11s", arg_volume_label);
274
275 dev = xopen(device_name, O_RDWR);
276 xfstat(dev, &st, device_name);
277
278
279
280
281 bytes_per_sect = SECTOR_SIZE;
282 if (!S_ISBLK(st.st_mode)) {
283 if (!S_ISREG(st.st_mode)) {
284 if (!argv[1])
285 bb_simple_error_msg_and_die("image size must be specified");
286 }
287
288 opts &= ~OPT_c;
289 } else {
290 int min_bytes_per_sect;
291#if 0
292 unsigned device_num;
293
294 device_num = st.st_rdev & 0xff3f;
295
296 if (!(opts & OPT_I) && (
297 device_num == 0x0300 ||
298 (device_num & 0xff0f) == 0x0800 ||
299 device_num == 0x0d00 ||
300 device_num == 0x1600 )
301 )
302 bb_error_msg_and_die("will not try to make filesystem on full-disk device (use -I if wanted)");
303
304 if (find_mount_point(device_name, 0))
305 bb_error_msg_and_die("can't format mounted filesystem");
306#endif
307
308
309 xioctl(dev, BLKSSZGET, &min_bytes_per_sect);
310 if (min_bytes_per_sect > SECTOR_SIZE) {
311 bytes_per_sect = min_bytes_per_sect;
312 bb_error_msg("for this device sector size is %u", min_bytes_per_sect);
313 }
314 }
315 volume_size_bytes = get_volume_size_in_bytes(dev, argv[1], 1024, 1);
316 volume_size_sect = volume_size_bytes / bytes_per_sect;
317
318
319
320
321 media_byte = 0xf8;
322 heads = 255;
323 sect_per_track = 63;
324 sect_per_clust = 1;
325 {
326 struct hd_geometry geometry;
327
328 struct floppy_struct param;
329
330
331 if (ioctl(dev, HDIO_GETGEO, &geometry) == 0
332 && geometry.sectors
333 && geometry.heads
334 ) {
335
336 sect_per_track = geometry.sectors;
337 heads = geometry.heads;
338
339 set_cluster_size:
340
341
342
343
344
345
346
347 sect_per_clust = 1;
348 if (volume_size_bytes >= 260*1024*1024) {
349 sect_per_clust = 8;
350
351
352
353 if (sizeof(off_t) > 4) {
354 unsigned t = (volume_size_bytes >> 31 >> 1);
355 if (t >= 8/4)
356 sect_per_clust = 16;
357 if (t >= 16/4)
358 sect_per_clust = 32;
359 }
360 }
361 } else {
362
363 int not_floppy = ioctl(dev, FDGETPRM, ¶m);
364 if (not_floppy == 0) {
365
366 sect_per_track = param.sect;
367 heads = param.head;
368 volume_size_sect = param.size;
369 volume_size_bytes = param.size * SECTOR_SIZE;
370 }
371
372 switch (volume_size_sect) {
373 case 2*360:
374 media_byte = 0xfd;
375 break;
376 case 2*720:
377 case 2*1200:
378 media_byte = 0xf9;
379 break;
380 default:
381 if (not_floppy)
382 goto set_cluster_size;
383 case 2*1440:
384 case 2*2880:
385 media_byte = 0xf0;
386 break;
387 }
388
389
390
391
392 heads = 2;
393 sect_per_track = (unsigned)volume_size_sect / 160;
394 if (sect_per_track < 9)
395 sect_per_track = 9;
396 }
397 }
398
399
400
401
402
403
404
405 if ((off_t)(volume_size_sect - reserved_sect) < 4)
406 bb_simple_error_msg_and_die("the image is too small for FAT32");
407 sect_per_fat = 1;
408 while (1) {
409 while (1) {
410 int spf_adj;
411 uoff_t tcl = (volume_size_sect - reserved_sect - NUM_FATS * sect_per_fat) / sect_per_clust;
412
413
414
415
416
417 if (tcl > 0x80ffffff)
418 goto next;
419 total_clust = tcl;
420
421
422
423
424
425
426 spf_adj = ((total_clust+2) + (bytes_per_sect/4)-1) / (bytes_per_sect/4) - sect_per_fat;
427#if 0
428 bb_error_msg("sect_per_clust:%u sect_per_fat:%u total_clust:%u",
429 sect_per_clust, sect_per_fat, (int)tcl);
430 bb_error_msg("adjust to sect_per_fat:%d", spf_adj);
431#endif
432 if (spf_adj <= 0) {
433
434
435 if (total_clust <= MAX_CLUST_32)
436 goto found_total_clust;
437
438 goto next;
439 }
440
441
442 sect_per_fat += ((unsigned)spf_adj / 2) | 1;
443 }
444 next:
445 if (sect_per_clust == 128)
446 bb_simple_error_msg_and_die("can't make FAT32 with >128 sectors/cluster");
447 sect_per_clust *= 2;
448 sect_per_fat = (sect_per_fat / 2) | 1;
449 }
450 found_total_clust:
451
452
453
454
455 if (opts & OPT_v) {
456 fprintf(stderr,
457 "Device '%s':\n"
458 "heads:%u, sectors/track:%u, bytes/sector:%u\n"
459 "media descriptor:%02x\n"
460 "total sectors:%"OFF_FMT"u, clusters:%u, sectors/cluster:%u\n"
461 "FATs:2, sectors/FAT:%u\n"
462 "volumeID:%08x, label:'%s'\n",
463 device_name,
464 heads, sect_per_track, bytes_per_sect,
465 (int)media_byte,
466 volume_size_sect, (int)total_clust, (int)sect_per_clust,
467 sect_per_fat,
468 (int)volume_id, volume_label11
469 );
470 }
471
472
473
474
475 {
476
477 unsigned bufsize = reserved_sect;
478
479 bufsize |= 2;
480 bufsize |= sect_per_clust;
481 buf = xzalloc(bufsize * bytes_per_sect);
482 }
483
484 {
485 struct msdos_boot_sector *boot_blk = (void*)buf;
486 struct fat32_fsinfo *info = (void*)(buf + bytes_per_sect);
487
488 strcpy(boot_blk->boot_jump_and_sys_id, "\xeb\x58\x90" "mkdosfs");
489 STORE_LE(boot_blk->bytes_per_sect, bytes_per_sect);
490 STORE_LE(boot_blk->sect_per_clust, sect_per_clust);
491
492 STORE_LE(boot_blk->reserved_sect, (uint16_t)reserved_sect);
493 STORE_LE(boot_blk->fats, 2);
494
495 if (volume_size_sect <= 0xffff)
496 STORE_LE(boot_blk->volume_size_sect, volume_size_sect);
497 STORE_LE(boot_blk->media_byte, media_byte);
498
499
500
501
502
503 STORE_LE(boot_blk->sect_per_track, sect_per_track);
504 STORE_LE(boot_blk->heads, heads);
505
506 STORE_LE(boot_blk->fat32_volume_size_sect, volume_size_sect);
507 STORE_LE(boot_blk->fat32_sect_per_fat, sect_per_fat);
508
509
510 STORE_LE(boot_blk->fat32_root_cluster, 2);
511 STORE_LE(boot_blk->fat32_info_sector, info_sector_number);
512 STORE_LE(boot_blk->fat32_backup_boot, backup_boot_sector);
513
514 STORE_LE(boot_blk->vi.ext_boot_sign, 0x29);
515 STORE_LE(boot_blk->vi.volume_id32, volume_id);
516 memcpy(boot_blk->vi.fs_type, "FAT32 ", sizeof(boot_blk->vi.fs_type));
517 memcpy(boot_blk->vi.volume_label, volume_label11, 11);
518 memcpy(boot_blk->boot_code, boot_code, sizeof(boot_code));
519 STORE_LE(boot_blk->boot_sign, BOOT_SIGN);
520
521 STORE_LE(info->signature1, FAT_FSINFO_SIG1);
522 STORE_LE(info->signature2, FAT_FSINFO_SIG2);
523
524 STORE_LE(info->free_clusters, (total_clust - 1));
525 STORE_LE(info->next_cluster, 2);
526 STORE_LE(info->boot_sign, BOOT_SIGN);
527
528
529 xwrite(dev, buf, bytes_per_sect * backup_boot_sector);
530
531 xwrite(dev, buf, bytes_per_sect * (reserved_sect - backup_boot_sector));
532 }
533
534 {
535 unsigned i,j;
536 unsigned char *fat = (void*)buf;
537
538 memset(buf, 0, bytes_per_sect * 2);
539
540 MARK_CLUSTER(0, 0x0fffff00 | media_byte);
541 MARK_CLUSTER(1, 0xffffffff);
542
543 MARK_CLUSTER(2, EOF_FAT32);
544 for (i = 0; i < NUM_FATS; i++) {
545 xwrite(dev, buf, bytes_per_sect);
546 for (j = 1; j < sect_per_fat; j++)
547 xwrite(dev, buf + bytes_per_sect, bytes_per_sect);
548 }
549 }
550
551
552
553 memset(buf, 0, sect_per_clust * bytes_per_sect);
554
555
556
557 if (strcmp(volume_label11, NO_NAME_11) != 0) {
558
559 struct msdos_dir_entry *de;
560#if 0
561 struct tm tm_time;
562 uint16_t t, d;
563#endif
564 de = (void*)buf;
565 memcpy(de->name, volume_label11, 11);
566 STORE_LE(de->attr, ATTR_VOLUME);
567#if 0
568 localtime_r(&create_time, &tm_time);
569 t = (tm_time.tm_sec >> 1) + (tm_time.tm_min << 5) + (tm_time.tm_hour << 11);
570 d = tm_time.tm_mday + ((tm_time.tm_mon+1) << 5) + ((tm_time.tm_year-80) << 9);
571 STORE_LE(de->time, t);
572 STORE_LE(de->date, d);
573
574 de->ctime = de->time;
575 de->cdate = de->date;
576 de->adate = de->date;
577#endif
578 }
579 xwrite(dev, buf, sect_per_clust * bytes_per_sect);
580
581#if 0
582 if (opts & OPT_c) {
583 uoff_t volume_size_blocks;
584 unsigned start_data_sector;
585 unsigned start_data_block;
586 unsigned badblocks = 0;
587 int try, got;
588 off_t currently_testing;
589 char *blkbuf = xmalloc(BLOCK_SIZE * TEST_BUFFER_BLOCKS);
590
591 volume_size_blocks = (volume_size_bytes >> BLOCK_SIZE_BITS);
592
593 start_data_sector = (reserved_sect + NUM_FATS * sect_per_fat) * (bytes_per_sect / SECTOR_SIZE);
594 start_data_block = (start_data_sector + SECTORS_PER_BLOCK - 1) / SECTORS_PER_BLOCK;
595
596 bb_error_msg("searching for bad blocks");
597 currently_testing = 0;
598 try = TEST_BUFFER_BLOCKS;
599 while (currently_testing < volume_size_blocks) {
600 if (currently_testing + try > volume_size_blocks)
601 try = volume_size_blocks - currently_testing;
602
603
604
605 xlseek(dev, currently_testing * BLOCK_SIZE, SEEK_SET);
606
607 got = read(dev, blkbuf, try * BLOCK_SIZE);
608 if (got < 0)
609 got = 0;
610 if (got & (BLOCK_SIZE - 1))
611 bb_error_msg("unexpected values in do_check: probably bugs");
612 got /= BLOCK_SIZE;
613 currently_testing += got;
614 if (got == try) {
615 try = TEST_BUFFER_BLOCKS;
616 continue;
617 }
618 try = 1;
619 if (currently_testing < start_data_block)
620 bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
621
622
623 for (i = 0; i < SECTORS_PER_BLOCK; i++) {
624 int cluster = (currently_testing * SECTORS_PER_BLOCK + i - start_data_sector) / (int) (sect_per_clust) / (bytes_per_sect / SECTOR_SIZE);
625 if (cluster < 0)
626 bb_error_msg_and_die("invalid cluster number in mark_sector: probably bug!");
627 MARK_CLUSTER(cluster, BAD_FAT32);
628 }
629 badblocks++;
630 currently_testing++;
631 }
632 free(blkbuf);
633 if (badblocks)
634 bb_error_msg("%d bad block(s)", badblocks);
635 }
636#endif
637
638
639 if (ENABLE_FEATURE_CLEAN_UP) {
640 free(buf);
641 close(dev);
642 }
643
644 return 0;
645}
646