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