1 /******************************************************************************
3 *****************************************************************************/
18 # if defined (__GNUC__)
19 # include <sys/time.h>
26 static int align_structures = 1;
27 static int orphaned_sectors = 0;
30 static size_t image_size = 0;
32 static long total_sectors = 0;
34 static int heads_per_cylinder = 255;
35 static int sectors_per_track = 63;
37 static unsigned int backup_boot = 0;
38 static unsigned int cluster_count = 0;
39 static unsigned int hidden_sectors = 0;
40 static unsigned int info_sector = 0;
41 static unsigned int media_descriptor = 0xf8;
42 static unsigned int number_of_fats = 2;
43 static unsigned int reserved_sectors = 0;
44 static unsigned int root_cluster = 2;
45 static unsigned int root_entries = 512;
46 static unsigned int sectors_per_cluster = 4;
47 static unsigned int sectors_per_fat = 0;
49 struct mkfs_state *state = 0;
50 const char *program_name = 0;
52 static unsigned char dummy_boot_code[] =
54 "\x31\xC0" /* xor ax, ax */
56 "\x8E\xD0" /* mov ss, ax */
57 "\xBC\x00\x7C" /* mov sp, 0x7c00 */
59 "\x0E\x1F" /* push cs, pop ds */
60 "\xEB\x19" /* jmp XSTRING */
62 "\x5E" /* PRN: pop si */
64 "\xAC" /* XLOOP: lodsb */
65 "\x08\xC0" /* or al, al */
66 "\x74\x09" /* jz EOF */
67 "\xB4\x0E" /* mov ah, 0x0e */
68 "\xBB\x07\x00" /* mov bx, 7 */
69 "\xCD\x10" /* int 0x10 */
70 "\xEB\xF2" /* jmp short XLOOP */
72 "\x31\xC0" /* EOF: xor ax, ax */
73 "\xCD\x16" /* int 0x16 */
74 "\xCD\x19" /* int 0x19 */
75 "\xF4" /* HANG: hlt */
76 "\xEB\xFD" /* jmp short HANG */
78 "\xE8\xE4\xFF" /* XSTRING: call PRN */
80 "Non-System disk or disk read error\r\n"
81 "Replace and strike any key when ready\r\n";
83 static int cdiv (int a, int b) {
84 return (a + b - 1) / b;
87 static int seekto (long offset) {
88 return fseek (ofp, (state->offset * 512) + offset, SEEK_SET);
91 static int set_fat_entry (unsigned int cluster, unsigned int value) {
93 unsigned char *scratch;
94 unsigned int i, offset, sector;
96 if (!(scratch = (unsigned char *) malloc (512))) {
100 if (state->size_fat == 12) {
102 offset = cluster + (cluster / 2);
105 } else if (state->size_fat == 16) {
107 offset = cluster * 2;
110 } else if (state->size_fat == 32) {
112 offset = cluster * 4;
123 * At this point, offset is the BYTE offset of the desired sector from the start
124 * of the FAT. Calculate the physical sector containing this FAT entry.
126 sector = (offset / 512) + reserved_sectors;
128 if (seekto (sector * 512)) {
132 report_at (program_name, 0, REPORT_ERROR, "failed whilst seeking %s", state->outfile);
137 if (fread (scratch, 512, 1, ofp) != 1) {
141 report_at (program_name, 0, REPORT_ERROR, "failed whilst reading %s", state->outfile);
147 * At this point, we "merely" need to extract the relevant entry. This is
148 * easy for FAT16 and FAT32, but a royal PITA for FAT12 as a single entry
149 * may span a sector boundary. The normal way around this is always to
150 * read two FAT sectors, but luxary is (by design intent) unavailable.
154 if (state->size_fat == 12) {
158 if (((cluster * 3) & 0x01) == 0) {
159 scratch[offset] = (unsigned char) (value & 0xFF);
161 scratch[offset] = (unsigned char) ((scratch[offset] & 0x0F) | (value & 0xF0));
164 for (i = 0; i < number_of_fats; i++) {
166 long temp = sector + (i * sectors_per_fat);
168 if (seekto (temp * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
179 if (seekto (sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
186 if (((cluster * 3) & 0x01) == 0) {
187 scratch[0] = (unsigned char) ((scratch[0] & 0xF0) | (value & 0x0F));
189 scratch[0] = (unsigned char) (value & 0xFF00);
196 if (((cluster * 3) & 0x01) == 0) {
198 scratch[offset] = (unsigned char) (value & 0x00FF);
199 scratch[offset + 1] = (unsigned char) ((scratch[offset + 1] & 0x00F0) | ((value & 0x0F00) >> 8));
203 scratch[offset] = (unsigned char) ((scratch[offset] & 0x000F) | ((value & 0x000F) << 4));
204 scratch[offset + 1] = (unsigned char) ((value & 0x0FF0) >> 4);
212 } else if (state->size_fat == 16) {
214 scratch[offset] = (value & 0xFF);
215 scratch[offset + 1] = (value >> 8) & 0xFF;
219 } else if (state->size_fat == 32) {
221 scratch[offset] = (value & 0xFF);
222 scratch[offset + 1] = (value >> 8) & 0xFF;
223 scratch[offset + 2] = (value >> 16) & 0xFF;
224 scratch[offset + 3] = (scratch[offset + 3] & 0xF0) | ((value >> 24) & 0xFF);
235 for (i = 0; i < number_of_fats; i++) {
237 long temp = sector + (i * sectors_per_fat);
239 if (seekto (temp * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
253 static unsigned int align_object (unsigned int sectors, unsigned int clustsize) {
255 if (align_structures) {
256 return (sectors + clustsize - 1) & ~(clustsize - 1);
263 static unsigned int generate_volume_id (void) {
265 #if defined (__PDOS__)
269 /* rand() returns int from [0,RAND_MAX], therefor only 31-bits. */
270 return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF));
272 #elif defined (__GNUC__)
276 if (gettimeofday (&now, 0) != 0 || now.tv_sec == (time_t) -1 || now.tv_sec < 0) {
280 /*- rand() returns int from [0,RAND_MAX], therefor only 31-bits. */
281 return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF));
285 /* volume id = current time, fudged for more uniqueness. */
286 return ((unsigned int) now.tv_sec << 20) | (unsigned int) now.tv_usec;
288 #elif defined (__WATCOMC__)
292 /* rand() returns int from [0,RAND_MAX], therefor only 31-bits. */
293 return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF));
299 static void establish_bpb (void) {
301 unsigned int maxclustsize, root_dir_sectors;
303 unsigned int clust12, clust16, clust32;
304 unsigned int fatdata1216, fatdata32;
305 unsigned int fatlength12, fatlength16, fatlength32;
306 unsigned int maxclust12, maxclust16, maxclust32;
308 int cylinder_times_heads;
309 total_sectors = (image_size / 512) + orphaned_sectors;
311 if ((unsigned long) total_sectors > UINT_MAX) {
313 report_at (program_name, 0, REPORT_WARNING, "target too large, space at end will be left unused.\n");
314 total_sectors = UINT_MAX;
318 if (total_sectors > (long) 65535 * 16 * 63) {
320 heads_per_cylinder = 16;
321 sectors_per_track = 63;
323 cylinder_times_heads = total_sectors / sectors_per_track;
327 sectors_per_track = 17;
328 cylinder_times_heads = total_sectors / sectors_per_track;
330 heads_per_cylinder = (cylinder_times_heads + 1023) >> 10;
332 if (heads_per_cylinder < 4) {
333 heads_per_cylinder = 4;
336 if (cylinder_times_heads >= heads_per_cylinder << 10 || heads_per_cylinder > 16) {
338 sectors_per_track = 31;
339 heads_per_cylinder = 16;
341 cylinder_times_heads = total_sectors / sectors_per_track;
345 if (cylinder_times_heads >= heads_per_cylinder << 10) {
347 sectors_per_track = 63;
348 heads_per_cylinder = 16;
350 cylinder_times_heads = total_sectors / sectors_per_track;
356 switch (total_sectors) {
358 case 320: /* 160KB 5.25" */
360 sectors_per_cluster = 2;
362 media_descriptor = 0xfe;
363 sectors_per_track = 8;
364 heads_per_cylinder = 1;
367 case 360: /* 180KB 5.25" */
369 sectors_per_cluster = 2;
371 media_descriptor = 0xfc;
372 sectors_per_track = 9;
373 heads_per_cylinder = 1;
376 case 640: /* 320KB 5.25" */
378 sectors_per_cluster = 2;
380 media_descriptor = 0xff;
381 sectors_per_track = 8;
382 heads_per_cylinder = 2;
385 case 720: /* 360KB 5.25" */
387 sectors_per_cluster = 2;
389 media_descriptor = 0xfd;
390 sectors_per_track = 9;
391 heads_per_cylinder = 2;
394 case 1280: /* 640KB 5.25" / 3.5" */
396 sectors_per_cluster = 2;
398 media_descriptor = 0xfb;
399 sectors_per_track = 8;
400 heads_per_cylinder = 2;
403 case 1440: /* 720KB 5.25" / 3.5" */
405 sectors_per_cluster = 2;
407 media_descriptor = 0xf9;
408 sectors_per_track = 9;
409 heads_per_cylinder = 2;
412 case 1640: /* 820KB 3.5" */
414 sectors_per_cluster = 2;
416 media_descriptor = 0xf9;
417 sectors_per_track = 10;
418 heads_per_cylinder = 2;
421 case 2400: /* 1.20MB 5.25" / 3.5" */
423 sectors_per_cluster = 1;
425 media_descriptor = 0xf9;
426 sectors_per_track = 15;
427 heads_per_cylinder = 2;
430 case 2880: /* 1.44MB 3.5" */
432 sectors_per_cluster = 1;
434 media_descriptor = 0xf0;
435 sectors_per_track = 18;
436 heads_per_cylinder = 2;
439 case 3360: /* 1.68MB 3.5" */
441 sectors_per_cluster = 1;
443 media_descriptor = 0xf0;
444 sectors_per_track = 21;
445 heads_per_cylinder = 2;
448 case 3444: /* 1.72MB 3.5" */
450 sectors_per_cluster = 1;
452 media_descriptor = 0xf0;
453 sectors_per_track = 21;
454 heads_per_cylinder = 2;
457 case 5760: /* 2.88MB 3.5" */
459 sectors_per_cluster = 2;
461 media_descriptor = 0xf0;
462 sectors_per_track = 36;
463 heads_per_cylinder = 2;
468 if (!state->size_fat && image_size >= (long) 512 * 1024 * 1024) {
469 state->size_fat = 32;
472 if (state->size_fat == 32) {
477 * For FAT32, try to do the same as M$'s format command
478 * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20):
480 * fs size <= 260M: 0.5k clusters
481 * fs size <= 8G: 4k clusters
482 * fs size <= 16G: 8k clusters
483 * fs size <= 32G: 16k clusters
484 * fs size > 32G: 32k clusters
486 sectors_per_cluster = (total_sectors > 32 * 1024 * 1024 * 2 ? 64 :
487 total_sectors > 16 * 1024 * 1024 * 2 ? 32 :
488 total_sectors > 8 * 1024 * 1024 * 2 ? 16 :
489 total_sectors > 260 * 1024 * 2 ? 8 : 1);
493 if (state->sectors_per_cluster) {
494 sectors_per_cluster = state->sectors_per_cluster;
497 hidden_sectors = state->offset;
499 if (!reserved_sectors) {
500 reserved_sectors = (state->size_fat == 32 ? 32 : 1);
503 /*if (align_structures) {*/
505 /** Align number of sectors to be multiple of sectors per track, needed by DOS and mtools. */
506 /*total_sectors = total_sectors / sectors_per_track * sectors_per_track;*/
510 if (total_sectors <= 8192) {
512 if (align_structures && state->verbose) {
513 report_at (program_name, 0, REPORT_WARNING, "Disabling alignment due to tiny filsystem\n");
516 align_structures = 0;
521 root_dir_sectors = cdiv (root_entries * 32, 512);
525 fatdata32 = total_sectors - align_object (reserved_sectors, sectors_per_cluster);
526 fatdata1216 = fatdata32 - align_object (root_dir_sectors, sectors_per_cluster);
528 if (state->verbose) {
529 fprintf (stderr, "Trying with %d sectors/cluster:\n", sectors_per_cluster);
533 * The factor 2 below avoids cut-off errors for number_of_fats == 1.
534 * The "number_of_fats * 3" is for the reserved first two FAT entries.
536 clust12 = 2 * ((long) fatdata1216 * 512 + number_of_fats * 3) / (2 * (int) sectors_per_cluster * 512 + number_of_fats * 3);
537 fatlength12 = cdiv (((clust12 + 2) * 3 + 1) >> 1, 512);
538 fatlength12 = align_object (fatlength12, sectors_per_cluster);
541 * Need to recalculate number of clusters, since the unused parts of the
542 * FATs and data area together could make up space for an additional,
543 * not really present cluster.
545 clust12 = (fatdata1216 - number_of_fats * fatlength12) / sectors_per_cluster;
546 maxclust12 = (fatlength12 * 2 * 512) / 3;
548 if (maxclust12 > MAX_CLUST_12) {
549 maxclust12 = MAX_CLUST_12;
552 if (state->verbose && (state->size_fat == 0 || state->size_fat == 12)) {
553 fprintf (stderr, "Trying FAT12: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n", clust12, fatlength12, maxclust12, MAX_CLUST_12);
556 if (clust12 > maxclust12) {
560 if (state->verbose && (state->size_fat == 0 || state->size_fat == 12)) {
561 fprintf (stderr, "Trying FAT12: too many clusters\n");
566 clust16 = ((long) fatdata1216 * 512 + number_of_fats * 4) / ((int) sectors_per_cluster * 512 + number_of_fats * 2);
567 fatlength16 = cdiv ((clust16 + 2) * 2, 512);
568 fatlength16 = align_object (fatlength16, sectors_per_cluster);
571 * Need to recalculate number of clusters, since the unused parts of the
572 * FATs and data area together could make up space for an additional,
573 * not really present cluster.
575 clust16 = (fatdata1216 - number_of_fats * fatlength16) / sectors_per_cluster;
576 maxclust16 = (fatlength16 * 512) / 2;
578 if (maxclust16 > MAX_CLUST_16) {
579 maxclust16 = MAX_CLUST_16;
582 if (state->verbose && (state->size_fat == 0 || state->size_fat == 16)) {
583 fprintf (stderr, "Trying FAT16: #clu=%u, fatlen=%u, maxclu=%u, limit=%u/%u\n", clust16, fatlength16, maxclust16, MIN_CLUST_16, MAX_CLUST_16);
586 if (clust16 > maxclust16) {
590 if (state->verbose && (state->size_fat == 0 || state->size_fat == 16)) {
591 fprintf (stderr, "Trying FAT16: too many clusters\n");
596 /** This avoids that the filesystem will be misdetected as having a 12-bit FAT. */
597 if (clust16 && clust16 < MIN_CLUST_16) {
601 if (state->verbose && (state->size_fat == 0 || state->size_fat == 16)) {
602 fprintf (stderr, "Trying FAT16: not enough clusters, would be misdected as FAT12\n");
607 clust32 = ((long) fatdata32 * 512 + number_of_fats * 8) / ((int) sectors_per_cluster * 512 + number_of_fats * 4);
608 fatlength32 = cdiv ((clust32 + 2) * 4, 512);
609 fatlength32 = align_object (fatlength32, sectors_per_cluster);
612 * Need to recalculate number of clusters, since the unused parts of the
613 * FATs and data area together could make up space for an additional,
614 * not really present cluster.
616 clust32 = (fatdata32 - number_of_fats * fatlength32) / sectors_per_cluster;
617 maxclust32 = (fatlength32 * 512) / 4;
619 if (maxclust32 > MAX_CLUST_32) {
620 maxclust32 = MAX_CLUST_32;
623 if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
624 fprintf (stderr, "Trying FAT32: #clu=%u, fatlen=%u, maxclu=%u, limit=%u/%u\n", clust32, fatlength32, maxclust32, MIN_CLUST_32, MAX_CLUST_32);
627 if (clust32 > maxclust32) {
631 if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
632 fprintf (stderr, "Trying FAT32: too many clusters\n");
637 if (clust32 && clust32 < MIN_CLUST_32 && !(state->size_fat_by_user && state->size_fat == 32)) {
641 if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
642 fprintf (stderr, "Trying FAT32: not enough clusters\n");
647 if ((clust12 && (state->size_fat == 0 || state->size_fat == 12)) || (clust16 && (state->size_fat == 0 || state->size_fat == 16)) || (clust32 && state->size_fat == 32)) {
651 sectors_per_cluster <<= 1;
653 } while (sectors_per_cluster && sectors_per_cluster <= maxclustsize);
655 /** Use the optimal FAT size if not specified. */
656 if (!state->size_fat) {
658 state->size_fat = (clust16 > clust12 ? 16 : 12);
660 if (state->verbose) {
661 report_at (program_name, 0, REPORT_WARNING, "Choosing %d-bits for FAT\n", state->size_fat);
666 switch (state->size_fat) {
670 cluster_count = clust12;
671 sectors_per_fat = fatlength12;
676 cluster_count = clust16;
677 sectors_per_fat = fatlength16;
682 cluster_count = clust32;
683 sectors_per_fat = fatlength32;
688 report_at (program_name, 0, REPORT_ERROR, "FAT not 12, 16 or 32 bits");
691 remove (state->outfile);
697 /** Adjust the reserved number of sectors for alignment. */
698 reserved_sectors = align_object (reserved_sectors, sectors_per_cluster);
700 /** Adjust the number of root directory entries to help enforce alignment. */
701 if (align_structures) {
702 root_entries = align_object (root_dir_sectors, sectors_per_cluster) * (512 >> 5);
705 if (state->size_fat == 32) {
713 if (reserved_sectors >= 7 && info_sector != 6) {
715 } else if (reserved_sectors > 3 + info_sector && info_sector != reserved_sectors - 2 && info_sector != reserved_sectors - 1) {
716 backup_boot = reserved_sectors - 2;
717 } else if (reserved_sectors >= 3 && info_sector != reserved_sectors - 1) {
718 backup_boot = reserved_sectors - 1;
725 if (backup_boot == info_sector) {
727 report_at (program_name, 0, REPORT_ERROR, "Backup boot sector must not be the same as the info sector (%d)", info_sector);
730 remove (state->outfile);
734 } else if (backup_boot >= reserved_sectors) {
736 report_at (program_name, 0, REPORT_ERROR, "Backup boot sector must be a reserved sector");
739 remove (state->outfile);
747 if (state->verbose) {
748 fprintf (stderr, "Using sector %d as backup boot sector (0 = none)\n", backup_boot);
753 if (!cluster_count) {
755 report_at (program_name, 0, REPORT_ERROR, "Not enough clusters to make a viable filesystem");
758 remove (state->outfile);
766 static void add_volume_label (void) {
768 struct msdos_dirent *de;
769 unsigned short date, time;
771 unsigned char *scratch;
774 if (!(scratch = (unsigned char *) malloc (512))) {
776 report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
779 remove (state->outfile);
785 if (state->size_fat == 32) {
787 long temp = reserved_sectors + (sectors_per_fat * 2);
788 offset += temp + ((root_cluster - 2) * sectors_per_cluster);
791 offset += reserved_sectors + (sectors_per_fat * 2);
794 if (seekto (offset * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
796 report_at (program_name, 0, REPORT_ERROR, "Failed whilst reading root directory");
800 remove (state->outfile);
806 de = (struct msdos_dirent *) scratch;
807 memset (de, 0, sizeof (*de));
809 date = generate_datestamp ();
810 time = generate_timestamp ();
812 memcpy (de->name, state->label, 11);
813 de->attr = ATTR_VOLUME_ID;
815 write721_to_byte_array (de->ctime, time);
816 write721_to_byte_array (de->cdate, date);
817 write721_to_byte_array (de->adate, date);
818 write721_to_byte_array (de->time, time);
819 write721_to_byte_array (de->date, date);
821 if (seekto (offset * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
823 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing root directory");
827 remove (state->outfile);
837 static void wipe_target (void) {
839 unsigned int i, sectors_to_wipe = 0;
842 if (!(blank = malloc (512))) {
844 report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
847 remove (state->outfile);
853 memset (blank, 0, 512);
855 sectors_to_wipe += reserved_sectors;
856 sectors_to_wipe += sectors_per_fat * 2;
859 sectors_to_wipe += (root_entries * 32) / 512;
861 sectors_to_wipe += 1;
866 for (i = 0; i < sectors_to_wipe; i++) {
868 if (fwrite (blank, 512, 1, ofp) != 1) {
870 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing blank sector");
874 remove (state->outfile);
886 static void write_reserved (void) {
888 struct msdos_boot_sector bs;
889 struct msdos_volume_info *vi = (state->size_fat == 32 ? &bs.fstype._fat32.vi : &bs.fstype._oldfat.vi);
891 memset (&bs, 0, sizeof (bs));
897 if ((ifp = fopen (state->boot, "rb")) == NULL) {
899 report_at (program_name, 0, REPORT_ERROR, "unable to open %s", state->boot);
902 remove (state->outfile);
908 fseek (ifp, 0, SEEK_END);
910 if (ftell (ifp) != sizeof (bs)) {
912 report_at (program_name, 0, REPORT_ERROR, "boot sector must be %lu bytes in size", (unsigned long) sizeof (bs));
916 remove (state->outfile);
922 fseek (ifp, 0, SEEK_SET);
924 if (fread (&bs, sizeof (bs), 1, ifp) != 1) {
926 report_at (program_name, 0, REPORT_ERROR, "failed to read %s", state->boot);
930 remove (state->outfile);
940 bs.boot_jump[0] = 0xEB;
941 bs.boot_jump[1] = ((state->size_fat == 32 ? (char *) &bs.fstype._fat32.boot_code : (char *) &bs.fstype._oldfat.boot_code) - (char *) &bs) - 2;
942 bs.boot_jump[2] = 0x90;
944 if (state->size_fat == 32) {
945 memcpy (bs.fstype._fat32.boot_code, dummy_boot_code, sizeof (dummy_boot_code));
947 memcpy (bs.fstype._oldfat.boot_code, dummy_boot_code, sizeof (dummy_boot_code));
950 bs.boot_sign[0] = 0x55;
951 bs.boot_sign[1] = 0xAA;
955 if (bs.boot_jump[0] != 0xEB || bs.boot_jump[1] < 0x16 || bs.boot_jump[2] != 0x90) {
956 goto _write_reserved;
959 memcpy (bs.system_id, "MSWIN4.1", 8);
961 bs.sectors_per_cluster = sectors_per_cluster;
962 bs.no_fats = number_of_fats;
963 bs.media_descriptor = media_descriptor;
965 write721_to_byte_array (bs.bytes_per_sector, 512);
966 write721_to_byte_array (bs.reserved_sectors, reserved_sectors);
967 write721_to_byte_array (bs.root_entries, root_entries);
968 write721_to_byte_array (bs.total_sectors16, total_sectors);
969 write721_to_byte_array (bs.sectors_per_fat16, sectors_per_fat);
971 if (bs.boot_jump[1] < 0x22) {
972 goto _write_reserved;
975 write721_to_byte_array (bs.sectors_per_track, sectors_per_track);
976 write721_to_byte_array (bs.heads_per_cylinder, heads_per_cylinder);
977 write741_to_byte_array (bs.hidden_sectors, hidden_sectors);
979 if (total_sectors > USHRT_MAX) {
981 write721_to_byte_array (bs.total_sectors16, 0);
982 write741_to_byte_array (bs.total_sectors32, total_sectors);
986 if (state->size_fat == 32) {
988 if (bs.boot_jump[1] < 0x58) {
989 goto _write_reserved;
992 write721_to_byte_array (bs.sectors_per_fat16, 0);
993 write741_to_byte_array (bs.fstype._fat32.sectors_per_fat32, sectors_per_fat);
995 write741_to_byte_array (bs.fstype._fat32.root_cluster, root_cluster);
996 write721_to_byte_array (bs.fstype._fat32.info_sector, info_sector);
997 write721_to_byte_array (bs.fstype._fat32.backup_boot, backup_boot);
999 vi->drive_no = (media_descriptor == 0xF8 ? 0x80 : 0x00);
1000 vi->ext_boot_sign = 0x29;
1002 write741_to_byte_array (vi->volume_id, generate_volume_id ());
1003 memcpy (vi->volume_label, state->label, 11);
1004 memcpy (vi->fs_type, "FAT32 ", 8);
1008 if (bs.boot_jump[1] < 0x3C) {
1009 goto _write_reserved;
1012 vi->drive_no = (media_descriptor == 0xF8 ? 0x80 : 0x00);
1013 vi->ext_boot_sign = 0x29;
1015 write741_to_byte_array (vi->volume_id, generate_volume_id ());
1016 memcpy (vi->volume_label, state->label, 11);
1018 if (state->size_fat == 12) {
1019 memcpy (vi->fs_type, "FAT12 ", 8);
1021 memcpy (vi->fs_type, "FAT16 ", 8);
1030 if (fwrite (&bs, sizeof (bs), 1, ofp) != 1) {
1032 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing %s", state->outfile);
1035 remove (state->outfile);
1037 exit (EXIT_FAILURE);
1041 if (state->size_fat == 32) {
1045 struct fat32_fsinfo *info;
1046 unsigned char *buffer;
1048 if (seekto (info_sector * 512)) {
1050 report_at (program_name, 0, REPORT_ERROR, "Failed whilst seeking %s", state->outfile);
1053 remove (state->outfile);
1055 exit (EXIT_FAILURE);
1059 if (!(buffer = (unsigned char *) malloc (512))) {
1061 report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
1064 remove (state->outfile);
1066 exit (EXIT_FAILURE);
1070 memset (buffer, 0, 512);
1072 /** fsinfo structure is at offset 0x1e0 in info sector by observation. */
1073 info = (struct fat32_fsinfo *) (buffer + 0x1e0);
1075 /** Info sector magic. */
1081 /** Magic for fsinfo structure. */
1082 write741_to_byte_array (info->signature, 0x61417272);
1084 /** We've allocated cluster 2 for the root directory. */
1085 write741_to_byte_array (info->free_clusters, cluster_count - 1);
1086 write741_to_byte_array (info->next_cluster, 2);
1088 /** Info sector also must have boot sign. */
1089 write721_to_byte_array (buffer + 0x1fe, 0xAA55);
1091 if (fwrite (buffer, 512, 1, ofp) != 1) {
1093 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing info sector");
1097 remove (state->outfile);
1099 exit (EXIT_FAILURE);
1109 if (seekto (backup_boot * 512) || fwrite (&bs, sizeof (bs), 1, ofp) != 1) {
1111 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing info sector");
1114 remove (state->outfile);
1116 exit (EXIT_FAILURE);
1126 int main (int argc, char **argv) {
1128 if (argc && *argv) {
1131 program_name = *argv;
1133 if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {
1134 program_name = (p + 1);
1139 state = xmalloc (sizeof (*state));
1140 parse_args (&argc, &argv, 1);
1142 if (!state->outfile) {
1144 report_at (program_name, 0, REPORT_ERROR, "no outfile file provided");
1145 return EXIT_FAILURE;
1149 image_size = state->blocks * 1024;
1150 image_size += state->offset * 512;
1152 if ((ofp = fopen (state->outfile, "r+b")) == NULL) {
1157 if ((ofp = fopen (state->outfile, "w+b")) == NULL) {
1159 report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", state->outfile);
1160 return EXIT_FAILURE;
1165 zero = xmalloc (512);
1169 if (fwrite (zero, 512, 1, ofp) != 1) {
1171 report_at (program_name, 0, REPORT_ERROR, "failed whilst writing '%s'", state->outfile);
1175 remove (state->outfile);
1177 return EXIT_FAILURE;
1189 if (image_size == 0) {
1191 fseek (ofp, 0, SEEK_END);
1192 image_size = ftell (ofp);
1198 if (state->offset * 512 > image_size) {
1200 report_at (program_name, 0, REPORT_ERROR, "size (%lu) of %s is less than the requested offset (%lu)", image_size, state->outfile, state->offset * 512);
1203 remove (state->outfile);
1205 return EXIT_FAILURE;
1209 image_size -= state->offset * 512;
1211 if (state->blocks) {
1213 if (state->blocks * 1024 > image_size) {
1215 report_at (program_name, 0, REPORT_ERROR, "size (%lu) of %s is less than the requested size (%lu)", image_size, state->outfile, state->blocks * 1024);
1218 remove (state->outfile);
1220 return EXIT_FAILURE;
1224 image_size = state->blocks * 1024;
1228 orphaned_sectors = (image_size % 1024) / 512;
1235 if (set_fat_entry (0, 0xFFFFFF00 | media_descriptor) < 0 || set_fat_entry (1, 0xFFFFFFFF) < 0) {
1237 report_at (program_name, 0, REPORT_ERROR, "Failed whilst setting FAT entry");
1240 remove (state->outfile);
1242 return EXIT_FAILURE;
1246 if (state->size_fat == 32) {
1248 if (set_fat_entry (2, 0x0FFFFFF8) < 0) {
1250 report_at (program_name, 0, REPORT_ERROR, "Failed whilst setting FAT entry");
1253 remove (state->outfile);
1255 return EXIT_FAILURE;
1261 if (memcmp (state->label, "NO NAME ", 11) != 0) {
1262 add_volume_label ();
1266 return EXIT_SUCCESS;