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