d752a9d464d72c702dbd6f972e69eef6586ff8d2
[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             media_descriptor = 0xfe;
401             sectors_per_track = 8;
402             heads_per_cylinder = 1;
403             break;
404         
405         case 360:                                                               /* 180KB 5.25" */
406         
407             sectors_per_cluster = 2;
408             root_entries = 112;
409             media_descriptor = 0xfc;
410             sectors_per_track = 9;
411             heads_per_cylinder = 1;
412             break;
413         
414         case 640:                                                               /* 320KB 5.25" */
415         
416             sectors_per_cluster = 2;
417             root_entries = 112;
418             media_descriptor = 0xff;
419             sectors_per_track = 8;
420             heads_per_cylinder = 2;
421             break;
422         
423         case 720:                                                               /* 360KB 5.25" */
424         
425             sectors_per_cluster = 2;
426             root_entries = 112;
427             media_descriptor = 0xfd;
428             sectors_per_track = 9;
429             heads_per_cylinder = 2;
430             break;
431         
432         case 1280:                                                              /* 640KB 5.25" / 3.5" */
433         
434             sectors_per_cluster = 2;
435             root_entries = 112;
436             media_descriptor = 0xfb;
437             sectors_per_track = 8;
438             heads_per_cylinder = 2;
439             break;
440         
441         case 1440:                                                              /* 720KB 5.25" / 3.5" */
442         
443             sectors_per_cluster = 2;
444             root_entries = 112;
445             media_descriptor = 0xf9;
446             sectors_per_track = 9;
447             heads_per_cylinder = 2;
448             break;
449         
450         case 1640:                                                              /* 820KB 3.5" */
451         
452             sectors_per_cluster = 2;
453             root_entries = 112;
454             media_descriptor = 0xf9;
455             sectors_per_track = 10;
456             heads_per_cylinder = 2;
457             break;
458         
459         case 2400:                                                              /* 1.20MB 5.25" / 3.5" */
460         
461             sectors_per_cluster = 1;
462             root_entries = 224;
463             media_descriptor = 0xf9;
464             sectors_per_track = 15;
465             heads_per_cylinder = 2;
466             break;
467         
468         case 2880:                                                              /* 1.44MB 3.5" */
469         
470             sectors_per_cluster = 1;
471             root_entries = 224;
472             media_descriptor = 0xf0;
473             sectors_per_track = 18;
474             heads_per_cylinder = 2;
475             break;
476         
477         case 3360:                                                              /* 1.68MB 3.5" */
478         
479             sectors_per_cluster = 1;
480             root_entries = 224;
481             media_descriptor = 0xf0;
482             sectors_per_track = 21;
483             heads_per_cylinder = 2;
484             break;
485         
486         case 3444:                                                              /* 1.72MB 3.5" */
487         
488             sectors_per_cluster = 1;
489             root_entries = 224;
490             media_descriptor = 0xf0;
491             sectors_per_track = 21;
492             heads_per_cylinder = 2;
493             break;
494         
495         case 5760:                                                              /* 2.88MB 3.5" */
496         
497             sectors_per_cluster = 2;
498             root_entries = 240;
499             media_descriptor = 0xf0;
500             sectors_per_track = 36;
501             heads_per_cylinder = 2;
502             break;
503     
504     }
505     
506     if (!state->size_fat && total_sectors >= 1048576) {
507         state->size_fat = 32;
508     }
509     
510     if (state->size_fat == 32) {
511     
512         root_entries = 0;
513         
514         /*
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):
517          * 
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
523          */
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);
528     
529     }
530     
531     if (state->sectors_per_cluster) {
532         sectors_per_cluster = state->sectors_per_cluster;
533     }
534     
535     if (!reserved_sectors) {
536         reserved_sectors = (state->size_fat == 32 ? 32 : 1);
537     }
538     
539     /*if (align_structures) {*/
540     
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;*/
543     
544     /*}*/
545     
546     if (total_sectors <= 8192) {
547     
548         if (align_structures && state->verbose) {
549             report_at (program_name, 0, REPORT_WARNING, "Disabling alignment due to tiny filsystem\n");
550         }
551         
552         align_structures = 0;
553     
554     }
555     
556     maxclustsize = 128;
557     root_dir_sectors = cdiv (root_entries * 32, 512);
558     
559     do {
560     
561         fatdata32 = total_sectors - align_object (reserved_sectors, sectors_per_cluster);
562         fatdata1216 = fatdata32 - align_object (root_dir_sectors, sectors_per_cluster);
563         
564         if (state->verbose) {
565             fprintf (stderr, "Trying with %d sectors/cluster:\n", sectors_per_cluster);
566         }
567         
568         /**
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.
571          */
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);
575         
576         /**
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.
580          */
581         clust12 = (fatdata1216 - number_of_fats * fatlength12) / sectors_per_cluster;
582         maxclust12 = (fatlength12 * 2 * 512) / 3;
583         
584         if (maxclust12 > MAX_CLUST_12) {
585             maxclust12 = MAX_CLUST_12;
586         }
587         
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);
590         }
591         
592         if (clust12 > maxclust12) {
593         
594             clust12 = 0;
595             
596             if (state->verbose && (state->size_fat == 0 || state->size_fat == 12)) {
597                 fprintf (stderr, "Trying FAT12: too many clusters\n");
598             }
599         
600         }
601         
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);
605         
606         /**
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.
610          */
611         clust16 = (fatdata1216 - number_of_fats * fatlength16) / sectors_per_cluster;
612         maxclust16 = (fatlength16 * 512) / 2;
613         
614         if (maxclust16 > MAX_CLUST_16) {
615             maxclust16 = MAX_CLUST_16;
616         }
617         
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);
620         }
621         
622         if (clust16 > maxclust16) {
623         
624             clust16 = 0;
625             
626             if (state->verbose && (state->size_fat == 0 || state->size_fat == 16)) {
627                 fprintf (stderr, "Trying FAT16: too many clusters\n");
628             }
629         
630         }
631         
632         /** This avoids that the filesystem will be misdetected as having a 12-bit FAT. */
633         if (clust16 && clust16 < MIN_CLUST_16) {
634         
635             clust16 = 0;
636             
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");
639             }
640         
641         }
642         
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);
646         
647         /**
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.
651          */
652         clust32 = (fatdata32 - number_of_fats * fatlength32) / sectors_per_cluster;
653         maxclust32 = (fatlength32 * 512) / 4;
654         
655         if (maxclust32 > MAX_CLUST_32) {
656             maxclust32 = MAX_CLUST_32;
657         }
658         
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);
661         }
662         
663         if (clust32 > maxclust32) {
664         
665             clust32 = 0;
666             
667             if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
668                 fprintf (stderr, "Trying FAT32: too many clusters\n");
669             }
670         
671         }
672         
673         if (clust32 && clust32 < MIN_CLUST_32 && !(state->size_fat_by_user && state->size_fat == 32)) {
674         
675             clust32 = 0;
676             
677             if (state->verbose && (state->size_fat == 0 || state->size_fat == 32)) {
678                 fprintf (stderr, "Trying FAT32: not enough clusters\n");
679             }
680         
681         }
682         
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)) {
684             break;
685         }
686         
687         sectors_per_cluster <<= 1;
688     
689     } while (sectors_per_cluster && sectors_per_cluster <= maxclustsize);
690     
691     /** Use the optimal FAT size if not specified. */
692     if (!state->size_fat) {
693     
694         state->size_fat = (clust16 > clust12 ? 16 : 12);
695         
696         if (state->verbose) {
697             report_at (program_name, 0, REPORT_WARNING, "Choosing %d-bits for FAT\n", state->size_fat);
698         }
699     
700     }
701     
702     switch (state->size_fat) {
703     
704         case 12:
705         
706             cluster_count = clust12;
707             sectors_per_fat = fatlength12;
708             break;
709         
710         case 16:
711         
712             cluster_count = clust16;
713             sectors_per_fat = fatlength16;
714             break;
715         
716         case 32:
717         
718             cluster_count = clust32;
719             sectors_per_fat = fatlength32;
720             break;
721         
722         default:
723         
724             report_at (program_name, 0, REPORT_ERROR, "FAT not 12, 16 or 32 bits");
725             
726             fclose (ofp);
727             remove (state->outfile);
728             
729             exit (EXIT_FAILURE);
730     
731     }
732     
733     /** Adjust the reserved number of sectors for alignment. */
734     reserved_sectors = align_object (reserved_sectors, sectors_per_cluster);
735     
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);
739     }
740     
741     if (state->size_fat == 32) {
742     
743         if (!info_sector) {
744             info_sector = 1;
745         }
746         
747         if (!backup_boot) {
748         
749             if (reserved_sectors >= 7 && info_sector != 6) {
750                 backup_boot = 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;
755             }
756         
757         }
758         
759         if (backup_boot) {
760         
761             if (backup_boot == info_sector) {
762             
763                 report_at (program_name, 0, REPORT_ERROR, "Backup boot sector must not be the same as the info sector (%d)", info_sector);
764                 
765                 fclose (ofp);
766                 remove (state->outfile);
767                 
768                 exit (EXIT_FAILURE);
769             
770             } else if (backup_boot >= reserved_sectors) {
771             
772                 report_at (program_name, 0, REPORT_ERROR, "Backup boot sector must be a reserved sector");
773                 
774                 fclose (ofp);
775                 remove (state->outfile);
776                 
777                 exit (EXIT_FAILURE);
778             
779             }
780         
781         }
782         
783         if (state->verbose) {
784             fprintf (stderr, "Using sector %d as backup boot sector (0 = none)\n", backup_boot);
785         }
786     
787     }
788     
789     if (!cluster_count) {
790     
791         report_at (program_name, 0, REPORT_ERROR, "Not enough clusters to make a viable filesystem");
792         
793         fclose (ofp);
794         remove (state->outfile);
795         
796         exit (EXIT_FAILURE);
797     
798     }
799
800 }
801
802 static void add_volume_label (void) {
803
804     struct msdos_dirent *de;
805     unsigned short date, xtime;
806     
807     unsigned char *scratch;
808     long offset = 0;
809     
810     if (!(scratch = (unsigned char *) malloc (512))) {
811     
812         report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
813         
814         fclose (ofp);
815         remove (state->outfile);
816         
817         exit (EXIT_FAILURE);
818     
819     }
820     
821     if (state->size_fat == 32) {
822     
823         long temp = reserved_sectors + (sectors_per_fat * 2);
824         offset += temp + ((root_cluster - 2) * sectors_per_cluster);
825     
826     } else {
827         offset += reserved_sectors + (sectors_per_fat * 2);
828     }
829     
830     if (seekto (offset * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
831     
832         report_at (program_name, 0, REPORT_ERROR, "Failed whilst reading root directory");
833         free (scratch);
834         
835         fclose (ofp);
836         remove (state->outfile);
837         
838         exit (EXIT_FAILURE);
839     
840     }
841     
842     de = (struct msdos_dirent *) scratch;
843     memset (de, 0, sizeof (*de));
844     
845     date = generate_datestamp ();
846     xtime = generate_timestamp ();
847     
848     memcpy (de->name, state->label, 11);
849     de->attr = ATTR_VOLUME_ID;
850     
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);
856     
857     if (seekto (offset * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
858     
859         report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing root directory");
860         free (scratch);
861         
862         fclose (ofp);
863         remove (state->outfile);
864         
865         exit (EXIT_FAILURE);
866     
867     }
868     
869     free (scratch);
870
871 }
872
873 static void wipe_target (void) {
874
875     unsigned int i, sectors_to_wipe = 0;
876     void *blank;
877     
878     if (!(blank = malloc (512))) {
879     
880         report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
881         
882         fclose (ofp);
883         remove (state->outfile);
884         
885         exit (EXIT_FAILURE);
886     
887     }
888     
889     memset (blank, 0, 512);
890     
891     sectors_to_wipe += reserved_sectors;
892     sectors_to_wipe += sectors_per_fat * 2;
893     
894     if (root_entries) {
895         sectors_to_wipe += (root_entries * 32) / 512;
896     } else {
897         sectors_to_wipe += 1;
898     }
899     
900     seekto (0);
901     
902     for (i = 0; i < sectors_to_wipe; i++) {
903     
904         if (fwrite (blank, 512, 1, ofp) != 1) {
905         
906             report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing blank sector");
907             free (blank);
908             
909             fclose (ofp);
910             remove (state->outfile);
911             
912             exit (EXIT_FAILURE);
913         
914         }
915     
916     }
917     
918     free (blank);
919
920 }
921
922 static void write_reserved (void) {
923
924     struct msdos_boot_sector bs;
925     struct msdos_volume_info *vi = (state->size_fat == 32 ? &bs.fstype._fat32.vi : &bs.fstype._oldfat.vi);
926     
927     memset (&bs, 0, sizeof (bs));
928     
929     if (state->boot) {
930     
931         FILE *ifp;
932         
933         if ((ifp = fopen (state->boot, "rb")) == NULL) {
934         
935             report_at (program_name, 0, REPORT_ERROR, "unable to open %s", state->boot);
936             
937             fclose (ofp);
938             remove (state->outfile);
939             
940             exit (EXIT_FAILURE);
941         
942         }
943         
944         fseek (ifp, 0, SEEK_END);
945         
946         if (ftell (ifp) != sizeof (bs)) {
947         
948             report_at (program_name, 0, REPORT_ERROR, "boot sector must be %lu bytes in size", (unsigned long) sizeof (bs));
949             fclose (ifp);
950             
951             fclose (ofp);
952             remove (state->outfile);
953             
954             exit (EXIT_FAILURE);
955         
956         }
957         
958         fseek (ifp, 0, SEEK_SET);
959         
960         if (fread (&bs, sizeof (bs), 1, ifp) != 1) {
961         
962             report_at (program_name, 0, REPORT_ERROR, "failed to read %s", state->boot);
963             fclose (ifp);
964             
965             fclose (ofp);
966             remove (state->outfile);
967             
968             exit (EXIT_FAILURE);
969         
970         }
971         
972         fclose (ifp);
973     
974     } else {
975     
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;
979         
980         if (state->size_fat == 32) {
981             memcpy (bs.fstype._fat32.boot_code, dummy_boot_code, sizeof (dummy_boot_code));
982         } else {
983             memcpy (bs.fstype._oldfat.boot_code, dummy_boot_code, sizeof (dummy_boot_code));
984         }
985         
986         bs.boot_sign[0] = 0x55;
987         bs.boot_sign[1] = 0xAA;
988     
989     }
990     
991     if (bs.boot_jump[0] != 0xEB || bs.boot_jump[1] < 0x16 || bs.boot_jump[2] != 0x90) {
992         goto _write_reserved;
993     }
994     
995     memcpy (bs.system_id, "MSWIN4.1", 8);
996     
997     bs.sectors_per_cluster = sectors_per_cluster;
998     bs.no_fats = number_of_fats;
999     bs.media_descriptor = media_descriptor;
1000     
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);
1006     
1007     if (bs.boot_jump[1] < 0x22) {
1008         goto _write_reserved;
1009     }
1010     
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);
1014     
1015     if (total_sectors > USHRT_MAX) {
1016     
1017         write721_to_byte_array (bs.total_sectors16, 0);
1018         write741_to_byte_array (bs.total_sectors32, total_sectors);
1019     
1020     }
1021     
1022     if (state->size_fat == 32) {
1023     
1024         if (bs.boot_jump[1] < 0x58) {
1025             goto _write_reserved;
1026         }
1027         
1028         write721_to_byte_array (bs.sectors_per_fat16, 0);
1029         write741_to_byte_array (bs.fstype._fat32.sectors_per_fat32, sectors_per_fat);
1030         
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);
1034         
1035         vi->drive_no = (media_descriptor == 0xF8 ? 0x80 : 0x00);
1036         vi->ext_boot_sign = 0x29;
1037         
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);
1041     
1042     } else {
1043     
1044         if (bs.boot_jump[1] != 0x3C) {
1045             goto _write_reserved;
1046         }
1047         
1048         vi->drive_no = (media_descriptor == 0xF8 ? 0x80 : 0x00);
1049         vi->ext_boot_sign = 0x29;
1050         
1051         write741_to_byte_array (vi->volume_id, generate_volume_id ());
1052         memcpy (vi->volume_label, state->label, 11);
1053         
1054         if (state->size_fat == 12) {
1055             memcpy (vi->fs_type, "FAT12   ", 8);
1056         } else {
1057             memcpy (vi->fs_type, "FAT16   ", 8);
1058         }
1059     
1060     }
1061
1062 _write_reserved:
1063
1064     seekto (0);
1065     
1066     if (fwrite (&bs, sizeof (bs), 1, ofp) != 1) {
1067     
1068         report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing %s", state->outfile);
1069         
1070         fclose (ofp);
1071         remove (state->outfile);
1072         
1073         exit (EXIT_FAILURE);
1074     
1075     }
1076     
1077     if (state->size_fat == 32) {
1078     
1079         if (info_sector) {
1080         
1081             struct fat32_fsinfo *info;
1082             unsigned char *buffer;
1083             
1084             if (seekto (info_sector * 512)) {
1085             
1086                 report_at (program_name, 0, REPORT_ERROR, "Failed whilst seeking %s", state->outfile);
1087                 
1088                 fclose (ofp);
1089                 remove (state->outfile);
1090                 
1091                 exit (EXIT_FAILURE);
1092             
1093             }
1094             
1095             if (!(buffer = (unsigned char *) malloc (512))) {
1096             
1097                 report_at (program_name, 0, REPORT_ERROR, "Failed to allocate memory");
1098                 
1099                 fclose (ofp);
1100                 remove (state->outfile);
1101                 
1102                 exit (EXIT_FAILURE);
1103             
1104             }
1105             
1106             memset (buffer, 0, 512);
1107             
1108             /** fsinfo structure is at offset 0x1e0 in info sector by observation. */
1109             info = (struct fat32_fsinfo *) (buffer + 0x1e0);
1110             
1111             /** Info sector magic. */
1112             buffer[0] = 'R';
1113             buffer[1] = 'R';
1114             buffer[2] = 'a';
1115             buffer[3] = 'A';
1116             
1117             /** Magic for fsinfo structure. */
1118             write741_to_byte_array (info->signature, 0x61417272);
1119             
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);
1123             
1124             /** Info sector also must have boot sign. */
1125             write721_to_byte_array (buffer + 0x1fe, 0xAA55);
1126             
1127             if (fwrite (buffer, 512, 1, ofp) != 1) {
1128             
1129                 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing info sector");
1130                 free (buffer);
1131                 
1132                 fclose (ofp);
1133                 remove (state->outfile);
1134                 
1135                 exit (EXIT_FAILURE);
1136             
1137             }
1138             
1139             free (buffer);
1140         
1141         }
1142         
1143         if (backup_boot) {
1144         
1145             if (seekto (backup_boot * 512) || fwrite (&bs, sizeof (bs), 1, ofp) != 1) {
1146             
1147                 report_at (program_name, 0, REPORT_ERROR, "Failed whilst writing info sector");
1148                 
1149                 fclose (ofp);
1150                 remove (state->outfile);
1151                 
1152                 exit (EXIT_FAILURE);
1153             
1154             }
1155         
1156         }
1157     
1158     }
1159
1160 }
1161
1162 struct vhd_footer {
1163
1164     unsigned char cookie[8];
1165     unsigned char features[4];
1166     
1167     struct {
1168     
1169         unsigned char major[2];
1170         unsigned char minor[2];
1171     
1172     } version;
1173     
1174     unsigned char next_offset[8];
1175     unsigned char modified_time[4];
1176     unsigned char creator_name[4];
1177     
1178     struct {
1179     
1180         unsigned char major[2];
1181         unsigned char minor[2];
1182     
1183     } creator_version;
1184     
1185     unsigned char creator_host[4];
1186     unsigned char disk_size[8];
1187     unsigned char data_size[8];
1188     
1189     struct {
1190     
1191         unsigned char cylinders[2];
1192         unsigned char heads_per_cyl;
1193         unsigned char secs_per_track;
1194     
1195     } disk_geom;
1196     
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];
1202
1203 };
1204
1205 int main (int argc, char **argv) {
1206
1207     if (argc && *argv) {
1208     
1209         char *p;
1210         program_name = *argv;
1211         
1212         if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {
1213             program_name = (p + 1);
1214         }
1215     
1216     }
1217     
1218     state = xmalloc (sizeof (*state));
1219     parse_args (&argc, &argv, 1);
1220     
1221     if (!state->outfile) {
1222     
1223         report_at (program_name, 0, REPORT_ERROR, "no outfile file provided");
1224         return EXIT_FAILURE;
1225     
1226     }
1227     
1228     image_size  = state->sectors * 512;
1229     image_size += state->offset * 512;
1230     
1231     if ((ofp = fopen (state->outfile, "r+b")) == NULL) {
1232     
1233         unsigned long len;
1234         void *zero;
1235         
1236         if ((ofp = fopen (state->outfile, "w+b")) == NULL) {
1237         
1238             report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", state->outfile);
1239             return EXIT_FAILURE;
1240         
1241         }
1242         
1243         len = image_size;
1244         zero = xmalloc (512);
1245         
1246         while (len > 0) {
1247         
1248             if (fwrite (zero, 512, 1, ofp) != 1) {
1249             
1250                 report_at (program_name, 0, REPORT_ERROR, "failed whilst writing '%s'", state->outfile);
1251                 fclose (ofp);
1252                 
1253                 free (zero);
1254                 remove (state->outfile);
1255                 
1256                 return EXIT_FAILURE;
1257             
1258             }
1259             
1260             len -= 512;
1261         
1262         }
1263         
1264         free (zero);
1265     
1266     } else {
1267     
1268         struct vhd_footer footer;
1269         long size = sizeof (footer);
1270         
1271         fseek (ofp, 0, SEEK_END);
1272         image_size = ftell (ofp);
1273         
1274         if (!fseek (ofp, ftell (ofp) - size, SEEK_SET)) {
1275         
1276             if (fread (&footer, size, 1, ofp) == 1) {
1277             
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) {
1279                 
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. */
1281                     image_size -= size;
1282                     image_size -= 512;
1283                 
1284                 }
1285             
1286             }
1287         
1288         }
1289     
1290     }
1291     
1292     total_sectors = image_size / 512;
1293     establish_bpb ();
1294     
1295     seekto (0);
1296     
1297     if (state->offset * 512 > image_size) {
1298     
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);
1300         
1301         fclose (ofp);
1302         remove (state->outfile);
1303         
1304         return EXIT_FAILURE;
1305     
1306     }
1307     
1308     image_size -= state->offset * 512;
1309     
1310     if (state->sectors) {
1311     
1312         if (state->sectors * 512 > image_size) {
1313         
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);
1315             
1316             fclose (ofp);
1317             remove (state->outfile);
1318             
1319             return EXIT_FAILURE;
1320         
1321         }
1322     
1323     }
1324     
1325     wipe_target ();
1326     write_reserved ();
1327     
1328     if (set_fat_entry (0, 0xFFFFFF00 | media_descriptor) < 0 || set_fat_entry (1, 0xFFFFFFFF) < 0) {
1329     
1330         report_at (program_name, 0, REPORT_ERROR, "Failed whilst setting FAT entry");
1331         
1332         fclose (ofp);
1333         remove (state->outfile);
1334         
1335         return EXIT_FAILURE;
1336     
1337     }
1338     
1339     if (state->size_fat == 32) {
1340     
1341         if (set_fat_entry (2, 0x0FFFFFF8) < 0) {
1342         
1343             report_at (program_name, 0, REPORT_ERROR, "Failed whilst setting FAT entry");
1344             
1345             fclose (ofp);
1346             remove (state->outfile);
1347             
1348             return EXIT_FAILURE;
1349         
1350         }
1351     
1352     }
1353     
1354     if (memcmp (state->label, "NO NAME    ", 11) != 0) {
1355         add_volume_label ();
1356     }
1357     
1358     fclose (ofp);
1359     return EXIT_SUCCESS;
1360
1361 }