1/* 2 * Copyright (c) 2000, 2005-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * Copyright (C) 1995, 1997 Wolfgang Solfrank 25 * Copyright (c) 1995 Martin Husemann 26 * 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 1. Redistributions of source code must retain the above copyright 31 * notice, this list of conditions and the following disclaimer. 32 * 2. Redistributions in binary form must reproduce the above copyright 33 * notice, this list of conditions and the following disclaimer in the 34 * documentation and/or other materials provided with the distribution. 35 * 3. All advertising materials mentioning features or use of this software 36 * must display the following acknowledgement: 37 * This product includes software developed by Martin Husemann 38 * and Wolfgang Solfrank. 39 * 4. Neither the name of the University nor the names of its contributors 40 * may be used to endorse or promote products derived from this software 41 * without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 44 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 45 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 46 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 48 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 52 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 */ 54 55 56#include <sys/cdefs.h> 57 58#include <stdlib.h> 59#include <string.h> 60#include <ctype.h> 61#include <stdio.h> 62#include <unistd.h> 63#include <errno.h> 64 65#include "ext.h" 66#include "fsutil.h" 67 68int 69readboot(dosfs, boot) 70 int dosfs; 71 struct bootblock *boot; 72{ 73 u_char block[MAX_SECTOR_SIZE]; 74 u_char fsinfo[MAX_SECTOR_SIZE]; 75 int ret = FSOK; 76 77 /* 78 * [2734381] Some devices have sector sizes greater than 512 bytes. These devices 79 * tend to return errors if you try to read less than a sector, so we try reading 80 * the maximum sector size (which may end up reading more than one sector). 81 */ 82 if (read(dosfs, block, MAX_SECTOR_SIZE) != MAX_SECTOR_SIZE) { 83 perr("could not read boot block"); 84 return FSFATAL; 85 } 86 87 /* [2699033] 88 * 89 * The first three bytes are an Intel x86 jump instruction. It should be one 90 * of the following forms: 91 * 0xE9 0x?? 0x?? 92 * 0xEB 0x?? 0x90 93 * 94 * [5016947] 95 * 96 * Windows doesn't actually check the third byte if the first byte is 0xEB, 97 * so we don't either 98 */ 99 if (block[0] != 0xE9 && block[0] != 0xEB) 100 { 101 pfatal("Invalid BS_jmpBoot in boot block: %02x%02x%02x\n", block[0], block[1], block[2]); 102 return FSFATAL; 103 } 104 105 memset(boot, 0, sizeof *boot); 106 boot->ValidFat = -1; 107 108 /* decode bios parameter block */ 109 boot->BytesPerSec = block[11] + (block[12] << 8); 110 boot->SecPerClust = block[13]; 111 boot->ResSectors = block[14] + (block[15] << 8); 112 boot->FATs = block[16]; 113 boot->RootDirEnts = block[17] + (block[18] << 8); 114 boot->Sectors = block[19] + (block[20] << 8); 115 boot->Media = block[21]; 116 boot->FATsmall = block[22] + (block[23] << 8); 117 boot->SecPerTrack = block[24] + (block[25] << 8); 118 boot->Heads = block[26] + (block[27] << 8); 119 boot->HiddenSecs = block[28] + (block[29] << 8) + (block[30] << 16) + (block[31] << 24); 120 boot->HugeSectors = block[32] + (block[33] << 8) + (block[34] << 16) + (block[35] << 24); 121 122 boot->FATsecs = boot->FATsmall; 123 boot->ClusterSize = boot->BytesPerSec * boot->SecPerClust; 124 125 /* 126 * Make sure the sector size is a power of two, and in the range 127 * 512..MAX_SECTOR_SIZE. 128 */ 129 if (boot->BytesPerSec < DOSBOOTBLOCKSIZE || boot->BytesPerSec > MAX_SECTOR_SIZE || 130 (boot->BytesPerSec & (boot->BytesPerSec - 1)) != 0) 131 { 132 pfatal("Invalid sector size: %u\n", boot->BytesPerSec); 133 return FSFATAL; 134 } 135 136 /* 137 * Make sure the sectors per cluster is reasonable. It must be a 138 * non-zero power of two. 139 * 140 * The FAT specification warns that the bytes per cluster shouldn't be 141 * allowed to be greater than 32KB (with 64KB supported on some systems), 142 * but we don't actually enforce that here. 143 */ 144 if (boot->SecPerClust == 0 || 145 (boot->SecPerClust & (boot->SecPerClust - 1)) != 0) 146 { 147 pfatal("Invalid sectors per cluster: %u\n", boot->SecPerClust); 148 return FSFATAL; 149 } 150 151 if (!boot->RootDirEnts) 152 boot->flags |= FAT32; 153 if (boot->flags & FAT32) { 154 boot->FATsecs = block[36] + (block[37] << 8) 155 + (block[38] << 16) + (block[39] << 24); 156 if (block[40] & 0x80) 157 boot->ValidFat = block[40] & 0x0f; 158 159 /* check version number: */ 160 if (block[42] || block[43]) { 161 /* Correct? XXX */ 162 pfatal("Unknown filesystem version: %x.%x\n", 163 block[43], block[42]); 164 return FSFATAL; 165 } 166 boot->RootCl = block[44] + (block[45] << 8) 167 + (block[46] << 16) + (block[47] << 24); 168 boot->FSInfo = block[48] + (block[49] << 8); 169 boot->Backup = block[50] + (block[51] << 8); 170 171 if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET) 172 != boot->FSInfo * boot->BytesPerSec 173 || read(dosfs, fsinfo, boot->BytesPerSec) 174 != boot->BytesPerSec) { 175 perr("could not read fsinfo block"); 176 return FSFATAL; 177 } 178 if (memcmp(fsinfo, "RRaA", 4) 179 || memcmp(fsinfo + 0x1e4, "rrAa", 4) 180 || fsinfo[0x1fc] 181 || fsinfo[0x1fd] 182 || fsinfo[0x1fe] != 0x55 183 || fsinfo[0x1ff] != 0xaa) { 184 pwarn("Invalid signature in fsinfo block\n"); 185 if (ask(0, "fix")) { 186 memcpy(fsinfo, "RRaA", 4); 187 memcpy(fsinfo + 0x1e4, "rrAa", 4); 188 fsinfo[0x1fc] = fsinfo[0x1fd] = 0; 189 fsinfo[0x1fe] = 0x55; 190 fsinfo[0x1ff] = 0xaa; 191 fsinfo[0x3fc] = fsinfo[0x3fd] = 0; 192 fsinfo[0x3fe] = 0x55; 193 fsinfo[0x3ff] = 0xaa; 194 if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET) 195 != boot->FSInfo * boot->BytesPerSec 196 || write(dosfs, fsinfo, boot->BytesPerSec) 197 != boot->BytesPerSec) { 198 perr("Unable to write FSInfo"); 199 return FSFATAL; 200 } 201 ret = FSBOOTMOD; 202 } else { 203 boot->FSInfo = 0; 204 ret = FSERROR; 205 } 206 } 207 if (boot->FSInfo) { 208 boot->FSFree = fsinfo[0x1e8] + (fsinfo[0x1e9] << 8) 209 + (fsinfo[0x1ea] << 16) 210 + (fsinfo[0x1eb] << 24); 211 boot->FSNext = fsinfo[0x1ec] + (fsinfo[0x1ed] << 8) 212 + (fsinfo[0x1ee] << 16) 213 + (fsinfo[0x1ef] << 24); 214 } 215 } 216 217 boot->ClusterOffset = (boot->RootDirEnts * 32 + boot->BytesPerSec - 1) 218 / boot->BytesPerSec 219 + boot->ResSectors 220 + boot->FATs * boot->FATsecs 221 - CLUST_FIRST * boot->SecPerClust; 222 223 if (boot->Sectors) { 224 boot->HugeSectors = 0; 225 boot->NumSectors = boot->Sectors; 226 } else 227 boot->NumSectors = boot->HugeSectors; 228 229 /* 230 * Note: NumClusters isn't actually the *number* (or count) of clusters. It is really 231 * the maximum cluster number plus one (which is the number of clusters plus two; 232 * it is also the number of valid FAT entries). It is meant to be used 233 * for looping over cluster numbers, or range checking cluster numbers. 234 */ 235 boot->NumClusters = (boot->NumSectors - boot->ClusterOffset) / boot->SecPerClust; 236 237 /* Since NumClusters is off by two, use constants that are off by two also. */ 238 if (boot->flags&FAT32) 239 boot->ClustMask = CLUST32_MASK; 240 else if (boot->NumClusters < (4085+2)) 241 boot->ClustMask = CLUST12_MASK; 242 else if (boot->NumClusters < (65526+2)) /* Windows allows 65525 clusters, so we should, too */ 243 boot->ClustMask = CLUST16_MASK; 244 else { 245 pfatal("Filesystem too big (%u clusters) for non-FAT32 partition\n", 246 boot->NumClusters-2); 247 return FSFATAL; 248 } 249 250 switch (boot->ClustMask) { 251 case CLUST32_MASK: 252 boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec) / 4; 253 break; 254 case CLUST16_MASK: 255 boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec) / 2; 256 break; 257 default: 258 boot->NumFatEntries = (boot->FATsecs * boot->BytesPerSec * 2) / 3; 259 break; 260 } 261 262 /* 263 * Verify that the FAT is large enough to hold the number of clusters 264 * that we think the volume has. Some digital cameras, and our own 265 * newfs_msdos, can create volumes whose total sector count is too large. 266 */ 267 if (boot->NumFatEntries < boot->NumClusters) { 268 pwarn("FAT size too small, %u entries won't fit into %u sectors\n", 269 boot->NumClusters, boot->FATsecs); 270 boot->NumClusters = boot->NumFatEntries; 271 if (ask(0, "Fix total sectors")) { 272 /* Need to recompute sectors based on clusters */ 273 boot->NumSectors = (boot->NumClusters * boot->SecPerClust) + boot->ClusterOffset; 274 if (boot->Sectors) { 275 boot->Sectors = boot->NumSectors; 276 block[19] = boot->NumSectors & 0xFF; 277 block[20] = (boot->NumSectors >> 8) & 0xFF; 278 } else { 279 boot->HugeSectors = boot->NumSectors; 280 block[32] = boot->NumSectors & 0xFF; 281 block[33] = (boot->NumSectors >> 8) & 0xFF; 282 block[34] = (boot->NumSectors >> 16) & 0xFF; 283 block[35] = (boot->NumSectors >> 24) & 0xFF; 284 } 285 if (lseek(dosfs, 0, SEEK_SET) != 0 || 286 write(dosfs, block, boot->BytesPerSec) != boot->BytesPerSec) 287 { 288 perr("could not write boot sector"); 289 return FSFATAL; 290 } 291 ret |= FSBOOTMOD; /* This flag is currently ignored by checkfilesys() */ 292 } else { 293 pwarn("Continuing, assuming %u clusters\n", boot->NumFatEntries-2); 294 /* 295 * We don't return an error here, so Mac OS X will automatically 296 * mount the volume without attempting to repair the disk just 297 * because of this problem (though it will end up fixing this 298 * problem if there was some other problem that had to be repaired 299 * before mounting). 300 */ 301 } 302 } 303 304 boot->NumFree = 0; 305 306 return ret; 307} 308 309int 310writefsinfo(dosfs, boot) 311 int dosfs; 312 struct bootblock *boot; 313{ 314 u_char fsinfo[MAX_SECTOR_SIZE]; 315 316 if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET) 317 != boot->FSInfo * boot->BytesPerSec 318 || read(dosfs, fsinfo, boot->BytesPerSec) != boot->BytesPerSec) { 319 perr("could not read fsinfo block"); 320 return FSFATAL; 321 } 322 fsinfo[0x1e8] = (u_char)boot->FSFree; 323 fsinfo[0x1e9] = (u_char)(boot->FSFree >> 8); 324 fsinfo[0x1ea] = (u_char)(boot->FSFree >> 16); 325 fsinfo[0x1eb] = (u_char)(boot->FSFree >> 24); 326 fsinfo[0x1ec] = (u_char)boot->FSNext; 327 fsinfo[0x1ed] = (u_char)(boot->FSNext >> 8); 328 fsinfo[0x1ee] = (u_char)(boot->FSNext >> 16); 329 fsinfo[0x1ef] = (u_char)(boot->FSNext >> 24); 330 if (lseek(dosfs, boot->FSInfo * boot->BytesPerSec, SEEK_SET) 331 != boot->FSInfo * boot->BytesPerSec 332 || write(dosfs, fsinfo, boot->BytesPerSec) 333 != boot->BytesPerSec) { 334 perr("Unable to write FSInfo"); 335 return FSFATAL; 336 } 337 /* 338 * Technically, we should return FSBOOTMOD here. 339 * 340 * However, since Win95 OSR2 (the first M$ OS that has 341 * support for FAT32) doesn't maintain the FSINFO block 342 * correctly, it has to be fixed pretty often. 343 * 344 * Therefor, we handle the FSINFO block only informally, 345 * fixing it if neccessary, but otherwise ignoring the 346 * fact that it was incorrect. 347 */ 348 return 0; 349} 350