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