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