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