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