50696eb608ce4989d845db7bbade6a2523fd863c
[dosfstools.git] / mkfs.c
1 /******************************************************************************
2  * @file            mkfs.c
3  *****************************************************************************/
4 #include    <limits.h>
5 #include    <stdio.h>
6 #include    <stdlib.h>
7 #include    <string.h>
8
9 #include    "common.h"
10 #include    "lib.h"
11 #include    "mkfs.h"
12 #include    "msdos.h"
13 #include    "report.h"
14 #include    "write7x.h"
15
16 #ifndef     __PDOS__
17 # if     defined (__GNUC__)
18 #  include  <sys/time.h>
19 #  include  <unistd.h>
20 # else
21 #  include  <io.h>
22 # endif
23 #endif
24
25 static int align_structures = 1;
26
27 static unsigned long image_size = 0;
28 static FILE *ofp;
29
30 static long total_sectors = 0;
31
32 static int heads_per_cylinder = 255;
33 static int sectors_per_track = 63;
34
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;
46
47 struct mkfs_state *state = 0;
48 const char *program_name = 0;
49
50 static unsigned char dummy_boot_code[] =
51
52     "\x31\xC0"                                                                  /* xor ax, ax */
53     "\xFA"                                                                      /* cli */
54     "\x8E\xD0"                                                                  /* mov ss, ax */
55     "\xBC\x00\x7C"                                                              /* mov sp, 0x7c00 */
56     "\xFB"                                                                      /* sti */
57     "\x0E\x1F"                                                                  /* push cs, pop ds */
58     "\xEB\x19"                                                                  /* jmp XSTRING */
59     
60     "\x5E"                                                                      /* PRN: pop si */
61     "\xFC"                                                                      /* cld */
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 */
69     
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 */
75     
76     "\xE8\xE4\xFF"                                                              /* XSTRING: call PRN */
77     
78     "Non-System disk or disk read error\r\n"
79     "Replace and strike any key when ready\r\n";
80
81 static int cdiv (int a, int b) {
82     return (a + b - 1) / b;
83 }
84
85 static int seekto (long offset) {
86     return fseek (ofp, (state->offset * 512) + offset, SEEK_SET);
87 }
88
89 static int set_fat_entry (unsigned int cluster, unsigned int value) {
90
91     unsigned char *scratch;
92     unsigned int i, offset, sector;
93     
94     if (!(scratch = (unsigned char *) malloc (512))) {
95         return -1;
96     }
97     
98     if (state->size_fat == 12) {
99     
100         offset = cluster + (cluster / 2);
101         value &= 0x0fff;
102     
103     } else if (state->size_fat == 16) {
104     
105         offset = cluster * 2;
106         value &= 0xffff;
107     
108     } else if (state->size_fat == 32) {
109     
110         offset = cluster * 4;
111         value &= 0x0fffffff;
112     
113     } else {
114     
115         free (scratch);
116         return -1;
117     
118     }
119     
120     /**
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.
123      */
124     sector = (offset / 512) + reserved_sectors;
125     
126     if (seekto (sector * 512)) {
127     
128         free (scratch);
129         
130         report_at (program_name, 0, REPORT_ERROR, "failed whilst seeking %s", state->outfile);
131         return -1;
132     
133     }
134     
135     if (fread (scratch, 512, 1, ofp) != 1) {
136     
137         free (scratch);
138         
139         report_at (program_name, 0, REPORT_ERROR, "failed whilst reading %s", state->outfile);
140         return -1;
141     
142     }
143     
144     /**
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.
149      */
150     offset %= 512;
151     
152     if (state->size_fat == 12) {
153     
154         if (offset == 511) {
155         
156             if (((cluster * 3) & 0x01) == 0) {
157                 scratch[offset] = (unsigned char) (value & 0xFF);
158             } else {
159                 scratch[offset] = (unsigned char) ((scratch[offset] & 0x0F) | (value & 0xF0));
160             }
161             
162             for (i = 0; i < number_of_fats; i++) {
163             
164                 long temp = sector + (i * sectors_per_fat);
165                 
166                 if (seekto (temp * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
167                 
168                     free (scratch);
169                     return -1;
170                 
171                 }
172             
173             }
174             
175             sector++;
176             
177             if (seekto (sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
178             
179                 free (scratch);
180                 return -1;
181             
182             }
183             
184             if (((cluster * 3) & 0x01) == 0) {
185                 scratch[0] = (unsigned char) ((scratch[0] & 0xF0) | (value & 0x0F));
186             } else {
187                 scratch[0] = (unsigned char) (value & 0xFF00);
188             }
189             
190             goto _write_fat;
191         
192         } else {
193         
194             if (((cluster * 3) & 0x01) == 0) {
195             
196                 scratch[offset] = (unsigned char) (value & 0x00FF);
197                 scratch[offset + 1] = (unsigned char) ((scratch[offset + 1] & 0x00F0) | ((value & 0x0F00) >> 8));
198             
199             } else {
200             
201                 scratch[offset] = (unsigned char) ((scratch[offset] & 0x000F) | ((value & 0x000F) << 4));
202                 scratch[offset + 1] = (unsigned char) ((value & 0x0FF0) >> 4);
203             
204             }
205             
206             goto _write_fat;
207         
208         }
209     
210     } else if (state->size_fat == 16) {
211     
212         scratch[offset] = (value & 0xFF);
213         scratch[offset + 1] = (value >> 8) & 0xFF;
214         
215         goto _write_fat;
216     
217     } else if (state->size_fat == 32) {
218     
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);
223         
224         goto _write_fat;
225     
226     }
227     
228     free (scratch);
229     return -1;
230
231 _write_fat:
232
233     for (i = 0; i < number_of_fats; i++) {
234     
235         long temp = sector + (i * sectors_per_fat);
236         
237         if (seekto (temp * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
238         
239             free (scratch);
240             return -1;
241         
242         }
243     
244     }
245     
246     free (scratch);
247     return 0;
248
249 }
250
251 static unsigned int align_object (unsigned int sectors, unsigned int clustsize) {
252
253     if (align_structures) {
254         return (sectors + clustsize - 1) & ~(clustsize - 1);
255     }
256     
257     return sectors;
258
259 }
260
261 static unsigned int generate_volume_id (void) {
262
263 #if     defined (__PDOS__)
264
265     srand (time (NULL));
266     
267     /* rand() returns int from [0,RAND_MAX], therefor only 31-bits. */
268     return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF));
269
270 #elif   defined (__GNUC__)
271
272     struct timeval now;
273     
274     if (gettimeofday (&now, 0) != 0 || now.tv_sec == (time_t) -1 || now.tv_sec < 0) {
275     
276         srand (getpid ());
277         
278         /*- rand() returns int from [0,RAND_MAX], therefor only 31-bits. */
279         return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF));
280     
281     }
282     
283     /* volume id = current time, fudged for more uniqueness. */
284     return ((unsigned int) now.tv_sec << 20) | (unsigned int) now.tv_usec;
285
286 #elif   defined (__WATCOMC__)
287
288     srand (getpid ());
289     
290     /* rand() returns int from [0,RAND_MAX], therefor only 31-bits. */
291     return (((unsigned int) (rand () & 0xFFFF)) << 16) | ((unsigned int) (rand() & 0xFFFF));
292
293 #endif
294
295 }
296
297 static void establish_bpb (void) {
298
299     unsigned int maxclustsize, root_dir_sectors;
300     
301     unsigned int clust12, clust16, clust32;
302     unsigned int fatdata1216, fatdata32;
303     unsigned int fatlength12, fatlength16, fatlength32;
304     unsigned int maxclust12, maxclust16, maxclust32;
305     
306     long cylinder_times_heads;
307     long sectors_per_cylinder;
308     
309     if ((unsigned long) total_sectors > UINT_MAX) {
310     
311         report_at (program_name, 0, REPORT_WARNING, "target too large, space at end will be left unused.\n");
312         total_sectors = UINT_MAX;
313     
314     }
315     
316     if (total_sectors > (long) 65535 * 16 * 63) {
317     
318         sectors_per_track = 63;
319         heads_per_cylinder = 255;
320         
321         cylinder_times_heads = total_sectors / sectors_per_track;
322     
323     } else {
324     
325         sectors_per_track = 17;
326         cylinder_times_heads = total_sectors / sectors_per_track;
327         
328         heads_per_cylinder = (cylinder_times_heads + 1023) >> 10;
329         
330         if (heads_per_cylinder < 4) {
331             heads_per_cylinder = 4;
332         }
333         
334         if (cylinder_times_heads >= heads_per_cylinder << 10 || heads_per_cylinder > 16) {
335         
336             sectors_per_track = 31;
337             heads_per_cylinder = 16;
338             
339             cylinder_times_heads = total_sectors / sectors_per_track;
340         
341         }
342         
343         if (cylinder_times_heads >= heads_per_cylinder << 10) {
344         
345             sectors_per_track = 63;
346             heads_per_cylinder = 16;
347             
348             cylinder_times_heads = total_sectors / sectors_per_track;
349         
350         }
351     
352     }
353     
354     sectors_per_cylinder = heads_per_cylinder * sectors_per_track;
355     
356     hidden_sectors = state->offset;
357     total_sectors = state->sectors;
358     
359     if (state->chs_align && hidden_sectors % sectors_per_track) {
360     
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);
363     
364     }
365     
366     if (state->chs_align) {
367     
368         long adjustment;
369         
370         if (total_sectors % sectors_per_cylinder) {
371             total_sectors = ((total_sectors / sectors_per_cylinder) + 1) * sectors_per_cylinder;
372         }
373         
374         if ((unsigned long) (hidden_sectors + total_sectors) > state->offset + state->sectors) {
375         
376             adjustment = (hidden_sectors + total_sectors) - (state->offset + state->sectors);
377             total_sectors -= adjustment;
378         
379         }
380         
381         if ((adjustment = (hidden_sectors + total_sectors) % sectors_per_cylinder)) {
382             total_sectors -= adjustment;
383         }
384         
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);
387         }
388     
389     }
390     
391     state->offset = hidden_sectors;
392     state->sectors = total_sectors;
393     
394     switch (total_sectors) {
395     
396         case 320:                                                               /* 160KB 5.25" */
397         
398             sectors_per_cluster = 2;
399             root_entries = 112;
400             sectors_per_track = 8;
401             heads_per_cylinder = 1;
402             
403             media_descriptor = 0xFE;
404             break;
405         
406         case 360:                                                               /* 180KB 5.25" */
407         
408             sectors_per_cluster = 2;
409             root_entries = 112;
410             sectors_per_track = 9;
411             heads_per_cylinder = 1;
412             
413             media_descriptor = 0xFC;
414             break;
415         
416         case 640:                                                               /* 320KB 5.25" */
417         
418             sectors_per_cluster = 2;
419             root_entries = 112;
420             sectors_per_track = 8;
421             heads_per_cylinder = 2;
422             
423             media_descriptor = 0xFF;
424             break;
425         
426         case 720:                                                               /* 360KB 5.25" */
427         
428             sectors_per_cluster = 2;
429             root_entries = 112;
430             sectors_per_track = 9;
431             heads_per_cylinder = 2;
432             
433             media_descriptor = 0xFD;
434             break;
435         
436         case 1280:                                                              /* 640KB 5.25" / 3.5" */
437         
438             sectors_per_cluster = 2;
439             root_entries = 112;
440             sectors_per_track = 8;
441             heads_per_cylinder = 2;
442             
443             media_descriptor = 0xFB;
444             break;
445         
446         case 1440:                                                              /* 720KB 5.25" / 3.5" */
447         
448             sectors_per_cluster = 2;
449             root_entries = 112;
450             sectors_per_track = 9;
451             heads_per_cylinder = 2;
452             
453             media_descriptor = 0xF9;
454             break;
455         
456         case 1640:                                                              /* 820KB 3.5" */
457         
458             sectors_per_cluster = 2;
459             root_entries = 112;
460             sectors_per_track = 10;
461             heads_per_cylinder = 2;
462             
463             media_descriptor = 0xF9;
464             break;
465         
466         case 2400:                                                              /* 1.20MB 5.25" / 3.5" */
467         
468             sectors_per_cluster = 1;
469             root_entries = 224;
470             sectors_per_track = 15;
471             heads_per_cylinder = 2;
472             
473             media_descriptor = 0xF9;
474             break;
475         
476         case 2880:                                                              /* 1.44MB 3.5" */
477         
478             sectors_per_cluster = 1;
479             root_entries = 224;
480             sectors_per_track = 18;
481             heads_per_cylinder = 2;
482             
483             media_descriptor = 0xF0;
484             break;
485         
486         case 3360:                                                              /* 1.68MB 3.5" */
487         
488             sectors_per_cluster = 1;
489             root_entries = 224;
490             sectors_per_track = 21;
491             heads_per_cylinder = 2;
492             
493             media_descriptor = 0xF0;
494             break;
495         
496         case 3444:                                                              /* 1.72MB 3.5" */
497         
498             sectors_per_cluster = 1;
499             root_entries = 224;
500             sectors_per_track = 21;
501             heads_per_cylinder = 2;
502             
503             media_descriptor = 0xF0;
504             break;
505         
506         case 5760:                                                              /* 2.88MB 3.5" */
507         
508             sectors_per_cluster = 2;
509             root_entries = 240;
510             sectors_per_track = 36;
511             heads_per_cylinder = 2;
512             
513             media_descriptor = 0xF0;
514             break;
515     
516     }
517     
518     if (!state->size_fat && total_sectors >= 1048576) {
519         state->size_fat = 32;
520     }
521     
522     if (state->size_fat == 32) {
523     
524         root_entries = 0;
525         
526         /*
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):
529          * 
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
535          */
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);
540     
541     }
542     
543     if (state->sectors_per_cluster) {
544         sectors_per_cluster = state->sectors_per_cluster;
545     }
546     
547     if (!reserved_sectors) {
548         reserved_sectors = (state->size_fat == 32 ? 32 : 1);
549     }
550     
551     /*if (align_structures) {*/
552     
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;*/
555     
556     /*}*/
557     
558     if (total_sectors <= 8192) {
559     
560         if (align_structures && state->verbose) {
561             report_at (program_name, 0, REPORT_WARNING, "Disabling alignment due to tiny filsystem\n");
562         }
563         
564         align_structures = 0;
565     
566     }
567     
568     maxclustsize = 128;
569     root_dir_sectors = cdiv (root_entries * 32, 512);
570     
571     do {
572     
573         fatdata32 = total_sectors - align_object (reserved_sectors, sectors_per_cluster);
574         fatdata1216 = fatdata32 - align_object (root_dir_sectors, sectors_per_cluster);
575         
576         if (state->verbose) {
577             fprintf (stderr, "Trying with %d sectors/cluster:\n", sectors_per_cluster);
578         }
579         
580         /**
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.
583          */
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);
587         
588         /**
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.
592          */
593         clust12 = (fatdata1216 - number_of_fats * fatlength12) / sectors_per_cluster;
594         maxclust12 = (fatlength12 * 2 * 512) / 3;
595         
596         if (maxclust12 > MAX_CLUST_12) {
597             maxclust12 = MAX_CLUST_12;
598         }
599         
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);
602         }
603         
604         if (clust12 > maxclust12) {
605         
606             clust12 = 0;
607             
608             if (state->verbose && (state->size_fat == 0 || state->size_fat == 12)) {
609                 fprintf (stderr, "Trying FAT12: too many clusters\n");
610             }
611         
612         }
613         
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);
617         
618         /**
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.
622          */
623         clust16 = (fatdata1216 - number_of_fats * fatlength16) / sectors_per_cluster;
624         maxclust16 = (fatlength16 * 512) / 2;
625         
626         if (maxclust16 > MAX_CLUST_16) {
627             maxclust16 = MAX_CLUST_16;
628         }
629         
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);
632         }
633         
634         if (clust16 > maxclust16) {
635         
636             clust16 = 0;
637             
638             if (state->verbose && (state->size_fat == 0 || state->size_fat == 16)) {
639                 fprintf (stderr, "Trying FAT16: too many clusters\n");
640             }
641         
642         }
643         
644         /** This avoids that the filesystem will be misdetected as having a 12-bit FAT. */
645         if (clust16 && clust16 < MIN_CLUST_16) {
646         
647             clust16 = 0;
648             
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");
651             }
652         
653         }
654         
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);
658         
659         /**
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.
663          */
664         clust32 = (fatdata32 - number_of_fats * fatlength32) / sectors_per_cluster;
665         maxclust32 = (fatlength32 * 512) / 4;
666         
667         if (maxclust32 > MAX_CLUST_32) {
668             maxclust32 = MAX_CLUST_32;
669         }
670         
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);
673         }
674         
675         if (clust32 > maxclust32) {
676         
677             clust32 = 0;
678             
679             if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
680                 fprintf (stderr, "Trying FAT32: too many clusters\n");
681             }
682         
683         }
684         
685         if (clust32 && clust32 < MIN_CLUST_32 && !(state->size_fat_by_user && state->size_fat == 32)) {
686         
687             clust32 = 0;
688             
689             if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
690                 fprintf (stderr, "Trying FAT32: not enough clusters\n");
691             }
692         
693         }
694         
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)) {
696             break;
697         }
698         
699         sectors_per_cluster <<= 1;
700     
701     } while (sectors_per_cluster && sectors_per_cluster <= maxclustsize);
702     
703     /** Use the optimal FAT size if not specified. */
704     if (!state->size_fat) {
705     
706         state->size_fat = (clust16 > clust12 ? 16 : 12);
707         
708         if (state->verbose) {
709             report_at (program_name, 0, REPORT_WARNING, "Choosing %d-bits for FAT\n", state->size_fat);
710         }
711     
712     }
713     
714     switch (state->size_fat) {
715     
716         case 12:
717         
718             cluster_count = clust12;
719             sectors_per_fat = fatlength12;
720             break;
721         
722         case 16:
723         
724             cluster_count = clust16;
725             sectors_per_fat = fatlength16;
726             break;
727         
728         case 32:
729         
730             cluster_count = clust32;
731             sectors_per_fat = fatlength32;
732             break;
733         
734         default:
735         
736             report_at (program_name, 0, REPORT_ERROR, "FAT not 12, 16 or 32 bits");
737             
738             fclose (ofp);
739             remove (state->outfile);
740             
741             exit (EXIT_FAILURE);
742     
743     }
744     
745     /** Adjust the reserved number of sectors for alignment. */
746     reserved_sectors = align_object (reserved_sectors, sectors_per_cluster);
747     
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);
751     }
752     
753     if (state->size_fat == 32) {
754     
755         if (!info_sector) {
756             info_sector = 1;
757         }
758         
759         if (!backup_boot) {
760         
761             if (reserved_sectors >= 7 && info_sector != 6) {
762                 backup_boot = 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;
767             }
768         
769         }
770         
771         if (backup_boot) {
772         
773             if (backup_boot == info_sector) {
774             
775                 report_at (program_name, 0, REPORT_ERROR, "Backup boot sector must not be the same as the info sector (%d)", info_sector);
776                 
777                 fclose (ofp);
778                 remove (state->outfile);
779                 
780                 exit (EXIT_FAILURE);
781             
782             } else if (backup_boot >= reserved_sectors) {
783             
784                 report_at (program_name, 0, REPORT_ERROR, "Backup boot sector must be a reserved sector");
785                 
786                 fclose (ofp);
787                 remove (state->outfile);
788                 
789                 exit (EXIT_FAILURE);
790             
791             }
792         
793         }
794         
795         if (state->verbose) {
796             fprintf (stderr, "Using sector %d as backup boot sector (0 = none)\n", backup_boot);
797         }
798     
799     }
800     
801     if (!cluster_count) {
802     
803         report_at (program_name, 0, REPORT_ERROR, "Not enough clusters to make a viable filesystem");
804         
805         fclose (ofp);
806         remove (state->outfile);
807         
808         exit (EXIT_FAILURE);
809     
810     }
811
812 }
813
814 static void add_volume_label (void) {
815
816     struct msdos_dirent *de;
817     unsigned short date, xtime;
818     
819     unsigned char *scratch;
820     long offset = 0;
821     
822     if (!(scratch = (unsigned char *) malloc (512))) {
823     
824         report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
825         
826         fclose (ofp);
827         remove (state->outfile);
828         
829         exit (EXIT_FAILURE);
830     
831     }
832     
833     if (state->size_fat == 32) {
834     
835         long temp = reserved_sectors + (sectors_per_fat * 2);
836         offset += temp + ((root_cluster - 2) * sectors_per_cluster);
837     
838     } else {
839         offset += reserved_sectors + (sectors_per_fat * 2);
840     }
841     
842     if (seekto (offset * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
843     
844         report_at (program_name, 0, REPORT_ERROR, "Failed whilst reading root directory");
845         free (scratch);
846         
847         fclose (ofp);
848         remove (state->outfile);
849         
850         exit (EXIT_FAILURE);
851     
852     }
853     
854     de = (struct msdos_dirent *) scratch;
855     memset (de, 0, sizeof (*de));
856     
857     date = generate_datestamp ();
858     xtime = generate_timestamp ();
859     
860     memcpy (de->name, state->label, 11);
861     de->attr = ATTR_VOLUME_ID;
862     
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);
868     
869     if (seekto (offset * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
870     
871         report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing root directory");
872         free (scratch);
873         
874         fclose (ofp);
875         remove (state->outfile);
876         
877         exit (EXIT_FAILURE);
878     
879     }
880     
881     free (scratch);
882
883 }
884
885 static void wipe_target (void) {
886
887     unsigned int i, sectors_to_wipe = 0;
888     void *blank;
889     
890     if (!(blank = malloc (512))) {
891     
892         report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
893         
894         fclose (ofp);
895         remove (state->outfile);
896         
897         exit (EXIT_FAILURE);
898     
899     }
900     
901     memset (blank, 0, 512);
902     
903     sectors_to_wipe += reserved_sectors;
904     sectors_to_wipe += sectors_per_fat * 2;
905     
906     if (root_entries) {
907         sectors_to_wipe += (root_entries * 32) / 512;
908     } else {
909         sectors_to_wipe += 1;
910     }
911     
912     seekto (0);
913     
914     for (i = 0; i < sectors_to_wipe; i++) {
915     
916         if (fwrite (blank, 512, 1, ofp) != 1) {
917         
918             report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing blank sector");
919             free (blank);
920             
921             fclose (ofp);
922             remove (state->outfile);
923             
924             exit (EXIT_FAILURE);
925         
926         }
927     
928     }
929     
930     free (blank);
931
932 }
933
934 static void write_reserved (void) {
935
936     struct msdos_boot_sector bs;
937     struct msdos_volume_info *vi = (state->size_fat == 32 ? &bs.fstype._fat32.vi : &bs.fstype._oldfat.vi);
938     
939     memset (&bs, 0, sizeof (bs));
940     
941     if (state->boot) {
942     
943         FILE *ifp;
944         
945         if ((ifp = fopen (state->boot, "rb")) == NULL) {
946         
947             report_at (program_name, 0, REPORT_ERROR, "unable to open %s", state->boot);
948             
949             fclose (ofp);
950             remove (state->outfile);
951             
952             exit (EXIT_FAILURE);
953         
954         }
955         
956         fseek (ifp, 0, SEEK_END);
957         
958         if (ftell (ifp) != sizeof (bs)) {
959         
960             report_at (program_name, 0, REPORT_ERROR, "boot sector must be %lu bytes in size", (unsigned long) sizeof (bs));
961             fclose (ifp);
962             
963             fclose (ofp);
964             remove (state->outfile);
965             
966             exit (EXIT_FAILURE);
967         
968         }
969         
970         fseek (ifp, 0, SEEK_SET);
971         
972         if (fread (&bs, sizeof (bs), 1, ifp) != 1) {
973         
974             report_at (program_name, 0, REPORT_ERROR, "failed to read %s", state->boot);
975             fclose (ifp);
976             
977             fclose (ofp);
978             remove (state->outfile);
979             
980             exit (EXIT_FAILURE);
981         
982         }
983         
984         fclose (ifp);
985     
986     } else {
987     
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;
991         
992         if (state->size_fat == 32) {
993             memcpy (bs.fstype._fat32.boot_code, dummy_boot_code, sizeof (dummy_boot_code));
994         } else {
995             memcpy (bs.fstype._oldfat.boot_code, dummy_boot_code, sizeof (dummy_boot_code));
996         }
997         
998         bs.boot_sign[0] = 0x55;
999         bs.boot_sign[1] = 0xAA;
1000     
1001     }
1002     
1003     if (bs.boot_jump[0] != 0xEB || bs.boot_jump[1] < 0x16 || bs.boot_jump[2] != 0x90) {
1004         goto _write_reserved;
1005     }
1006     
1007     memcpy (bs.system_id, "MSWIN4.1", 8);
1008     
1009     bs.sectors_per_cluster = sectors_per_cluster;
1010     bs.no_fats = number_of_fats;
1011     bs.media_descriptor = media_descriptor;
1012     
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);
1018     
1019     if (bs.boot_jump[1] < 0x22) {
1020         goto _write_reserved;
1021     }
1022     
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);
1026     
1027     if (total_sectors > USHRT_MAX) {
1028     
1029         write721_to_byte_array (bs.total_sectors16, 0);
1030         write741_to_byte_array (bs.total_sectors32, total_sectors);
1031     
1032     }
1033     
1034     if (state->size_fat == 32) {
1035     
1036         if (bs.boot_jump[1] < 0x58) {
1037             goto _write_reserved;
1038         }
1039         
1040         write721_to_byte_array (bs.sectors_per_fat16, 0);
1041         write741_to_byte_array (bs.fstype._fat32.sectors_per_fat32, sectors_per_fat);
1042         
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);
1046         
1047         vi->drive_no = (media_descriptor == 0xF8 ? 0x80 : 0x00);
1048         vi->ext_boot_sign = 0x29;
1049         
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);
1053     
1054     } else {
1055     
1056         if (bs.boot_jump[1] != 0x3C) {
1057             goto _write_reserved;
1058         }
1059         
1060         vi->drive_no = (media_descriptor == 0xF8 ? 0x80 : 0x00);
1061         vi->ext_boot_sign = 0x29;
1062         
1063         write741_to_byte_array (vi->volume_id, generate_volume_id ());
1064         memcpy (vi->volume_label, state->label, 11);
1065         
1066         if (state->size_fat == 12) {
1067             memcpy (vi->fs_type, "FAT12   ", 8);
1068         } else {
1069             memcpy (vi->fs_type, "FAT16   ", 8);
1070         }
1071     
1072     }
1073
1074 _write_reserved:
1075
1076     seekto (0);
1077     
1078     if (fwrite (&bs, sizeof (bs), 1, ofp) != 1) {
1079     
1080         report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing %s", state->outfile);
1081         
1082         fclose (ofp);
1083         remove (state->outfile);
1084         
1085         exit (EXIT_FAILURE);
1086     
1087     }
1088     
1089     if (state->size_fat == 32) {
1090     
1091         if (info_sector) {
1092         
1093             struct fat32_fsinfo *info;
1094             unsigned char *buffer;
1095             
1096             if (seekto (info_sector * 512)) {
1097             
1098                 report_at (program_name, 0, REPORT_ERROR, "Failed whilst seeking %s", state->outfile);
1099                 
1100                 fclose (ofp);
1101                 remove (state->outfile);
1102                 
1103                 exit (EXIT_FAILURE);
1104             
1105             }
1106             
1107             if (!(buffer = (unsigned char *) malloc (512))) {
1108             
1109                 report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
1110                 
1111                 fclose (ofp);
1112                 remove (state->outfile);
1113                 
1114                 exit (EXIT_FAILURE);
1115             
1116             }
1117             
1118             memset (buffer, 0, 512);
1119             
1120             /** fsinfo structure is at offset 0x1e0 in info sector by observation. */
1121             info = (struct fat32_fsinfo *) (buffer + 0x1e0);
1122             
1123             /** Info sector magic. */
1124             buffer[0] = 'R';
1125             buffer[1] = 'R';
1126             buffer[2] = 'a';
1127             buffer[3] = 'A';
1128             
1129             /** Magic for fsinfo structure. */
1130             write741_to_byte_array (info->signature, 0x61417272);
1131             
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);
1135             
1136             /** Info sector also must have boot sign. */
1137             write721_to_byte_array (buffer + 0x1fe, 0xAA55);
1138             
1139             if (fwrite (buffer, 512, 1, ofp) != 1) {
1140             
1141                 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing info sector");
1142                 free (buffer);
1143                 
1144                 fclose (ofp);
1145                 remove (state->outfile);
1146                 
1147                 exit (EXIT_FAILURE);
1148             
1149             }
1150             
1151             free (buffer);
1152         
1153         }
1154         
1155         if (backup_boot) {
1156         
1157             if (seekto (backup_boot * 512) || fwrite (&bs, sizeof (bs), 1, ofp) != 1) {
1158             
1159                 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing info sector");
1160                 
1161                 fclose (ofp);
1162                 remove (state->outfile);
1163                 
1164                 exit (EXIT_FAILURE);
1165             
1166             }
1167         
1168         }
1169     
1170     }
1171
1172 }
1173
1174 struct vhd_footer {
1175
1176     unsigned char cookie[8];
1177     unsigned char features[4];
1178     
1179     struct {
1180     
1181         unsigned char major[2];
1182         unsigned char minor[2];
1183     
1184     } version;
1185     
1186     unsigned char next_offset[8];
1187     unsigned char modified_time[4];
1188     unsigned char creator_name[4];
1189     
1190     struct {
1191     
1192         unsigned char major[2];
1193         unsigned char minor[2];
1194     
1195     } creator_version;
1196     
1197     unsigned char creator_host[4];
1198     unsigned char disk_size[8];
1199     unsigned char data_size[8];
1200     
1201     struct {
1202     
1203         unsigned char cylinders[2];
1204         unsigned char heads_per_cyl;
1205         unsigned char secs_per_track;
1206     
1207     } disk_geom;
1208     
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];
1214
1215 };
1216
1217 int main (int argc, char **argv) {
1218
1219     if (argc && *argv) {
1220     
1221         char *p;
1222         program_name = *argv;
1223         
1224         if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {
1225             program_name = (p + 1);
1226         }
1227     
1228     }
1229     
1230     state = xmalloc (sizeof (*state));
1231     parse_args (&argc, &argv, 1);
1232     
1233     if (!state->outfile) {
1234     
1235         report_at (program_name, 0, REPORT_ERROR, "no outfile file provided");
1236         return EXIT_FAILURE;
1237     
1238     }
1239     
1240     image_size  = state->sectors * 512;
1241     image_size += state->offset * 512;
1242     
1243     if ((ofp = fopen (state->outfile, "r+b")) == NULL) {
1244     
1245         unsigned long len;
1246         void *zero;
1247         
1248         if ((ofp = fopen (state->outfile, "w+b")) == NULL) {
1249         
1250             report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", state->outfile);
1251             return EXIT_FAILURE;
1252         
1253         }
1254         
1255         len = image_size;
1256         zero = xmalloc (512);
1257         
1258         while (len > 0) {
1259         
1260             if (fwrite (zero, 512, 1, ofp) != 1) {
1261             
1262                 report_at (program_name, 0, REPORT_ERROR, "failed whilst writing '%s'", state->outfile);
1263                 fclose (ofp);
1264                 
1265                 free (zero);
1266                 remove (state->outfile);
1267                 
1268                 return EXIT_FAILURE;
1269             
1270             }
1271             
1272             len -= 512;
1273         
1274         }
1275         
1276         free (zero);
1277     
1278     } else {
1279     
1280         struct vhd_footer footer;
1281         long size = sizeof (footer);
1282         
1283         fseek (ofp, 0, SEEK_END);
1284         image_size = ftell (ofp);
1285         
1286         if (!fseek (ofp, ftell (ofp) - size, SEEK_SET)) {
1287         
1288             if (fread (&footer, size, 1, ofp) == 1) {
1289             
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) {
1291                 
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. */
1293                     image_size -= size;
1294                     image_size -= 512;
1295                 
1296                 }
1297             
1298             }
1299         
1300         }
1301     
1302     }
1303     
1304     total_sectors = image_size / 512;
1305     establish_bpb ();
1306     
1307     seekto (0);
1308     
1309     if (state->offset * 512 > image_size) {
1310     
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);
1312         
1313         fclose (ofp);
1314         remove (state->outfile);
1315         
1316         return EXIT_FAILURE;
1317     
1318     }
1319     
1320     image_size -= state->offset * 512;
1321     
1322     if (state->sectors) {
1323     
1324         if (state->sectors * 512 > image_size) {
1325         
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);
1327             
1328             fclose (ofp);
1329             remove (state->outfile);
1330             
1331             return EXIT_FAILURE;
1332         
1333         }
1334     
1335     }
1336     
1337     wipe_target ();
1338     write_reserved ();
1339     
1340     if (set_fat_entry (0, 0xFFFFFF00 | media_descriptor) < 0 || set_fat_entry (1, 0xFFFFFFFF) < 0) {
1341     
1342         report_at (program_name, 0, REPORT_ERROR, "Failed whilst setting FAT entry");
1343         
1344         fclose (ofp);
1345         remove (state->outfile);
1346         
1347         return EXIT_FAILURE;
1348     
1349     }
1350     
1351     if (state->size_fat == 32) {
1352     
1353         if (set_fat_entry (2, 0x0FFFFFF8) < 0) {
1354         
1355             report_at (program_name, 0, REPORT_ERROR, "Failed whilst setting FAT entry");
1356             
1357             fclose (ofp);
1358             remove (state->outfile);
1359             
1360             return EXIT_FAILURE;
1361         
1362         }
1363     
1364     }
1365     
1366     if (memcmp (state->label, "NO NAME    ", 11) != 0) {
1367         add_volume_label ();
1368     }
1369     
1370     fclose (ofp);
1371     return EXIT_SUCCESS;
1372
1373 }