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