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 media_descriptor = 0xfe;
401 sectors_per_track = 8;
402 heads_per_cylinder = 1;
405 case 360: /* 180KB 5.25" */
407 sectors_per_cluster = 2;
409 media_descriptor = 0xfc;
410 sectors_per_track = 9;
411 heads_per_cylinder = 1;
414 case 640: /* 320KB 5.25" */
416 sectors_per_cluster = 2;
418 media_descriptor = 0xff;
419 sectors_per_track = 8;
420 heads_per_cylinder = 2;
423 case 720: /* 360KB 5.25" */
425 sectors_per_cluster = 2;
427 media_descriptor = 0xfd;
428 sectors_per_track = 9;
429 heads_per_cylinder = 2;
432 case 1280: /* 640KB 5.25" / 3.5" */
434 sectors_per_cluster = 2;
436 media_descriptor = 0xfb;
437 sectors_per_track = 8;
438 heads_per_cylinder = 2;
441 case 1440: /* 720KB 5.25" / 3.5" */
443 sectors_per_cluster = 2;
445 media_descriptor = 0xf9;
446 sectors_per_track = 9;
447 heads_per_cylinder = 2;
450 case 1640: /* 820KB 3.5" */
452 sectors_per_cluster = 2;
454 media_descriptor = 0xf9;
455 sectors_per_track = 10;
456 heads_per_cylinder = 2;
459 case 2400: /* 1.20MB 5.25" / 3.5" */
461 sectors_per_cluster = 1;
463 media_descriptor = 0xf9;
464 sectors_per_track = 15;
465 heads_per_cylinder = 2;
468 case 2880: /* 1.44MB 3.5" */
470 sectors_per_cluster = 1;
472 media_descriptor = 0xf0;
473 sectors_per_track = 18;
474 heads_per_cylinder = 2;
477 case 3360: /* 1.68MB 3.5" */
479 sectors_per_cluster = 1;
481 media_descriptor = 0xf0;
482 sectors_per_track = 21;
483 heads_per_cylinder = 2;
486 case 3444: /* 1.72MB 3.5" */
488 sectors_per_cluster = 1;
490 media_descriptor = 0xf0;
491 sectors_per_track = 21;
492 heads_per_cylinder = 2;
495 case 5760: /* 2.88MB 3.5" */
497 sectors_per_cluster = 2;
499 media_descriptor = 0xf0;
500 sectors_per_track = 36;
501 heads_per_cylinder = 2;
506 if (!state->size_fat && total_sectors >= 1048576) {
507 state->size_fat = 32;
510 if (state->size_fat == 32) {
515 * For FAT32, try to do the same as M$'s format command
516 * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20):
518 * fs size <= 260M: 0.5k clusters
519 * fs size <= 8G: 4k clusters
520 * fs size <= 16G: 8k clusters
521 * fs size <= 32G: 16k clusters
522 * fs size > 32G: 32k clusters
524 sectors_per_cluster = (total_sectors > 32 * 1024 * 1024 * 2 ? 64 :
525 total_sectors > 16 * 1024 * 1024 * 2 ? 32 :
526 total_sectors > 8 * 1024 * 1024 * 2 ? 16 :
527 total_sectors > 260 * 1024 * 2 ? 8 : 1);
531 if (state->sectors_per_cluster) {
532 sectors_per_cluster = state->sectors_per_cluster;
535 if (!reserved_sectors) {
536 reserved_sectors = (state->size_fat == 32 ? 32 : 1);
539 /*if (align_structures) {*/
541 /** Align number of sectors to be multiple of sectors per track, needed by DOS and mtools. */
542 /*total_sectors = total_sectors / sectors_per_track * sectors_per_track;*/
546 if (total_sectors <= 8192) {
548 if (align_structures && state->verbose) {
549 report_at (program_name, 0, REPORT_WARNING, "Disabling alignment due to tiny filsystem\n");
552 align_structures = 0;
557 root_dir_sectors = cdiv (root_entries * 32, 512);
561 fatdata32 = total_sectors - align_object (reserved_sectors, sectors_per_cluster);
562 fatdata1216 = fatdata32 - align_object (root_dir_sectors, sectors_per_cluster);
564 if (state->verbose) {
565 fprintf (stderr, "Trying with %d sectors/cluster:\n", sectors_per_cluster);
569 * The factor 2 below avoids cut-off errors for number_of_fats == 1.
570 * The "number_of_fats * 3" is for the reserved first two FAT entries.
572 clust12 = 2 * ((long) fatdata1216 * 512 + number_of_fats * 3) / (2 * (int) sectors_per_cluster * 512 + number_of_fats * 3);
573 fatlength12 = cdiv (((clust12 + 2) * 3 + 1) >> 1, 512);
574 fatlength12 = align_object (fatlength12, sectors_per_cluster);
577 * Need to recalculate number of clusters, since the unused parts of the
578 * FATs and data area together could make up space for an additional,
579 * not really present cluster.
581 clust12 = (fatdata1216 - number_of_fats * fatlength12) / sectors_per_cluster;
582 maxclust12 = (fatlength12 * 2 * 512) / 3;
584 if (maxclust12 > MAX_CLUST_12) {
585 maxclust12 = MAX_CLUST_12;
588 if (state->verbose && (state->size_fat == 0 || state->size_fat == 12)) {
589 fprintf (stderr, "Trying FAT12: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n", clust12, fatlength12, maxclust12, MAX_CLUST_12);
592 if (clust12 > maxclust12) {
596 if (state->verbose && (state->size_fat == 0 || state->size_fat == 12)) {
597 fprintf (stderr, "Trying FAT12: too many clusters\n");
602 clust16 = ((long) fatdata1216 * 512 + number_of_fats * 4) / ((int) sectors_per_cluster * 512 + number_of_fats * 2);
603 fatlength16 = cdiv ((clust16 + 2) * 2, 512);
604 fatlength16 = align_object (fatlength16, sectors_per_cluster);
607 * Need to recalculate number of clusters, since the unused parts of the
608 * FATs and data area together could make up space for an additional,
609 * not really present cluster.
611 clust16 = (fatdata1216 - number_of_fats * fatlength16) / sectors_per_cluster;
612 maxclust16 = (fatlength16 * 512) / 2;
614 if (maxclust16 > MAX_CLUST_16) {
615 maxclust16 = MAX_CLUST_16;
618 if (state->verbose && (state->size_fat == 0 || state->size_fat == 16)) {
619 fprintf (stderr, "Trying FAT16: #clu=%u, fatlen=%u, maxclu=%u, limit=%u/%u\n", clust16, fatlength16, maxclust16, MIN_CLUST_16, MAX_CLUST_16);
622 if (clust16 > maxclust16) {
626 if (state->verbose && (state->size_fat == 0 || state->size_fat == 16)) {
627 fprintf (stderr, "Trying FAT16: too many clusters\n");
632 /** This avoids that the filesystem will be misdetected as having a 12-bit FAT. */
633 if (clust16 && clust16 < MIN_CLUST_16) {
637 if (state->verbose && (state->size_fat == 0 || state->size_fat == 16)) {
638 fprintf (stderr, "Trying FAT16: not enough clusters, would be misdected as FAT12\n");
643 clust32 = ((long) fatdata32 * 512 + number_of_fats * 8) / ((int) sectors_per_cluster * 512 + number_of_fats * 4);
644 fatlength32 = cdiv ((clust32 + 2) * 4, 512);
645 fatlength32 = align_object (fatlength32, sectors_per_cluster);
648 * Need to recalculate number of clusters, since the unused parts of the
649 * FATs and data area together could make up space for an additional,
650 * not really present cluster.
652 clust32 = (fatdata32 - number_of_fats * fatlength32) / sectors_per_cluster;
653 maxclust32 = (fatlength32 * 512) / 4;
655 if (maxclust32 > MAX_CLUST_32) {
656 maxclust32 = MAX_CLUST_32;
659 if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
660 fprintf (stderr, "Trying FAT32: #clu=%u, fatlen=%u, maxclu=%u, limit=%u/%u\n", clust32, fatlength32, maxclust32, MIN_CLUST_32, MAX_CLUST_32);
663 if (clust32 > maxclust32) {
667 if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
668 fprintf (stderr, "Trying FAT32: too many clusters\n");
673 if (clust32 && clust32 < MIN_CLUST_32 && !(state->size_fat_by_user && state->size_fat == 32)) {
677 if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
678 fprintf (stderr, "Trying FAT32: not enough clusters\n");
683 if ((clust12 && (state->size_fat == 0 || state->size_fat == 12)) || (clust16 && (state->size_fat == 0 || state->size_fat == 16)) || (clust32 && state->size_fat == 32)) {
687 sectors_per_cluster <<= 1;
689 } while (sectors_per_cluster && sectors_per_cluster <= maxclustsize);
691 /** Use the optimal FAT size if not specified. */
692 if (!state->size_fat) {
694 state->size_fat = (clust16 > clust12 ? 16 : 12);
696 if (state->verbose) {
697 report_at (program_name, 0, REPORT_WARNING, "Choosing %d-bits for FAT\n", state->size_fat);
702 switch (state->size_fat) {
706 cluster_count = clust12;
707 sectors_per_fat = fatlength12;
712 cluster_count = clust16;
713 sectors_per_fat = fatlength16;
718 cluster_count = clust32;
719 sectors_per_fat = fatlength32;
724 report_at (program_name, 0, REPORT_ERROR, "FAT not 12, 16 or 32 bits");
727 remove (state->outfile);
733 /** Adjust the reserved number of sectors for alignment. */
734 reserved_sectors = align_object (reserved_sectors, sectors_per_cluster);
736 /** Adjust the number of root directory entries to help enforce alignment. */
737 if (align_structures) {
738 root_entries = align_object (root_dir_sectors, sectors_per_cluster) * (512 >> 5);
741 if (state->size_fat == 32) {
749 if (reserved_sectors >= 7 && info_sector != 6) {
751 } else if (reserved_sectors > 3 + info_sector && info_sector != reserved_sectors - 2 && info_sector != reserved_sectors - 1) {
752 backup_boot = reserved_sectors - 2;
753 } else if (reserved_sectors >= 3 && info_sector != reserved_sectors - 1) {
754 backup_boot = reserved_sectors - 1;
761 if (backup_boot == info_sector) {
763 report_at (program_name, 0, REPORT_ERROR, "Backup boot sector must not be the same as the info sector (%d)", info_sector);
766 remove (state->outfile);
770 } else if (backup_boot >= reserved_sectors) {
772 report_at (program_name, 0, REPORT_ERROR, "Backup boot sector must be a reserved sector");
775 remove (state->outfile);
783 if (state->verbose) {
784 fprintf (stderr, "Using sector %d as backup boot sector (0 = none)\n", backup_boot);
789 if (!cluster_count) {
791 report_at (program_name, 0, REPORT_ERROR, "Not enough clusters to make a viable filesystem");
794 remove (state->outfile);
802 static void add_volume_label (void) {
804 struct msdos_dirent *de;
805 unsigned short date, xtime;
807 unsigned char *scratch;
810 if (!(scratch = (unsigned char *) malloc (512))) {
812 report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
815 remove (state->outfile);
821 if (state->size_fat == 32) {
823 long temp = reserved_sectors + (sectors_per_fat * 2);
824 offset += temp + ((root_cluster - 2) * sectors_per_cluster);
827 offset += reserved_sectors + (sectors_per_fat * 2);
830 if (seekto (offset * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
832 report_at (program_name, 0, REPORT_ERROR, "Failed whilst reading root directory");
836 remove (state->outfile);
842 de = (struct msdos_dirent *) scratch;
843 memset (de, 0, sizeof (*de));
845 date = generate_datestamp ();
846 xtime = generate_timestamp ();
848 memcpy (de->name, state->label, 11);
849 de->attr = ATTR_VOLUME_ID;
851 write721_to_byte_array (de->xctime, xtime);
852 write721_to_byte_array (de->cdate, date);
853 write721_to_byte_array (de->adate, date);
854 write721_to_byte_array (de->xtime, xtime);
855 write721_to_byte_array (de->date, date);
857 if (seekto (offset * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
859 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing root directory");
863 remove (state->outfile);
873 static void wipe_target (void) {
875 unsigned int i, sectors_to_wipe = 0;
878 if (!(blank = malloc (512))) {
880 report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
883 remove (state->outfile);
889 memset (blank, 0, 512);
891 sectors_to_wipe += reserved_sectors;
892 sectors_to_wipe += sectors_per_fat * 2;
895 sectors_to_wipe += (root_entries * 32) / 512;
897 sectors_to_wipe += 1;
902 for (i = 0; i < sectors_to_wipe; i++) {
904 if (fwrite (blank, 512, 1, ofp) != 1) {
906 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing blank sector");
910 remove (state->outfile);
922 static void write_reserved (void) {
924 struct msdos_boot_sector bs;
925 struct msdos_volume_info *vi = (state->size_fat == 32 ? &bs.fstype._fat32.vi : &bs.fstype._oldfat.vi);
927 memset (&bs, 0, sizeof (bs));
933 if ((ifp = fopen (state->boot, "rb")) == NULL) {
935 report_at (program_name, 0, REPORT_ERROR, "unable to open %s", state->boot);
938 remove (state->outfile);
944 fseek (ifp, 0, SEEK_END);
946 if (ftell (ifp) != sizeof (bs)) {
948 report_at (program_name, 0, REPORT_ERROR, "boot sector must be %lu bytes in size", (unsigned long) sizeof (bs));
952 remove (state->outfile);
958 fseek (ifp, 0, SEEK_SET);
960 if (fread (&bs, sizeof (bs), 1, ifp) != 1) {
962 report_at (program_name, 0, REPORT_ERROR, "failed to read %s", state->boot);
966 remove (state->outfile);
976 bs.boot_jump[0] = 0xEB;
977 bs.boot_jump[1] = ((state->size_fat == 32 ? (char *) &bs.fstype._fat32.boot_code : (char *) &bs.fstype._oldfat.boot_code) - (char *) &bs) - 2;
978 bs.boot_jump[2] = 0x90;
980 if (state->size_fat == 32) {
981 memcpy (bs.fstype._fat32.boot_code, dummy_boot_code, sizeof (dummy_boot_code));
983 memcpy (bs.fstype._oldfat.boot_code, dummy_boot_code, sizeof (dummy_boot_code));
986 bs.boot_sign[0] = 0x55;
987 bs.boot_sign[1] = 0xAA;
991 if (bs.boot_jump[0] != 0xEB || bs.boot_jump[1] < 0x16 || bs.boot_jump[2] != 0x90) {
992 goto _write_reserved;
995 memcpy (bs.system_id, "MSWIN4.1", 8);
997 bs.sectors_per_cluster = sectors_per_cluster;
998 bs.no_fats = number_of_fats;
999 bs.media_descriptor = media_descriptor;
1001 write721_to_byte_array (bs.bytes_per_sector, 512);
1002 write721_to_byte_array (bs.reserved_sectors, reserved_sectors);
1003 write721_to_byte_array (bs.root_entries, root_entries);
1004 write721_to_byte_array (bs.total_sectors16, total_sectors);
1005 write721_to_byte_array (bs.sectors_per_fat16, sectors_per_fat);
1007 if (bs.boot_jump[1] < 0x22) {
1008 goto _write_reserved;
1011 write721_to_byte_array (bs.sectors_per_track, sectors_per_track);
1012 write721_to_byte_array (bs.heads_per_cylinder, heads_per_cylinder);
1013 write741_to_byte_array (bs.hidden_sectors, hidden_sectors);
1015 if (total_sectors > USHRT_MAX) {
1017 write721_to_byte_array (bs.total_sectors16, 0);
1018 write741_to_byte_array (bs.total_sectors32, total_sectors);
1022 if (state->size_fat == 32) {
1024 if (bs.boot_jump[1] < 0x58) {
1025 goto _write_reserved;
1028 write721_to_byte_array (bs.sectors_per_fat16, 0);
1029 write741_to_byte_array (bs.fstype._fat32.sectors_per_fat32, sectors_per_fat);
1031 write741_to_byte_array (bs.fstype._fat32.root_cluster, root_cluster);
1032 write721_to_byte_array (bs.fstype._fat32.info_sector, info_sector);
1033 write721_to_byte_array (bs.fstype._fat32.backup_boot, backup_boot);
1035 vi->drive_no = (media_descriptor == 0xF8 ? 0x80 : 0x00);
1036 vi->ext_boot_sign = 0x29;
1038 write741_to_byte_array (vi->volume_id, generate_volume_id ());
1039 memcpy (vi->volume_label, state->label, 11);
1040 memcpy (vi->fs_type, "FAT32 ", 8);
1044 if (bs.boot_jump[1] != 0x3C) {
1045 goto _write_reserved;
1048 vi->drive_no = (media_descriptor == 0xF8 ? 0x80 : 0x00);
1049 vi->ext_boot_sign = 0x29;
1051 write741_to_byte_array (vi->volume_id, generate_volume_id ());
1052 memcpy (vi->volume_label, state->label, 11);
1054 if (state->size_fat == 12) {
1055 memcpy (vi->fs_type, "FAT12 ", 8);
1057 memcpy (vi->fs_type, "FAT16 ", 8);
1066 if (fwrite (&bs, sizeof (bs), 1, ofp) != 1) {
1068 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing %s", state->outfile);
1071 remove (state->outfile);
1073 exit (EXIT_FAILURE);
1077 if (state->size_fat == 32) {
1081 struct fat32_fsinfo *info;
1082 unsigned char *buffer;
1084 if (seekto (info_sector * 512)) {
1086 report_at (program_name, 0, REPORT_ERROR, "Failed whilst seeking %s", state->outfile);
1089 remove (state->outfile);
1091 exit (EXIT_FAILURE);
1095 if (!(buffer = (unsigned char *) malloc (512))) {
1097 report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
1100 remove (state->outfile);
1102 exit (EXIT_FAILURE);
1106 memset (buffer, 0, 512);
1108 /** fsinfo structure is at offset 0x1e0 in info sector by observation. */
1109 info = (struct fat32_fsinfo *) (buffer + 0x1e0);
1111 /** Info sector magic. */
1117 /** Magic for fsinfo structure. */
1118 write741_to_byte_array (info->signature, 0x61417272);
1120 /** We've allocated cluster 2 for the root directory. */
1121 write741_to_byte_array (info->free_clusters, cluster_count - 1);
1122 write741_to_byte_array (info->next_cluster, 2);
1124 /** Info sector also must have boot sign. */
1125 write721_to_byte_array (buffer + 0x1fe, 0xAA55);
1127 if (fwrite (buffer, 512, 1, ofp) != 1) {
1129 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing info sector");
1133 remove (state->outfile);
1135 exit (EXIT_FAILURE);
1145 if (seekto (backup_boot * 512) || fwrite (&bs, sizeof (bs), 1, ofp) != 1) {
1147 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing info sector");
1150 remove (state->outfile);
1152 exit (EXIT_FAILURE);
1164 unsigned char cookie[8];
1165 unsigned char features[4];
1169 unsigned char major[2];
1170 unsigned char minor[2];
1174 unsigned char next_offset[8];
1175 unsigned char modified_time[4];
1176 unsigned char creator_name[4];
1180 unsigned char major[2];
1181 unsigned char minor[2];
1185 unsigned char creator_host[4];
1186 unsigned char disk_size[8];
1187 unsigned char data_size[8];
1191 unsigned char cylinders[2];
1192 unsigned char heads_per_cyl;
1193 unsigned char secs_per_track;
1197 unsigned char disk_type[4];
1198 unsigned char checksum[4];
1199 unsigned char identifier[16];
1200 unsigned char saved_state;
1201 unsigned char reserved[427];
1205 int main (int argc, char **argv) {
1207 if (argc && *argv) {
1210 program_name = *argv;
1212 if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {
1213 program_name = (p + 1);
1218 state = xmalloc (sizeof (*state));
1219 parse_args (&argc, &argv, 1);
1221 if (!state->outfile) {
1223 report_at (program_name, 0, REPORT_ERROR, "no outfile file provided");
1224 return EXIT_FAILURE;
1228 image_size = state->sectors * 512;
1229 image_size += state->offset * 512;
1231 if ((ofp = fopen (state->outfile, "r+b")) == NULL) {
1236 if ((ofp = fopen (state->outfile, "w+b")) == NULL) {
1238 report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", state->outfile);
1239 return EXIT_FAILURE;
1244 zero = xmalloc (512);
1248 if (fwrite (zero, 512, 1, ofp) != 1) {
1250 report_at (program_name, 0, REPORT_ERROR, "failed whilst writing '%s'", state->outfile);
1254 remove (state->outfile);
1256 return EXIT_FAILURE;
1268 struct vhd_footer footer;
1269 long size = sizeof (footer);
1271 fseek (ofp, 0, SEEK_END);
1272 image_size = ftell (ofp);
1274 if (!fseek (ofp, ftell (ofp) - size, SEEK_SET)) {
1276 if (fread (&footer, size, 1, ofp) == 1) {
1278 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) {
1280 /* 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. */
1292 total_sectors = image_size / 512;
1297 if (state->offset * 512 > image_size) {
1299 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);
1302 remove (state->outfile);
1304 return EXIT_FAILURE;
1308 image_size -= state->offset * 512;
1310 if (state->sectors) {
1312 if (state->sectors * 512 > image_size) {
1314 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);
1317 remove (state->outfile);
1319 return EXIT_FAILURE;
1328 if (set_fat_entry (0, 0xFFFFFF00 | media_descriptor) < 0 || set_fat_entry (1, 0xFFFFFFFF) < 0) {
1330 report_at (program_name, 0, REPORT_ERROR, "Failed whilst setting FAT entry");
1333 remove (state->outfile);
1335 return EXIT_FAILURE;
1339 if (state->size_fat == 32) {
1341 if (set_fat_entry (2, 0x0FFFFFF8) < 0) {
1343 report_at (program_name, 0, REPORT_ERROR, "Failed whilst setting FAT entry");
1346 remove (state->outfile);
1348 return EXIT_FAILURE;
1354 if (memcmp (state->label, "NO NAME ", 11) != 0) {
1355 add_volume_label ();
1359 return EXIT_SUCCESS;