xref: /freebsd/sbin/fsck_msdosfs/boot.c (revision eba230afba4932f02a1ca44efc797cf7499a5cb0)
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