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