11de7b4b8SPedro F. Giffuni /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
40121b42aSDavid E. O'Brien * Copyright (C) 1995, 1997 Wolfgang Solfrank
50121b42aSDavid E. O'Brien * Copyright (c) 1995 Martin Husemann
60121b42aSDavid E. O'Brien *
70121b42aSDavid E. O'Brien * Redistribution and use in source and binary forms, with or without
80121b42aSDavid E. O'Brien * modification, are permitted provided that the following conditions
90121b42aSDavid E. O'Brien * are met:
100121b42aSDavid E. O'Brien * 1. Redistributions of source code must retain the above copyright
110121b42aSDavid E. O'Brien * notice, this list of conditions and the following disclaimer.
120121b42aSDavid E. O'Brien * 2. Redistributions in binary form must reproduce the above copyright
130121b42aSDavid E. O'Brien * notice, this list of conditions and the following disclaimer in the
140121b42aSDavid E. O'Brien * documentation and/or other materials provided with the distribution.
150121b42aSDavid E. O'Brien *
160121b42aSDavid E. O'Brien * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
170121b42aSDavid E. O'Brien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
180121b42aSDavid E. O'Brien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
190121b42aSDavid E. O'Brien * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
200121b42aSDavid E. O'Brien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
210121b42aSDavid E. O'Brien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
220121b42aSDavid E. O'Brien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
230121b42aSDavid E. O'Brien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
240121b42aSDavid E. O'Brien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
250121b42aSDavid E. O'Brien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
260121b42aSDavid E. O'Brien */
270121b42aSDavid E. O'Brien
280121b42aSDavid E. O'Brien
290121b42aSDavid E. O'Brien #include <sys/cdefs.h>
300121b42aSDavid E. O'Brien #ifndef lint
3143f19409SXin LI __RCSID("$NetBSD: boot.c,v 1.22 2020/01/11 16:29:07 christos Exp $");
320121b42aSDavid E. O'Brien #endif /* not lint */
330121b42aSDavid E. O'Brien
34b770b080SXin LI #include <sys/param.h>
35b770b080SXin LI
36b770b080SXin LI #include <stdint.h>
370121b42aSDavid E. O'Brien #include <stdlib.h>
380121b42aSDavid E. O'Brien #include <string.h>
390121b42aSDavid E. O'Brien #include <stdio.h>
400121b42aSDavid E. O'Brien #include <unistd.h>
410121b42aSDavid E. O'Brien
420121b42aSDavid E. O'Brien #include "ext.h"
430121b42aSDavid E. O'Brien #include "fsutil.h"
440121b42aSDavid E. O'Brien
450121b42aSDavid E. O'Brien int
readboot(int dosfs,struct bootblock * boot)466069db97SKonstantin Belousov readboot(int dosfs, struct bootblock *boot)
470121b42aSDavid E. O'Brien {
480121b42aSDavid E. O'Brien u_char block[DOSBOOTBLOCKSIZE];
490121b42aSDavid E. O'Brien u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
500121b42aSDavid E. O'Brien int ret = FSOK;
510121b42aSDavid E. O'Brien
523bbc4438SUlrich Spörlein if ((size_t)read(dosfs, block, sizeof block) != sizeof block) {
536cf357bcSUlrich Spörlein perr("could not read boot block");
540121b42aSDavid E. O'Brien return FSFATAL;
550121b42aSDavid E. O'Brien }
560121b42aSDavid E. O'Brien
570121b42aSDavid E. O'Brien if (block[510] != 0x55 || block[511] != 0xaa) {
5848790afaSBrian Somers pfatal("Invalid signature in boot block: %02x%02x",
5948790afaSBrian Somers block[511], block[510]);
600121b42aSDavid E. O'Brien return FSFATAL;
610121b42aSDavid E. O'Brien }
620121b42aSDavid E. O'Brien
630121b42aSDavid E. O'Brien memset(boot, 0, sizeof *boot);
640121b42aSDavid E. O'Brien boot->ValidFat = -1;
650121b42aSDavid E. O'Brien
66b770b080SXin LI /* Decode BIOS Parameter Block */
67b770b080SXin LI
68b770b080SXin LI /* Bytes per sector: can only be 512, 1024, 2048 and 4096. */
6975fb5353SKonstantin Belousov boot->bpbBytesPerSec = block[11] + (block[12] << 8);
70b770b080SXin LI if (boot->bpbBytesPerSec < DOSBOOTBLOCKSIZE_REAL ||
71b770b080SXin LI boot->bpbBytesPerSec > DOSBOOTBLOCKSIZE ||
72b770b080SXin LI !powerof2(boot->bpbBytesPerSec)) {
736f0f1072SXin LI pfatal("Invalid sector size: %u", boot->bpbBytesPerSec);
746f0f1072SXin LI return FSFATAL;
756f0f1072SXin LI }
76b770b080SXin LI
77b770b080SXin LI /* Sectors per cluster: can only be: 1, 2, 4, 8, 16, 32, 64, 128. */
78b770b080SXin LI boot->bpbSecPerClust = block[13];
79b770b080SXin LI if (boot->bpbSecPerClust == 0 || !powerof2(boot->bpbSecPerClust)) {
80b770b080SXin LI pfatal("Invalid cluster size: %u", boot->bpbSecPerClust);
81b770b080SXin LI return FSFATAL;
82b770b080SXin LI }
83b770b080SXin LI
84b770b080SXin LI /* Reserved sectors: must be non-zero */
85b770b080SXin LI boot->bpbResSectors = block[14] + (block[15] << 8);
86b770b080SXin LI if (boot->bpbResSectors < 1) {
87b770b080SXin LI pfatal("Invalid reserved sectors: %u",
88b770b080SXin LI boot->bpbResSectors);
89b770b080SXin LI return FSFATAL;
90b770b080SXin LI }
91b770b080SXin LI
92b770b080SXin LI /* Number of FATs */
93b770b080SXin LI boot->bpbFATs = block[16];
947f2b7ec9SXin LI if (boot->bpbFATs == 0) {
957f2b7ec9SXin LI pfatal("Invalid number of FATs: %u", boot->bpbFATs);
967f2b7ec9SXin LI return FSFATAL;
977f2b7ec9SXin LI }
980121b42aSDavid E. O'Brien
99b770b080SXin LI /* Root directory entries for FAT12 and FAT16 */
100b770b080SXin LI boot->bpbRootDirEnts = block[17] + (block[18] << 8);
101b770b080SXin LI if (!boot->bpbRootDirEnts) {
102b770b080SXin LI /* bpbRootDirEnts = 0 suggests that we are FAT32 */
103b770b080SXin LI boot->flags |= FAT32;
104b770b080SXin LI }
105b770b080SXin LI
106b770b080SXin LI /* Total sectors (16 bits) */
107b770b080SXin LI boot->bpbSectors = block[19] + (block[20] << 8);
108b770b080SXin LI if (boot->bpbSectors != 0 && (boot->flags & FAT32)) {
109b770b080SXin LI pfatal("Invalid 16-bit total sector count on FAT32: %u",
110b770b080SXin LI boot->bpbSectors);
1110121b42aSDavid E. O'Brien return FSFATAL;
1120121b42aSDavid E. O'Brien }
1130121b42aSDavid E. O'Brien
114b770b080SXin LI /* Media type: ignored */
115b770b080SXin LI boot->bpbMedia = block[21];
116b770b080SXin LI
117b770b080SXin LI /* FAT12/FAT16: 16-bit count of sectors per FAT */
118b770b080SXin LI boot->bpbFATsmall = block[22] + (block[23] << 8);
119b770b080SXin LI if (boot->bpbFATsmall != 0 && (boot->flags & FAT32)) {
120b770b080SXin LI pfatal("Invalid 16-bit FAT sector count on FAT32: %u",
121b770b080SXin LI boot->bpbFATsmall);
122b770b080SXin LI return FSFATAL;
123b770b080SXin LI }
124b770b080SXin LI
125b770b080SXin LI /* Legacy CHS geometry numbers: ignored */
126b770b080SXin LI boot->SecPerTrack = block[24] + (block[25] << 8);
127b770b080SXin LI boot->bpbHeads = block[26] + (block[27] << 8);
128b770b080SXin LI
129b770b080SXin LI /* Hidden sectors: ignored */
130b770b080SXin LI boot->bpbHiddenSecs = block[28] + (block[29] << 8) +
131b770b080SXin LI (block[30] << 16) + (block[31] << 24);
132b770b080SXin LI
133b770b080SXin LI /* Total sectors (32 bits) */
134b770b080SXin LI boot->bpbHugeSectors = block[32] + (block[33] << 8) +
135b770b080SXin LI (block[34] << 16) + (block[35] << 24);
136b770b080SXin LI if (boot->bpbHugeSectors == 0) {
137b770b080SXin LI if (boot->flags & FAT32) {
138b770b080SXin LI pfatal("FAT32 with sector count of zero");
139b770b080SXin LI return FSFATAL;
140b770b080SXin LI } else if (boot->bpbSectors == 0) {
141b770b080SXin LI pfatal("FAT with sector count of zero");
142b770b080SXin LI return FSFATAL;
143b770b080SXin LI }
144b770b080SXin LI boot->NumSectors = boot->bpbSectors;
145b770b080SXin LI } else {
146b770b080SXin LI if (boot->bpbSectors != 0) {
147b770b080SXin LI pfatal("Invalid FAT sector count");
148b770b080SXin LI return FSFATAL;
149b770b080SXin LI }
150b770b080SXin LI boot->NumSectors = boot->bpbHugeSectors;
151b770b080SXin LI }
152b770b080SXin LI
153b770b080SXin LI if (boot->flags & FAT32) {
1546f0f1072SXin LI /* If the OEM Name field is EXFAT, it's not FAT32, so bail */
1556f0f1072SXin LI if (!memcmp(&block[3], "EXFAT ", 8)) {
1566f0f1072SXin LI pfatal("exFAT filesystem is not supported.");
1576f0f1072SXin LI return FSFATAL;
1586f0f1072SXin LI }
1596f0f1072SXin LI
160b770b080SXin LI /* 32-bit count of sectors per FAT */
161b770b080SXin LI boot->FATsecs = block[36] + (block[37] << 8)
162b770b080SXin LI + (block[38] << 16) + (block[39] << 24);
163b770b080SXin LI
164b770b080SXin LI if (block[40] & 0x80)
165b770b080SXin LI boot->ValidFat = block[40] & 0x0f;
166b770b080SXin LI
167b770b080SXin LI /* FAT32 version, bail out if not 0.0 */
168b770b080SXin LI if (block[42] || block[43]) {
169b770b080SXin LI pfatal("Unknown file system version: %x.%x",
170b770b080SXin LI block[43], block[42]);
171b770b080SXin LI return FSFATAL;
172b770b080SXin LI }
173b770b080SXin LI
174b770b080SXin LI /*
175b770b080SXin LI * Cluster number of the first cluster of root directory.
176b770b080SXin LI *
177b770b080SXin LI * Should be 2 but do not require it.
178b770b080SXin LI */
179b770b080SXin LI boot->bpbRootClust = block[44] + (block[45] << 8)
180b770b080SXin LI + (block[46] << 16) + (block[47] << 24);
181b770b080SXin LI
182b770b080SXin LI /* Sector number of the FSInfo structure, usually 1 */
183b770b080SXin LI boot->bpbFSInfo = block[48] + (block[49] << 8);
184b770b080SXin LI
185b770b080SXin LI /* Sector number of the backup boot block, ignored */
186b770b080SXin LI boot->bpbBackup = block[50] + (block[51] << 8);
187b770b080SXin LI
188b770b080SXin LI /* Check basic parameters */
189b770b080SXin LI if (boot->bpbFSInfo == 0) {
1906f0f1072SXin LI /*
1916f0f1072SXin LI * Either the BIOS Parameter Block has been corrupted,
1926f0f1072SXin LI * or this is not a FAT32 filesystem, most likely an
1936f0f1072SXin LI * exFAT filesystem.
1946f0f1072SXin LI */
1956f0f1072SXin LI pfatal("Invalid FAT32 Extended BIOS Parameter Block");
1966f0f1072SXin LI return FSFATAL;
1976f0f1072SXin LI }
198b770b080SXin LI
199b770b080SXin LI /* Read in and verify the FSInfo block */
20048790afaSBrian Somers if (lseek(dosfs, boot->bpbFSInfo * boot->bpbBytesPerSec,
20148790afaSBrian Somers SEEK_SET) != boot->bpbFSInfo * boot->bpbBytesPerSec
20248790afaSBrian Somers || read(dosfs, fsinfo, sizeof fsinfo) != sizeof fsinfo) {
2036cf357bcSUlrich Spörlein perr("could not read fsinfo block");
2040121b42aSDavid E. O'Brien return FSFATAL;
2050121b42aSDavid E. O'Brien }
2060121b42aSDavid E. O'Brien if (memcmp(fsinfo, "RRaA", 4)
2070121b42aSDavid E. O'Brien || memcmp(fsinfo + 0x1e4, "rrAa", 4)
2080121b42aSDavid E. O'Brien || fsinfo[0x1fc]
2090121b42aSDavid E. O'Brien || fsinfo[0x1fd]
2100121b42aSDavid E. O'Brien || fsinfo[0x1fe] != 0x55
2110121b42aSDavid E. O'Brien || fsinfo[0x1ff] != 0xaa
2120121b42aSDavid E. O'Brien || fsinfo[0x3fc]
2130121b42aSDavid E. O'Brien || fsinfo[0x3fd]
2140121b42aSDavid E. O'Brien || fsinfo[0x3fe] != 0x55
2150121b42aSDavid E. O'Brien || fsinfo[0x3ff] != 0xaa) {
216dc401d49SYaroslav Tykhiy pwarn("Invalid signature in fsinfo block\n");
217dc401d49SYaroslav Tykhiy if (ask(0, "Fix")) {
2180121b42aSDavid E. O'Brien memcpy(fsinfo, "RRaA", 4);
2190121b42aSDavid E. O'Brien memcpy(fsinfo + 0x1e4, "rrAa", 4);
2200121b42aSDavid E. O'Brien fsinfo[0x1fc] = fsinfo[0x1fd] = 0;
2210121b42aSDavid E. O'Brien fsinfo[0x1fe] = 0x55;
2220121b42aSDavid E. O'Brien fsinfo[0x1ff] = 0xaa;
2230121b42aSDavid E. O'Brien fsinfo[0x3fc] = fsinfo[0x3fd] = 0;
2240121b42aSDavid E. O'Brien fsinfo[0x3fe] = 0x55;
2250121b42aSDavid E. O'Brien fsinfo[0x3ff] = 0xaa;
22648790afaSBrian Somers if (lseek(dosfs, boot->bpbFSInfo *
22748790afaSBrian Somers boot->bpbBytesPerSec, SEEK_SET)
22875fb5353SKonstantin Belousov != boot->bpbFSInfo * boot->bpbBytesPerSec
2290121b42aSDavid E. O'Brien || write(dosfs, fsinfo, sizeof fsinfo)
2300121b42aSDavid E. O'Brien != sizeof fsinfo) {
2316cf357bcSUlrich Spörlein perr("Unable to write bpbFSInfo");
2320121b42aSDavid E. O'Brien return FSFATAL;
2330121b42aSDavid E. O'Brien }
2340121b42aSDavid E. O'Brien ret = FSBOOTMOD;
2350121b42aSDavid E. O'Brien } else
23675fb5353SKonstantin Belousov boot->bpbFSInfo = 0;
237b770b080SXin LI } else {
238b770b080SXin LI /* We appear to have a valid FSInfo block, decode */
2390121b42aSDavid E. O'Brien boot->FSFree = fsinfo[0x1e8] + (fsinfo[0x1e9] << 8)
2400121b42aSDavid E. O'Brien + (fsinfo[0x1ea] << 16)
2410121b42aSDavid E. O'Brien + (fsinfo[0x1eb] << 24);
2420121b42aSDavid E. O'Brien boot->FSNext = fsinfo[0x1ec] + (fsinfo[0x1ed] << 8)
2430121b42aSDavid E. O'Brien + (fsinfo[0x1ee] << 16)
2440121b42aSDavid E. O'Brien + (fsinfo[0x1ef] << 24);
2450121b42aSDavid E. O'Brien }
246b770b080SXin LI } else {
247b770b080SXin LI /* !FAT32: FAT12/FAT16 */
248b770b080SXin LI boot->FATsecs = boot->bpbFATsmall;
2490121b42aSDavid E. O'Brien }
2500121b42aSDavid E. O'Brien
251ed0879d9SXin LI if (boot->FATsecs < 1 || boot->FATsecs > UINT32_MAX / boot->bpbFATs) {
252b770b080SXin LI pfatal("Invalid FATs(%u) with FATsecs(%zu)",
253b770b080SXin LI boot->bpbFATs, (size_t)boot->FATsecs);
2540121b42aSDavid E. O'Brien return FSFATAL;
2550121b42aSDavid E. O'Brien }
256b770b080SXin LI
257eb1c42c1SXin LI boot->FirstCluster = (boot->bpbRootDirEnts * 32 +
258f7a30054SXin LI boot->bpbBytesPerSec - 1) / boot->bpbBytesPerSec +
259eb1c42c1SXin LI boot->bpbResSectors + boot->bpbFATs * boot->FATsecs;
260eb1c42c1SXin LI
261eb1c42c1SXin LI if (boot->FirstCluster + boot->bpbSecPerClust > boot->NumSectors) {
262eb1c42c1SXin LI pfatal("Cluster offset too large (%u clusters)\n",
263eb1c42c1SXin LI boot->FirstCluster);
264eb1c42c1SXin LI return FSFATAL;
265eb1c42c1SXin LI }
266eb1c42c1SXin LI
267d3dd6679SXin LI /*
26843f19409SXin LI * The number of clusters is derived from available data sectors,
26943f19409SXin LI * divided by sectors per cluster.
270d3dd6679SXin LI */
27143f19409SXin LI boot->NumClusters =
27243f19409SXin LI (boot->NumSectors - boot->FirstCluster) / boot->bpbSecPerClust;
2730121b42aSDavid E. O'Brien
2749708ba9fSXin LI if (boot->flags & FAT32) {
2759708ba9fSXin LI if (boot->NumClusters > (CLUST_RSRVD & CLUST32_MASK)) {
2769708ba9fSXin LI pfatal("Filesystem too big (%u clusters) for FAT32 partition",
2779708ba9fSXin LI boot->NumClusters);
2789708ba9fSXin LI return FSFATAL;
2799708ba9fSXin LI }
2809708ba9fSXin LI if (boot->NumClusters < (CLUST_RSRVD & CLUST16_MASK)) {
2819708ba9fSXin LI pfatal("Filesystem too small (%u clusters) for FAT32 partition",
2829708ba9fSXin LI boot->NumClusters);
2839708ba9fSXin LI return FSFATAL;
2849708ba9fSXin LI }
2850121b42aSDavid E. O'Brien boot->ClustMask = CLUST32_MASK;
2869708ba9fSXin LI
2879708ba9fSXin LI if (boot->bpbRootClust < CLUST_FIRST ||
2889708ba9fSXin LI boot->bpbRootClust >= boot->NumClusters) {
2899708ba9fSXin LI pfatal("Root directory starts with cluster out of range(%u)",
2909708ba9fSXin LI boot->bpbRootClust);
2919708ba9fSXin LI return FSFATAL;
2929708ba9fSXin LI }
2939708ba9fSXin LI } else if (boot->NumClusters < (CLUST_RSRVD&CLUST12_MASK)) {
2940121b42aSDavid E. O'Brien boot->ClustMask = CLUST12_MASK;
2959708ba9fSXin LI } else if (boot->NumClusters < (CLUST_RSRVD&CLUST16_MASK)) {
2960121b42aSDavid E. O'Brien boot->ClustMask = CLUST16_MASK;
2979708ba9fSXin LI } else {
2980121b42aSDavid E. O'Brien pfatal("Filesystem too big (%u clusters) for non-FAT32 partition",
2990121b42aSDavid E. O'Brien boot->NumClusters);
3000121b42aSDavid E. O'Brien return FSFATAL;
3010121b42aSDavid E. O'Brien }
3020121b42aSDavid E. O'Brien
3030121b42aSDavid E. O'Brien switch (boot->ClustMask) {
3040121b42aSDavid E. O'Brien case CLUST32_MASK:
30575fb5353SKonstantin Belousov boot->NumFatEntries = (boot->FATsecs * boot->bpbBytesPerSec) / 4;
3060121b42aSDavid E. O'Brien break;
3070121b42aSDavid E. O'Brien case CLUST16_MASK:
30875fb5353SKonstantin Belousov boot->NumFatEntries = (boot->FATsecs * boot->bpbBytesPerSec) / 2;
3090121b42aSDavid E. O'Brien break;
3100121b42aSDavid E. O'Brien default:
31175fb5353SKonstantin Belousov boot->NumFatEntries = (boot->FATsecs * boot->bpbBytesPerSec * 2) / 3;
3120121b42aSDavid E. O'Brien break;
3130121b42aSDavid E. O'Brien }
3140121b42aSDavid E. O'Brien
315d3dd6679SXin LI if (boot->NumFatEntries < boot->NumClusters) {
3160121b42aSDavid E. O'Brien pfatal("FAT size too small, %u entries won't fit into %u sectors\n",
3170121b42aSDavid E. O'Brien boot->NumClusters, boot->FATsecs);
3180121b42aSDavid E. O'Brien return FSFATAL;
3190121b42aSDavid E. O'Brien }
320d3dd6679SXin LI
321d3dd6679SXin LI /*
32243f19409SXin LI * There are two reserved clusters. To avoid adding CLUST_FIRST every
32343f19409SXin LI * time we perform boundary checks, we increment the NumClusters by 2,
324d3dd6679SXin LI * which is CLUST_FIRST to denote the first out-of-range cluster number.
325d3dd6679SXin LI */
326d3dd6679SXin LI boot->NumClusters += CLUST_FIRST;
327d3dd6679SXin LI
32875fb5353SKonstantin Belousov boot->ClusterSize = boot->bpbBytesPerSec * boot->bpbSecPerClust;
3290121b42aSDavid E. O'Brien
3300121b42aSDavid E. O'Brien boot->NumFiles = 1;
3310121b42aSDavid E. O'Brien boot->NumFree = 0;
3320121b42aSDavid E. O'Brien
3330121b42aSDavid E. O'Brien return ret;
3340121b42aSDavid E. O'Brien }
3350121b42aSDavid E. O'Brien
3360121b42aSDavid E. O'Brien int
writefsinfo(int dosfs,struct bootblock * boot)3376069db97SKonstantin Belousov writefsinfo(int dosfs, struct bootblock *boot)
3380121b42aSDavid E. O'Brien {
3390121b42aSDavid E. O'Brien u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
3400121b42aSDavid E. O'Brien
34175fb5353SKonstantin Belousov if (lseek(dosfs, boot->bpbFSInfo * boot->bpbBytesPerSec, SEEK_SET)
34275fb5353SKonstantin Belousov != boot->bpbFSInfo * boot->bpbBytesPerSec
3430121b42aSDavid E. O'Brien || read(dosfs, fsinfo, sizeof fsinfo) != sizeof fsinfo) {
3446cf357bcSUlrich Spörlein perr("could not read fsinfo block");
3450121b42aSDavid E. O'Brien return FSFATAL;
3460121b42aSDavid E. O'Brien }
3470121b42aSDavid E. O'Brien fsinfo[0x1e8] = (u_char)boot->FSFree;
3480121b42aSDavid E. O'Brien fsinfo[0x1e9] = (u_char)(boot->FSFree >> 8);
3490121b42aSDavid E. O'Brien fsinfo[0x1ea] = (u_char)(boot->FSFree >> 16);
3500121b42aSDavid E. O'Brien fsinfo[0x1eb] = (u_char)(boot->FSFree >> 24);
3510121b42aSDavid E. O'Brien fsinfo[0x1ec] = (u_char)boot->FSNext;
3520121b42aSDavid E. O'Brien fsinfo[0x1ed] = (u_char)(boot->FSNext >> 8);
3530121b42aSDavid E. O'Brien fsinfo[0x1ee] = (u_char)(boot->FSNext >> 16);
3540121b42aSDavid E. O'Brien fsinfo[0x1ef] = (u_char)(boot->FSNext >> 24);
35575fb5353SKonstantin Belousov if (lseek(dosfs, boot->bpbFSInfo * boot->bpbBytesPerSec, SEEK_SET)
35675fb5353SKonstantin Belousov != boot->bpbFSInfo * boot->bpbBytesPerSec
3570121b42aSDavid E. O'Brien || write(dosfs, fsinfo, sizeof fsinfo)
3580121b42aSDavid E. O'Brien != sizeof fsinfo) {
3596cf357bcSUlrich Spörlein perr("Unable to write bpbFSInfo");
3600121b42aSDavid E. O'Brien return FSFATAL;
3610121b42aSDavid E. O'Brien }
3620121b42aSDavid E. O'Brien /*
3630121b42aSDavid E. O'Brien * Technically, we should return FSBOOTMOD here.
3640121b42aSDavid E. O'Brien *
3650121b42aSDavid E. O'Brien * However, since Win95 OSR2 (the first M$ OS that has
3660121b42aSDavid E. O'Brien * support for FAT32) doesn't maintain the FSINFO block
3670121b42aSDavid E. O'Brien * correctly, it has to be fixed pretty often.
3680121b42aSDavid E. O'Brien *
369727d995cSXin LI * Therefore, we handle the FSINFO block only informally,
3704029695dSTim J. Robbins * fixing it if necessary, but otherwise ignoring the
3710121b42aSDavid E. O'Brien * fact that it was incorrect.
3720121b42aSDavid E. O'Brien */
3730121b42aSDavid E. O'Brien return 0;
3740121b42aSDavid E. O'Brien }
375