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