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