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