1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1999 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 /* 28 * fsck_pcfs -- routines for manipulating the FAT. 29 */ 30 #include <stdio.h> 31 #include <unistd.h> 32 #include <stdlib.h> 33 #include <libintl.h> 34 #include <sys/dktp/fdisk.h> 35 #include <sys/fs/pc_fs.h> 36 #include <sys/fs/pc_dir.h> 37 #include <sys/fs/pc_label.h> 38 #include "pcfs_common.h" 39 #include "fsck_pcfs.h" 40 41 extern int32_t BytesPerCluster; 42 extern int32_t TotalClusters; 43 extern int32_t LastCluster; 44 extern off64_t FirstClusterOffset; 45 extern off64_t PartitionOffset; 46 extern bpb_t TheBIOSParameterBlock; 47 extern int ReadOnly; 48 extern int IsFAT32; 49 extern int Verbose; 50 51 static uchar_t *TheFAT; 52 static int FATRewriteNeeded = 0; 53 54 int32_t FATSize; 55 short FATEntrySize; 56 57 static off64_t 58 seekFAT(int fd) 59 { 60 off64_t seekto; 61 /* 62 * The FAT(s) immediately follows the reserved sectors. 63 */ 64 seekto = TheBIOSParameterBlock.bpb.resv_sectors * 65 TheBIOSParameterBlock.bpb.bytes_per_sector + PartitionOffset; 66 return (lseek64(fd, seekto, SEEK_SET)); 67 } 68 69 void 70 getFAT(int fd) 71 { 72 ssize_t bytesRead; 73 74 if (TheFAT != NULL) { 75 return; 76 } else if ((TheFAT = (uchar_t *)malloc(FATSize)) == NULL) { 77 mountSanityCheckFails(); 78 perror(gettext("No memory for a copy of the FAT")); 79 (void) close(fd); 80 exit(7); 81 } 82 if (seekFAT(fd) < 0) { 83 mountSanityCheckFails(); 84 perror(gettext("Cannot seek to FAT")); 85 (void) close(fd); 86 exit(7); 87 } 88 if (Verbose) 89 (void) fprintf(stderr, 90 gettext("Reading FAT\n")); 91 if ((bytesRead = read(fd, TheFAT, FATSize)) != FATSize) { 92 mountSanityCheckFails(); 93 if (bytesRead < 0) { 94 perror(gettext("Cannot read a FAT")); 95 } else { 96 (void) fprintf(stderr, 97 gettext("Short read of FAT.")); 98 } 99 (void) close(fd); 100 exit(7); 101 } 102 /* 103 * XXX - might want to read the other copies of the FAT 104 * for comparison and/or to use if the first one seems hosed. 105 */ 106 if (Verbose) { 107 (void) fprintf(stderr, 108 gettext("Dump of FAT's first 32 bytes.\n")); 109 header_for_dump(); 110 dump_bytes(TheFAT, 32); 111 } 112 } 113 114 void 115 writeFATMods(int fd) 116 { 117 ssize_t bytesWritten; 118 119 if (TheFAT == NULL) { 120 (void) fprintf(stderr, 121 gettext("Internal error: No FAT to write\n")); 122 (void) close(fd); 123 exit(11); 124 } 125 if (!FATRewriteNeeded) { 126 if (Verbose) { 127 (void) fprintf(stderr, 128 gettext("No FAT changes need to be written.\n")); 129 } 130 return; 131 } 132 if (ReadOnly) 133 return; 134 if (Verbose) 135 (void) fprintf(stderr, gettext("Writing FAT\n")); 136 if (seekFAT(fd) < 0) { 137 perror(gettext("Cannot seek to FAT")); 138 (void) close(fd); 139 exit(11); 140 } 141 if ((bytesWritten = write(fd, TheFAT, FATSize)) != FATSize) { 142 if (bytesWritten < 0) { 143 perror(gettext("Cannot write FAT")); 144 } else { 145 (void) fprintf(stderr, 146 gettext("Short write of FAT.")); 147 } 148 (void) close(fd); 149 exit(11); 150 } 151 FATRewriteNeeded = 0; 152 } 153 154 /* 155 * checkFAT32CleanBit() 156 * Return non-zero if the bit indicating proper Windows shutdown has 157 * been set. 158 */ 159 int 160 checkFAT32CleanBit(int fd) 161 { 162 getFAT(fd); 163 return (TheFAT[WIN_SHUTDOWN_STATUS_BYTE] & WIN_SHUTDOWN_BIT_MASK); 164 } 165 166 static uchar_t * 167 findClusterEntryInFAT(int32_t currentCluster) 168 { 169 int32_t idx; 170 if (FATEntrySize == 32) { 171 idx = currentCluster * 4; 172 } else if (FATEntrySize == 16) { 173 idx = currentCluster * 2; 174 } else { 175 idx = currentCluster + currentCluster/2; 176 } 177 return (TheFAT + idx); 178 } 179 180 /* 181 * {read,write}FATentry 182 * For the 16 and 32 bit FATs these routines are relatively easy 183 * to follow. 184 * 185 * 12 bit FATs are kind of strange, though. The magic index for 186 * 12 bit FATS computed below, 1.5 * clusterNum, is a 187 * simplification that there are 8 bits in a byte, so you need 188 * 1.5 bytes per entry. 189 * 190 * It's easiest to think about FAT12 entries in pairs: 191 * 192 * --------------------------------------------- 193 * | mid1 | low1 | low2 | high1 | high2 | mid2 | 194 * --------------------------------------------- 195 * 196 * Each box in the diagram represents a nibble (4 bits) of a FAT 197 * entry. A FAT entry is made up of three nibbles. So if you 198 * look closely, you'll see that first byte of the pair of 199 * entries contains the low and middle nibbles of the first 200 * entry. The second byte has the low nibble of the second entry 201 * and the high nibble of the first entry. Those two bytes alone 202 * are enough to read the first entry. The second FAT entry is 203 * finished out by the last nibble pair. 204 */ 205 int32_t 206 readFATEntry(int32_t currentCluster) 207 { 208 int32_t value; 209 uchar_t *ep; 210 211 ep = findClusterEntryInFAT(currentCluster); 212 if (FATEntrySize == 32) { 213 read_32_bits(ep, (uint32_t *)&value); 214 } else if (FATEntrySize == 16) { 215 read_16_bits(ep, (uint32_t *)&value); 216 /* 217 * Convert 16 bit entry to 32 bit if we are 218 * into the reserved or higher values. 219 */ 220 if (value >= PCF_RESCLUSTER) 221 value |= 0xFFF0000; 222 } else { 223 value = 0; 224 if (currentCluster & 1) { 225 /* 226 * Odd numbered cluster 227 */ 228 value = (((unsigned int)*ep++ & 0xf0) >> 4); 229 value += (*ep << 4); 230 } else { 231 value = *ep++; 232 value += ((*ep & 0x0f) << 8); 233 } 234 /* 235 * Convert 12 bit entry to 32 bit if we are 236 * into the reserved or higher values. 237 */ 238 if (value >= PCF_12BCLUSTER) 239 value |= 0xFFFF000; 240 } 241 return (value); 242 } 243 244 void 245 writeFATEntry(int32_t currentCluster, int32_t value) 246 { 247 uchar_t *ep; 248 249 FATRewriteNeeded = 1; 250 ep = findClusterEntryInFAT(currentCluster); 251 if (FATEntrySize == 32) { 252 store_32_bits(&ep, value); 253 } else if (FATEntrySize == 16) { 254 store_16_bits(&ep, value); 255 } else { 256 if (currentCluster & 1) { 257 /* 258 * Odd numbered cluster 259 */ 260 *ep = (*ep & 0x0f) | ((value << 4) & 0xf0); 261 ep++; 262 *ep = (value >> 4) & 0xff; 263 } else { 264 *ep++ = value & 0xff; 265 *ep = (*ep & 0xf0) | ((value >> 8) & 0x0f); 266 } 267 } 268 } 269 270 /* 271 * reservedInFAT - Is this cluster marked in the reserved range? 272 * The range from PCF_RESCLUSTER32 to PCF_BADCLUSTER32 - 1, 273 * have been reserved by Microsoft. No cluster should be 274 * marked with these; they are effectively invalid cluster values. 275 */ 276 int 277 reservedInFAT(int32_t clusterNum) 278 { 279 int32_t e; 280 281 e = readFATEntry(clusterNum); 282 return (e >= PCF_RESCLUSTER32 && e < PCF_BADCLUSTER32); 283 } 284 285 /* 286 * badInFAT - Is this cluster marked as bad? I.e., is it inaccessible? 287 */ 288 int 289 badInFAT(int32_t clusterNum) 290 { 291 return (readFATEntry(clusterNum) == PCF_BADCLUSTER32); 292 } 293 294 /* 295 * lastInFAT - Is this cluster marked as free? I.e., is it available 296 * for use? 297 */ 298 int 299 freeInFAT(int32_t clusterNum) 300 { 301 return (readFATEntry(clusterNum) == PCF_FREECLUSTER); 302 } 303 304 /* 305 * lastInFAT - Is this cluster the last in its cluster chain? 306 */ 307 int 308 lastInFAT(int32_t clusterNum) 309 { 310 return (readFATEntry(clusterNum) == PCF_LASTCLUSTER32); 311 } 312 313 /* 314 * markLastInFAT - Mark this cluster as the last in its cluster chain. 315 */ 316 void 317 markLastInFAT(int32_t clusterNum) 318 { 319 writeFATEntry(clusterNum, PCF_LASTCLUSTER32); 320 } 321 322 void 323 markFreeInFAT(int32_t clusterNum) 324 { 325 writeFATEntry(clusterNum, PCF_FREECLUSTER); 326 } 327 328 void 329 markBadInFAT(int32_t clusterNum) 330 { 331 writeFATEntry(clusterNum, PCF_BADCLUSTER32); 332 } 333