1 /******************************************************************************
3 *****************************************************************************/
17 # if defined (__GNUC__)
18 # include <sys/time.h>
25 static int align_structures = 1;
27 static unsigned long image_size = 0;
30 static long total_sectors = 0;
32 static int heads_per_cylinder = 255;
33 static int sectors_per_track = 63;
35 static unsigned int backup_boot = 0;
36 static unsigned int cluster_count = 0;
37 static unsigned int hidden_sectors = 0;
38 static unsigned int info_sector = 0;
39 static unsigned int media_descriptor = 0xf8;
40 static unsigned int number_of_fats = 2;
41 static unsigned int reserved_sectors = 0;
42 static unsigned int root_cluster = 2;
43 static unsigned int root_entries = 512;
44 static unsigned int sectors_per_cluster = 4;
45 static unsigned int sectors_per_fat = 0;
47 struct mkfs_state *state = 0;
48 const char *program_name = 0;
50 static unsigned char dummy_boot_code[] =
52 "\x31\xC0" /* xor ax, ax */
54 "\x8E\xD0" /* mov ss, ax */
55 "\xBC\x00\x7C" /* mov sp, 0x7c00 */
57 "\x0E\x1F" /* push cs, pop ds */
58 "\xEB\x19" /* jmp XSTRING */
60 "\x5E" /* PRN: pop si */
62 "\xAC" /* XLOOP: lodsb */
63 "\x08\xC0" /* or al, al */
64 "\x74\x09" /* jz EOF */
65 "\xB4\x0E" /* mov ah, 0x0e */
66 "\xBB\x07\x00" /* mov bx, 7 */
67 "\xCD\x10" /* int 0x10 */
68 "\xEB\xF2" /* jmp short XLOOP */
70 "\x31\xC0" /* EOF: xor ax, ax */
71 "\xCD\x16" /* int 0x16 */
72 "\xCD\x19" /* int 0x19 */
73 "\xF4" /* HANG: hlt */
74 "\xEB\xFD" /* jmp short HANG */
76 "\xE8\xE4\xFF" /* XSTRING: call PRN */
78 "Non-System disk or disk read error\r\n"
79 "Replace and strike any key when ready\r\n";
81 static int cdiv (int a, int b) {
82 return (a + b - 1) / b;
85 static int seekto (long offset) {
86 return fseek (ofp, (state->offset * 512) + offset, SEEK_SET);
89 static int set_fat_entry (unsigned int cluster, unsigned int value) {
91 unsigned char *scratch;
92 unsigned int i, offset, sector;
94 if (!(scratch = (unsigned char *) malloc (512))) {
98 if (state->size_fat == 12) {
100 offset = cluster + (cluster / 2);
103 } else if (state->size_fat == 16) {
105 offset = cluster * 2;
108 } else if (state->size_fat == 32) {
110 offset = cluster * 4;
121 * At this point, offset is the BYTE offset of the desired sector from the start
122 * of the FAT. Calculate the physical sector containing this FAT entry.
124 sector = (offset / 512) + reserved_sectors;
126 if (seekto (sector * 512)) {
130 report_at (program_name, 0, REPORT_ERROR, "failed whilst seeking %s", state->outfile);
135 if (fread (scratch, 512, 1, ofp) != 1) {
139 report_at (program_name, 0, REPORT_ERROR, "failed whilst reading %s", state->outfile);
145 * At this point, we "merely" need to extract the relevant entry. This is
146 * easy for FAT16 and FAT32, but a royal PITA for FAT12 as a single entry
147 * may span a sector boundary. The normal way around this is always to
148 * read two FAT sectors, but luxary is (by design intent) unavailable.
152 if (state->size_fat == 12) {
156 if (((cluster * 3) & 0x01) == 0) {
157 scratch[offset] = (unsigned char) (value & 0xFF);
159 scratch[offset] = (unsigned char) ((scratch[offset] & 0x0F) | (value & 0xF0));
162 for (i = 0; i < number_of_fats; i++) {
164 long temp = sector + (i * sectors_per_fat);
166 if (seekto (temp * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
177 if (seekto (sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
184 if (((cluster * 3) & 0x01) == 0) {
185 scratch[0] = (unsigned char) ((scratch[0] & 0xF0) | (value & 0x0F));
187 scratch[0] = (unsigned char) (value & 0xFF00);
194 if (((cluster * 3) & 0x01) == 0) {
196 scratch[offset] = (unsigned char) (value & 0x00FF);
197 scratch[offset + 1] = (unsigned char) ((scratch[offset + 1] & 0x00F0) | ((value & 0x0F00) >> 8));
201 scratch[offset] = (unsigned char) ((scratch[offset] & 0x000F) | ((value & 0x000F) << 4));
202 scratch[offset + 1] = (unsigned char) ((value & 0x0FF0) >> 4);
210 } else if (state->size_fat == 16) {
212 scratch[offset] = (value & 0xFF);
213 scratch[offset + 1] = (value >> 8) & 0xFF;
217 } else if (state->size_fat == 32) {
219 scratch[offset] = (value & 0xFF);
220 scratch[offset + 1] = (value >> 8) & 0xFF;
221 scratch[offset + 2] = (value >> 16) & 0xFF;
222 scratch[offset + 3] = (scratch[offset + 3] & 0xF0) | ((value >> 24) & 0xFF);
233 for (i = 0; i < number_of_fats; i++) {
235 long temp = sector + (i * sectors_per_fat);
237 if (seekto (temp * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
251 static unsigned int align_object (unsigned int sectors, unsigned int clustsize) {
253 if (align_structures) {
254 return (sectors + clustsize - 1) & ~(clustsize - 1);
261 static unsigned int generate_volume_id (void) {
263 #if defined (__PDOS__)
267 /* rand() returns int from [0,RAND_MAX], therefor only 31-bits. */
268 return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF));
270 #elif defined (__GNUC__)
274 if (gettimeofday (&now, 0) != 0 || now.tv_sec == (time_t) -1 || now.tv_sec < 0) {
278 /*- rand() returns int from [0,RAND_MAX], therefor only 31-bits. */
279 return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF));
283 /* volume id = current time, fudged for more uniqueness. */
284 return ((unsigned int) now.tv_sec << 20) | (unsigned int) now.tv_usec;
286 #elif defined (__WATCOMC__)
290 /* rand() returns int from [0,RAND_MAX], therefor only 31-bits. */
291 return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF));
297 static void establish_bpb (void) {
299 unsigned int maxclustsize, root_dir_sectors;
301 unsigned int clust12, clust16, clust32;
302 unsigned int fatdata1216, fatdata32;
303 unsigned int fatlength12, fatlength16, fatlength32;
304 unsigned int maxclust12, maxclust16, maxclust32;
306 long cylinder_times_heads;
307 long sectors_per_cylinder;
309 if ((unsigned long) total_sectors > UINT_MAX) {
311 report_at (program_name, 0, REPORT_WARNING, "target too large, space at end will be left unused.\n");
312 total_sectors = UINT_MAX;
316 if (total_sectors > (long) 65535 * 16 * 63) {
318 sectors_per_track = 63;
319 heads_per_cylinder = 255;
321 cylinder_times_heads = total_sectors / sectors_per_track;
325 sectors_per_track = 17;
326 cylinder_times_heads = total_sectors / sectors_per_track;
328 heads_per_cylinder = (cylinder_times_heads + 1023) >> 10;
330 if (heads_per_cylinder < 4) {
331 heads_per_cylinder = 4;
334 if (cylinder_times_heads >= heads_per_cylinder << 10 || heads_per_cylinder > 16) {
336 sectors_per_track = 31;
337 heads_per_cylinder = 16;
339 cylinder_times_heads = total_sectors / sectors_per_track;
343 if (cylinder_times_heads >= heads_per_cylinder << 10) {
345 sectors_per_track = 63;
346 heads_per_cylinder = 16;
348 cylinder_times_heads = total_sectors / sectors_per_track;
354 sectors_per_cylinder = heads_per_cylinder * sectors_per_track;
356 hidden_sectors = state->offset;
357 total_sectors = state->sectors;
359 if (state->chs_align && hidden_sectors % sectors_per_track) {
361 hidden_sectors = ((hidden_sectors / sectors_per_track) + 1) * sectors_per_track;
362 report_at (program_name, 0, REPORT_WARNING, "hidden sectors changed from %lu to %lu", state->offset, hidden_sectors);
366 if (state->chs_align) {
370 if (total_sectors % sectors_per_cylinder) {
371 total_sectors = ((total_sectors / sectors_per_cylinder) + 1) * sectors_per_cylinder;
374 if ((unsigned long) (hidden_sectors + total_sectors) > state->offset + state->sectors) {
376 adjustment = (hidden_sectors + total_sectors) - (state->offset + state->sectors);
377 total_sectors -= adjustment;
381 if ((adjustment = (hidden_sectors + total_sectors) % sectors_per_cylinder)) {
382 total_sectors -= adjustment;
385 if ((unsigned long) total_sectors != state->sectors) {
386 report_at (program_name, 0, REPORT_WARNING, "total sectors changed from %lu to %lu", state->sectors, total_sectors);
391 state->offset = hidden_sectors;
392 state->sectors = total_sectors;
394 switch (total_sectors) {
396 case 320: /* 160KB 5.25" */
398 sectors_per_cluster = 2;
400 sectors_per_track = 8;
401 heads_per_cylinder = 1;
403 media_descriptor = 0xFE;
406 case 360: /* 180KB 5.25" */
408 sectors_per_cluster = 2;
410 sectors_per_track = 9;
411 heads_per_cylinder = 1;
413 media_descriptor = 0xFC;
416 case 640: /* 320KB 5.25" */
418 sectors_per_cluster = 2;
420 sectors_per_track = 8;
421 heads_per_cylinder = 2;
423 media_descriptor = 0xFF;
426 case 720: /* 360KB 5.25" */
428 sectors_per_cluster = 2;
430 sectors_per_track = 9;
431 heads_per_cylinder = 2;
433 media_descriptor = 0xFD;
436 case 1280: /* 640KB 5.25" / 3.5" */
438 sectors_per_cluster = 2;
440 sectors_per_track = 8;
441 heads_per_cylinder = 2;
443 media_descriptor = 0xFB;
446 case 1440: /* 720KB 5.25" / 3.5" */
448 sectors_per_cluster = 2;
450 sectors_per_track = 9;
451 heads_per_cylinder = 2;
453 media_descriptor = 0xF9;
456 case 1640: /* 820KB 3.5" */
458 sectors_per_cluster = 2;
460 sectors_per_track = 10;
461 heads_per_cylinder = 2;
463 media_descriptor = 0xF9;
466 case 2400: /* 1.20MB 5.25" / 3.5" */
468 sectors_per_cluster = 1;
470 sectors_per_track = 15;
471 heads_per_cylinder = 2;
473 media_descriptor = 0xF9;
476 case 2880: /* 1.44MB 3.5" */
478 sectors_per_cluster = 1;
480 sectors_per_track = 18;
481 heads_per_cylinder = 2;
483 media_descriptor = 0xF0;
486 case 3360: /* 1.68MB 3.5" */
488 sectors_per_cluster = 1;
490 sectors_per_track = 21;
491 heads_per_cylinder = 2;
493 media_descriptor = 0xF0;
496 case 3444: /* 1.72MB 3.5" */
498 sectors_per_cluster = 1;
500 sectors_per_track = 21;
501 heads_per_cylinder = 2;
503 media_descriptor = 0xF0;
506 case 5760: /* 2.88MB 3.5" */
508 sectors_per_cluster = 2;
510 sectors_per_track = 36;
511 heads_per_cylinder = 2;
513 media_descriptor = 0xF0;
518 if (!state->size_fat && total_sectors >= 1048576) {
519 state->size_fat = 32;
522 if (state->size_fat == 32) {
527 * For FAT32, try to do the same as M$'s format command
528 * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20):
530 * fs size <= 260M: 0.5k clusters
531 * fs size <= 8G: 4k clusters
532 * fs size <= 16G: 8k clusters
533 * fs size <= 32G: 16k clusters
534 * fs size > 32G: 32k clusters
536 sectors_per_cluster = (total_sectors > 32 * 1024 * 1024 * 2 ? 64 :
537 total_sectors > 16 * 1024 * 1024 * 2 ? 32 :
538 total_sectors > 8 * 1024 * 1024 * 2 ? 16 :
539 total_sectors > 260 * 1024 * 2 ? 8 : 1);
543 if (state->sectors_per_cluster) {
544 sectors_per_cluster = state->sectors_per_cluster;
547 if (!reserved_sectors) {
548 reserved_sectors = (state->size_fat == 32 ? 32 : 1);
551 /*if (align_structures) {*/
553 /** Align number of sectors to be multiple of sectors per track, needed by DOS and mtools. */
554 /*total_sectors = total_sectors / sectors_per_track * sectors_per_track;*/
558 if (total_sectors <= 8192) {
560 if (align_structures && state->verbose) {
561 report_at (program_name, 0, REPORT_WARNING, "Disabling alignment due to tiny filsystem\n");
564 align_structures = 0;
569 root_dir_sectors = cdiv (root_entries * 32, 512);
573 fatdata32 = total_sectors - align_object (reserved_sectors, sectors_per_cluster);
574 fatdata1216 = fatdata32 - align_object (root_dir_sectors, sectors_per_cluster);
576 if (state->verbose) {
577 fprintf (stderr, "Trying with %d sectors/cluster:\n", sectors_per_cluster);
581 * The factor 2 below avoids cut-off errors for number_of_fats == 1.
582 * The "number_of_fats * 3" is for the reserved first two FAT entries.
584 clust12 = 2 * ((long) fatdata1216 * 512 + number_of_fats * 3) / (2 * (int) sectors_per_cluster * 512 + number_of_fats * 3);
585 fatlength12 = cdiv (((clust12 + 2) * 3 + 1) >> 1, 512);
586 fatlength12 = align_object (fatlength12, sectors_per_cluster);
589 * Need to recalculate number of clusters, since the unused parts of the
590 * FATs and data area together could make up space for an additional,
591 * not really present cluster.
593 clust12 = (fatdata1216 - number_of_fats * fatlength12) / sectors_per_cluster;
594 maxclust12 = (fatlength12 * 2 * 512) / 3;
596 if (maxclust12 > MAX_CLUST_12) {
597 maxclust12 = MAX_CLUST_12;
600 if (state->verbose && (state->size_fat == 0 || state->size_fat == 12)) {
601 fprintf (stderr, "Trying FAT12: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n", clust12, fatlength12, maxclust12, MAX_CLUST_12);
604 if (clust12 > maxclust12) {
608 if (state->verbose && (state->size_fat == 0 || state->size_fat == 12)) {
609 fprintf (stderr, "Trying FAT12: too many clusters\n");
614 clust16 = ((long) fatdata1216 * 512 + number_of_fats * 4) / ((int) sectors_per_cluster * 512 + number_of_fats * 2);
615 fatlength16 = cdiv ((clust16 + 2) * 2, 512);
616 fatlength16 = align_object (fatlength16, sectors_per_cluster);
619 * Need to recalculate number of clusters, since the unused parts of the
620 * FATs and data area together could make up space for an additional,
621 * not really present cluster.
623 clust16 = (fatdata1216 - number_of_fats * fatlength16) / sectors_per_cluster;
624 maxclust16 = (fatlength16 * 512) / 2;
626 if (maxclust16 > MAX_CLUST_16) {
627 maxclust16 = MAX_CLUST_16;
630 if (state->verbose && (state->size_fat == 0 || state->size_fat == 16)) {
631 fprintf (stderr, "Trying FAT16: #clu=%u, fatlen=%u, maxclu=%u, limit=%u/%u\n", clust16, fatlength16, maxclust16, MIN_CLUST_16, MAX_CLUST_16);
634 if (clust16 > maxclust16) {
638 if (state->verbose && (state->size_fat == 0 || state->size_fat == 16)) {
639 fprintf (stderr, "Trying FAT16: too many clusters\n");
644 /** This avoids that the filesystem will be misdetected as having a 12-bit FAT. */
645 if (clust16 && clust16 < MIN_CLUST_16) {
649 if (state->verbose && (state->size_fat == 0 || state->size_fat == 16)) {
650 fprintf (stderr, "Trying FAT16: not enough clusters, would be misdected as FAT12\n");
655 clust32 = ((long) fatdata32 * 512 + number_of_fats * 8) / ((int) sectors_per_cluster * 512 + number_of_fats * 4);
656 fatlength32 = cdiv ((clust32 + 2) * 4, 512);
657 fatlength32 = align_object (fatlength32, sectors_per_cluster);
660 * Need to recalculate number of clusters, since the unused parts of the
661 * FATs and data area together could make up space for an additional,
662 * not really present cluster.
664 clust32 = (fatdata32 - number_of_fats * fatlength32) / sectors_per_cluster;
665 maxclust32 = (fatlength32 * 512) / 4;
667 if (maxclust32 > MAX_CLUST_32) {
668 maxclust32 = MAX_CLUST_32;
671 if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
672 fprintf (stderr, "Trying FAT32: #clu=%u, fatlen=%u, maxclu=%u, limit=%u/%u\n", clust32, fatlength32, maxclust32, MIN_CLUST_32, MAX_CLUST_32);
675 if (clust32 > maxclust32) {
679 if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
680 fprintf (stderr, "Trying FAT32: too many clusters\n");
685 if (clust32 && clust32 < MIN_CLUST_32 && !(state->size_fat_by_user && state->size_fat == 32)) {
689 if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
690 fprintf (stderr, "Trying FAT32: not enough clusters\n");
695 if ((clust12 && (state->size_fat == 0 || state->size_fat == 12)) || (clust16 && (state->size_fat == 0 || state->size_fat == 16)) || (clust32 && state->size_fat == 32)) {
699 sectors_per_cluster <<= 1;
701 } while (sectors_per_cluster && sectors_per_cluster <= maxclustsize);
703 /** Use the optimal FAT size if not specified. */
704 if (!state->size_fat) {
706 state->size_fat = (clust16 > clust12 ? 16 : 12);
708 if (state->verbose) {
709 report_at (program_name, 0, REPORT_WARNING, "Choosing %d-bits for FAT\n", state->size_fat);
714 switch (state->size_fat) {
718 cluster_count = clust12;
719 sectors_per_fat = fatlength12;
724 cluster_count = clust16;
725 sectors_per_fat = fatlength16;
730 cluster_count = clust32;
731 sectors_per_fat = fatlength32;
736 report_at (program_name, 0, REPORT_ERROR, "FAT not 12, 16 or 32 bits");
739 remove (state->outfile);
745 /** Adjust the reserved number of sectors for alignment. */
746 reserved_sectors = align_object (reserved_sectors, sectors_per_cluster);
748 /** Adjust the number of root directory entries to help enforce alignment. */
749 if (align_structures) {
750 root_entries = align_object (root_dir_sectors, sectors_per_cluster) * (512 >> 5);
753 if (state->size_fat == 32) {
761 if (reserved_sectors >= 7 && info_sector != 6) {
763 } else if (reserved_sectors > 3 + info_sector && info_sector != reserved_sectors - 2 && info_sector != reserved_sectors - 1) {
764 backup_boot = reserved_sectors - 2;
765 } else if (reserved_sectors >= 3 && info_sector != reserved_sectors - 1) {
766 backup_boot = reserved_sectors - 1;
773 if (backup_boot == info_sector) {
775 report_at (program_name, 0, REPORT_ERROR, "Backup boot sector must not be the same as the info sector (%d)", info_sector);
778 remove (state->outfile);
782 } else if (backup_boot >= reserved_sectors) {
784 report_at (program_name, 0, REPORT_ERROR, "Backup boot sector must be a reserved sector");
787 remove (state->outfile);
795 if (state->verbose) {
796 fprintf (stderr, "Using sector %d as backup boot sector (0 = none)\n", backup_boot);
801 if (!cluster_count) {
803 report_at (program_name, 0, REPORT_ERROR, "Not enough clusters to make a viable filesystem");
806 remove (state->outfile);
814 static void add_volume_label (void) {
816 struct msdos_dirent *de;
817 unsigned short date, xtime;
819 unsigned char *scratch;
822 if (!(scratch = (unsigned char *) malloc (512))) {
824 report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
827 remove (state->outfile);
833 if (state->size_fat == 32) {
835 long temp = reserved_sectors + (sectors_per_fat * 2);
836 offset += temp + ((root_cluster - 2) * sectors_per_cluster);
839 offset += reserved_sectors + (sectors_per_fat * 2);
842 if (seekto (offset * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
844 report_at (program_name, 0, REPORT_ERROR, "Failed whilst reading root directory");
848 remove (state->outfile);
854 de = (struct msdos_dirent *) scratch;
855 memset (de, 0, sizeof (*de));
857 date = generate_datestamp ();
858 xtime = generate_timestamp ();
860 memcpy (de->name, state->label, 11);
861 de->attr = ATTR_VOLUME_ID;
863 write721_to_byte_array (de->xctime, xtime);
864 write721_to_byte_array (de->cdate, date);
865 write721_to_byte_array (de->adate, date);
866 write721_to_byte_array (de->xtime, xtime);
867 write721_to_byte_array (de->date, date);
869 if (seekto (offset * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
871 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing root directory");
875 remove (state->outfile);
885 static void wipe_target (void) {
887 unsigned int i, sectors_to_wipe = 0;
890 if (!(blank = malloc (512))) {
892 report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
895 remove (state->outfile);
901 memset (blank, 0, 512);
903 sectors_to_wipe += reserved_sectors;
904 sectors_to_wipe += sectors_per_fat * 2;
907 sectors_to_wipe += (root_entries * 32) / 512;
909 sectors_to_wipe += 1;
914 for (i = 0; i < sectors_to_wipe; i++) {
916 if (fwrite (blank, 512, 1, ofp) != 1) {
918 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing blank sector");
922 remove (state->outfile);
934 static void write_reserved (void) {
936 struct msdos_boot_sector bs;
937 struct msdos_volume_info *vi = (state->size_fat == 32 ? &bs.fstype._fat32.vi : &bs.fstype._oldfat.vi);
939 memset (&bs, 0, sizeof (bs));
945 if ((ifp = fopen (state->boot, "rb")) == NULL) {
947 report_at (program_name, 0, REPORT_ERROR, "unable to open %s", state->boot);
950 remove (state->outfile);
956 fseek (ifp, 0, SEEK_END);
958 if (ftell (ifp) != sizeof (bs)) {
960 report_at (program_name, 0, REPORT_ERROR, "boot sector must be %lu bytes in size", (unsigned long) sizeof (bs));
964 remove (state->outfile);
970 fseek (ifp, 0, SEEK_SET);
972 if (fread (&bs, sizeof (bs), 1, ifp) != 1) {
974 report_at (program_name, 0, REPORT_ERROR, "failed to read %s", state->boot);
978 remove (state->outfile);
988 bs.boot_jump[0] = 0xEB;
989 bs.boot_jump[1] = ((state->size_fat == 32 ? (char *) &bs.fstype._fat32.boot_code : (char *) &bs.fstype._oldfat.boot_code) - (char *) &bs) - 2;
990 bs.boot_jump[2] = 0x90;
992 if (state->size_fat == 32) {
993 memcpy (bs.fstype._fat32.boot_code, dummy_boot_code, sizeof (dummy_boot_code));
995 memcpy (bs.fstype._oldfat.boot_code, dummy_boot_code, sizeof (dummy_boot_code));
998 bs.boot_sign[0] = 0x55;
999 bs.boot_sign[1] = 0xAA;
1003 if (bs.boot_jump[0] != 0xEB || bs.boot_jump[1] < 0x16 || bs.boot_jump[2] != 0x90) {
1004 goto _write_reserved;
1007 memcpy (bs.system_id, "MSWIN4.1", 8);
1009 bs.sectors_per_cluster = sectors_per_cluster;
1010 bs.no_fats = number_of_fats;
1011 bs.media_descriptor = media_descriptor;
1013 write721_to_byte_array (bs.bytes_per_sector, 512);
1014 write721_to_byte_array (bs.reserved_sectors, reserved_sectors);
1015 write721_to_byte_array (bs.root_entries, root_entries);
1016 write721_to_byte_array (bs.total_sectors16, total_sectors);
1017 write721_to_byte_array (bs.sectors_per_fat16, sectors_per_fat);
1019 if (bs.boot_jump[1] < 0x22) {
1020 goto _write_reserved;
1023 write721_to_byte_array (bs.sectors_per_track, sectors_per_track);
1024 write721_to_byte_array (bs.heads_per_cylinder, heads_per_cylinder);
1025 write741_to_byte_array (bs.hidden_sectors, hidden_sectors);
1027 if (total_sectors > USHRT_MAX) {
1029 write721_to_byte_array (bs.total_sectors16, 0);
1030 write741_to_byte_array (bs.total_sectors32, total_sectors);
1034 if (state->size_fat == 32) {
1036 if (bs.boot_jump[1] < 0x58) {
1037 goto _write_reserved;
1040 write721_to_byte_array (bs.sectors_per_fat16, 0);
1041 write741_to_byte_array (bs.fstype._fat32.sectors_per_fat32, sectors_per_fat);
1043 write741_to_byte_array (bs.fstype._fat32.root_cluster, root_cluster);
1044 write721_to_byte_array (bs.fstype._fat32.info_sector, info_sector);
1045 write721_to_byte_array (bs.fstype._fat32.backup_boot, backup_boot);
1047 vi->drive_no = (media_descriptor == 0xF8 ? 0x80 : 0x00);
1048 vi->ext_boot_sign = 0x29;
1050 write741_to_byte_array (vi->volume_id, generate_volume_id ());
1051 memcpy (vi->volume_label, state->label, 11);
1052 memcpy (vi->fs_type, "FAT32 ", 8);
1056 if (bs.boot_jump[1] != 0x3C) {
1057 goto _write_reserved;
1060 vi->drive_no = (media_descriptor == 0xF8 ? 0x80 : 0x00);
1061 vi->ext_boot_sign = 0x29;
1063 write741_to_byte_array (vi->volume_id, generate_volume_id ());
1064 memcpy (vi->volume_label, state->label, 11);
1066 if (state->size_fat == 12) {
1067 memcpy (vi->fs_type, "FAT12 ", 8);
1069 memcpy (vi->fs_type, "FAT16 ", 8);
1078 if (fwrite (&bs, sizeof (bs), 1, ofp) != 1) {
1080 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing %s", state->outfile);
1083 remove (state->outfile);
1085 exit (EXIT_FAILURE);
1089 if (state->size_fat == 32) {
1093 struct fat32_fsinfo *info;
1094 unsigned char *buffer;
1096 if (seekto (info_sector * 512)) {
1098 report_at (program_name, 0, REPORT_ERROR, "Failed whilst seeking %s", state->outfile);
1101 remove (state->outfile);
1103 exit (EXIT_FAILURE);
1107 if (!(buffer = (unsigned char *) malloc (512))) {
1109 report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
1112 remove (state->outfile);
1114 exit (EXIT_FAILURE);
1118 memset (buffer, 0, 512);
1120 /** fsinfo structure is at offset 0x1e0 in info sector by observation. */
1121 info = (struct fat32_fsinfo *) (buffer + 0x1e0);
1123 /** Info sector magic. */
1129 /** Magic for fsinfo structure. */
1130 write741_to_byte_array (info->signature, 0x61417272);
1132 /** We've allocated cluster 2 for the root directory. */
1133 write741_to_byte_array (info->free_clusters, cluster_count - 1);
1134 write741_to_byte_array (info->next_cluster, 2);
1136 /** Info sector also must have boot sign. */
1137 write721_to_byte_array (buffer + 0x1fe, 0xAA55);
1139 if (fwrite (buffer, 512, 1, ofp) != 1) {
1141 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing info sector");
1145 remove (state->outfile);
1147 exit (EXIT_FAILURE);
1157 if (seekto (backup_boot * 512) || fwrite (&bs, sizeof (bs), 1, ofp) != 1) {
1159 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing info sector");
1162 remove (state->outfile);
1164 exit (EXIT_FAILURE);
1176 unsigned char cookie[8];
1177 unsigned char features[4];
1181 unsigned char major[2];
1182 unsigned char minor[2];
1186 unsigned char next_offset[8];
1187 unsigned char modified_time[4];
1188 unsigned char creator_name[4];
1192 unsigned char major[2];
1193 unsigned char minor[2];
1197 unsigned char creator_host[4];
1198 unsigned char disk_size[8];
1199 unsigned char data_size[8];
1203 unsigned char cylinders[2];
1204 unsigned char heads_per_cyl;
1205 unsigned char secs_per_track;
1209 unsigned char disk_type[4];
1210 unsigned char checksum[4];
1211 unsigned char identifier[16];
1212 unsigned char saved_state;
1213 unsigned char reserved[427];
1217 int main (int argc, char **argv) {
1219 if (argc && *argv) {
1222 program_name = *argv;
1224 if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {
1225 program_name = (p + 1);
1230 state = xmalloc (sizeof (*state));
1231 parse_args (&argc, &argv, 1);
1233 if (!state->outfile) {
1235 report_at (program_name, 0, REPORT_ERROR, "no outfile file provided");
1236 return EXIT_FAILURE;
1240 image_size = state->sectors * 512;
1241 image_size += state->offset * 512;
1243 if ((ofp = fopen (state->outfile, "r+b")) == NULL) {
1248 if ((ofp = fopen (state->outfile, "w+b")) == NULL) {
1250 report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", state->outfile);
1251 return EXIT_FAILURE;
1256 zero = xmalloc (512);
1260 if (fwrite (zero, 512, 1, ofp) != 1) {
1262 report_at (program_name, 0, REPORT_ERROR, "failed whilst writing '%s'", state->outfile);
1266 remove (state->outfile);
1268 return EXIT_FAILURE;
1280 struct vhd_footer footer;
1281 long size = sizeof (footer);
1283 fseek (ofp, 0, SEEK_END);
1284 image_size = ftell (ofp);
1286 if (!fseek (ofp, ftell (ofp) - size, SEEK_SET)) {
1288 if (fread (&footer, size, 1, ofp) == 1) {
1290 if (footer.cookie[0] == 0x63 && footer.cookie[1] == 0x6F && footer.cookie[2] == 0x6E && footer.cookie[3] == 0x65 && footer.cookie[4] == 0x63 && footer.cookie[5] == 0x74 && footer.cookie[6] == 0x69 && footer.cookie[7] == 0x78) {
1292 /* Okay, if we reach this we'll assume that we have a hard disk image so subtract the footer size and 512 for the MBR. */
1304 total_sectors = image_size / 512;
1309 if (state->offset * 512 > image_size) {
1311 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);
1314 remove (state->outfile);
1316 return EXIT_FAILURE;
1320 image_size -= state->offset * 512;
1322 if (state->sectors) {
1324 if (state->sectors * 512 > image_size) {
1326 report_at (program_name, 0, REPORT_ERROR, "size (%lu) of %s is less than the requested size (%lu)", image_size, state->outfile, state->sectors * 512);
1329 remove (state->outfile);
1331 return EXIT_FAILURE;
1340 if (set_fat_entry (0, 0xFFFFFF00 | media_descriptor) < 0 || set_fat_entry (1, 0xFFFFFFFF) < 0) {
1342 report_at (program_name, 0, REPORT_ERROR, "Failed whilst setting FAT entry");
1345 remove (state->outfile);
1347 return EXIT_FAILURE;
1351 if (state->size_fat == 32) {
1353 if (set_fat_entry (2, 0x0FFFFFF8) < 0) {
1355 report_at (program_name, 0, REPORT_ERROR, "Failed whilst setting FAT entry");
1358 remove (state->outfile);
1360 return EXIT_FAILURE;
1366 if (memcmp (state->label, "NO NAME ", 11) != 0) {
1367 add_volume_label ();
1371 return EXIT_SUCCESS;