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
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.
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]
23 * Copyright (c) 1999 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * fsck_pcfs -- routines for manipulating the FAT.
36 #include <sys/dktp/fdisk.h>
37 #include <sys/fs/pc_fs.h>
38 #include <sys/fs/pc_dir.h>
39 #include <sys/fs/pc_label.h>
40 #include "pcfs_common.h"
41 #include "fsck_pcfs.h"
43 extern int32_t BytesPerCluster
;
44 extern int32_t TotalClusters
;
45 extern int32_t LastCluster
;
46 extern off64_t FirstClusterOffset
;
47 extern off64_t PartitionOffset
;
48 extern bpb_t TheBIOSParameterBlock
;
53 static uchar_t
*TheFAT
;
54 static int FATRewriteNeeded
= 0;
64 * The FAT(s) immediately follows the reserved sectors.
66 seekto
= TheBIOSParameterBlock
.bpb
.resv_sectors
*
67 TheBIOSParameterBlock
.bpb
.bytes_per_sector
+ PartitionOffset
;
68 return (lseek64(fd
, seekto
, SEEK_SET
));
78 } else if ((TheFAT
= (uchar_t
*)malloc(FATSize
)) == NULL
) {
79 mountSanityCheckFails();
80 perror(gettext("No memory for a copy of the FAT"));
84 if (seekFAT(fd
) < 0) {
85 mountSanityCheckFails();
86 perror(gettext("Cannot seek to FAT"));
91 (void) fprintf(stderr
,
92 gettext("Reading FAT\n"));
93 if ((bytesRead
= read(fd
, TheFAT
, FATSize
)) != FATSize
) {
94 mountSanityCheckFails();
96 perror(gettext("Cannot read a FAT"));
98 (void) fprintf(stderr
,
99 gettext("Short read of FAT."));
105 * XXX - might want to read the other copies of the FAT
106 * for comparison and/or to use if the first one seems hosed.
109 (void) fprintf(stderr
,
110 gettext("Dump of FAT's first 32 bytes.\n"));
112 dump_bytes(TheFAT
, 32);
119 ssize_t bytesWritten
;
121 if (TheFAT
== NULL
) {
122 (void) fprintf(stderr
,
123 gettext("Internal error: No FAT to write\n"));
127 if (!FATRewriteNeeded
) {
129 (void) fprintf(stderr
,
130 gettext("No FAT changes need to be written.\n"));
137 (void) fprintf(stderr
, gettext("Writing FAT\n"));
138 if (seekFAT(fd
) < 0) {
139 perror(gettext("Cannot seek to FAT"));
143 if ((bytesWritten
= write(fd
, TheFAT
, FATSize
)) != FATSize
) {
144 if (bytesWritten
< 0) {
145 perror(gettext("Cannot write FAT"));
147 (void) fprintf(stderr
,
148 gettext("Short write of FAT."));
153 FATRewriteNeeded
= 0;
157 * checkFAT32CleanBit()
158 * Return non-zero if the bit indicating proper Windows shutdown has
162 checkFAT32CleanBit(int fd
)
165 return (TheFAT
[WIN_SHUTDOWN_STATUS_BYTE
] & WIN_SHUTDOWN_BIT_MASK
);
169 findClusterEntryInFAT(int32_t currentCluster
)
172 if (FATEntrySize
== 32) {
173 idx
= currentCluster
* 4;
174 } else if (FATEntrySize
== 16) {
175 idx
= currentCluster
* 2;
177 idx
= currentCluster
+ currentCluster
/2;
179 return (TheFAT
+ idx
);
183 * {read,write}FATentry
184 * For the 16 and 32 bit FATs these routines are relatively easy
187 * 12 bit FATs are kind of strange, though. The magic index for
188 * 12 bit FATS computed below, 1.5 * clusterNum, is a
189 * simplification that there are 8 bits in a byte, so you need
190 * 1.5 bytes per entry.
192 * It's easiest to think about FAT12 entries in pairs:
194 * ---------------------------------------------
195 * | mid1 | low1 | low2 | high1 | high2 | mid2 |
196 * ---------------------------------------------
198 * Each box in the diagram represents a nibble (4 bits) of a FAT
199 * entry. A FAT entry is made up of three nibbles. So if you
200 * look closely, you'll see that first byte of the pair of
201 * entries contains the low and middle nibbles of the first
202 * entry. The second byte has the low nibble of the second entry
203 * and the high nibble of the first entry. Those two bytes alone
204 * are enough to read the first entry. The second FAT entry is
205 * finished out by the last nibble pair.
208 readFATEntry(int32_t currentCluster
)
213 ep
= findClusterEntryInFAT(currentCluster
);
214 if (FATEntrySize
== 32) {
215 read_32_bits(ep
, (uint32_t *)&value
);
216 } else if (FATEntrySize
== 16) {
217 read_16_bits(ep
, (uint32_t *)&value
);
219 * Convert 16 bit entry to 32 bit if we are
220 * into the reserved or higher values.
222 if (value
>= PCF_RESCLUSTER
)
226 if (currentCluster
& 1) {
228 * Odd numbered cluster
230 value
= (((unsigned int)*ep
++ & 0xf0) >> 4);
234 value
+= ((*ep
& 0x0f) << 8);
237 * Convert 12 bit entry to 32 bit if we are
238 * into the reserved or higher values.
240 if (value
>= PCF_12BCLUSTER
)
247 writeFATEntry(int32_t currentCluster
, int32_t value
)
251 FATRewriteNeeded
= 1;
252 ep
= findClusterEntryInFAT(currentCluster
);
253 if (FATEntrySize
== 32) {
254 store_32_bits(&ep
, value
);
255 } else if (FATEntrySize
== 16) {
256 store_16_bits(&ep
, value
);
258 if (currentCluster
& 1) {
260 * Odd numbered cluster
262 *ep
= (*ep
& 0x0f) | ((value
<< 4) & 0xf0);
264 *ep
= (value
>> 4) & 0xff;
266 *ep
++ = value
& 0xff;
267 *ep
= (*ep
& 0xf0) | ((value
>> 8) & 0x0f);
273 * reservedInFAT - Is this cluster marked in the reserved range?
274 * The range from PCF_RESCLUSTER32 to PCF_BADCLUSTER32 - 1,
275 * have been reserved by Microsoft. No cluster should be
276 * marked with these; they are effectively invalid cluster values.
279 reservedInFAT(int32_t clusterNum
)
283 e
= readFATEntry(clusterNum
);
284 return (e
>= PCF_RESCLUSTER32
&& e
< PCF_BADCLUSTER32
);
288 * badInFAT - Is this cluster marked as bad? I.e., is it inaccessible?
291 badInFAT(int32_t clusterNum
)
293 return (readFATEntry(clusterNum
) == PCF_BADCLUSTER32
);
297 * lastInFAT - Is this cluster marked as free? I.e., is it available
301 freeInFAT(int32_t clusterNum
)
303 return (readFATEntry(clusterNum
) == PCF_FREECLUSTER
);
307 * lastInFAT - Is this cluster the last in its cluster chain?
310 lastInFAT(int32_t clusterNum
)
312 return (readFATEntry(clusterNum
) == PCF_LASTCLUSTER32
);
316 * markLastInFAT - Mark this cluster as the last in its cluster chain.
319 markLastInFAT(int32_t clusterNum
)
321 writeFATEntry(clusterNum
, PCF_LASTCLUSTER32
);
325 markFreeInFAT(int32_t clusterNum
)
327 writeFATEntry(clusterNum
, PCF_FREECLUSTER
);
331 markBadInFAT(int32_t clusterNum
)
333 writeFATEntry(clusterNum
, PCF_BADCLUSTER32
);