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