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