158d4c6c35633437182289e3d226d156d31d3e801San Mehat/*
258d4c6c35633437182289e3d226d156d31d3e801San Mehat * Copyright (C) 1995, 1997 Wolfgang Solfrank
358d4c6c35633437182289e3d226d156d31d3e801San Mehat * Copyright (c) 1995 Martin Husemann
458d4c6c35633437182289e3d226d156d31d3e801San Mehat *
558d4c6c35633437182289e3d226d156d31d3e801San Mehat * Redistribution and use in source and binary forms, with or without
658d4c6c35633437182289e3d226d156d31d3e801San Mehat * modification, are permitted provided that the following conditions
758d4c6c35633437182289e3d226d156d31d3e801San Mehat * are met:
858d4c6c35633437182289e3d226d156d31d3e801San Mehat * 1. Redistributions of source code must retain the above copyright
958d4c6c35633437182289e3d226d156d31d3e801San Mehat *    notice, this list of conditions and the following disclaimer.
1058d4c6c35633437182289e3d226d156d31d3e801San Mehat * 2. Redistributions in binary form must reproduce the above copyright
1158d4c6c35633437182289e3d226d156d31d3e801San Mehat *    notice, this list of conditions and the following disclaimer in the
1258d4c6c35633437182289e3d226d156d31d3e801San Mehat *    documentation and/or other materials provided with the distribution.
1358d4c6c35633437182289e3d226d156d31d3e801San Mehat * 3. All advertising materials mentioning features or use of this software
1458d4c6c35633437182289e3d226d156d31d3e801San Mehat *    must display the following acknowledgement:
1558d4c6c35633437182289e3d226d156d31d3e801San Mehat *	This product includes software developed by Martin Husemann
1658d4c6c35633437182289e3d226d156d31d3e801San Mehat *	and Wolfgang Solfrank.
1758d4c6c35633437182289e3d226d156d31d3e801San Mehat * 4. Neither the name of the University nor the names of its contributors
1858d4c6c35633437182289e3d226d156d31d3e801San Mehat *    may be used to endorse or promote products derived from this software
1958d4c6c35633437182289e3d226d156d31d3e801San Mehat *    without specific prior written permission.
2058d4c6c35633437182289e3d226d156d31d3e801San Mehat *
2158d4c6c35633437182289e3d226d156d31d3e801San Mehat * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
2258d4c6c35633437182289e3d226d156d31d3e801San Mehat * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2358d4c6c35633437182289e3d226d156d31d3e801San Mehat * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2458d4c6c35633437182289e3d226d156d31d3e801San Mehat * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2558d4c6c35633437182289e3d226d156d31d3e801San Mehat * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2658d4c6c35633437182289e3d226d156d31d3e801San Mehat * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2758d4c6c35633437182289e3d226d156d31d3e801San Mehat * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2858d4c6c35633437182289e3d226d156d31d3e801San Mehat * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2958d4c6c35633437182289e3d226d156d31d3e801San Mehat * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3058d4c6c35633437182289e3d226d156d31d3e801San Mehat * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3158d4c6c35633437182289e3d226d156d31d3e801San Mehat */
3258d4c6c35633437182289e3d226d156d31d3e801San Mehat
3358d4c6c35633437182289e3d226d156d31d3e801San Mehat
3458d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <sys/cdefs.h>
3558d4c6c35633437182289e3d226d156d31d3e801San Mehat#ifndef lint
3658d4c6c35633437182289e3d226d156d31d3e801San Mehat__RCSID("$NetBSD: boot.c,v 1.9 2003/07/24 19:25:46 ws Exp $");
3758d4c6c35633437182289e3d226d156d31d3e801San Mehatstatic const char rcsid[] =
3858d4c6c35633437182289e3d226d156d31d3e801San Mehat  "$FreeBSD: src/sbin/fsck_msdosfs/boot.c,v 1.4.28.1 2009/04/15 03:14:26 kensmith Exp $";
3958d4c6c35633437182289e3d226d156d31d3e801San Mehat#endif /* not lint */
4058d4c6c35633437182289e3d226d156d31d3e801San Mehat
4158d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <stdlib.h>
4258d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <string.h>
4358d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <ctype.h>
4458d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <stdio.h>
4558d4c6c35633437182289e3d226d156d31d3e801San Mehat#include <unistd.h>
4658d4c6c35633437182289e3d226d156d31d3e801San Mehat
4758d4c6c35633437182289e3d226d156d31d3e801San Mehat#include "ext.h"
4858d4c6c35633437182289e3d226d156d31d3e801San Mehat#include "fsutil.h"
4958d4c6c35633437182289e3d226d156d31d3e801San Mehat
5058d4c6c35633437182289e3d226d156d31d3e801San Mehatint
5158d4c6c35633437182289e3d226d156d31d3e801San Mehatreadboot(dosfs, boot)
5258d4c6c35633437182289e3d226d156d31d3e801San Mehat	int dosfs;
5358d4c6c35633437182289e3d226d156d31d3e801San Mehat	struct bootblock *boot;
5458d4c6c35633437182289e3d226d156d31d3e801San Mehat{
5558d4c6c35633437182289e3d226d156d31d3e801San Mehat	u_char block[DOSBOOTBLOCKSIZE];
5658d4c6c35633437182289e3d226d156d31d3e801San Mehat	u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
5758d4c6c35633437182289e3d226d156d31d3e801San Mehat	u_char backup[DOSBOOTBLOCKSIZE];
5858d4c6c35633437182289e3d226d156d31d3e801San Mehat	int ret = FSOK;
5958d4c6c35633437182289e3d226d156d31d3e801San Mehat
6058d4c6c35633437182289e3d226d156d31d3e801San Mehat	if (read(dosfs, block, sizeof block) < sizeof block) {
6158d4c6c35633437182289e3d226d156d31d3e801San Mehat		perror("could not read boot block");
6258d4c6c35633437182289e3d226d156d31d3e801San Mehat                exit(2);
6358d4c6c35633437182289e3d226d156d31d3e801San Mehat	}
6458d4c6c35633437182289e3d226d156d31d3e801San Mehat
6558d4c6c35633437182289e3d226d156d31d3e801San Mehat	if (block[510] != 0x55 || block[511] != 0xaa) {
6658d4c6c35633437182289e3d226d156d31d3e801San Mehat		pfatal("Invalid signature in boot block: %02x%02x", block[511], block[510]);
6758d4c6c35633437182289e3d226d156d31d3e801San Mehat                exit(2);
6858d4c6c35633437182289e3d226d156d31d3e801San Mehat	}
6958d4c6c35633437182289e3d226d156d31d3e801San Mehat
7058d4c6c35633437182289e3d226d156d31d3e801San Mehat	memset(boot, 0, sizeof *boot);
7158d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->ValidFat = -1;
7258d4c6c35633437182289e3d226d156d31d3e801San Mehat
7358d4c6c35633437182289e3d226d156d31d3e801San Mehat	/* decode bios parameter block */
7458d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->BytesPerSec = block[11] + (block[12] << 8);
7558d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->SecPerClust = block[13];
7658d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->ResSectors = block[14] + (block[15] << 8);
7758d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->FATs = block[16];
7858d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->RootDirEnts = block[17] + (block[18] << 8);
7958d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->Sectors = block[19] + (block[20] << 8);
8058d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->Media = block[21];
8158d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->FATsmall = block[22] + (block[23] << 8);
8258d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->SecPerTrack = block[24] + (block[25] << 8);
8358d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->Heads = block[26] + (block[27] << 8);
8458d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->HiddenSecs = block[28] + (block[29] << 8) + (block[30] << 16) + (block[31] << 24);
8558d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->HugeSectors = block[32] + (block[33] << 8) + (block[34] << 16) + (block[35] << 24);
8658d4c6c35633437182289e3d226d156d31d3e801San Mehat
8758d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->FATsecs = boot->FATsmall;
8858d4c6c35633437182289e3d226d156d31d3e801San Mehat
8958d4c6c35633437182289e3d226d156d31d3e801San Mehat	if (!boot->RootDirEnts)
9058d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->flags |= FAT32;
9158d4c6c35633437182289e3d226d156d31d3e801San Mehat	if (boot->flags & FAT32) {
9258d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->FATsecs = block[36] + (block[37] << 8)
9358d4c6c35633437182289e3d226d156d31d3e801San Mehat				+ (block[38] << 16) + (block[39] << 24);
9458d4c6c35633437182289e3d226d156d31d3e801San Mehat		if (block[40] & 0x80)
9558d4c6c35633437182289e3d226d156d31d3e801San Mehat			boot->ValidFat = block[40] & 0x0f;
9658d4c6c35633437182289e3d226d156d31d3e801San Mehat
9758d4c6c35633437182289e3d226d156d31d3e801San Mehat		/* check version number: */
9858d4c6c35633437182289e3d226d156d31d3e801San Mehat		if (block[42] || block[43]) {
9958d4c6c35633437182289e3d226d156d31d3e801San Mehat			/* Correct?				XXX */
10058d4c6c35633437182289e3d226d156d31d3e801San Mehat			pfatal("Unknown file system version: %x.%x",
10158d4c6c35633437182289e3d226d156d31d3e801San Mehat			       block[43], block[42]);
10258d4c6c35633437182289e3d226d156d31d3e801San Mehat                        exit(2);
10358d4c6c35633437182289e3d226d156d31d3e801San Mehat		}
10458d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->RootCl = block[44] + (block[45] << 8)
10558d4c6c35633437182289e3d226d156d31d3e801San Mehat			       + (block[46] << 16) + (block[47] << 24);
10658d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->FSInfo = block[48] + (block[49] << 8);
10758d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->Backup = block[50] + (block[51] << 8);
10858d4c6c35633437182289e3d226d156d31d3e801San Mehat
10958d4c6c35633437182289e3d226d156d31d3e801San Mehat		if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
11058d4c6c35633437182289e3d226d156d31d3e801San Mehat		    != boot->FSInfo * boot->BytesPerSec
11158d4c6c35633437182289e3d226d156d31d3e801San Mehat		    || read(dosfs, fsinfo, sizeof fsinfo)
11258d4c6c35633437182289e3d226d156d31d3e801San Mehat		    != sizeof fsinfo) {
11358d4c6c35633437182289e3d226d156d31d3e801San Mehat			perror("could not read fsinfo block");
11458d4c6c35633437182289e3d226d156d31d3e801San Mehat			return FSFATAL;
11558d4c6c35633437182289e3d226d156d31d3e801San Mehat		}
11658d4c6c35633437182289e3d226d156d31d3e801San Mehat		if (memcmp(fsinfo, "RRaA", 4)
11758d4c6c35633437182289e3d226d156d31d3e801San Mehat		    || memcmp(fsinfo + 0x1e4, "rrAa", 4)
11858d4c6c35633437182289e3d226d156d31d3e801San Mehat		    || fsinfo[0x1fc]
11958d4c6c35633437182289e3d226d156d31d3e801San Mehat		    || fsinfo[0x1fd]
12058d4c6c35633437182289e3d226d156d31d3e801San Mehat		    || fsinfo[0x1fe] != 0x55
12158d4c6c35633437182289e3d226d156d31d3e801San Mehat		    || fsinfo[0x1ff] != 0xaa
12258d4c6c35633437182289e3d226d156d31d3e801San Mehat		    || fsinfo[0x3fc]
12358d4c6c35633437182289e3d226d156d31d3e801San Mehat		    || fsinfo[0x3fd]
12458d4c6c35633437182289e3d226d156d31d3e801San Mehat		    || fsinfo[0x3fe] != 0x55
12558d4c6c35633437182289e3d226d156d31d3e801San Mehat		    || fsinfo[0x3ff] != 0xaa) {
12658d4c6c35633437182289e3d226d156d31d3e801San Mehat			pwarn("Invalid signature in fsinfo block\n");
12758d4c6c35633437182289e3d226d156d31d3e801San Mehat			if (ask(1, "fix")) {
12858d4c6c35633437182289e3d226d156d31d3e801San Mehat				memcpy(fsinfo, "RRaA", 4);
12958d4c6c35633437182289e3d226d156d31d3e801San Mehat				memcpy(fsinfo + 0x1e4, "rrAa", 4);
13058d4c6c35633437182289e3d226d156d31d3e801San Mehat				fsinfo[0x1fc] = fsinfo[0x1fd] = 0;
13158d4c6c35633437182289e3d226d156d31d3e801San Mehat				fsinfo[0x1fe] = 0x55;
13258d4c6c35633437182289e3d226d156d31d3e801San Mehat				fsinfo[0x1ff] = 0xaa;
13358d4c6c35633437182289e3d226d156d31d3e801San Mehat				fsinfo[0x3fc] = fsinfo[0x3fd] = 0;
13458d4c6c35633437182289e3d226d156d31d3e801San Mehat				fsinfo[0x3fe] = 0x55;
13558d4c6c35633437182289e3d226d156d31d3e801San Mehat				fsinfo[0x3ff] = 0xaa;
13658d4c6c35633437182289e3d226d156d31d3e801San Mehat				if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
13758d4c6c35633437182289e3d226d156d31d3e801San Mehat				    != boot->FSInfo * boot->BytesPerSec
13858d4c6c35633437182289e3d226d156d31d3e801San Mehat				    || write(dosfs, fsinfo, sizeof fsinfo)
13958d4c6c35633437182289e3d226d156d31d3e801San Mehat				    != sizeof fsinfo) {
14058d4c6c35633437182289e3d226d156d31d3e801San Mehat					perror("Unable to write FSInfo");
14158d4c6c35633437182289e3d226d156d31d3e801San Mehat					return FSFATAL;
14258d4c6c35633437182289e3d226d156d31d3e801San Mehat				}
14358d4c6c35633437182289e3d226d156d31d3e801San Mehat				ret = FSBOOTMOD;
14458d4c6c35633437182289e3d226d156d31d3e801San Mehat			} else
14558d4c6c35633437182289e3d226d156d31d3e801San Mehat				boot->FSInfo = 0;
14658d4c6c35633437182289e3d226d156d31d3e801San Mehat		}
14758d4c6c35633437182289e3d226d156d31d3e801San Mehat		if (boot->FSInfo) {
14858d4c6c35633437182289e3d226d156d31d3e801San Mehat			boot->FSFree = fsinfo[0x1e8] + (fsinfo[0x1e9] << 8)
14958d4c6c35633437182289e3d226d156d31d3e801San Mehat				       + (fsinfo[0x1ea] << 16)
15058d4c6c35633437182289e3d226d156d31d3e801San Mehat				       + (fsinfo[0x1eb] << 24);
15158d4c6c35633437182289e3d226d156d31d3e801San Mehat			boot->FSNext = fsinfo[0x1ec] + (fsinfo[0x1ed] << 8)
15258d4c6c35633437182289e3d226d156d31d3e801San Mehat				       + (fsinfo[0x1ee] << 16)
15358d4c6c35633437182289e3d226d156d31d3e801San Mehat				       + (fsinfo[0x1ef] << 24);
15458d4c6c35633437182289e3d226d156d31d3e801San Mehat		}
15558d4c6c35633437182289e3d226d156d31d3e801San Mehat
15658d4c6c35633437182289e3d226d156d31d3e801San Mehat		if (lseek(dosfs, boot->Backup * boot->BytesPerSec, SEEK_SET)
15758d4c6c35633437182289e3d226d156d31d3e801San Mehat		    != boot->Backup * boot->BytesPerSec
15858d4c6c35633437182289e3d226d156d31d3e801San Mehat		    || read(dosfs, backup, sizeof backup) != sizeof  backup) {
15958d4c6c35633437182289e3d226d156d31d3e801San Mehat			perror("could not read backup bootblock");
16058d4c6c35633437182289e3d226d156d31d3e801San Mehat			return FSFATAL;
16158d4c6c35633437182289e3d226d156d31d3e801San Mehat		}
16258d4c6c35633437182289e3d226d156d31d3e801San Mehat		backup[65] = block[65];				/* XXX */
16358d4c6c35633437182289e3d226d156d31d3e801San Mehat		if (memcmp(block + 11, backup + 11, 79)) {
164b47b16353f3db228711dded9f7c975b820059ddcSan Mehat                        char tmp[255];
165b47b16353f3db228711dded9f7c975b820059ddcSan Mehat                        int i;
166b47b16353f3db228711dded9f7c975b820059ddcSan Mehat
167b47b16353f3db228711dded9f7c975b820059ddcSan Mehat			/*
168b47b16353f3db228711dded9f7c975b820059ddcSan Mehat			 * For now, lets not bail out if they don't match
169b47b16353f3db228711dded9f7c975b820059ddcSan Mehat			 * It seems a lot of sdcards are formatted with
170b47b16353f3db228711dded9f7c975b820059ddcSan Mehat			 * the backup either empty or containing garbage.
171b47b16353f3db228711dded9f7c975b820059ddcSan Mehat			 */
172b47b16353f3db228711dded9f7c975b820059ddcSan Mehat
173b47b16353f3db228711dded9f7c975b820059ddcSan Mehat			pwarn("Primary/Backup bootblock miscompare\n");
174b47b16353f3db228711dded9f7c975b820059ddcSan Mehat
175b47b16353f3db228711dded9f7c975b820059ddcSan Mehat                        strcpy(tmp, "");
176b47b16353f3db228711dded9f7c975b820059ddcSan Mehat                        pwarn("Primary:\n");
177b47b16353f3db228711dded9f7c975b820059ddcSan Mehat			for (i = 0; i < 79; i++) {
178b47b16353f3db228711dded9f7c975b820059ddcSan Mehat				char tmp2[16];
179b47b16353f3db228711dded9f7c975b820059ddcSan Mehat                                snprintf(tmp2, sizeof(tmp2), "%.2x ", block[11 + i]);
180b47b16353f3db228711dded9f7c975b820059ddcSan Mehat				strcat(tmp, tmp2);
181b47b16353f3db228711dded9f7c975b820059ddcSan Mehat                        }
182b47b16353f3db228711dded9f7c975b820059ddcSan Mehat                        pwarn("%s\n", tmp);
183b47b16353f3db228711dded9f7c975b820059ddcSan Mehat
184b47b16353f3db228711dded9f7c975b820059ddcSan Mehat			strcpy(tmp, "");
185b47b16353f3db228711dded9f7c975b820059ddcSan Mehat                        pwarn("Backup:\n");
186b47b16353f3db228711dded9f7c975b820059ddcSan Mehat			for (i = 0; i < 79; i++) {
187b47b16353f3db228711dded9f7c975b820059ddcSan Mehat				char tmp2[16];
188b47b16353f3db228711dded9f7c975b820059ddcSan Mehat                                snprintf(tmp2, sizeof(tmp2), "%.2x ", backup[11 + i]);
189b47b16353f3db228711dded9f7c975b820059ddcSan Mehat				strcat(tmp, tmp2);
190b47b16353f3db228711dded9f7c975b820059ddcSan Mehat                        }
191b47b16353f3db228711dded9f7c975b820059ddcSan Mehat                        pwarn("%s\n", tmp);
19258d4c6c35633437182289e3d226d156d31d3e801San Mehat		}
19358d4c6c35633437182289e3d226d156d31d3e801San Mehat		/* Check backup FSInfo?					XXX */
19458d4c6c35633437182289e3d226d156d31d3e801San Mehat	}
19558d4c6c35633437182289e3d226d156d31d3e801San Mehat
19658d4c6c35633437182289e3d226d156d31d3e801San Mehat	if (boot->BytesPerSec % DOSBOOTBLOCKSIZE != 0) {
19758d4c6c35633437182289e3d226d156d31d3e801San Mehat		pfatal("Invalid sector size: %u", boot->BytesPerSec);
19858d4c6c35633437182289e3d226d156d31d3e801San Mehat		return FSFATAL;
19958d4c6c35633437182289e3d226d156d31d3e801San Mehat	}
20058d4c6c35633437182289e3d226d156d31d3e801San Mehat	if (boot->SecPerClust == 0) {
20158d4c6c35633437182289e3d226d156d31d3e801San Mehat		pfatal("Invalid cluster size: %u", boot->SecPerClust);
20258d4c6c35633437182289e3d226d156d31d3e801San Mehat		return FSFATAL;
20358d4c6c35633437182289e3d226d156d31d3e801San Mehat	}
204fe7400ddb5e99a790cd3977f9e5151d8ea929a14Sebastian Rasmussen	if (boot->BytesPerSec == 0) {
205fe7400ddb5e99a790cd3977f9e5151d8ea929a14Sebastian Rasmussen		pfatal("Invalid sector size: %u", boot->BytesPerSec);
206fe7400ddb5e99a790cd3977f9e5151d8ea929a14Sebastian Rasmussen		return FSFATAL;
207fe7400ddb5e99a790cd3977f9e5151d8ea929a14Sebastian Rasmussen	}
2086c29bbe8d58e6fe8755935a04166ecf82ff31f47Sebastian Rasmussen	if (boot->FATs == 0) {
2096c29bbe8d58e6fe8755935a04166ecf82ff31f47Sebastian Rasmussen		pfatal("Invalid number of FATs: %u", boot->FATs);
2106c29bbe8d58e6fe8755935a04166ecf82ff31f47Sebastian Rasmussen		return FSFATAL;
2116c29bbe8d58e6fe8755935a04166ecf82ff31f47Sebastian Rasmussen	}
21258d4c6c35633437182289e3d226d156d31d3e801San Mehat	if (boot->Sectors) {
21358d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->HugeSectors = 0;
21458d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->NumSectors = boot->Sectors;
21558d4c6c35633437182289e3d226d156d31d3e801San Mehat	} else
21658d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->NumSectors = boot->HugeSectors;
217fe7400ddb5e99a790cd3977f9e5151d8ea929a14Sebastian Rasmussen
218fe7400ddb5e99a790cd3977f9e5151d8ea929a14Sebastian Rasmussen	boot->ClusterOffset = (boot->RootDirEnts * 32 + boot->BytesPerSec - 1)
219fe7400ddb5e99a790cd3977f9e5151d8ea929a14Sebastian Rasmussen	    / boot->BytesPerSec
220fe7400ddb5e99a790cd3977f9e5151d8ea929a14Sebastian Rasmussen	    + boot->ResSectors
221fe7400ddb5e99a790cd3977f9e5151d8ea929a14Sebastian Rasmussen	    + boot->FATs * boot->FATsecs
222fe7400ddb5e99a790cd3977f9e5151d8ea929a14Sebastian Rasmussen	    - CLUST_FIRST * boot->SecPerClust;
223fe7400ddb5e99a790cd3977f9e5151d8ea929a14Sebastian Rasmussen
22458d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->NumClusters = (boot->NumSectors - boot->ClusterOffset) / boot->SecPerClust;
22558d4c6c35633437182289e3d226d156d31d3e801San Mehat
22658d4c6c35633437182289e3d226d156d31d3e801San Mehat	if (boot->flags&FAT32)
22758d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->ClustMask = CLUST32_MASK;
22858d4c6c35633437182289e3d226d156d31d3e801San Mehat	else if (boot->NumClusters < (CLUST_RSRVD&CLUST12_MASK))
22958d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->ClustMask = CLUST12_MASK;
23058d4c6c35633437182289e3d226d156d31d3e801San Mehat	else if (boot->NumClusters < (CLUST_RSRVD&CLUST16_MASK))
23158d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->ClustMask = CLUST16_MASK;
23258d4c6c35633437182289e3d226d156d31d3e801San Mehat	else {
23358d4c6c35633437182289e3d226d156d31d3e801San Mehat		pfatal("Filesystem too big (%u clusters) for non-FAT32 partition",
23458d4c6c35633437182289e3d226d156d31d3e801San Mehat		       boot->NumClusters);
23558d4c6c35633437182289e3d226d156d31d3e801San Mehat		return FSFATAL;
23658d4c6c35633437182289e3d226d156d31d3e801San Mehat	}
23758d4c6c35633437182289e3d226d156d31d3e801San Mehat
23858d4c6c35633437182289e3d226d156d31d3e801San Mehat	switch (boot->ClustMask) {
23958d4c6c35633437182289e3d226d156d31d3e801San Mehat	case CLUST32_MASK:
24058d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec) / 4;
24158d4c6c35633437182289e3d226d156d31d3e801San Mehat		break;
24258d4c6c35633437182289e3d226d156d31d3e801San Mehat	case CLUST16_MASK:
24358d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec) / 2;
24458d4c6c35633437182289e3d226d156d31d3e801San Mehat		break;
24558d4c6c35633437182289e3d226d156d31d3e801San Mehat	default:
24658d4c6c35633437182289e3d226d156d31d3e801San Mehat		boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec * 2) / 3;
24758d4c6c35633437182289e3d226d156d31d3e801San Mehat		break;
24858d4c6c35633437182289e3d226d156d31d3e801San Mehat	}
24958d4c6c35633437182289e3d226d156d31d3e801San Mehat
25058d4c6c35633437182289e3d226d156d31d3e801San Mehat	if (boot->NumFatEntries < boot->NumClusters) {
25158d4c6c35633437182289e3d226d156d31d3e801San Mehat		pfatal("FAT size too small, %u entries won't fit into %u sectors\n",
25258d4c6c35633437182289e3d226d156d31d3e801San Mehat		       boot->NumClusters, boot->FATsecs);
25358d4c6c35633437182289e3d226d156d31d3e801San Mehat		return FSFATAL;
25458d4c6c35633437182289e3d226d156d31d3e801San Mehat	}
25558d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->ClusterSize = boot->BytesPerSec * boot->SecPerClust;
25658d4c6c35633437182289e3d226d156d31d3e801San Mehat
25758d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->NumFiles = 1;
25858d4c6c35633437182289e3d226d156d31d3e801San Mehat	boot->NumFree = 0;
25958d4c6c35633437182289e3d226d156d31d3e801San Mehat
26058d4c6c35633437182289e3d226d156d31d3e801San Mehat	return ret;
26158d4c6c35633437182289e3d226d156d31d3e801San Mehat}
26258d4c6c35633437182289e3d226d156d31d3e801San Mehat
26358d4c6c35633437182289e3d226d156d31d3e801San Mehatint
26458d4c6c35633437182289e3d226d156d31d3e801San Mehatwritefsinfo(dosfs, boot)
26558d4c6c35633437182289e3d226d156d31d3e801San Mehat	int dosfs;
26658d4c6c35633437182289e3d226d156d31d3e801San Mehat	struct bootblock *boot;
26758d4c6c35633437182289e3d226d156d31d3e801San Mehat{
26858d4c6c35633437182289e3d226d156d31d3e801San Mehat	u_char fsinfo[2 * DOSBOOTBLOCKSIZE];
26958d4c6c35633437182289e3d226d156d31d3e801San Mehat
27058d4c6c35633437182289e3d226d156d31d3e801San Mehat	if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
27158d4c6c35633437182289e3d226d156d31d3e801San Mehat	    != boot->FSInfo * boot->BytesPerSec
27258d4c6c35633437182289e3d226d156d31d3e801San Mehat	    || read(dosfs, fsinfo, sizeof fsinfo) != sizeof fsinfo) {
27358d4c6c35633437182289e3d226d156d31d3e801San Mehat		perror("could not read fsinfo block");
27458d4c6c35633437182289e3d226d156d31d3e801San Mehat		return FSFATAL;
27558d4c6c35633437182289e3d226d156d31d3e801San Mehat	}
27658d4c6c35633437182289e3d226d156d31d3e801San Mehat	fsinfo[0x1e8] = (u_char)boot->FSFree;
27758d4c6c35633437182289e3d226d156d31d3e801San Mehat	fsinfo[0x1e9] = (u_char)(boot->FSFree >> 8);
27858d4c6c35633437182289e3d226d156d31d3e801San Mehat	fsinfo[0x1ea] = (u_char)(boot->FSFree >> 16);
27958d4c6c35633437182289e3d226d156d31d3e801San Mehat	fsinfo[0x1eb] = (u_char)(boot->FSFree >> 24);
28058d4c6c35633437182289e3d226d156d31d3e801San Mehat	fsinfo[0x1ec] = (u_char)boot->FSNext;
28158d4c6c35633437182289e3d226d156d31d3e801San Mehat	fsinfo[0x1ed] = (u_char)(boot->FSNext >> 8);
28258d4c6c35633437182289e3d226d156d31d3e801San Mehat	fsinfo[0x1ee] = (u_char)(boot->FSNext >> 16);
28358d4c6c35633437182289e3d226d156d31d3e801San Mehat	fsinfo[0x1ef] = (u_char)(boot->FSNext >> 24);
28458d4c6c35633437182289e3d226d156d31d3e801San Mehat	if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET)
28558d4c6c35633437182289e3d226d156d31d3e801San Mehat	    != boot->FSInfo * boot->BytesPerSec
28658d4c6c35633437182289e3d226d156d31d3e801San Mehat	    || write(dosfs, fsinfo, sizeof fsinfo)
28758d4c6c35633437182289e3d226d156d31d3e801San Mehat	    != sizeof fsinfo) {
28858d4c6c35633437182289e3d226d156d31d3e801San Mehat		perror("Unable to write FSInfo");
28958d4c6c35633437182289e3d226d156d31d3e801San Mehat		return FSFATAL;
29058d4c6c35633437182289e3d226d156d31d3e801San Mehat	}
29158d4c6c35633437182289e3d226d156d31d3e801San Mehat	/*
29258d4c6c35633437182289e3d226d156d31d3e801San Mehat	 * Technically, we should return FSBOOTMOD here.
29358d4c6c35633437182289e3d226d156d31d3e801San Mehat	 *
29458d4c6c35633437182289e3d226d156d31d3e801San Mehat	 * However, since Win95 OSR2 (the first M$ OS that has
29558d4c6c35633437182289e3d226d156d31d3e801San Mehat	 * support for FAT32) doesn't maintain the FSINFO block
29658d4c6c35633437182289e3d226d156d31d3e801San Mehat	 * correctly, it has to be fixed pretty often.
29758d4c6c35633437182289e3d226d156d31d3e801San Mehat	 *
29858d4c6c35633437182289e3d226d156d31d3e801San Mehat	 * Therefor, we handle the FSINFO block only informally,
29958d4c6c35633437182289e3d226d156d31d3e801San Mehat	 * fixing it if necessary, but otherwise ignoring the
30058d4c6c35633437182289e3d226d156d31d3e801San Mehat	 * fact that it was incorrect.
30158d4c6c35633437182289e3d226d156d31d3e801San Mehat	 */
30258d4c6c35633437182289e3d226d156d31d3e801San Mehat	return 0;
30358d4c6c35633437182289e3d226d156d31d3e801San Mehat}
304