fix formatting
[reactos.git] / reactos / boot / freeldr / freeldr / fs / fat.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <freeldr.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 BOOLEAN gCacheEnabled = FALSE;
26
27 ULONG BytesPerSector; /* Number of bytes per sector */
28 ULONG SectorsPerCluster; /* Number of sectors per cluster */
29 ULONG FatVolumeStartSector; /* Absolute starting sector of the partition */
30 ULONG FatSectorStart; /* Starting sector of 1st FAT table */
31 ULONG ActiveFatSectorStart; /* Starting sector of active FAT table */
32 ULONG NumberOfFats; /* Number of FAT tables */
33 ULONG SectorsPerFat; /* Sectors per FAT table */
34 ULONG RootDirSectorStart; /* Starting sector of the root directory (non-fat32) */
35 ULONG RootDirSectors; /* Number of sectors of the root directory (non-fat32) */
36 ULONG RootDirStartCluster; /* Starting cluster number of the root directory (fat32 only) */
37 ULONG DataSectorStart; /* Starting sector of the data area */
38
39 ULONG FatType = 0; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
40 ULONG FatDriveNumber = 0;
41
42 VOID FatSwapFatBootSector(PFAT_BOOTSECTOR Obj)
43 {
44 SW(Obj, BytesPerSector);
45 SW(Obj, ReservedSectors);
46 SW(Obj, RootDirEntries);
47 SW(Obj, TotalSectors);
48 SW(Obj, SectorsPerFat);
49 SW(Obj, SectorsPerTrack);
50 SW(Obj, NumberOfHeads);
51 SD(Obj, HiddenSectors);
52 SD(Obj, TotalSectorsBig);
53 SD(Obj, VolumeSerialNumber);
54 SW(Obj, BootSectorMagic);
55 }
56
57 VOID FatSwapFat32BootSector(PFAT32_BOOTSECTOR Obj)
58 {
59 SW(Obj, BytesPerSector);
60 SW(Obj, ReservedSectors);
61 SW(Obj, RootDirEntries);
62 SW(Obj, TotalSectors);
63 SW(Obj, SectorsPerFat);
64 SW(Obj, NumberOfHeads);
65 SD(Obj, HiddenSectors);
66 SD(Obj, TotalSectorsBig);
67 SD(Obj, SectorsPerFatBig);
68 SW(Obj, ExtendedFlags);
69 SW(Obj, FileSystemVersion);
70 SD(Obj, RootDirStartCluster);
71 SW(Obj, FsInfo);
72 SW(Obj, BackupBootSector);
73 SD(Obj, VolumeSerialNumber);
74 SW(Obj, BootSectorMagic);
75 }
76
77 VOID FatSwapFatXBootSector(PFATX_BOOTSECTOR Obj)
78 {
79 SD(Obj, VolumeSerialNumber);
80 SD(Obj, SectorsPerCluster);
81 SW(Obj, NumberOfFats);
82 }
83
84 VOID FatSwapDirEntry(PDIRENTRY Obj)
85 {
86 SW(Obj, CreateTime);
87 SW(Obj, CreateDate);
88 SW(Obj, LastAccessDate);
89 SW(Obj, ClusterHigh);
90 SW(Obj, Time);
91 SW(Obj, Date);
92 SW(Obj, ClusterLow);
93 SD(Obj, Size);
94 }
95
96 VOID FatSwapLFNDirEntry(PLFN_DIRENTRY Obj)
97 {
98 int i;
99 SW(Obj, StartCluster);
100 for(i = 0; i < 5; i++)
101 Obj->Name0_4[i] = SWAPW(Obj->Name0_4[i]);
102 for(i = 0; i < 6; i++)
103 Obj->Name5_10[i] = SWAPW(Obj->Name5_10[i]);
104 for(i = 0; i < 2; i++)
105 Obj->Name11_12[i] = SWAPW(Obj->Name11_12[i]);
106 }
107
108 VOID FatSwapFatXDirEntry(PFATX_DIRENTRY Obj)
109 {
110 SD(Obj, StartCluster);
111 SD(Obj, Size);
112 SW(Obj, Time);
113 SW(Obj, Date);
114 SW(Obj, CreateTime);
115 SW(Obj, CreateDate);
116 SW(Obj, LastAccessTime);
117 SW(Obj, LastAccessDate);
118 }
119
120 BOOLEAN FatOpenVolume(UCHAR DriveNumber, ULONGLONG VolumeStartSector, ULONGLONG PartitionSectorCount)
121 {
122 char ErrMsg[80];
123 ULONG FatSize;
124 PFAT_BOOTSECTOR FatVolumeBootSector;
125 PFAT32_BOOTSECTOR Fat32VolumeBootSector;
126 PFATX_BOOTSECTOR FatXVolumeBootSector;
127
128 DbgPrint((DPRINT_FILESYSTEM, "FatOpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber, VolumeStartSector));
129
130 // Store the drive number
131 FatDriveNumber = DriveNumber;
132
133 //
134 // Allocate the memory to hold the boot sector
135 //
136 FatVolumeBootSector = (PFAT_BOOTSECTOR) MmHeapAlloc(512);
137 Fat32VolumeBootSector = (PFAT32_BOOTSECTOR) FatVolumeBootSector;
138 FatXVolumeBootSector = (PFATX_BOOTSECTOR) FatVolumeBootSector;
139
140 //
141 // Make sure we got the memory
142 //
143 if (FatVolumeBootSector == NULL)
144 {
145 FileSystemError("Out of memory.");
146 return FALSE;
147 }
148
149 // Now try to read the boot sector
150 // If this fails then abort
151 if (!MachDiskReadLogicalSectors(DriveNumber, VolumeStartSector, 1, (PVOID)DISKREADBUFFER))
152 {
153 MmHeapFree(FatVolumeBootSector);
154 return FALSE;
155 }
156 RtlCopyMemory(FatVolumeBootSector, (PVOID)DISKREADBUFFER, 512);
157
158 // Get the FAT type
159 FatType = FatDetermineFatType(FatVolumeBootSector, PartitionSectorCount);
160
161 // Dump boot sector (and swap it for big endian systems)
162 DbgPrint((DPRINT_FILESYSTEM, "Dumping boot sector:\n"));
163 if (ISFATX(FatType))
164 {
165 FatSwapFatXBootSector(FatXVolumeBootSector);
166 DbgPrint((DPRINT_FILESYSTEM, "sizeof(FATX_BOOTSECTOR) = 0x%x.\n", sizeof(FATX_BOOTSECTOR)));
167
168 DbgPrint((DPRINT_FILESYSTEM, "FileSystemType: %c%c%c%c.\n", FatXVolumeBootSector->FileSystemType[0], FatXVolumeBootSector->FileSystemType[1], FatXVolumeBootSector->FileSystemType[2], FatXVolumeBootSector->FileSystemType[3]));
169 DbgPrint((DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", FatXVolumeBootSector->VolumeSerialNumber));
170 DbgPrint((DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", FatXVolumeBootSector->SectorsPerCluster));
171 DbgPrint((DPRINT_FILESYSTEM, "NumberOfFats: %d\n", FatXVolumeBootSector->NumberOfFats));
172 DbgPrint((DPRINT_FILESYSTEM, "Unknown: 0x%x\n", FatXVolumeBootSector->Unknown));
173
174 DbgPrint((DPRINT_FILESYSTEM, "FatType %s\n", FatType == FATX16 ? "FATX16" : "FATX32"));
175
176 }
177 else if (FatType == FAT32)
178 {
179 FatSwapFat32BootSector(Fat32VolumeBootSector);
180 DbgPrint((DPRINT_FILESYSTEM, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR)));
181
182 DbgPrint((DPRINT_FILESYSTEM, "JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector->JumpBoot[0], Fat32VolumeBootSector->JumpBoot[1], Fat32VolumeBootSector->JumpBoot[2]));
183 DbgPrint((DPRINT_FILESYSTEM, "OemName: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->OemName[0], Fat32VolumeBootSector->OemName[1], Fat32VolumeBootSector->OemName[2], Fat32VolumeBootSector->OemName[3], Fat32VolumeBootSector->OemName[4], Fat32VolumeBootSector->OemName[5], Fat32VolumeBootSector->OemName[6], Fat32VolumeBootSector->OemName[7]));
184 DbgPrint((DPRINT_FILESYSTEM, "BytesPerSector: %d\n", Fat32VolumeBootSector->BytesPerSector));
185 DbgPrint((DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", Fat32VolumeBootSector->SectorsPerCluster));
186 DbgPrint((DPRINT_FILESYSTEM, "ReservedSectors: %d\n", Fat32VolumeBootSector->ReservedSectors));
187 DbgPrint((DPRINT_FILESYSTEM, "NumberOfFats: %d\n", Fat32VolumeBootSector->NumberOfFats));
188 DbgPrint((DPRINT_FILESYSTEM, "RootDirEntries: %d\n", Fat32VolumeBootSector->RootDirEntries));
189 DbgPrint((DPRINT_FILESYSTEM, "TotalSectors: %d\n", Fat32VolumeBootSector->TotalSectors));
190 DbgPrint((DPRINT_FILESYSTEM, "MediaDescriptor: 0x%x\n", Fat32VolumeBootSector->MediaDescriptor));
191 DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFat: %d\n", Fat32VolumeBootSector->SectorsPerFat));
192 DbgPrint((DPRINT_FILESYSTEM, "SectorsPerTrack: %d\n", Fat32VolumeBootSector->SectorsPerTrack));
193 DbgPrint((DPRINT_FILESYSTEM, "NumberOfHeads: %d\n", Fat32VolumeBootSector->NumberOfHeads));
194 DbgPrint((DPRINT_FILESYSTEM, "HiddenSectors: %d\n", Fat32VolumeBootSector->HiddenSectors));
195 DbgPrint((DPRINT_FILESYSTEM, "TotalSectorsBig: %d\n", Fat32VolumeBootSector->TotalSectorsBig));
196 DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFatBig: %d\n", Fat32VolumeBootSector->SectorsPerFatBig));
197 DbgPrint((DPRINT_FILESYSTEM, "ExtendedFlags: 0x%x\n", Fat32VolumeBootSector->ExtendedFlags));
198 DbgPrint((DPRINT_FILESYSTEM, "FileSystemVersion: 0x%x\n", Fat32VolumeBootSector->FileSystemVersion));
199 DbgPrint((DPRINT_FILESYSTEM, "RootDirStartCluster: %d\n", Fat32VolumeBootSector->RootDirStartCluster));
200 DbgPrint((DPRINT_FILESYSTEM, "FsInfo: %d\n", Fat32VolumeBootSector->FsInfo));
201 DbgPrint((DPRINT_FILESYSTEM, "BackupBootSector: %d\n", Fat32VolumeBootSector->BackupBootSector));
202 DbgPrint((DPRINT_FILESYSTEM, "Reserved: 0x%x\n", Fat32VolumeBootSector->Reserved));
203 DbgPrint((DPRINT_FILESYSTEM, "DriveNumber: 0x%x\n", Fat32VolumeBootSector->DriveNumber));
204 DbgPrint((DPRINT_FILESYSTEM, "Reserved1: 0x%x\n", Fat32VolumeBootSector->Reserved1));
205 DbgPrint((DPRINT_FILESYSTEM, "BootSignature: 0x%x\n", Fat32VolumeBootSector->BootSignature));
206 DbgPrint((DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector->VolumeSerialNumber));
207 DbgPrint((DPRINT_FILESYSTEM, "VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->VolumeLabel[0], Fat32VolumeBootSector->VolumeLabel[1], Fat32VolumeBootSector->VolumeLabel[2], Fat32VolumeBootSector->VolumeLabel[3], Fat32VolumeBootSector->VolumeLabel[4], Fat32VolumeBootSector->VolumeLabel[5], Fat32VolumeBootSector->VolumeLabel[6], Fat32VolumeBootSector->VolumeLabel[7], Fat32VolumeBootSector->VolumeLabel[8], Fat32VolumeBootSector->VolumeLabel[9], Fat32VolumeBootSector->VolumeLabel[10]));
208 DbgPrint((DPRINT_FILESYSTEM, "FileSystemType: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->FileSystemType[0], Fat32VolumeBootSector->FileSystemType[1], Fat32VolumeBootSector->FileSystemType[2], Fat32VolumeBootSector->FileSystemType[3], Fat32VolumeBootSector->FileSystemType[4], Fat32VolumeBootSector->FileSystemType[5], Fat32VolumeBootSector->FileSystemType[6], Fat32VolumeBootSector->FileSystemType[7]));
209 DbgPrint((DPRINT_FILESYSTEM, "BootSectorMagic: 0x%x\n", Fat32VolumeBootSector->BootSectorMagic));
210 }
211 else
212 {
213 FatSwapFatBootSector(FatVolumeBootSector);
214 DbgPrint((DPRINT_FILESYSTEM, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR)));
215
216 DbgPrint((DPRINT_FILESYSTEM, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector->JumpBoot[0], FatVolumeBootSector->JumpBoot[1], FatVolumeBootSector->JumpBoot[2]));
217 DbgPrint((DPRINT_FILESYSTEM, "OemName: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector->OemName[0], FatVolumeBootSector->OemName[1], FatVolumeBootSector->OemName[2], FatVolumeBootSector->OemName[3], FatVolumeBootSector->OemName[4], FatVolumeBootSector->OemName[5], FatVolumeBootSector->OemName[6], FatVolumeBootSector->OemName[7]));
218 DbgPrint((DPRINT_FILESYSTEM, "BytesPerSector: %d\n", FatVolumeBootSector->BytesPerSector));
219 DbgPrint((DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", FatVolumeBootSector->SectorsPerCluster));
220 DbgPrint((DPRINT_FILESYSTEM, "ReservedSectors: %d\n", FatVolumeBootSector->ReservedSectors));
221 DbgPrint((DPRINT_FILESYSTEM, "NumberOfFats: %d\n", FatVolumeBootSector->NumberOfFats));
222 DbgPrint((DPRINT_FILESYSTEM, "RootDirEntries: %d\n", FatVolumeBootSector->RootDirEntries));
223 DbgPrint((DPRINT_FILESYSTEM, "TotalSectors: %d\n", FatVolumeBootSector->TotalSectors));
224 DbgPrint((DPRINT_FILESYSTEM, "MediaDescriptor: 0x%x\n", FatVolumeBootSector->MediaDescriptor));
225 DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFat: %d\n", FatVolumeBootSector->SectorsPerFat));
226 DbgPrint((DPRINT_FILESYSTEM, "SectorsPerTrack: %d\n", FatVolumeBootSector->SectorsPerTrack));
227 DbgPrint((DPRINT_FILESYSTEM, "NumberOfHeads: %d\n", FatVolumeBootSector->NumberOfHeads));
228 DbgPrint((DPRINT_FILESYSTEM, "HiddenSectors: %d\n", FatVolumeBootSector->HiddenSectors));
229 DbgPrint((DPRINT_FILESYSTEM, "TotalSectorsBig: %d\n", FatVolumeBootSector->TotalSectorsBig));
230 DbgPrint((DPRINT_FILESYSTEM, "DriveNumber: 0x%x\n", FatVolumeBootSector->DriveNumber));
231 DbgPrint((DPRINT_FILESYSTEM, "Reserved1: 0x%x\n", FatVolumeBootSector->Reserved1));
232 DbgPrint((DPRINT_FILESYSTEM, "BootSignature: 0x%x\n", FatVolumeBootSector->BootSignature));
233 DbgPrint((DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector->VolumeSerialNumber));
234 DbgPrint((DPRINT_FILESYSTEM, "VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", FatVolumeBootSector->VolumeLabel[0], FatVolumeBootSector->VolumeLabel[1], FatVolumeBootSector->VolumeLabel[2], FatVolumeBootSector->VolumeLabel[3], FatVolumeBootSector->VolumeLabel[4], FatVolumeBootSector->VolumeLabel[5], FatVolumeBootSector->VolumeLabel[6], FatVolumeBootSector->VolumeLabel[7], FatVolumeBootSector->VolumeLabel[8], FatVolumeBootSector->VolumeLabel[9], FatVolumeBootSector->VolumeLabel[10]));
235 DbgPrint((DPRINT_FILESYSTEM, "FileSystemType: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector->FileSystemType[0], FatVolumeBootSector->FileSystemType[1], FatVolumeBootSector->FileSystemType[2], FatVolumeBootSector->FileSystemType[3], FatVolumeBootSector->FileSystemType[4], FatVolumeBootSector->FileSystemType[5], FatVolumeBootSector->FileSystemType[6], FatVolumeBootSector->FileSystemType[7]));
236 DbgPrint((DPRINT_FILESYSTEM, "BootSectorMagic: 0x%x\n", FatVolumeBootSector->BootSectorMagic));
237 }
238
239 //
240 // Set the correct partition offset
241 //
242 FatVolumeStartSector = VolumeStartSector;
243
244 //
245 // Check the boot sector magic
246 //
247 if (! ISFATX(FatType) && FatVolumeBootSector->BootSectorMagic != 0xaa55)
248 {
249 sprintf(ErrMsg, "Invalid boot sector magic on drive 0x%x (expected 0xaa55 found 0x%x)",
250 DriveNumber, FatVolumeBootSector->BootSectorMagic);
251 FileSystemError(ErrMsg);
252 MmHeapFree(FatVolumeBootSector);
253 return FALSE;
254 }
255
256 //
257 // Check the FAT cluster size
258 // We do not support clusters bigger than 64k
259 //
260 if ((ISFATX(FatType) && 64 * 1024 < FatXVolumeBootSector->SectorsPerCluster * 512) ||
261 (! ISFATX(FatType) && 64 * 1024 < FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector))
262 {
263 FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
264 MmHeapFree(FatVolumeBootSector);
265 return FALSE;
266 }
267
268 //
269 // Clear our variables
270 //
271 FatSectorStart = 0;
272 ActiveFatSectorStart = 0;
273 NumberOfFats = 0;
274 RootDirSectorStart = 0;
275 DataSectorStart = 0;
276 SectorsPerFat = 0;
277 RootDirSectors = 0;
278
279 //
280 // Get the sectors per FAT,
281 // root directory starting sector,
282 // and data sector start
283 //
284 if (ISFATX(FatType))
285 {
286 BytesPerSector = 512;
287 SectorsPerCluster = SWAPD(FatXVolumeBootSector->SectorsPerCluster);
288 FatSectorStart = (4096 / BytesPerSector);
289 ActiveFatSectorStart = FatSectorStart;
290 NumberOfFats = 1;
291 FatSize = PartitionSectorCount / SectorsPerCluster *
292 (FATX16 == FatType ? 2 : 4);
293 SectorsPerFat = (((FatSize + 4095) / 4096) * 4096) / BytesPerSector;
294
295 RootDirSectorStart = FatSectorStart + NumberOfFats * SectorsPerFat;
296 RootDirSectors = FatXVolumeBootSector->SectorsPerCluster;
297
298 DataSectorStart = RootDirSectorStart + RootDirSectors;
299 }
300 else if (FatType != FAT32)
301 {
302 BytesPerSector = FatVolumeBootSector->BytesPerSector;
303 SectorsPerCluster = FatVolumeBootSector->SectorsPerCluster;
304 FatSectorStart = FatVolumeBootSector->ReservedSectors;
305 ActiveFatSectorStart = FatSectorStart;
306 NumberOfFats = FatVolumeBootSector->NumberOfFats;
307 SectorsPerFat = FatVolumeBootSector->SectorsPerFat;
308
309 RootDirSectorStart = FatSectorStart + NumberOfFats * SectorsPerFat;
310 RootDirSectors = ((FatVolumeBootSector->RootDirEntries * 32) + (BytesPerSector - 1)) / BytesPerSector;
311
312 DataSectorStart = RootDirSectorStart + RootDirSectors;
313 }
314 else
315 {
316 BytesPerSector = Fat32VolumeBootSector->BytesPerSector;
317 SectorsPerCluster = Fat32VolumeBootSector->SectorsPerCluster;
318 FatSectorStart = Fat32VolumeBootSector->ReservedSectors;
319 ActiveFatSectorStart = FatSectorStart +
320 ((Fat32VolumeBootSector->ExtendedFlags & 0x80) ? ((Fat32VolumeBootSector->ExtendedFlags & 0x0f) * Fat32VolumeBootSector->SectorsPerFatBig) : 0);
321 NumberOfFats = Fat32VolumeBootSector->NumberOfFats;
322 SectorsPerFat = Fat32VolumeBootSector->SectorsPerFatBig;
323
324 RootDirStartCluster = Fat32VolumeBootSector->RootDirStartCluster;
325 DataSectorStart = FatSectorStart + NumberOfFats * SectorsPerFat;
326
327 //
328 // Check version
329 // we only work with version 0
330 //
331 if (Fat32VolumeBootSector->FileSystemVersion != 0)
332 {
333 FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
334 return FALSE;
335 }
336 }
337 MmHeapFree(FatVolumeBootSector);
338
339 if (gCacheEnabled)
340 {
341 //
342 // Initialize the disk cache for this drive
343 //
344 if (!CacheInitializeDrive(DriveNumber))
345 {
346 return FALSE;
347 }
348
349 //
350 // Force the FAT sectors into the cache
351 // as long as it is FAT12 or FAT16. FAT32 can
352 // have a multi-megabyte FAT so we don't want that.
353 //
354 if (FatType != FAT32 && FatType != FATX32)
355 {
356 if (!CacheForceDiskSectorsIntoCache(DriveNumber, ActiveFatSectorStart, SectorsPerFat))
357 {
358 return FALSE;
359 }
360 }
361 }
362 else
363 {
364 GEOMETRY DriveGeometry;
365 ULONG BlockSize;
366
367 // Initialize drive by getting its geometry
368 if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry))
369 {
370 return FALSE;
371 }
372
373 BlockSize = MachDiskGetCacheableBlockCount(DriveNumber);
374 }
375
376 return TRUE;
377 }
378
379 ULONG FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector, ULONG PartitionSectorCount)
380 {
381 ULONG RootDirSectors;
382 ULONG DataSectorCount;
383 ULONG SectorsPerFat;
384 ULONG TotalSectors;
385 ULONG CountOfClusters;
386 PFAT32_BOOTSECTOR Fat32BootSector = (PFAT32_BOOTSECTOR)FatBootSector;
387 PFATX_BOOTSECTOR FatXBootSector = (PFATX_BOOTSECTOR)FatBootSector;
388
389 if (0 == strncmp(FatXBootSector->FileSystemType, "FATX", 4))
390 {
391 CountOfClusters = PartitionSectorCount / FatXBootSector->SectorsPerCluster;
392 if (CountOfClusters < 65525)
393 {
394 /* Volume is FATX16 */
395 return FATX16;
396 }
397 else
398 {
399 /* Volume is FAT32 */
400 return FATX32;
401 }
402 }
403 else
404 {
405 RootDirSectors = ((SWAPW(FatBootSector->RootDirEntries) * 32) + (SWAPW(FatBootSector->BytesPerSector) - 1)) / SWAPW(FatBootSector->BytesPerSector);
406 SectorsPerFat = SWAPW(FatBootSector->SectorsPerFat) ? SWAPW(FatBootSector->SectorsPerFat) : SWAPD(Fat32BootSector->SectorsPerFatBig);
407 TotalSectors = SWAPW(FatBootSector->TotalSectors) ? SWAPW(FatBootSector->TotalSectors) : SWAPD(FatBootSector->TotalSectorsBig);
408 DataSectorCount = TotalSectors - (SWAPW(FatBootSector->ReservedSectors) + (FatBootSector->NumberOfFats * SectorsPerFat) + RootDirSectors);
409
410 //mjl
411 if (FatBootSector->SectorsPerCluster == 0)
412 CountOfClusters = 0;
413 else
414 CountOfClusters = DataSectorCount / FatBootSector->SectorsPerCluster;
415
416 if (CountOfClusters < 4085)
417 {
418 /* Volume is FAT12 */
419 return FAT12;
420 }
421 else if (CountOfClusters < 65525)
422 {
423 /* Volume is FAT16 */
424 return FAT16;
425 }
426 else
427 {
428 /* Volume is FAT32 */
429 return FAT32;
430 }
431 }
432 }
433
434 PVOID FatBufferDirectory(ULONG DirectoryStartCluster, ULONG *DirectorySize, BOOLEAN RootDirectory)
435 {
436 PVOID DirectoryBuffer;
437
438 DbgPrint((DPRINT_FILESYSTEM, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster, (RootDirectory ? "TRUE" : "FALSE")));
439
440 /*
441 * For FAT32, the root directory is nothing special. We can treat it the same
442 * as a subdirectory.
443 */
444 if (RootDirectory && FAT32 == FatType)
445 {
446 DirectoryStartCluster = RootDirStartCluster;
447 RootDirectory = FALSE;
448 }
449
450 //
451 // Calculate the size of the directory
452 //
453 if (RootDirectory)
454 {
455 *DirectorySize = RootDirSectors * BytesPerSector;
456 }
457 else
458 {
459 *DirectorySize = FatCountClustersInChain(DirectoryStartCluster) * SectorsPerCluster * BytesPerSector;
460 }
461
462 //
463 // Attempt to allocate memory for directory buffer
464 //
465 DbgPrint((DPRINT_FILESYSTEM, "Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize));
466 DirectoryBuffer = MmHeapAlloc(*DirectorySize);
467
468 if (DirectoryBuffer == NULL)
469 {
470 return NULL;
471 }
472
473 //
474 // Now read directory contents into DirectoryBuffer
475 //
476 if (RootDirectory)
477 {
478 if (!FatReadVolumeSectors(FatDriveNumber, RootDirSectorStart, RootDirSectors, DirectoryBuffer))
479 {
480 MmHeapFree(DirectoryBuffer);
481 return NULL;
482 }
483 }
484 else
485 {
486 if (!FatReadClusterChain(DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer))
487 {
488 MmHeapFree(DirectoryBuffer);
489 return NULL;
490 }
491 }
492
493 return DirectoryBuffer;
494 }
495
496 BOOLEAN FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
497 {
498 ULONG EntryCount;
499 ULONG CurrentEntry;
500 CHAR LfnNameBuffer[265];
501 CHAR ShortNameBuffer[20];
502 ULONG StartCluster;
503 DIRENTRY OurDirEntry;
504 LFN_DIRENTRY OurLfnDirEntry;
505 PDIRENTRY DirEntry = &OurDirEntry;
506 PLFN_DIRENTRY LfnDirEntry = &OurLfnDirEntry;
507
508 EntryCount = DirectorySize / sizeof(DIRENTRY);
509
510 DbgPrint((DPRINT_FILESYSTEM, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer, EntryCount, FileName));
511
512 memset(ShortNameBuffer, 0, 13 * sizeof(CHAR));
513 memset(LfnNameBuffer, 0, 261 * sizeof(CHAR));
514
515 for (CurrentEntry=0; CurrentEntry<EntryCount; CurrentEntry++, DirectoryBuffer = ((PDIRENTRY)DirectoryBuffer)+1)
516 {
517 OurLfnDirEntry = *((PLFN_DIRENTRY) DirectoryBuffer);
518 FatSwapLFNDirEntry(LfnDirEntry);
519 OurDirEntry = *((PDIRENTRY) DirectoryBuffer);
520 FatSwapDirEntry(DirEntry);
521
522 //DbgPrint((DPRINT_FILESYSTEM, "Dumping directory entry %d:\n", CurrentEntry));
523 //DbgDumpBuffer(DPRINT_FILESYSTEM, DirEntry, sizeof(DIRENTRY));
524
525 //
526 // Check if this is the last file in the directory
527 // If DirEntry[0] == 0x00 then that means all the
528 // entries after this one are unused. If this is the
529 // last entry then we didn't find the file in this directory.
530 //
531 if (DirEntry->FileName[0] == '\0')
532 {
533 return FALSE;
534 }
535
536 //
537 // Check if this is a deleted entry or not
538 //
539 if (DirEntry->FileName[0] == '\xE5')
540 {
541 memset(ShortNameBuffer, 0, 13 * sizeof(CHAR));
542 memset(LfnNameBuffer, 0, 261 * sizeof(CHAR));
543 continue;
544 }
545
546 //
547 // Check if this is a LFN entry
548 // If so it needs special handling
549 //
550 if (DirEntry->Attr == ATTR_LONG_NAME)
551 {
552 //
553 // Check to see if this is a deleted LFN entry, if so continue
554 //
555 if (LfnDirEntry->SequenceNumber & 0x80)
556 {
557 continue;
558 }
559
560 //
561 // Mask off high two bits of sequence number
562 // and make the sequence number zero-based
563 //
564 LfnDirEntry->SequenceNumber &= 0x3F;
565 LfnDirEntry->SequenceNumber--;
566
567 //
568 // Get all 13 LFN entry characters
569 //
570 if (LfnDirEntry->Name0_4[0] != 0xFFFF)
571 {
572 LfnNameBuffer[0 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[0];
573 }
574 if (LfnDirEntry->Name0_4[1] != 0xFFFF)
575 {
576 LfnNameBuffer[1 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[1];
577 }
578 if (LfnDirEntry->Name0_4[2] != 0xFFFF)
579 {
580 LfnNameBuffer[2 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[2];
581 }
582 if (LfnDirEntry->Name0_4[3] != 0xFFFF)
583 {
584 LfnNameBuffer[3 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[3];
585 }
586 if (LfnDirEntry->Name0_4[4] != 0xFFFF)
587 {
588 LfnNameBuffer[4 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[4];
589 }
590 if (LfnDirEntry->Name5_10[0] != 0xFFFF)
591 {
592 LfnNameBuffer[5 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[0];
593 }
594 if (LfnDirEntry->Name5_10[1] != 0xFFFF)
595 {
596 LfnNameBuffer[6 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[1];
597 }
598 if (LfnDirEntry->Name5_10[2] != 0xFFFF)
599 {
600 LfnNameBuffer[7 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[2];
601 }
602 if (LfnDirEntry->Name5_10[3] != 0xFFFF)
603 {
604 LfnNameBuffer[8 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[3];
605 }
606 if (LfnDirEntry->Name5_10[4] != 0xFFFF)
607 {
608 LfnNameBuffer[9 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[4];
609 }
610 if (LfnDirEntry->Name5_10[5] != 0xFFFF)
611 {
612 LfnNameBuffer[10 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[5];
613 }
614 if (LfnDirEntry->Name11_12[0] != 0xFFFF)
615 {
616 LfnNameBuffer[11 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[0];
617 }
618 if (LfnDirEntry->Name11_12[1] != 0xFFFF)
619 {
620 LfnNameBuffer[12 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[1];
621 }
622
623 //DbgPrint((DPRINT_FILESYSTEM, "Dumping long name buffer:\n"));
624 //DbgDumpBuffer(DPRINT_FILESYSTEM, LfnNameBuffer, 260);
625
626 continue;
627 }
628
629 //
630 // Check for the volume label attribute
631 // and skip over this entry if found
632 //
633 if (DirEntry->Attr & ATTR_VOLUMENAME)
634 {
635 memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR));
636 memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR));
637 continue;
638 }
639
640 //
641 // If we get here then we've found a short file name
642 // entry and LfnNameBuffer contains the long file
643 // name or zeroes. All we have to do now is see if the
644 // file name matches either the short or long file name
645 // and fill in the FAT_FILE_INFO structure if it does
646 // or zero our buffers and continue looking.
647 //
648
649 //
650 // Get short file name
651 //
652 FatParseShortFileName(ShortNameBuffer, DirEntry);
653
654 DbgPrint((DPRINT_FILESYSTEM, "Entry: %d LFN = %s\n", CurrentEntry, LfnNameBuffer));
655 DbgPrint((DPRINT_FILESYSTEM, "Entry: %d DOS name = %s\n", CurrentEntry, ShortNameBuffer));
656
657 //
658 // See if the file name matches either the short or long name
659 //
660 if (((strlen(FileName) == strlen(LfnNameBuffer)) && (_stricmp(FileName, LfnNameBuffer) == 0)) ||
661 ((strlen(FileName) == strlen(ShortNameBuffer)) && (_stricmp(FileName, ShortNameBuffer) == 0))) {
662 //
663 // We found the entry, now fill in the FAT_FILE_INFO struct
664 //
665 FatFileInfoPointer->FileSize = DirEntry->Size;
666 FatFileInfoPointer->FilePointer = 0;
667
668 DbgPrint((DPRINT_FILESYSTEM, "MSDOS Directory Entry:\n"));
669 DbgPrint((DPRINT_FILESYSTEM, "FileName[11] = %c%c%c%c%c%c%c%c%c%c%c\n", DirEntry->FileName[0], DirEntry->FileName[1], DirEntry->FileName[2], DirEntry->FileName[3], DirEntry->FileName[4], DirEntry->FileName[5], DirEntry->FileName[6], DirEntry->FileName[7], DirEntry->FileName[8], DirEntry->FileName[9], DirEntry->FileName[10]));
670 DbgPrint((DPRINT_FILESYSTEM, "Attr = 0x%x\n", DirEntry->Attr));
671 DbgPrint((DPRINT_FILESYSTEM, "ReservedNT = 0x%x\n", DirEntry->ReservedNT));
672 DbgPrint((DPRINT_FILESYSTEM, "TimeInTenths = %d\n", DirEntry->TimeInTenths));
673 DbgPrint((DPRINT_FILESYSTEM, "CreateTime = %d\n", DirEntry->CreateTime));
674 DbgPrint((DPRINT_FILESYSTEM, "CreateDate = %d\n", DirEntry->CreateDate));
675 DbgPrint((DPRINT_FILESYSTEM, "LastAccessDate = %d\n", DirEntry->LastAccessDate));
676 DbgPrint((DPRINT_FILESYSTEM, "ClusterHigh = 0x%x\n", DirEntry->ClusterHigh));
677 DbgPrint((DPRINT_FILESYSTEM, "Time = %d\n", DirEntry->Time));
678 DbgPrint((DPRINT_FILESYSTEM, "Date = %d\n", DirEntry->Date));
679 DbgPrint((DPRINT_FILESYSTEM, "ClusterLow = 0x%x\n", DirEntry->ClusterLow));
680 DbgPrint((DPRINT_FILESYSTEM, "Size = %d\n", DirEntry->Size));
681
682 //
683 // Get the cluster chain
684 //
685 StartCluster = ((ULONG)DirEntry->ClusterHigh << 16) + DirEntry->ClusterLow;
686 DbgPrint((DPRINT_FILESYSTEM, "StartCluster = 0x%x\n", StartCluster));
687 FatFileInfoPointer->FileFatChain = FatGetClusterChainArray(StartCluster);
688
689 //
690 // See if memory allocation failed
691 //
692 if (FatFileInfoPointer->FileFatChain == NULL)
693 {
694 return FALSE;
695 }
696
697 return TRUE;
698 }
699
700 //
701 // Nope, no match - zero buffers and continue looking
702 //
703 memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR));
704 memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR));
705 continue;
706 }
707
708 return FALSE;
709 }
710
711 static BOOLEAN FatXSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
712 {
713 ULONG EntryCount;
714 ULONG CurrentEntry;
715 ULONG FileNameLen;
716 FATX_DIRENTRY OurDirEntry;
717 PFATX_DIRENTRY DirEntry = &OurDirEntry;
718
719 EntryCount = DirectorySize / sizeof(FATX_DIRENTRY);
720
721 DbgPrint((DPRINT_FILESYSTEM, "FatXSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer, EntryCount, FileName));
722
723 FileNameLen = strlen(FileName);
724
725 for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++, DirectoryBuffer = ((PFATX_DIRENTRY)DirectoryBuffer)+1)
726 {
727 OurDirEntry = *(PFATX_DIRENTRY) DirectoryBuffer;
728 FatSwapFatXDirEntry(&OurDirEntry);
729 if (0xff == DirEntry->FileNameSize)
730 {
731 break;
732 }
733 if (0xe5 == DirEntry->FileNameSize)
734 {
735 continue;
736 }
737 if (FileNameLen == DirEntry->FileNameSize &&
738 0 == _strnicmp(FileName, DirEntry->FileName, FileNameLen))
739 {
740 /*
741 * We found the entry, now fill in the FAT_FILE_INFO struct
742 */
743 FatFileInfoPointer->FileSize = DirEntry->Size;
744 FatFileInfoPointer->FilePointer = 0;
745
746 DbgPrint((DPRINT_FILESYSTEM, "FATX Directory Entry:\n"));
747 DbgPrint((DPRINT_FILESYSTEM, "FileNameSize = %d\n", DirEntry->FileNameSize));
748 DbgPrint((DPRINT_FILESYSTEM, "Attr = 0x%x\n", DirEntry->Attr));
749 DbgPrint((DPRINT_FILESYSTEM, "StartCluster = 0x%x\n", DirEntry->StartCluster));
750 DbgPrint((DPRINT_FILESYSTEM, "Size = %d\n", DirEntry->Size));
751 DbgPrint((DPRINT_FILESYSTEM, "Time = %d\n", DirEntry->Time));
752 DbgPrint((DPRINT_FILESYSTEM, "Date = %d\n", DirEntry->Date));
753 DbgPrint((DPRINT_FILESYSTEM, "CreateTime = %d\n", DirEntry->CreateTime));
754 DbgPrint((DPRINT_FILESYSTEM, "CreateDate = %d\n", DirEntry->CreateDate));
755 DbgPrint((DPRINT_FILESYSTEM, "LastAccessTime = %d\n", DirEntry->LastAccessTime));
756 DbgPrint((DPRINT_FILESYSTEM, "LastAccessDate = %d\n", DirEntry->LastAccessDate));
757
758 /*
759 * Get the cluster chain
760 */
761 FatFileInfoPointer->FileFatChain = FatGetClusterChainArray(DirEntry->StartCluster);
762
763 /*
764 * See if memory allocation failed
765 */
766 if (NULL == FatFileInfoPointer->FileFatChain)
767 {
768 return FALSE;
769 }
770
771 return TRUE;
772 }
773 }
774
775 return FALSE;
776 }
777
778 /*
779 * FatLookupFile()
780 * This function searches the file system for the
781 * specified filename and fills in a FAT_FILE_INFO structure
782 * with info describing the file, etc. returns true
783 * if the file exists or false otherwise
784 */
785 BOOLEAN FatLookupFile(PCSTR FileName, PFAT_FILE_INFO FatFileInfoPointer)
786 {
787 UINT32 i;
788 ULONG NumberOfPathParts;
789 CHAR PathPart[261];
790 PVOID DirectoryBuffer;
791 ULONG DirectoryStartCluster = 0;
792 ULONG DirectorySize;
793 FAT_FILE_INFO FatFileInfo;
794
795 DbgPrint((DPRINT_FILESYSTEM, "FatLookupFile() FileName = %s\n", FileName));
796
797 memset(FatFileInfoPointer, 0, sizeof(FAT_FILE_INFO));
798
799 //
800 // Figure out how many sub-directories we are nested in
801 //
802 NumberOfPathParts = FsGetNumPathParts(FileName);
803
804 //
805 // Loop once for each part
806 //
807 for (i=0; i<NumberOfPathParts; i++)
808 {
809 //
810 // Get first path part
811 //
812 FsGetFirstNameFromPath(PathPart, FileName);
813
814 //
815 // Advance to the next part of the path
816 //
817 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
818 {
819 }
820 FileName++;
821
822 //
823 // Buffer the directory contents
824 //
825 DirectoryBuffer = FatBufferDirectory(DirectoryStartCluster, &DirectorySize, (i == 0) );
826 if (DirectoryBuffer == NULL)
827 {
828 return FALSE;
829 }
830
831 //
832 // Search for file name in directory
833 //
834 if (ISFATX(FatType))
835 {
836 if (!FatXSearchDirectoryBufferForFile(DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo))
837 {
838 MmHeapFree(DirectoryBuffer);
839 return FALSE;
840 }
841 }
842 else
843 {
844 if (!FatSearchDirectoryBufferForFile(DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo))
845 {
846 MmHeapFree(DirectoryBuffer);
847 return FALSE;
848 }
849 }
850
851 MmHeapFree(DirectoryBuffer);
852
853 //
854 // If we have another sub-directory to go then
855 // grab the start cluster and free the fat chain array
856 //
857 if ((i+1) < NumberOfPathParts)
858 {
859 DirectoryStartCluster = FatFileInfo.FileFatChain[0];
860 MmHeapFree(FatFileInfo.FileFatChain);
861 }
862 }
863
864 memcpy(FatFileInfoPointer, &FatFileInfo, sizeof(FAT_FILE_INFO));
865
866 return TRUE;
867 }
868
869 /*
870 * FatParseFileName()
871 * This function parses a directory entry name which
872 * is in the form of "FILE EXT" and puts it in Buffer
873 * in the form of "file.ext"
874 */
875 void FatParseShortFileName(PCHAR Buffer, PDIRENTRY DirEntry)
876 {
877 ULONG Idx;
878
879 Idx = 0;
880 RtlZeroMemory(Buffer, 13);
881
882 //
883 // Fixup first character
884 //
885 if (DirEntry->FileName[0] == 0x05)
886 {
887 DirEntry->FileName[0] = 0xE5;
888 }
889
890 //
891 // Get the file name
892 //
893 while (Idx < 8)
894 {
895 if (DirEntry->FileName[Idx] == ' ')
896 {
897 break;
898 }
899
900 Buffer[Idx] = DirEntry->FileName[Idx];
901 Idx++;
902 }
903
904 //
905 // Get extension
906 //
907 if ((DirEntry->FileName[8] != ' '))
908 {
909 Buffer[Idx++] = '.';
910 Buffer[Idx++] = (DirEntry->FileName[8] == ' ') ? '\0' : DirEntry->FileName[8];
911 Buffer[Idx++] = (DirEntry->FileName[9] == ' ') ? '\0' : DirEntry->FileName[9];
912 Buffer[Idx++] = (DirEntry->FileName[10] == ' ') ? '\0' : DirEntry->FileName[10];
913 }
914
915 DbgPrint((DPRINT_FILESYSTEM, "FatParseShortFileName() ShortName = %s\n", Buffer));
916 }
917
918 /*
919 * FatGetFatEntry()
920 * returns the Fat entry for a given cluster number
921 */
922 BOOLEAN FatGetFatEntry(ULONG Cluster, ULONG* ClusterPointer)
923 {
924 ULONG fat = 0;
925 UINT32 FatOffset;
926 UINT32 ThisFatSecNum;
927 UINT32 ThisFatEntOffset;
928
929 DbgPrint((DPRINT_FILESYSTEM, "FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster));
930
931 switch(FatType)
932 {
933 case FAT12:
934
935 FatOffset = Cluster + (Cluster / 2);
936 ThisFatSecNum = ActiveFatSectorStart + (FatOffset / BytesPerSector);
937 ThisFatEntOffset = (FatOffset % BytesPerSector);
938
939 DbgPrint((DPRINT_FILESYSTEM, "FatOffset: %d\n", FatOffset));
940 DbgPrint((DPRINT_FILESYSTEM, "ThisFatSecNum: %d\n", ThisFatSecNum));
941 DbgPrint((DPRINT_FILESYSTEM, "ThisFatEntOffset: %d\n", ThisFatEntOffset));
942
943 if (ThisFatEntOffset == (BytesPerSector - 1))
944 {
945 if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 2, (PVOID)FILESYSBUFFER))
946 {
947 return FALSE;
948 }
949 }
950 else
951 {
952 if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
953 {
954 return FALSE;
955 }
956 }
957
958 fat = *((USHORT *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset));
959 fat = SWAPW(fat);
960 if (Cluster & 0x0001)
961 fat = fat >> 4; /* Cluster number is ODD */
962 else
963 fat = fat & 0x0FFF; /* Cluster number is EVEN */
964
965 break;
966
967 case FAT16:
968 case FATX16:
969
970 FatOffset = (Cluster * 2);
971 ThisFatSecNum = ActiveFatSectorStart + (FatOffset / BytesPerSector);
972 ThisFatEntOffset = (FatOffset % BytesPerSector);
973
974 if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
975 {
976 return FALSE;
977 }
978
979 fat = *((USHORT *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset));
980 fat = SWAPW(fat);
981
982 break;
983
984 case FAT32:
985 case FATX32:
986
987 FatOffset = (Cluster * 4);
988 ThisFatSecNum = ActiveFatSectorStart + (FatOffset / BytesPerSector);
989 ThisFatEntOffset = (FatOffset % BytesPerSector);
990
991 if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
992 {
993 return FALSE;
994 }
995
996 // Get the fat entry
997 fat = (*((ULONG *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset))) & 0x0FFFFFFF;
998 fat = SWAPD(fat);
999
1000 break;
1001
1002 }
1003
1004 DbgPrint((DPRINT_FILESYSTEM, "FAT entry is 0x%x.\n", fat));
1005
1006 *ClusterPointer = fat;
1007
1008 return TRUE;
1009 }
1010
1011 /*
1012 * FatOpenFile()
1013 * Tries to open the file 'name' and returns true or false
1014 * for success and failure respectively
1015 */
1016 FILE* FatOpenFile(PCSTR FileName)
1017 {
1018 FAT_FILE_INFO TempFatFileInfo;
1019 PFAT_FILE_INFO FileHandle;
1020
1021 DbgPrint((DPRINT_FILESYSTEM, "FatOpenFile() FileName = %s\n", FileName));
1022
1023 if (!FatLookupFile(FileName, &TempFatFileInfo))
1024 {
1025 return NULL;
1026 }
1027
1028 FileHandle = MmHeapAlloc(sizeof(FAT_FILE_INFO));
1029
1030 if (FileHandle == NULL)
1031 {
1032 return NULL;
1033 }
1034
1035 memcpy(FileHandle, &TempFatFileInfo, sizeof(FAT_FILE_INFO));
1036
1037 return (FILE*)FileHandle;
1038 }
1039
1040 ULONG FatCountClustersInChain(ULONG StartCluster)
1041 {
1042 ULONG ClusterCount = 0;
1043
1044 DbgPrint((DPRINT_FILESYSTEM, "FatCountClustersInChain() StartCluster = %d\n", StartCluster));
1045
1046 while (1)
1047 {
1048 //
1049 // If end of chain then break out of our cluster counting loop
1050 //
1051 if (((FatType == FAT12) && (StartCluster >= 0xff8)) ||
1052 ((FatType == FAT16 || FatType == FATX16) && (StartCluster >= 0xfff8)) ||
1053 ((FatType == FAT32 || FatType == FATX32) && (StartCluster >= 0x0ffffff8)))
1054 {
1055 break;
1056 }
1057
1058 //
1059 // Increment count
1060 //
1061 ClusterCount++;
1062
1063 //
1064 // Get next cluster
1065 //
1066 if (!FatGetFatEntry(StartCluster, &StartCluster))
1067 {
1068 return 0;
1069 }
1070 }
1071
1072 DbgPrint((DPRINT_FILESYSTEM, "FatCountClustersInChain() ClusterCount = %d\n", ClusterCount));
1073
1074 return ClusterCount;
1075 }
1076
1077 ULONG* FatGetClusterChainArray(ULONG StartCluster)
1078 {
1079 ULONG ClusterCount;
1080 ULONG ArraySize;
1081 ULONG* ArrayPointer;
1082 ULONG Idx;
1083
1084 DbgPrint((DPRINT_FILESYSTEM, "FatGetClusterChainArray() StartCluster = %d\n", StartCluster));
1085
1086 ClusterCount = FatCountClustersInChain(StartCluster) + 1; // Lets get the 0x0ffffff8 on the end of the array
1087 ArraySize = ClusterCount * sizeof(ULONG);
1088
1089 //
1090 // Allocate array memory
1091 //
1092 ArrayPointer = MmHeapAlloc(ArraySize);
1093
1094 if (ArrayPointer == NULL)
1095 {
1096 return NULL;
1097 }
1098
1099 //
1100 // Loop through and set array values
1101 //
1102 for (Idx=0; Idx<ClusterCount; Idx++)
1103 {
1104 //
1105 // Set current cluster
1106 //
1107 ArrayPointer[Idx] = StartCluster;
1108
1109 //
1110 // Don't try to get next cluster for last cluster
1111 //
1112 if (((FatType == FAT12) && (StartCluster >= 0xff8)) ||
1113 ((FatType == FAT16 || FatType == FATX16) && (StartCluster >= 0xfff8)) ||
1114 ((FatType == FAT32 || FatType == FATX32) && (StartCluster >= 0x0ffffff8)))
1115 {
1116 Idx++;
1117 break;
1118 }
1119
1120 //
1121 // Get next cluster
1122 //
1123 if (!FatGetFatEntry(StartCluster, &StartCluster))
1124 {
1125 MmHeapFree(ArrayPointer);
1126 return NULL;
1127 }
1128 }
1129
1130 return ArrayPointer;
1131 }
1132
1133 /*
1134 * FatReadCluster()
1135 * Reads the specified cluster into memory
1136 */
1137 BOOLEAN FatReadCluster(ULONG ClusterNumber, PVOID Buffer)
1138 {
1139 ULONG ClusterStartSector;
1140
1141 ClusterStartSector = ((ClusterNumber - 2) * SectorsPerCluster) + DataSectorStart;
1142
1143 DbgPrint((DPRINT_FILESYSTEM, "FatReadCluster() ClusterNumber = %d Buffer = 0x%x ClusterStartSector = %d\n", ClusterNumber, Buffer, ClusterStartSector));
1144
1145 if (!FatReadVolumeSectors(FatDriveNumber, ClusterStartSector, SectorsPerCluster, (PVOID)FILESYSBUFFER))
1146 {
1147 return FALSE;
1148 }
1149
1150 memcpy(Buffer, (PVOID)FILESYSBUFFER, SectorsPerCluster * BytesPerSector);
1151
1152 return TRUE;
1153 }
1154
1155 /*
1156 * FatReadClusterChain()
1157 * Reads the specified clusters into memory
1158 */
1159 BOOLEAN FatReadClusterChain(ULONG StartClusterNumber, ULONG NumberOfClusters, PVOID Buffer)
1160 {
1161 ULONG ClusterStartSector;
1162
1163 DbgPrint((DPRINT_FILESYSTEM, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer));
1164
1165 while (NumberOfClusters > 0)
1166 {
1167
1168 DbgPrint((DPRINT_FILESYSTEM, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer));
1169 //
1170 // Calculate starting sector for cluster
1171 //
1172 ClusterStartSector = ((StartClusterNumber - 2) * SectorsPerCluster) + DataSectorStart;
1173
1174 //
1175 // Read cluster into memory
1176 //
1177 if (!FatReadVolumeSectors(FatDriveNumber, ClusterStartSector, SectorsPerCluster, (PVOID)FILESYSBUFFER))
1178 {
1179 return FALSE;
1180 }
1181
1182 memcpy(Buffer, (PVOID)FILESYSBUFFER, SectorsPerCluster * BytesPerSector);
1183
1184 //
1185 // Decrement count of clusters left to read
1186 //
1187 NumberOfClusters--;
1188
1189 //
1190 // Increment buffer address by cluster size
1191 //
1192 Buffer = (PVOID)((ULONG_PTR)Buffer + (SectorsPerCluster * BytesPerSector));
1193
1194 //
1195 // Get next cluster
1196 //
1197 if (!FatGetFatEntry(StartClusterNumber, &StartClusterNumber))
1198 {
1199 return FALSE;
1200 }
1201
1202 //
1203 // If end of chain then break out of our cluster reading loop
1204 //
1205 if (((FatType == FAT12) && (StartClusterNumber >= 0xff8)) ||
1206 ((FatType == FAT16 || FatType == FATX16) && (StartClusterNumber >= 0xfff8)) ||
1207 ((FatType == FAT32 || FatType == FATX32) && (StartClusterNumber >= 0x0ffffff8)))
1208 {
1209 break;
1210 }
1211 }
1212
1213 return TRUE;
1214 }
1215
1216 /*
1217 * FatReadPartialCluster()
1218 * Reads part of a cluster into memory
1219 */
1220 BOOLEAN FatReadPartialCluster(ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
1221 {
1222 ULONG ClusterStartSector;
1223
1224 DbgPrint((DPRINT_FILESYSTEM, "FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber, StartingOffset, Length, Buffer));
1225
1226 ClusterStartSector = ((ClusterNumber - 2) * SectorsPerCluster) + DataSectorStart;
1227
1228 if (!FatReadVolumeSectors(FatDriveNumber, ClusterStartSector, SectorsPerCluster, (PVOID)FILESYSBUFFER))
1229 {
1230 return FALSE;
1231 }
1232
1233 memcpy(Buffer, (PVOID)((ULONG_PTR)FILESYSBUFFER + StartingOffset), Length);
1234
1235 return TRUE;
1236 }
1237
1238 /*
1239 * FatReadFile()
1240 * Reads BytesToRead from open file and
1241 * returns the number of bytes read in BytesRead
1242 */
1243 BOOLEAN FatReadFile(FILE *FileHandle, ULONG BytesToRead, ULONG* BytesRead, PVOID Buffer)
1244 {
1245 PFAT_FILE_INFO FatFileInfo = (PFAT_FILE_INFO)FileHandle;
1246 ULONG ClusterNumber;
1247 ULONG OffsetInCluster;
1248 ULONG LengthInCluster;
1249 ULONG NumberOfClusters;
1250 ULONG BytesPerCluster;
1251
1252 DbgPrint((DPRINT_FILESYSTEM, "FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead, Buffer));
1253
1254 if (BytesRead != NULL)
1255 {
1256 *BytesRead = 0;
1257 }
1258
1259 //
1260 // If they are trying to read past the
1261 // end of the file then return success
1262 // with BytesRead == 0
1263 //
1264 if (FatFileInfo->FilePointer >= FatFileInfo->FileSize)
1265 {
1266 return TRUE;
1267 }
1268
1269 //
1270 // If they are trying to read more than there is to read
1271 // then adjust the amount to read
1272 //
1273 if ((FatFileInfo->FilePointer + BytesToRead) > FatFileInfo->FileSize)
1274 {
1275 BytesToRead = (FatFileInfo->FileSize - FatFileInfo->FilePointer);
1276 }
1277
1278 //
1279 // Ok, now we have to perform at most 3 calculations
1280 // I'll draw you a picture (using nifty ASCII art):
1281 //
1282 // CurrentFilePointer -+
1283 // |
1284 // +----------------+
1285 // |
1286 // +-----------+-----------+-----------+-----------+
1287 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
1288 // +-----------+-----------+-----------+-----------+
1289 // | |
1290 // +---------------+--------------------+
1291 // |
1292 // BytesToRead -------+
1293 //
1294 // 1 - The first calculation (and read) will align
1295 // the file pointer with the next cluster.
1296 // boundary (if we are supposed to read that much)
1297 // 2 - The next calculation (and read) will read
1298 // in all the full clusters that the requested
1299 // amount of data would cover (in this case
1300 // clusters 2 & 3).
1301 // 3 - The last calculation (and read) would read
1302 // in the remainder of the data requested out of
1303 // the last cluster.
1304 //
1305
1306 BytesPerCluster = SectorsPerCluster * BytesPerSector;
1307
1308 //
1309 // Only do the first read if we
1310 // aren't aligned on a cluster boundary
1311 //
1312 if (FatFileInfo->FilePointer % BytesPerCluster)
1313 {
1314 //
1315 // Do the math for our first read
1316 //
1317 ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster);
1318 ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber];
1319 OffsetInCluster = (FatFileInfo->FilePointer % BytesPerCluster);
1320 LengthInCluster = (BytesToRead > (BytesPerCluster - OffsetInCluster)) ? (BytesPerCluster - OffsetInCluster) : BytesToRead;
1321
1322 //
1323 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1324 //
1325 if (!FatReadPartialCluster(ClusterNumber, OffsetInCluster, LengthInCluster, Buffer))
1326 {
1327 return FALSE;
1328 }
1329 if (BytesRead != NULL)
1330 {
1331 *BytesRead += LengthInCluster;
1332 }
1333 BytesToRead -= LengthInCluster;
1334 FatFileInfo->FilePointer += LengthInCluster;
1335 Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInCluster);
1336 }
1337
1338 //
1339 // Do the math for our second read (if any data left)
1340 //
1341 if (BytesToRead > 0)
1342 {
1343 //
1344 // Determine how many full clusters we need to read
1345 //
1346 NumberOfClusters = (BytesToRead / BytesPerCluster);
1347
1348 if (NumberOfClusters > 0)
1349 {
1350 ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster);
1351 ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber];
1352
1353 //
1354 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1355 //
1356 if (!FatReadClusterChain(ClusterNumber, NumberOfClusters, Buffer))
1357 {
1358 return FALSE;
1359 }
1360 if (BytesRead != NULL)
1361 {
1362 *BytesRead += (NumberOfClusters * BytesPerCluster);
1363 }
1364 BytesToRead -= (NumberOfClusters * BytesPerCluster);
1365 FatFileInfo->FilePointer += (NumberOfClusters * BytesPerCluster);
1366 Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfClusters * BytesPerCluster));
1367 }
1368 }
1369
1370 //
1371 // Do the math for our third read (if any data left)
1372 //
1373 if (BytesToRead > 0)
1374 {
1375 ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster);
1376 ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber];
1377
1378 //
1379 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1380 //
1381 if (!FatReadPartialCluster(ClusterNumber, 0, BytesToRead, Buffer))
1382 {
1383 return FALSE;
1384 }
1385 if (BytesRead != NULL)
1386 {
1387 *BytesRead += BytesToRead;
1388 }
1389 FatFileInfo->FilePointer += BytesToRead;
1390 BytesToRead -= BytesToRead;
1391 Buffer = (PVOID)((ULONG_PTR)Buffer + BytesToRead);
1392 }
1393
1394 return TRUE;
1395 }
1396
1397 ULONG FatGetFileSize(FILE *FileHandle)
1398 {
1399 PFAT_FILE_INFO FatFileHandle = (PFAT_FILE_INFO)FileHandle;
1400
1401 DbgPrint((DPRINT_FILESYSTEM, "FatGetFileSize() FileSize = %d\n", FatFileHandle->FileSize));
1402
1403 return FatFileHandle->FileSize;
1404 }
1405
1406 VOID FatSetFilePointer(FILE *FileHandle, ULONG NewFilePointer)
1407 {
1408 PFAT_FILE_INFO FatFileHandle = (PFAT_FILE_INFO)FileHandle;
1409
1410 DbgPrint((DPRINT_FILESYSTEM, "FatSetFilePointer() NewFilePointer = %d\n", NewFilePointer));
1411
1412 FatFileHandle->FilePointer = NewFilePointer;
1413 }
1414
1415 ULONG FatGetFilePointer(FILE *FileHandle)
1416 {
1417 PFAT_FILE_INFO FatFileHandle = (PFAT_FILE_INFO)FileHandle;
1418
1419 DbgPrint((DPRINT_FILESYSTEM, "FatGetFilePointer() FilePointer = %d\n", FatFileHandle->FilePointer));
1420
1421 return FatFileHandle->FilePointer;
1422 }
1423
1424 BOOLEAN FatReadVolumeSectors(ULONG DriveNumber, ULONG SectorNumber, ULONG SectorCount, PVOID Buffer)
1425 {
1426 if (gCacheEnabled)
1427 {
1428 return CacheReadDiskSectors(DriveNumber, SectorNumber + FatVolumeStartSector, SectorCount, Buffer);
1429 }
1430 else
1431 {
1432 // Now try to read in the block
1433 if (!MachDiskReadLogicalSectors(DriveNumber, SectorNumber + FatVolumeStartSector, SectorCount, (PVOID)DISKREADBUFFER))
1434 {
1435 return FALSE;
1436 }
1437
1438 // Copy data to the caller
1439 RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, SectorCount * BytesPerSector);
1440
1441 // Return success
1442 return TRUE;
1443 }
1444 }
1445
1446 const FS_VTBL FatVtbl = {
1447 FatOpenVolume,
1448 FatOpenFile,
1449 NULL,
1450 FatReadFile,
1451 FatGetFileSize,
1452 FatSetFilePointer,
1453 FatGetFilePointer,
1454 };