xref: /aosp_15_r20/external/fsck_msdos/boot.c (revision 9558e6ac2e10ab0fef46fdd14187b840555f86f4)
1*9558e6acSTreehugger Robot /*-
2*9558e6acSTreehugger Robot  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*9558e6acSTreehugger Robot  *
4*9558e6acSTreehugger Robot  * Copyright (C) 1995, 1997 Wolfgang Solfrank
5*9558e6acSTreehugger Robot  * Copyright (c) 1995 Martin Husemann
6*9558e6acSTreehugger Robot  *
7*9558e6acSTreehugger Robot  * Redistribution and use in source and binary forms, with or without
8*9558e6acSTreehugger Robot  * modification, are permitted provided that the following conditions
9*9558e6acSTreehugger Robot  * are met:
10*9558e6acSTreehugger Robot  * 1. Redistributions of source code must retain the above copyright
11*9558e6acSTreehugger Robot  *    notice, this list of conditions and the following disclaimer.
12*9558e6acSTreehugger Robot  * 2. Redistributions in binary form must reproduce the above copyright
13*9558e6acSTreehugger Robot  *    notice, this list of conditions and the following disclaimer in the
14*9558e6acSTreehugger Robot  *    documentation and/or other materials provided with the distribution.
15*9558e6acSTreehugger Robot  *
16*9558e6acSTreehugger Robot  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
17*9558e6acSTreehugger Robot  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*9558e6acSTreehugger Robot  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*9558e6acSTreehugger Robot  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*9558e6acSTreehugger Robot  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*9558e6acSTreehugger Robot  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*9558e6acSTreehugger Robot  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*9558e6acSTreehugger Robot  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*9558e6acSTreehugger Robot  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*9558e6acSTreehugger Robot  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*9558e6acSTreehugger Robot  */
27*9558e6acSTreehugger Robot 
28*9558e6acSTreehugger Robot 
29*9558e6acSTreehugger Robot #include <sys/cdefs.h>
30*9558e6acSTreehugger Robot #ifndef lint
31*9558e6acSTreehugger Robot __RCSID("$NetBSD: boot.c,v 1.22 2020/01/11 16:29:07 christos Exp $");
32*9558e6acSTreehugger Robot static const char rcsid[] =
33*9558e6acSTreehugger Robot   "$FreeBSD$";
34*9558e6acSTreehugger Robot #endif /* not lint */
35*9558e6acSTreehugger Robot 
36*9558e6acSTreehugger Robot #include <sys/param.h>
37*9558e6acSTreehugger Robot 
38*9558e6acSTreehugger Robot #include <stdint.h>
39*9558e6acSTreehugger Robot #include <stdlib.h>
40*9558e6acSTreehugger Robot #include <string.h>
41*9558e6acSTreehugger Robot #include <stdio.h>
42*9558e6acSTreehugger Robot #include <unistd.h>
43*9558e6acSTreehugger Robot 
44*9558e6acSTreehugger Robot #include "ext.h"
45*9558e6acSTreehugger Robot #include "fsutil.h"
46*9558e6acSTreehugger Robot 
47*9558e6acSTreehugger Robot int
readboot(int dosfs,struct bootblock * boot)48*9558e6acSTreehugger Robot readboot(int dosfs, struct bootblock *boot)
49*9558e6acSTreehugger Robot {
50*9558e6acSTreehugger Robot 	u_char block[DOSBOOTBLOCKSIZE];
51*9558e6acSTreehugger Robot 	u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
52*9558e6acSTreehugger Robot 	int ret = FSOK;
53*9558e6acSTreehugger Robot 
54*9558e6acSTreehugger Robot 	if ((size_t)read(dosfs, block, sizeof block) != sizeof block) {
55*9558e6acSTreehugger Robot 		perr("could not read boot block");
56*9558e6acSTreehugger Robot 		return FSFATAL;
57*9558e6acSTreehugger Robot 	}
58*9558e6acSTreehugger Robot 
59*9558e6acSTreehugger Robot 	if (block[510] != 0x55 || block[511] != 0xaa) {
60*9558e6acSTreehugger Robot 		pfatal("Invalid signature in boot block: %02x%02x",
61*9558e6acSTreehugger Robot 		    block[511], block[510]);
62*9558e6acSTreehugger Robot 		return FSFATAL;
63*9558e6acSTreehugger Robot 	}
64*9558e6acSTreehugger Robot 
65*9558e6acSTreehugger Robot 	memset(boot, 0, sizeof *boot);
66*9558e6acSTreehugger Robot 	boot->ValidFat = -1;
67*9558e6acSTreehugger Robot 
68*9558e6acSTreehugger Robot 	/* Decode BIOS Parameter Block */
69*9558e6acSTreehugger Robot 
70*9558e6acSTreehugger Robot 	/* Bytes per sector: can only be  512, 1024, 2048 and 4096. */
71*9558e6acSTreehugger Robot 	boot->bpbBytesPerSec = block[11] + (block[12] << 8);
72*9558e6acSTreehugger Robot 	if (boot->bpbBytesPerSec < DOSBOOTBLOCKSIZE_REAL ||
73*9558e6acSTreehugger Robot 	    boot->bpbBytesPerSec > DOSBOOTBLOCKSIZE ||
74*9558e6acSTreehugger Robot 	    !powerof2(boot->bpbBytesPerSec)) {
75*9558e6acSTreehugger Robot 		pfatal("Invalid sector size: %u", boot->bpbBytesPerSec);
76*9558e6acSTreehugger Robot 		return FSFATAL;
77*9558e6acSTreehugger Robot 	}
78*9558e6acSTreehugger Robot 
79*9558e6acSTreehugger Robot 	/* Sectors per cluster: can only be: 1, 2, 4, 8, 16, 32, 64, 128. */
80*9558e6acSTreehugger Robot 	boot->bpbSecPerClust = block[13];
81*9558e6acSTreehugger Robot 	if (boot->bpbSecPerClust == 0 || !powerof2(boot->bpbSecPerClust)) {
82*9558e6acSTreehugger Robot 		pfatal("Invalid cluster size: %u", boot->bpbSecPerClust);
83*9558e6acSTreehugger Robot 		return FSFATAL;
84*9558e6acSTreehugger Robot 	}
85*9558e6acSTreehugger Robot 
86*9558e6acSTreehugger Robot 	/* Reserved sectors: must be non-zero */
87*9558e6acSTreehugger Robot 	boot->bpbResSectors = block[14] + (block[15] << 8);
88*9558e6acSTreehugger Robot 	if (boot->bpbResSectors < 1) {
89*9558e6acSTreehugger Robot 		pfatal("Invalid reserved sectors: %u",
90*9558e6acSTreehugger Robot 		    boot->bpbResSectors);
91*9558e6acSTreehugger Robot 		return FSFATAL;
92*9558e6acSTreehugger Robot 	}
93*9558e6acSTreehugger Robot 
94*9558e6acSTreehugger Robot 	/* Number of FATs */
95*9558e6acSTreehugger Robot 	boot->bpbFATs = block[16];
96*9558e6acSTreehugger Robot 	if (boot->bpbFATs == 0) {
97*9558e6acSTreehugger Robot 		pfatal("Invalid number of FATs: %u", boot->bpbFATs);
98*9558e6acSTreehugger Robot 		return FSFATAL;
99*9558e6acSTreehugger Robot 	}
100*9558e6acSTreehugger Robot 
101*9558e6acSTreehugger Robot 	/* Root directory entries for FAT12 and FAT16 */
102*9558e6acSTreehugger Robot 	boot->bpbRootDirEnts = block[17] + (block[18] << 8);
103*9558e6acSTreehugger Robot 	if (!boot->bpbRootDirEnts) {
104*9558e6acSTreehugger Robot 		/* bpbRootDirEnts = 0 suggests that we are FAT32 */
105*9558e6acSTreehugger Robot 		boot->flags |= FAT32;
106*9558e6acSTreehugger Robot 	}
107*9558e6acSTreehugger Robot 
108*9558e6acSTreehugger Robot 	/* Total sectors (16 bits) */
109*9558e6acSTreehugger Robot 	boot->bpbSectors = block[19] + (block[20] << 8);
110*9558e6acSTreehugger Robot 	if (boot->bpbSectors != 0 && (boot->flags & FAT32)) {
111*9558e6acSTreehugger Robot 		pfatal("Invalid 16-bit total sector count on FAT32: %u",
112*9558e6acSTreehugger Robot 		    boot->bpbSectors);
113*9558e6acSTreehugger Robot 		return FSFATAL;
114*9558e6acSTreehugger Robot 	}
115*9558e6acSTreehugger Robot 
116*9558e6acSTreehugger Robot 	/* Media type: ignored */
117*9558e6acSTreehugger Robot 	boot->bpbMedia = block[21];
118*9558e6acSTreehugger Robot 
119*9558e6acSTreehugger Robot 	/* FAT12/FAT16: 16-bit count of sectors per FAT */
120*9558e6acSTreehugger Robot 	boot->bpbFATsmall = block[22] + (block[23] << 8);
121*9558e6acSTreehugger Robot 	if (boot->bpbFATsmall != 0 && (boot->flags & FAT32)) {
122*9558e6acSTreehugger Robot 		pfatal("Invalid 16-bit FAT sector count on FAT32: %u",
123*9558e6acSTreehugger Robot 		    boot->bpbFATsmall);
124*9558e6acSTreehugger Robot 		return FSFATAL;
125*9558e6acSTreehugger Robot 	}
126*9558e6acSTreehugger Robot 
127*9558e6acSTreehugger Robot 	/* Legacy CHS geometry numbers: ignored */
128*9558e6acSTreehugger Robot 	boot->SecPerTrack = block[24] + (block[25] << 8);
129*9558e6acSTreehugger Robot 	boot->bpbHeads = block[26] + (block[27] << 8);
130*9558e6acSTreehugger Robot 
131*9558e6acSTreehugger Robot 	/* Hidden sectors: ignored */
132*9558e6acSTreehugger Robot 	boot->bpbHiddenSecs = block[28] + (block[29] << 8) +
133*9558e6acSTreehugger Robot 	    (block[30] << 16) + (block[31] << 24);
134*9558e6acSTreehugger Robot 
135*9558e6acSTreehugger Robot 	/* Total sectors (32 bits) */
136*9558e6acSTreehugger Robot 	boot->bpbHugeSectors = block[32] + (block[33] << 8) +
137*9558e6acSTreehugger Robot 	    (block[34] << 16) + (block[35] << 24);
138*9558e6acSTreehugger Robot 	if (boot->bpbHugeSectors == 0) {
139*9558e6acSTreehugger Robot 		if (boot->flags & FAT32) {
140*9558e6acSTreehugger Robot 			pfatal("FAT32 with sector count of zero");
141*9558e6acSTreehugger Robot 			return FSFATAL;
142*9558e6acSTreehugger Robot 		} else if (boot->bpbSectors == 0) {
143*9558e6acSTreehugger Robot 			pfatal("FAT with sector count of zero");
144*9558e6acSTreehugger Robot 			return FSFATAL;
145*9558e6acSTreehugger Robot 		}
146*9558e6acSTreehugger Robot 		boot->NumSectors = boot->bpbSectors;
147*9558e6acSTreehugger Robot 	} else {
148*9558e6acSTreehugger Robot 		if (boot->bpbSectors != 0) {
149*9558e6acSTreehugger Robot 			pfatal("Invalid FAT sector count");
150*9558e6acSTreehugger Robot 			return FSFATAL;
151*9558e6acSTreehugger Robot 		}
152*9558e6acSTreehugger Robot 		boot->NumSectors = boot->bpbHugeSectors;
153*9558e6acSTreehugger Robot 	}
154*9558e6acSTreehugger Robot 
155*9558e6acSTreehugger Robot 	if (boot->flags & FAT32) {
156*9558e6acSTreehugger Robot 		/* If the OEM Name field is EXFAT, it's not FAT32, so bail */
157*9558e6acSTreehugger Robot 		if (!memcmp(&block[3], "EXFAT   ", 8)) {
158*9558e6acSTreehugger Robot 			pfatal("exFAT filesystem is not supported.");
159*9558e6acSTreehugger Robot 			return FSFATAL;
160*9558e6acSTreehugger Robot 		}
161*9558e6acSTreehugger Robot 
162*9558e6acSTreehugger Robot 		/* 32-bit count of sectors per FAT */
163*9558e6acSTreehugger Robot 		boot->FATsecs = block[36] + (block[37] << 8)
164*9558e6acSTreehugger Robot 				+ (block[38] << 16) + (block[39] << 24);
165*9558e6acSTreehugger Robot 
166*9558e6acSTreehugger Robot 		if (block[40] & 0x80)
167*9558e6acSTreehugger Robot 			boot->ValidFat = block[40] & 0x0f;
168*9558e6acSTreehugger Robot 
169*9558e6acSTreehugger Robot 		/* FAT32 version, bail out if not 0.0 */
170*9558e6acSTreehugger Robot 		if (block[42] || block[43]) {
171*9558e6acSTreehugger Robot 			pfatal("Unknown file system version: %x.%x",
172*9558e6acSTreehugger Robot 			       block[43], block[42]);
173*9558e6acSTreehugger Robot 			return FSFATAL;
174*9558e6acSTreehugger Robot 		}
175*9558e6acSTreehugger Robot 
176*9558e6acSTreehugger Robot 		/*
177*9558e6acSTreehugger Robot 		 * Cluster number of the first cluster of root directory.
178*9558e6acSTreehugger Robot 		 *
179*9558e6acSTreehugger Robot 		 * Should be 2 but do not require it.
180*9558e6acSTreehugger Robot 		 */
181*9558e6acSTreehugger Robot 		boot->bpbRootClust = block[44] + (block[45] << 8)
182*9558e6acSTreehugger Robot 			       + (block[46] << 16) + (block[47] << 24);
183*9558e6acSTreehugger Robot 
184*9558e6acSTreehugger Robot 		/* Sector number of the FSInfo structure, usually 1 */
185*9558e6acSTreehugger Robot 		boot->bpbFSInfo = block[48] + (block[49] << 8);
186*9558e6acSTreehugger Robot 
187*9558e6acSTreehugger Robot 		/* Sector number of the backup boot block, ignored */
188*9558e6acSTreehugger Robot 		boot->bpbBackup = block[50] + (block[51] << 8);
189*9558e6acSTreehugger Robot 
190*9558e6acSTreehugger Robot 		/* Check basic parameters */
191*9558e6acSTreehugger Robot 		if (boot->bpbFSInfo == 0) {
192*9558e6acSTreehugger Robot 			/*
193*9558e6acSTreehugger Robot 			 * Either the BIOS Parameter Block has been corrupted,
194*9558e6acSTreehugger Robot 			 * or this is not a FAT32 filesystem, most likely an
195*9558e6acSTreehugger Robot 			 * exFAT filesystem.
196*9558e6acSTreehugger Robot 			 */
197*9558e6acSTreehugger Robot 			pfatal("Invalid FAT32 Extended BIOS Parameter Block");
198*9558e6acSTreehugger Robot 			return FSFATAL;
199*9558e6acSTreehugger Robot 		}
200*9558e6acSTreehugger Robot 
201*9558e6acSTreehugger Robot 		/* Read in and verify the FSInfo block */
202*9558e6acSTreehugger Robot 		if (lseek(dosfs, boot->bpbFSInfo * boot->bpbBytesPerSec,
203*9558e6acSTreehugger Robot 		    SEEK_SET) != boot->bpbFSInfo * boot->bpbBytesPerSec
204*9558e6acSTreehugger Robot 		    || read(dosfs, fsinfo, sizeof fsinfo) != sizeof fsinfo) {
205*9558e6acSTreehugger Robot 			perr("could not read fsinfo block");
206*9558e6acSTreehugger Robot 			return FSFATAL;
207*9558e6acSTreehugger Robot 		}
208*9558e6acSTreehugger Robot 		if (memcmp(fsinfo, "RRaA", 4)
209*9558e6acSTreehugger Robot 		    || memcmp(fsinfo + 0x1e4, "rrAa", 4)
210*9558e6acSTreehugger Robot 		    || fsinfo[0x1fc]
211*9558e6acSTreehugger Robot 		    || fsinfo[0x1fd]
212*9558e6acSTreehugger Robot 		    || fsinfo[0x1fe] != 0x55
213*9558e6acSTreehugger Robot 		    || fsinfo[0x1ff] != 0xaa
214*9558e6acSTreehugger Robot 		    || fsinfo[0x3fc]
215*9558e6acSTreehugger Robot 		    || fsinfo[0x3fd]
216*9558e6acSTreehugger Robot 		    || fsinfo[0x3fe] != 0x55
217*9558e6acSTreehugger Robot 		    || fsinfo[0x3ff] != 0xaa) {
218*9558e6acSTreehugger Robot 			pwarn("Invalid signature in fsinfo block\n");
219*9558e6acSTreehugger Robot 			if (ask(0, "Fix")) {
220*9558e6acSTreehugger Robot 				memcpy(fsinfo, "RRaA", 4);
221*9558e6acSTreehugger Robot 				memcpy(fsinfo + 0x1e4, "rrAa", 4);
222*9558e6acSTreehugger Robot 				fsinfo[0x1fc] = fsinfo[0x1fd] = 0;
223*9558e6acSTreehugger Robot 				fsinfo[0x1fe] = 0x55;
224*9558e6acSTreehugger Robot 				fsinfo[0x1ff] = 0xaa;
225*9558e6acSTreehugger Robot 				fsinfo[0x3fc] = fsinfo[0x3fd] = 0;
226*9558e6acSTreehugger Robot 				fsinfo[0x3fe] = 0x55;
227*9558e6acSTreehugger Robot 				fsinfo[0x3ff] = 0xaa;
228*9558e6acSTreehugger Robot 				if (lseek(dosfs, boot->bpbFSInfo *
229*9558e6acSTreehugger Robot 				    boot->bpbBytesPerSec, SEEK_SET)
230*9558e6acSTreehugger Robot 				    != boot->bpbFSInfo * boot->bpbBytesPerSec
231*9558e6acSTreehugger Robot 				    || write(dosfs, fsinfo, sizeof fsinfo)
232*9558e6acSTreehugger Robot 				    != sizeof fsinfo) {
233*9558e6acSTreehugger Robot 					perr("Unable to write bpbFSInfo");
234*9558e6acSTreehugger Robot 					return FSFATAL;
235*9558e6acSTreehugger Robot 				}
236*9558e6acSTreehugger Robot 				ret = FSBOOTMOD;
237*9558e6acSTreehugger Robot 			} else
238*9558e6acSTreehugger Robot 				boot->bpbFSInfo = 0;
239*9558e6acSTreehugger Robot 		} else {
240*9558e6acSTreehugger Robot 			/* We appear to have a valid FSInfo block, decode */
241*9558e6acSTreehugger Robot 			boot->FSFree = fsinfo[0x1e8] + (fsinfo[0x1e9] << 8)
242*9558e6acSTreehugger Robot 				       + (fsinfo[0x1ea] << 16)
243*9558e6acSTreehugger Robot 				       + (fsinfo[0x1eb] << 24);
244*9558e6acSTreehugger Robot 			boot->FSNext = fsinfo[0x1ec] + (fsinfo[0x1ed] << 8)
245*9558e6acSTreehugger Robot 				       + (fsinfo[0x1ee] << 16)
246*9558e6acSTreehugger Robot 				       + (fsinfo[0x1ef] << 24);
247*9558e6acSTreehugger Robot 		}
248*9558e6acSTreehugger Robot 	} else {
249*9558e6acSTreehugger Robot 		/* !FAT32: FAT12/FAT16 */
250*9558e6acSTreehugger Robot 		boot->FATsecs = boot->bpbFATsmall;
251*9558e6acSTreehugger Robot 	}
252*9558e6acSTreehugger Robot 
253*9558e6acSTreehugger Robot 	if (boot->FATsecs < 1 || boot->FATsecs > UINT32_MAX / boot->bpbFATs) {
254*9558e6acSTreehugger Robot 		pfatal("Invalid FATs(%u) with FATsecs(%zu)",
255*9558e6acSTreehugger Robot 			boot->bpbFATs, (size_t)boot->FATsecs);
256*9558e6acSTreehugger Robot 		return FSFATAL;
257*9558e6acSTreehugger Robot 	}
258*9558e6acSTreehugger Robot 
259*9558e6acSTreehugger Robot 	boot->FirstCluster = (boot->bpbRootDirEnts * 32 +
260*9558e6acSTreehugger Robot 	    boot->bpbBytesPerSec - 1) / boot->bpbBytesPerSec +
261*9558e6acSTreehugger Robot 	    boot->bpbResSectors + boot->bpbFATs * boot->FATsecs;
262*9558e6acSTreehugger Robot 
263*9558e6acSTreehugger Robot 	if (boot->FirstCluster + boot->bpbSecPerClust > boot->NumSectors) {
264*9558e6acSTreehugger Robot 		pfatal("Cluster offset too large (%u clusters)\n",
265*9558e6acSTreehugger Robot 		    boot->FirstCluster);
266*9558e6acSTreehugger Robot 		return FSFATAL;
267*9558e6acSTreehugger Robot 	}
268*9558e6acSTreehugger Robot 
269*9558e6acSTreehugger Robot 	/*
270*9558e6acSTreehugger Robot 	 * The number of clusters is derived from available data sectors,
271*9558e6acSTreehugger Robot 	 * divided by sectors per cluster.
272*9558e6acSTreehugger Robot 	 */
273*9558e6acSTreehugger Robot 	boot->NumClusters =
274*9558e6acSTreehugger Robot 	    (boot->NumSectors - boot->FirstCluster) / boot->bpbSecPerClust;
275*9558e6acSTreehugger Robot 
276*9558e6acSTreehugger Robot 	if (boot->flags & FAT32) {
277*9558e6acSTreehugger Robot 		if (boot->NumClusters > (CLUST_RSRVD & CLUST32_MASK)) {
278*9558e6acSTreehugger Robot 			pfatal("Filesystem too big (%u clusters) for FAT32 partition",
279*9558e6acSTreehugger Robot 			    boot->NumClusters);
280*9558e6acSTreehugger Robot 			return FSFATAL;
281*9558e6acSTreehugger Robot 		}
282*9558e6acSTreehugger Robot 		if (boot->NumClusters < (CLUST_RSRVD & CLUST16_MASK)) {
283*9558e6acSTreehugger Robot 			pfatal("Filesystem too small (%u clusters) for FAT32 partition",
284*9558e6acSTreehugger Robot 			    boot->NumClusters);
285*9558e6acSTreehugger Robot 			return FSFATAL;
286*9558e6acSTreehugger Robot 		}
287*9558e6acSTreehugger Robot 		boot->ClustMask = CLUST32_MASK;
288*9558e6acSTreehugger Robot 
289*9558e6acSTreehugger Robot 		if (boot->bpbRootClust < CLUST_FIRST ||
290*9558e6acSTreehugger Robot 		    boot->bpbRootClust >= boot->NumClusters) {
291*9558e6acSTreehugger Robot 			pfatal("Root directory starts with cluster out of range(%u)",
292*9558e6acSTreehugger Robot 			       boot->bpbRootClust);
293*9558e6acSTreehugger Robot 			return FSFATAL;
294*9558e6acSTreehugger Robot 		}
295*9558e6acSTreehugger Robot 	} else if (boot->NumClusters < (CLUST_RSRVD&CLUST12_MASK)) {
296*9558e6acSTreehugger Robot 		boot->ClustMask = CLUST12_MASK;
297*9558e6acSTreehugger Robot 	} else if (boot->NumClusters < (CLUST_RSRVD&CLUST16_MASK)) {
298*9558e6acSTreehugger Robot 		boot->ClustMask = CLUST16_MASK;
299*9558e6acSTreehugger Robot 	} else {
300*9558e6acSTreehugger Robot 		pfatal("Filesystem too big (%u clusters) for non-FAT32 partition",
301*9558e6acSTreehugger Robot 		       boot->NumClusters);
302*9558e6acSTreehugger Robot 		return FSFATAL;
303*9558e6acSTreehugger Robot 	}
304*9558e6acSTreehugger Robot 
305*9558e6acSTreehugger Robot 	switch (boot->ClustMask) {
306*9558e6acSTreehugger Robot 	case CLUST32_MASK:
307*9558e6acSTreehugger Robot 		boot->NumFatEntries = (boot->FATsecs * boot->bpbBytesPerSec) / 4;
308*9558e6acSTreehugger Robot 		break;
309*9558e6acSTreehugger Robot 	case CLUST16_MASK:
310*9558e6acSTreehugger Robot 		boot->NumFatEntries = (boot->FATsecs * boot->bpbBytesPerSec) / 2;
311*9558e6acSTreehugger Robot 		break;
312*9558e6acSTreehugger Robot 	default:
313*9558e6acSTreehugger Robot 		boot->NumFatEntries = (boot->FATsecs * boot->bpbBytesPerSec * 2) / 3;
314*9558e6acSTreehugger Robot 		break;
315*9558e6acSTreehugger Robot 	}
316*9558e6acSTreehugger Robot 
317*9558e6acSTreehugger Robot 	if (boot->NumFatEntries < boot->NumClusters) {
318*9558e6acSTreehugger Robot 		pfatal("FAT size too small, %u entries won't fit into %u sectors\n",
319*9558e6acSTreehugger Robot 		       boot->NumClusters, boot->FATsecs);
320*9558e6acSTreehugger Robot 		return FSFATAL;
321*9558e6acSTreehugger Robot 	}
322*9558e6acSTreehugger Robot 
323*9558e6acSTreehugger Robot 	/*
324*9558e6acSTreehugger Robot 	 * There are two reserved clusters. To avoid adding CLUST_FIRST every
325*9558e6acSTreehugger Robot 	 * time we perform boundary checks, we increment the NumClusters by 2,
326*9558e6acSTreehugger Robot 	 * which is CLUST_FIRST to denote the first out-of-range cluster number.
327*9558e6acSTreehugger Robot 	 */
328*9558e6acSTreehugger Robot 	boot->NumClusters += CLUST_FIRST;
329*9558e6acSTreehugger Robot 
330*9558e6acSTreehugger Robot 	boot->ClusterSize = boot->bpbBytesPerSec * boot->bpbSecPerClust;
331*9558e6acSTreehugger Robot 
332*9558e6acSTreehugger Robot 	boot->NumFiles = 1;
333*9558e6acSTreehugger Robot 	boot->NumFree = 0;
334*9558e6acSTreehugger Robot 
335*9558e6acSTreehugger Robot 	return ret;
336*9558e6acSTreehugger Robot }
337*9558e6acSTreehugger Robot 
338*9558e6acSTreehugger Robot int
writefsinfo(int dosfs,struct bootblock * boot)339*9558e6acSTreehugger Robot writefsinfo(int dosfs, struct bootblock *boot)
340*9558e6acSTreehugger Robot {
341*9558e6acSTreehugger Robot 	u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
342*9558e6acSTreehugger Robot 
343*9558e6acSTreehugger Robot 	if (lseek(dosfs, boot->bpbFSInfo * boot->bpbBytesPerSec, SEEK_SET)
344*9558e6acSTreehugger Robot 	    != boot->bpbFSInfo * boot->bpbBytesPerSec
345*9558e6acSTreehugger Robot 	    || read(dosfs, fsinfo, sizeof fsinfo) != sizeof fsinfo) {
346*9558e6acSTreehugger Robot 		perr("could not read fsinfo block");
347*9558e6acSTreehugger Robot 		return FSFATAL;
348*9558e6acSTreehugger Robot 	}
349*9558e6acSTreehugger Robot 	fsinfo[0x1e8] = (u_char)boot->FSFree;
350*9558e6acSTreehugger Robot 	fsinfo[0x1e9] = (u_char)(boot->FSFree >> 8);
351*9558e6acSTreehugger Robot 	fsinfo[0x1ea] = (u_char)(boot->FSFree >> 16);
352*9558e6acSTreehugger Robot 	fsinfo[0x1eb] = (u_char)(boot->FSFree >> 24);
353*9558e6acSTreehugger Robot 	fsinfo[0x1ec] = (u_char)boot->FSNext;
354*9558e6acSTreehugger Robot 	fsinfo[0x1ed] = (u_char)(boot->FSNext >> 8);
355*9558e6acSTreehugger Robot 	fsinfo[0x1ee] = (u_char)(boot->FSNext >> 16);
356*9558e6acSTreehugger Robot 	fsinfo[0x1ef] = (u_char)(boot->FSNext >> 24);
357*9558e6acSTreehugger Robot 	if (lseek(dosfs, boot->bpbFSInfo * boot->bpbBytesPerSec, SEEK_SET)
358*9558e6acSTreehugger Robot 	    != boot->bpbFSInfo * boot->bpbBytesPerSec
359*9558e6acSTreehugger Robot 	    || write(dosfs, fsinfo, sizeof fsinfo)
360*9558e6acSTreehugger Robot 	    != sizeof fsinfo) {
361*9558e6acSTreehugger Robot 		perr("Unable to write bpbFSInfo");
362*9558e6acSTreehugger Robot 		return FSFATAL;
363*9558e6acSTreehugger Robot 	}
364*9558e6acSTreehugger Robot 	/*
365*9558e6acSTreehugger Robot 	 * Technically, we should return FSBOOTMOD here.
366*9558e6acSTreehugger Robot 	 *
367*9558e6acSTreehugger Robot 	 * However, since Win95 OSR2 (the first M$ OS that has
368*9558e6acSTreehugger Robot 	 * support for FAT32) doesn't maintain the FSINFO block
369*9558e6acSTreehugger Robot 	 * correctly, it has to be fixed pretty often.
370*9558e6acSTreehugger Robot 	 *
371*9558e6acSTreehugger Robot 	 * Therefore, we handle the FSINFO block only informally,
372*9558e6acSTreehugger Robot 	 * fixing it if necessary, but otherwise ignoring the
373*9558e6acSTreehugger Robot 	 * fact that it was incorrect.
374*9558e6acSTreehugger Robot 	 */
375*9558e6acSTreehugger Robot 	return 0;
376*9558e6acSTreehugger Robot }
377