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