Sync with trunk r43123
[reactos.git] / reactos / boot / freeldr / freeldr / fs / fat.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 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
22 #define NDEBUG
23 #include <debug.h>
24
25 ULONG FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector, ULONG PartitionSectorCount);
26 PVOID FatBufferDirectory(ULONG DirectoryStartCluster, ULONG* EntryCountPointer, BOOLEAN RootDirectory);
27 BOOLEAN FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG EntryCount, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer);
28 LONG FatLookupFile(PCSTR FileName, ULONG DeviceId, PFAT_FILE_INFO FatFileInfoPointer);
29 void FatParseShortFileName(PCHAR Buffer, PDIRENTRY DirEntry);
30 BOOLEAN FatGetFatEntry(ULONG Cluster, ULONG* ClusterPointer);
31 ULONG FatCountClustersInChain(ULONG StartCluster);
32 ULONG* FatGetClusterChainArray(ULONG StartCluster);
33 BOOLEAN FatReadCluster(ULONG ClusterNumber, PVOID Buffer);
34 BOOLEAN FatReadClusterChain(ULONG StartClusterNumber, ULONG NumberOfClusters, PVOID Buffer);
35 BOOLEAN FatReadPartialCluster(ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer);
36 BOOLEAN FatReadFile(PFAT_FILE_INFO FatFileInfo, ULONG BytesToRead, ULONG* BytesRead, PVOID Buffer);
37 BOOLEAN FatReadVolumeSectors(ULONG DriveNumber, ULONG SectorNumber, ULONG SectorCount, PVOID Buffer);
38
39 ULONG BytesPerSector; /* Number of bytes per sector */
40 ULONG SectorsPerCluster; /* Number of sectors per cluster */
41 ULONG FatVolumeStartSector; /* Absolute starting sector of the partition */
42 ULONG FatSectorStart; /* Starting sector of 1st FAT table */
43 ULONG ActiveFatSectorStart; /* Starting sector of active FAT table */
44 ULONG NumberOfFats; /* Number of FAT tables */
45 ULONG SectorsPerFat; /* Sectors per FAT table */
46 ULONG RootDirSectorStart; /* Starting sector of the root directory (non-fat32) */
47 ULONG RootDirSectors; /* Number of sectors of the root directory (non-fat32) */
48 ULONG RootDirStartCluster; /* Starting cluster number of the root directory (fat32 only) */
49 ULONG DataSectorStart; /* Starting sector of the data area */
50
51 ULONG FatType = 0; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
52 ULONG FatDriveNumber = 0;
53
54 VOID FatSwapFatBootSector(PFAT_BOOTSECTOR Obj)
55 {
56 SW(Obj, BytesPerSector);
57 SW(Obj, ReservedSectors);
58 SW(Obj, RootDirEntries);
59 SW(Obj, TotalSectors);
60 SW(Obj, SectorsPerFat);
61 SW(Obj, SectorsPerTrack);
62 SW(Obj, NumberOfHeads);
63 SD(Obj, HiddenSectors);
64 SD(Obj, TotalSectorsBig);
65 SD(Obj, VolumeSerialNumber);
66 SW(Obj, BootSectorMagic);
67 }
68
69 VOID FatSwapFat32BootSector(PFAT32_BOOTSECTOR Obj)
70 {
71 SW(Obj, BytesPerSector);
72 SW(Obj, ReservedSectors);
73 SW(Obj, RootDirEntries);
74 SW(Obj, TotalSectors);
75 SW(Obj, SectorsPerFat);
76 SW(Obj, NumberOfHeads);
77 SD(Obj, HiddenSectors);
78 SD(Obj, TotalSectorsBig);
79 SD(Obj, SectorsPerFatBig);
80 SW(Obj, ExtendedFlags);
81 SW(Obj, FileSystemVersion);
82 SD(Obj, RootDirStartCluster);
83 SW(Obj, FsInfo);
84 SW(Obj, BackupBootSector);
85 SD(Obj, VolumeSerialNumber);
86 SW(Obj, BootSectorMagic);
87 }
88
89 VOID FatSwapFatXBootSector(PFATX_BOOTSECTOR Obj)
90 {
91 SD(Obj, VolumeSerialNumber);
92 SD(Obj, SectorsPerCluster);
93 SW(Obj, NumberOfFats);
94 }
95
96 VOID FatSwapDirEntry(PDIRENTRY Obj)
97 {
98 SW(Obj, CreateTime);
99 SW(Obj, CreateDate);
100 SW(Obj, LastAccessDate);
101 SW(Obj, ClusterHigh);
102 SW(Obj, Time);
103 SW(Obj, Date);
104 SW(Obj, ClusterLow);
105 SD(Obj, Size);
106 }
107
108 VOID FatSwapLFNDirEntry(PLFN_DIRENTRY Obj)
109 {
110 int i;
111 SW(Obj, StartCluster);
112 for(i = 0; i < 5; i++)
113 Obj->Name0_4[i] = SWAPW(Obj->Name0_4[i]);
114 for(i = 0; i < 6; i++)
115 Obj->Name5_10[i] = SWAPW(Obj->Name5_10[i]);
116 for(i = 0; i < 2; i++)
117 Obj->Name11_12[i] = SWAPW(Obj->Name11_12[i]);
118 }
119
120 VOID FatSwapFatXDirEntry(PFATX_DIRENTRY Obj)
121 {
122 SD(Obj, StartCluster);
123 SD(Obj, Size);
124 SW(Obj, Time);
125 SW(Obj, Date);
126 SW(Obj, CreateTime);
127 SW(Obj, CreateDate);
128 SW(Obj, LastAccessTime);
129 SW(Obj, LastAccessDate);
130 }
131
132 BOOLEAN FatOpenVolume(UCHAR DriveNumber, ULONGLONG VolumeStartSector, ULONGLONG PartitionSectorCount)
133 {
134 char ErrMsg[80];
135 ULONG FatSize;
136 PFAT_BOOTSECTOR FatVolumeBootSector;
137 PFAT32_BOOTSECTOR Fat32VolumeBootSector;
138 PFATX_BOOTSECTOR FatXVolumeBootSector;
139
140 DPRINTM(DPRINT_FILESYSTEM, "FatOpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber, VolumeStartSector);
141
142 // Store the drive number
143 FatDriveNumber = DriveNumber;
144
145 //
146 // Allocate the memory to hold the boot sector
147 //
148 FatVolumeBootSector = (PFAT_BOOTSECTOR) MmHeapAlloc(512);
149 Fat32VolumeBootSector = (PFAT32_BOOTSECTOR) FatVolumeBootSector;
150 FatXVolumeBootSector = (PFATX_BOOTSECTOR) FatVolumeBootSector;
151
152 //
153 // Make sure we got the memory
154 //
155 if (FatVolumeBootSector == NULL)
156 {
157 FileSystemError("Out of memory.");
158 return FALSE;
159 }
160
161 // Now try to read the boot sector
162 // If this fails then abort
163 if (!MachDiskReadLogicalSectors(DriveNumber, VolumeStartSector, 1, (PVOID)DISKREADBUFFER))
164 {
165 MmHeapFree(FatVolumeBootSector);
166 return FALSE;
167 }
168 RtlCopyMemory(FatVolumeBootSector, (PVOID)DISKREADBUFFER, 512);
169
170 // Get the FAT type
171 FatType = FatDetermineFatType(FatVolumeBootSector, PartitionSectorCount);
172
173 // Dump boot sector (and swap it for big endian systems)
174 DPRINTM(DPRINT_FILESYSTEM, "Dumping boot sector:\n");
175 if (ISFATX(FatType))
176 {
177 FatSwapFatXBootSector(FatXVolumeBootSector);
178 DPRINTM(DPRINT_FILESYSTEM, "sizeof(FATX_BOOTSECTOR) = 0x%x.\n", sizeof(FATX_BOOTSECTOR));
179
180 DPRINTM(DPRINT_FILESYSTEM, "FileSystemType: %c%c%c%c.\n", FatXVolumeBootSector->FileSystemType[0], FatXVolumeBootSector->FileSystemType[1], FatXVolumeBootSector->FileSystemType[2], FatXVolumeBootSector->FileSystemType[3]);
181 DPRINTM(DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", FatXVolumeBootSector->VolumeSerialNumber);
182 DPRINTM(DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", FatXVolumeBootSector->SectorsPerCluster);
183 DPRINTM(DPRINT_FILESYSTEM, "NumberOfFats: %d\n", FatXVolumeBootSector->NumberOfFats);
184 DPRINTM(DPRINT_FILESYSTEM, "Unknown: 0x%x\n", FatXVolumeBootSector->Unknown);
185
186 DPRINTM(DPRINT_FILESYSTEM, "FatType %s\n", FatType == FATX16 ? "FATX16" : "FATX32");
187
188 }
189 else if (FatType == FAT32)
190 {
191 FatSwapFat32BootSector(Fat32VolumeBootSector);
192 DPRINTM(DPRINT_FILESYSTEM, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR));
193
194 DPRINTM(DPRINT_FILESYSTEM, "JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector->JumpBoot[0], Fat32VolumeBootSector->JumpBoot[1], Fat32VolumeBootSector->JumpBoot[2]);
195 DPRINTM(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]);
196 DPRINTM(DPRINT_FILESYSTEM, "BytesPerSector: %d\n", Fat32VolumeBootSector->BytesPerSector);
197 DPRINTM(DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", Fat32VolumeBootSector->SectorsPerCluster);
198 DPRINTM(DPRINT_FILESYSTEM, "ReservedSectors: %d\n", Fat32VolumeBootSector->ReservedSectors);
199 DPRINTM(DPRINT_FILESYSTEM, "NumberOfFats: %d\n", Fat32VolumeBootSector->NumberOfFats);
200 DPRINTM(DPRINT_FILESYSTEM, "RootDirEntries: %d\n", Fat32VolumeBootSector->RootDirEntries);
201 DPRINTM(DPRINT_FILESYSTEM, "TotalSectors: %d\n", Fat32VolumeBootSector->TotalSectors);
202 DPRINTM(DPRINT_FILESYSTEM, "MediaDescriptor: 0x%x\n", Fat32VolumeBootSector->MediaDescriptor);
203 DPRINTM(DPRINT_FILESYSTEM, "SectorsPerFat: %d\n", Fat32VolumeBootSector->SectorsPerFat);
204 DPRINTM(DPRINT_FILESYSTEM, "SectorsPerTrack: %d\n", Fat32VolumeBootSector->SectorsPerTrack);
205 DPRINTM(DPRINT_FILESYSTEM, "NumberOfHeads: %d\n", Fat32VolumeBootSector->NumberOfHeads);
206 DPRINTM(DPRINT_FILESYSTEM, "HiddenSectors: %d\n", Fat32VolumeBootSector->HiddenSectors);
207 DPRINTM(DPRINT_FILESYSTEM, "TotalSectorsBig: %d\n", Fat32VolumeBootSector->TotalSectorsBig);
208 DPRINTM(DPRINT_FILESYSTEM, "SectorsPerFatBig: %d\n", Fat32VolumeBootSector->SectorsPerFatBig);
209 DPRINTM(DPRINT_FILESYSTEM, "ExtendedFlags: 0x%x\n", Fat32VolumeBootSector->ExtendedFlags);
210 DPRINTM(DPRINT_FILESYSTEM, "FileSystemVersion: 0x%x\n", Fat32VolumeBootSector->FileSystemVersion);
211 DPRINTM(DPRINT_FILESYSTEM, "RootDirStartCluster: %d\n", Fat32VolumeBootSector->RootDirStartCluster);
212 DPRINTM(DPRINT_FILESYSTEM, "FsInfo: %d\n", Fat32VolumeBootSector->FsInfo);
213 DPRINTM(DPRINT_FILESYSTEM, "BackupBootSector: %d\n", Fat32VolumeBootSector->BackupBootSector);
214 DPRINTM(DPRINT_FILESYSTEM, "Reserved: 0x%x\n", Fat32VolumeBootSector->Reserved);
215 DPRINTM(DPRINT_FILESYSTEM, "DriveNumber: 0x%x\n", Fat32VolumeBootSector->DriveNumber);
216 DPRINTM(DPRINT_FILESYSTEM, "Reserved1: 0x%x\n", Fat32VolumeBootSector->Reserved1);
217 DPRINTM(DPRINT_FILESYSTEM, "BootSignature: 0x%x\n", Fat32VolumeBootSector->BootSignature);
218 DPRINTM(DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector->VolumeSerialNumber);
219 DPRINTM(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]);
220 DPRINTM(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]);
221 DPRINTM(DPRINT_FILESYSTEM, "BootSectorMagic: 0x%x\n", Fat32VolumeBootSector->BootSectorMagic);
222 }
223 else
224 {
225 FatSwapFatBootSector(FatVolumeBootSector);
226 DPRINTM(DPRINT_FILESYSTEM, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR));
227
228 DPRINTM(DPRINT_FILESYSTEM, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector->JumpBoot[0], FatVolumeBootSector->JumpBoot[1], FatVolumeBootSector->JumpBoot[2]);
229 DPRINTM(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]);
230 DPRINTM(DPRINT_FILESYSTEM, "BytesPerSector: %d\n", FatVolumeBootSector->BytesPerSector);
231 DPRINTM(DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", FatVolumeBootSector->SectorsPerCluster);
232 DPRINTM(DPRINT_FILESYSTEM, "ReservedSectors: %d\n", FatVolumeBootSector->ReservedSectors);
233 DPRINTM(DPRINT_FILESYSTEM, "NumberOfFats: %d\n", FatVolumeBootSector->NumberOfFats);
234 DPRINTM(DPRINT_FILESYSTEM, "RootDirEntries: %d\n", FatVolumeBootSector->RootDirEntries);
235 DPRINTM(DPRINT_FILESYSTEM, "TotalSectors: %d\n", FatVolumeBootSector->TotalSectors);
236 DPRINTM(DPRINT_FILESYSTEM, "MediaDescriptor: 0x%x\n", FatVolumeBootSector->MediaDescriptor);
237 DPRINTM(DPRINT_FILESYSTEM, "SectorsPerFat: %d\n", FatVolumeBootSector->SectorsPerFat);
238 DPRINTM(DPRINT_FILESYSTEM, "SectorsPerTrack: %d\n", FatVolumeBootSector->SectorsPerTrack);
239 DPRINTM(DPRINT_FILESYSTEM, "NumberOfHeads: %d\n", FatVolumeBootSector->NumberOfHeads);
240 DPRINTM(DPRINT_FILESYSTEM, "HiddenSectors: %d\n", FatVolumeBootSector->HiddenSectors);
241 DPRINTM(DPRINT_FILESYSTEM, "TotalSectorsBig: %d\n", FatVolumeBootSector->TotalSectorsBig);
242 DPRINTM(DPRINT_FILESYSTEM, "DriveNumber: 0x%x\n", FatVolumeBootSector->DriveNumber);
243 DPRINTM(DPRINT_FILESYSTEM, "Reserved1: 0x%x\n", FatVolumeBootSector->Reserved1);
244 DPRINTM(DPRINT_FILESYSTEM, "BootSignature: 0x%x\n", FatVolumeBootSector->BootSignature);
245 DPRINTM(DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector->VolumeSerialNumber);
246 DPRINTM(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]);
247 DPRINTM(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]);
248 DPRINTM(DPRINT_FILESYSTEM, "BootSectorMagic: 0x%x\n", FatVolumeBootSector->BootSectorMagic);
249 }
250
251 //
252 // Set the correct partition offset
253 //
254 FatVolumeStartSector = VolumeStartSector;
255
256 //
257 // Check the boot sector magic
258 //
259 if (! ISFATX(FatType) && FatVolumeBootSector->BootSectorMagic != 0xaa55)
260 {
261 sprintf(ErrMsg, "Invalid boot sector magic on drive 0x%x (expected 0xaa55 found 0x%x)",
262 DriveNumber, FatVolumeBootSector->BootSectorMagic);
263 FileSystemError(ErrMsg);
264 MmHeapFree(FatVolumeBootSector);
265 return FALSE;
266 }
267
268 //
269 // Check the FAT cluster size
270 // We do not support clusters bigger than 64k
271 //
272 if ((ISFATX(FatType) && 64 * 1024 < FatXVolumeBootSector->SectorsPerCluster * 512) ||
273 (! ISFATX(FatType) && 64 * 1024 < FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector))
274 {
275 FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
276 MmHeapFree(FatVolumeBootSector);
277 return FALSE;
278 }
279
280 //
281 // Clear our variables
282 //
283 FatSectorStart = 0;
284 ActiveFatSectorStart = 0;
285 NumberOfFats = 0;
286 RootDirSectorStart = 0;
287 DataSectorStart = 0;
288 SectorsPerFat = 0;
289 RootDirSectors = 0;
290
291 //
292 // Get the sectors per FAT,
293 // root directory starting sector,
294 // and data sector start
295 //
296 if (ISFATX(FatType))
297 {
298 BytesPerSector = 512;
299 SectorsPerCluster = SWAPD(FatXVolumeBootSector->SectorsPerCluster);
300 FatSectorStart = (4096 / BytesPerSector);
301 ActiveFatSectorStart = FatSectorStart;
302 NumberOfFats = 1;
303 FatSize = PartitionSectorCount / SectorsPerCluster *
304 (FATX16 == FatType ? 2 : 4);
305 SectorsPerFat = (((FatSize + 4095) / 4096) * 4096) / BytesPerSector;
306
307 RootDirSectorStart = FatSectorStart + NumberOfFats * SectorsPerFat;
308 RootDirSectors = FatXVolumeBootSector->SectorsPerCluster;
309
310 DataSectorStart = RootDirSectorStart + RootDirSectors;
311 }
312 else if (FatType != FAT32)
313 {
314 BytesPerSector = FatVolumeBootSector->BytesPerSector;
315 SectorsPerCluster = FatVolumeBootSector->SectorsPerCluster;
316 FatSectorStart = FatVolumeBootSector->ReservedSectors;
317 ActiveFatSectorStart = FatSectorStart;
318 NumberOfFats = FatVolumeBootSector->NumberOfFats;
319 SectorsPerFat = FatVolumeBootSector->SectorsPerFat;
320
321 RootDirSectorStart = FatSectorStart + NumberOfFats * SectorsPerFat;
322 RootDirSectors = ((FatVolumeBootSector->RootDirEntries * 32) + (BytesPerSector - 1)) / BytesPerSector;
323
324 DataSectorStart = RootDirSectorStart + RootDirSectors;
325 }
326 else
327 {
328 BytesPerSector = Fat32VolumeBootSector->BytesPerSector;
329 SectorsPerCluster = Fat32VolumeBootSector->SectorsPerCluster;
330 FatSectorStart = Fat32VolumeBootSector->ReservedSectors;
331 ActiveFatSectorStart = FatSectorStart +
332 ((Fat32VolumeBootSector->ExtendedFlags & 0x80) ? ((Fat32VolumeBootSector->ExtendedFlags & 0x0f) * Fat32VolumeBootSector->SectorsPerFatBig) : 0);
333 NumberOfFats = Fat32VolumeBootSector->NumberOfFats;
334 SectorsPerFat = Fat32VolumeBootSector->SectorsPerFatBig;
335
336 RootDirStartCluster = Fat32VolumeBootSector->RootDirStartCluster;
337 DataSectorStart = FatSectorStart + NumberOfFats * SectorsPerFat;
338
339 //
340 // Check version
341 // we only work with version 0
342 //
343 if (Fat32VolumeBootSector->FileSystemVersion != 0)
344 {
345 FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
346 return FALSE;
347 }
348 }
349 MmHeapFree(FatVolumeBootSector);
350
351 {
352 GEOMETRY DriveGeometry;
353 ULONG BlockSize;
354
355 // Initialize drive by getting its geometry
356 if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry))
357 {
358 return FALSE;
359 }
360
361 BlockSize = MachDiskGetCacheableBlockCount(DriveNumber);
362 }
363
364 return TRUE;
365 }
366
367 ULONG FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector, ULONG PartitionSectorCount)
368 {
369 ULONG RootDirSectors;
370 ULONG DataSectorCount;
371 ULONG SectorsPerFat;
372 ULONG TotalSectors;
373 ULONG CountOfClusters;
374 PFAT32_BOOTSECTOR Fat32BootSector = (PFAT32_BOOTSECTOR)FatBootSector;
375 PFATX_BOOTSECTOR FatXBootSector = (PFATX_BOOTSECTOR)FatBootSector;
376
377 if (0 == strncmp(FatXBootSector->FileSystemType, "FATX", 4))
378 {
379 CountOfClusters = PartitionSectorCount / FatXBootSector->SectorsPerCluster;
380 if (CountOfClusters < 65525)
381 {
382 /* Volume is FATX16 */
383 return FATX16;
384 }
385 else
386 {
387 /* Volume is FAT32 */
388 return FATX32;
389 }
390 }
391 else
392 {
393 RootDirSectors = ((SWAPW(FatBootSector->RootDirEntries) * 32) + (SWAPW(FatBootSector->BytesPerSector) - 1)) / SWAPW(FatBootSector->BytesPerSector);
394 SectorsPerFat = SWAPW(FatBootSector->SectorsPerFat) ? SWAPW(FatBootSector->SectorsPerFat) : SWAPD(Fat32BootSector->SectorsPerFatBig);
395 TotalSectors = SWAPW(FatBootSector->TotalSectors) ? SWAPW(FatBootSector->TotalSectors) : SWAPD(FatBootSector->TotalSectorsBig);
396 DataSectorCount = TotalSectors - (SWAPW(FatBootSector->ReservedSectors) + (FatBootSector->NumberOfFats * SectorsPerFat) + RootDirSectors);
397
398 //mjl
399 if (FatBootSector->SectorsPerCluster == 0)
400 CountOfClusters = 0;
401 else
402 CountOfClusters = DataSectorCount / FatBootSector->SectorsPerCluster;
403
404 if (CountOfClusters < 4085)
405 {
406 /* Volume is FAT12 */
407 return FAT12;
408 }
409 else if (CountOfClusters < 65525)
410 {
411 /* Volume is FAT16 */
412 return FAT16;
413 }
414 else
415 {
416 /* Volume is FAT32 */
417 return FAT32;
418 }
419 }
420 }
421
422 PVOID FatBufferDirectory(ULONG DirectoryStartCluster, ULONG *DirectorySize, BOOLEAN RootDirectory)
423 {
424 PVOID DirectoryBuffer;
425
426 DPRINTM(DPRINT_FILESYSTEM, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster, (RootDirectory ? "TRUE" : "FALSE"));
427
428 /*
429 * For FAT32, the root directory is nothing special. We can treat it the same
430 * as a subdirectory.
431 */
432 if (RootDirectory && FAT32 == FatType)
433 {
434 DirectoryStartCluster = RootDirStartCluster;
435 RootDirectory = FALSE;
436 }
437
438 //
439 // Calculate the size of the directory
440 //
441 if (RootDirectory)
442 {
443 *DirectorySize = RootDirSectors * BytesPerSector;
444 }
445 else
446 {
447 *DirectorySize = FatCountClustersInChain(DirectoryStartCluster) * SectorsPerCluster * BytesPerSector;
448 }
449
450 //
451 // Attempt to allocate memory for directory buffer
452 //
453 DPRINTM(DPRINT_FILESYSTEM, "Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize);
454 DirectoryBuffer = MmHeapAlloc(*DirectorySize);
455
456 if (DirectoryBuffer == NULL)
457 {
458 return NULL;
459 }
460
461 //
462 // Now read directory contents into DirectoryBuffer
463 //
464 if (RootDirectory)
465 {
466 if (!FatReadVolumeSectors(FatDriveNumber, RootDirSectorStart, RootDirSectors, DirectoryBuffer))
467 {
468 MmHeapFree(DirectoryBuffer);
469 return NULL;
470 }
471 }
472 else
473 {
474 if (!FatReadClusterChain(DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer))
475 {
476 MmHeapFree(DirectoryBuffer);
477 return NULL;
478 }
479 }
480
481 return DirectoryBuffer;
482 }
483
484 BOOLEAN FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
485 {
486 ULONG EntryCount;
487 ULONG CurrentEntry;
488 CHAR LfnNameBuffer[265];
489 CHAR ShortNameBuffer[20];
490 ULONG StartCluster;
491 DIRENTRY OurDirEntry;
492 LFN_DIRENTRY OurLfnDirEntry;
493 PDIRENTRY DirEntry = &OurDirEntry;
494 PLFN_DIRENTRY LfnDirEntry = &OurLfnDirEntry;
495
496 EntryCount = DirectorySize / sizeof(DIRENTRY);
497
498 DPRINTM(DPRINT_FILESYSTEM, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer, EntryCount, FileName);
499
500 memset(ShortNameBuffer, 0, 13 * sizeof(CHAR));
501 memset(LfnNameBuffer, 0, 261 * sizeof(CHAR));
502
503 for (CurrentEntry=0; CurrentEntry<EntryCount; CurrentEntry++, DirectoryBuffer = ((PDIRENTRY)DirectoryBuffer)+1)
504 {
505 OurLfnDirEntry = *((PLFN_DIRENTRY) DirectoryBuffer);
506 FatSwapLFNDirEntry(LfnDirEntry);
507 OurDirEntry = *((PDIRENTRY) DirectoryBuffer);
508 FatSwapDirEntry(DirEntry);
509
510 //DPRINTM(DPRINT_FILESYSTEM, "Dumping directory entry %d:\n", CurrentEntry);
511 //DbgDumpBuffer(DPRINT_FILESYSTEM, DirEntry, sizeof(DIRENTRY));
512
513 //
514 // Check if this is the last file in the directory
515 // If DirEntry[0] == 0x00 then that means all the
516 // entries after this one are unused. If this is the
517 // last entry then we didn't find the file in this directory.
518 //
519 if (DirEntry->FileName[0] == '\0')
520 {
521 return FALSE;
522 }
523
524 //
525 // Check if this is a deleted entry or not
526 //
527 if (DirEntry->FileName[0] == '\xE5')
528 {
529 memset(ShortNameBuffer, 0, 13 * sizeof(CHAR));
530 memset(LfnNameBuffer, 0, 261 * sizeof(CHAR));
531 continue;
532 }
533
534 //
535 // Check if this is a LFN entry
536 // If so it needs special handling
537 //
538 if (DirEntry->Attr == ATTR_LONG_NAME)
539 {
540 //
541 // Check to see if this is a deleted LFN entry, if so continue
542 //
543 if (LfnDirEntry->SequenceNumber & 0x80)
544 {
545 continue;
546 }
547
548 //
549 // Mask off high two bits of sequence number
550 // and make the sequence number zero-based
551 //
552 LfnDirEntry->SequenceNumber &= 0x3F;
553 LfnDirEntry->SequenceNumber--;
554
555 //
556 // Get all 13 LFN entry characters
557 //
558 if (LfnDirEntry->Name0_4[0] != 0xFFFF)
559 {
560 LfnNameBuffer[0 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[0];
561 }
562 if (LfnDirEntry->Name0_4[1] != 0xFFFF)
563 {
564 LfnNameBuffer[1 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[1];
565 }
566 if (LfnDirEntry->Name0_4[2] != 0xFFFF)
567 {
568 LfnNameBuffer[2 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[2];
569 }
570 if (LfnDirEntry->Name0_4[3] != 0xFFFF)
571 {
572 LfnNameBuffer[3 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[3];
573 }
574 if (LfnDirEntry->Name0_4[4] != 0xFFFF)
575 {
576 LfnNameBuffer[4 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[4];
577 }
578 if (LfnDirEntry->Name5_10[0] != 0xFFFF)
579 {
580 LfnNameBuffer[5 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[0];
581 }
582 if (LfnDirEntry->Name5_10[1] != 0xFFFF)
583 {
584 LfnNameBuffer[6 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[1];
585 }
586 if (LfnDirEntry->Name5_10[2] != 0xFFFF)
587 {
588 LfnNameBuffer[7 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[2];
589 }
590 if (LfnDirEntry->Name5_10[3] != 0xFFFF)
591 {
592 LfnNameBuffer[8 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[3];
593 }
594 if (LfnDirEntry->Name5_10[4] != 0xFFFF)
595 {
596 LfnNameBuffer[9 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[4];
597 }
598 if (LfnDirEntry->Name5_10[5] != 0xFFFF)
599 {
600 LfnNameBuffer[10 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[5];
601 }
602 if (LfnDirEntry->Name11_12[0] != 0xFFFF)
603 {
604 LfnNameBuffer[11 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[0];
605 }
606 if (LfnDirEntry->Name11_12[1] != 0xFFFF)
607 {
608 LfnNameBuffer[12 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[1];
609 }
610
611 //DPRINTM(DPRINT_FILESYSTEM, "Dumping long name buffer:\n");
612 //DbgDumpBuffer(DPRINT_FILESYSTEM, LfnNameBuffer, 260);
613
614 continue;
615 }
616
617 //
618 // Check for the volume label attribute
619 // and skip over this entry if found
620 //
621 if (DirEntry->Attr & ATTR_VOLUMENAME)
622 {
623 memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR));
624 memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR));
625 continue;
626 }
627
628 //
629 // If we get here then we've found a short file name
630 // entry and LfnNameBuffer contains the long file
631 // name or zeroes. All we have to do now is see if the
632 // file name matches either the short or long file name
633 // and fill in the FAT_FILE_INFO structure if it does
634 // or zero our buffers and continue looking.
635 //
636
637 //
638 // Get short file name
639 //
640 FatParseShortFileName(ShortNameBuffer, DirEntry);
641
642 DPRINTM(DPRINT_FILESYSTEM, "Entry: %d LFN = %s\n", CurrentEntry, LfnNameBuffer);
643 DPRINTM(DPRINT_FILESYSTEM, "Entry: %d DOS name = %s\n", CurrentEntry, ShortNameBuffer);
644
645 //
646 // See if the file name matches either the short or long name
647 //
648 if (((strlen(FileName) == strlen(LfnNameBuffer)) && (_stricmp(FileName, LfnNameBuffer) == 0)) ||
649 ((strlen(FileName) == strlen(ShortNameBuffer)) && (_stricmp(FileName, ShortNameBuffer) == 0))) {
650 //
651 // We found the entry, now fill in the FAT_FILE_INFO struct
652 //
653 FatFileInfoPointer->FileSize = DirEntry->Size;
654 FatFileInfoPointer->FilePointer = 0;
655
656 DPRINTM(DPRINT_FILESYSTEM, "MSDOS Directory Entry:\n");
657 DPRINTM(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]);
658 DPRINTM(DPRINT_FILESYSTEM, "Attr = 0x%x\n", DirEntry->Attr);
659 DPRINTM(DPRINT_FILESYSTEM, "ReservedNT = 0x%x\n", DirEntry->ReservedNT);
660 DPRINTM(DPRINT_FILESYSTEM, "TimeInTenths = %d\n", DirEntry->TimeInTenths);
661 DPRINTM(DPRINT_FILESYSTEM, "CreateTime = %d\n", DirEntry->CreateTime);
662 DPRINTM(DPRINT_FILESYSTEM, "CreateDate = %d\n", DirEntry->CreateDate);
663 DPRINTM(DPRINT_FILESYSTEM, "LastAccessDate = %d\n", DirEntry->LastAccessDate);
664 DPRINTM(DPRINT_FILESYSTEM, "ClusterHigh = 0x%x\n", DirEntry->ClusterHigh);
665 DPRINTM(DPRINT_FILESYSTEM, "Time = %d\n", DirEntry->Time);
666 DPRINTM(DPRINT_FILESYSTEM, "Date = %d\n", DirEntry->Date);
667 DPRINTM(DPRINT_FILESYSTEM, "ClusterLow = 0x%x\n", DirEntry->ClusterLow);
668 DPRINTM(DPRINT_FILESYSTEM, "Size = %d\n", DirEntry->Size);
669
670 //
671 // Get the cluster chain
672 //
673 StartCluster = ((ULONG)DirEntry->ClusterHigh << 16) + DirEntry->ClusterLow;
674 DPRINTM(DPRINT_FILESYSTEM, "StartCluster = 0x%x\n", StartCluster);
675 FatFileInfoPointer->FileFatChain = FatGetClusterChainArray(StartCluster);
676
677 //
678 // See if memory allocation failed
679 //
680 if (FatFileInfoPointer->FileFatChain == NULL)
681 {
682 return FALSE;
683 }
684
685 return TRUE;
686 }
687
688 //
689 // Nope, no match - zero buffers and continue looking
690 //
691 memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR));
692 memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR));
693 continue;
694 }
695
696 return FALSE;
697 }
698
699 static BOOLEAN FatXSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
700 {
701 ULONG EntryCount;
702 ULONG CurrentEntry;
703 ULONG FileNameLen;
704 FATX_DIRENTRY OurDirEntry;
705 PFATX_DIRENTRY DirEntry = &OurDirEntry;
706
707 EntryCount = DirectorySize / sizeof(FATX_DIRENTRY);
708
709 DPRINTM(DPRINT_FILESYSTEM, "FatXSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer, EntryCount, FileName);
710
711 FileNameLen = strlen(FileName);
712
713 for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++, DirectoryBuffer = ((PFATX_DIRENTRY)DirectoryBuffer)+1)
714 {
715 OurDirEntry = *(PFATX_DIRENTRY) DirectoryBuffer;
716 FatSwapFatXDirEntry(&OurDirEntry);
717 if (0xff == DirEntry->FileNameSize)
718 {
719 break;
720 }
721 if (0xe5 == DirEntry->FileNameSize)
722 {
723 continue;
724 }
725 if (FileNameLen == DirEntry->FileNameSize &&
726 0 == _strnicmp(FileName, DirEntry->FileName, FileNameLen))
727 {
728 /*
729 * We found the entry, now fill in the FAT_FILE_INFO struct
730 */
731 FatFileInfoPointer->FileSize = DirEntry->Size;
732 FatFileInfoPointer->FilePointer = 0;
733
734 DPRINTM(DPRINT_FILESYSTEM, "FATX Directory Entry:\n");
735 DPRINTM(DPRINT_FILESYSTEM, "FileNameSize = %d\n", DirEntry->FileNameSize);
736 DPRINTM(DPRINT_FILESYSTEM, "Attr = 0x%x\n", DirEntry->Attr);
737 DPRINTM(DPRINT_FILESYSTEM, "StartCluster = 0x%x\n", DirEntry->StartCluster);
738 DPRINTM(DPRINT_FILESYSTEM, "Size = %d\n", DirEntry->Size);
739 DPRINTM(DPRINT_FILESYSTEM, "Time = %d\n", DirEntry->Time);
740 DPRINTM(DPRINT_FILESYSTEM, "Date = %d\n", DirEntry->Date);
741 DPRINTM(DPRINT_FILESYSTEM, "CreateTime = %d\n", DirEntry->CreateTime);
742 DPRINTM(DPRINT_FILESYSTEM, "CreateDate = %d\n", DirEntry->CreateDate);
743 DPRINTM(DPRINT_FILESYSTEM, "LastAccessTime = %d\n", DirEntry->LastAccessTime);
744 DPRINTM(DPRINT_FILESYSTEM, "LastAccessDate = %d\n", DirEntry->LastAccessDate);
745
746 /*
747 * Get the cluster chain
748 */
749 FatFileInfoPointer->FileFatChain = FatGetClusterChainArray(DirEntry->StartCluster);
750
751 /*
752 * See if memory allocation failed
753 */
754 if (NULL == FatFileInfoPointer->FileFatChain)
755 {
756 return FALSE;
757 }
758
759 return TRUE;
760 }
761 }
762
763 return FALSE;
764 }
765
766 /*
767 * FatLookupFile()
768 * This function searches the file system for the
769 * specified filename and fills in an FAT_FILE_INFO structure
770 * with info describing the file, etc. returns ARC error code
771 */
772 LONG FatLookupFile(PCSTR FileName, ULONG DeviceId, PFAT_FILE_INFO FatFileInfoPointer)
773 {
774 UINT32 i;
775 ULONG NumberOfPathParts;
776 CHAR PathPart[261];
777 PVOID DirectoryBuffer;
778 ULONG DirectoryStartCluster = 0;
779 ULONG DirectorySize;
780 FAT_FILE_INFO FatFileInfo;
781
782 DPRINTM(DPRINT_FILESYSTEM, "FatLookupFile() FileName = %s\n", FileName);
783
784 memset(FatFileInfoPointer, 0, sizeof(FAT_FILE_INFO));
785
786 //
787 // Figure out how many sub-directories we are nested in
788 //
789 NumberOfPathParts = FsGetNumPathParts(FileName);
790
791 //
792 // Loop once for each part
793 //
794 for (i=0; i<NumberOfPathParts; i++)
795 {
796 //
797 // Get first path part
798 //
799 FsGetFirstNameFromPath(PathPart, FileName);
800
801 //
802 // Advance to the next part of the path
803 //
804 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
805 {
806 }
807 FileName++;
808
809 //
810 // Buffer the directory contents
811 //
812 DirectoryBuffer = FatBufferDirectory(DirectoryStartCluster, &DirectorySize, (i == 0) );
813 if (DirectoryBuffer == NULL)
814 {
815 return ENOMEM;
816 }
817
818 //
819 // Search for file name in directory
820 //
821 if (ISFATX(FatType))
822 {
823 if (!FatXSearchDirectoryBufferForFile(DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo))
824 {
825 MmHeapFree(DirectoryBuffer);
826 return ENOENT;
827 }
828 }
829 else
830 {
831 if (!FatSearchDirectoryBufferForFile(DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo))
832 {
833 MmHeapFree(DirectoryBuffer);
834 return ENOENT;
835 }
836 }
837
838 MmHeapFree(DirectoryBuffer);
839
840 //
841 // If we have another sub-directory to go then
842 // grab the start cluster and free the fat chain array
843 //
844 if ((i+1) < NumberOfPathParts)
845 {
846 DirectoryStartCluster = FatFileInfo.FileFatChain[0];
847 MmHeapFree(FatFileInfo.FileFatChain);
848 }
849 }
850
851 memcpy(FatFileInfoPointer, &FatFileInfo, sizeof(FAT_FILE_INFO));
852
853 return ESUCCESS;
854 }
855
856 /*
857 * FatParseFileName()
858 * This function parses a directory entry name which
859 * is in the form of "FILE EXT" and puts it in Buffer
860 * in the form of "file.ext"
861 */
862 void FatParseShortFileName(PCHAR Buffer, PDIRENTRY DirEntry)
863 {
864 ULONG Idx;
865
866 Idx = 0;
867 RtlZeroMemory(Buffer, 13);
868
869 //
870 // Fixup first character
871 //
872 if (DirEntry->FileName[0] == 0x05)
873 {
874 DirEntry->FileName[0] = 0xE5;
875 }
876
877 //
878 // Get the file name
879 //
880 while (Idx < 8)
881 {
882 if (DirEntry->FileName[Idx] == ' ')
883 {
884 break;
885 }
886
887 Buffer[Idx] = DirEntry->FileName[Idx];
888 Idx++;
889 }
890
891 //
892 // Get extension
893 //
894 if ((DirEntry->FileName[8] != ' '))
895 {
896 Buffer[Idx++] = '.';
897 Buffer[Idx++] = (DirEntry->FileName[8] == ' ') ? '\0' : DirEntry->FileName[8];
898 Buffer[Idx++] = (DirEntry->FileName[9] == ' ') ? '\0' : DirEntry->FileName[9];
899 Buffer[Idx++] = (DirEntry->FileName[10] == ' ') ? '\0' : DirEntry->FileName[10];
900 }
901
902 DPRINTM(DPRINT_FILESYSTEM, "FatParseShortFileName() ShortName = %s\n", Buffer);
903 }
904
905 /*
906 * FatGetFatEntry()
907 * returns the Fat entry for a given cluster number
908 */
909 BOOLEAN FatGetFatEntry(ULONG Cluster, ULONG* ClusterPointer)
910 {
911 ULONG fat = 0;
912 UINT32 FatOffset;
913 UINT32 ThisFatSecNum;
914 UINT32 ThisFatEntOffset;
915
916 DPRINTM(DPRINT_FILESYSTEM, "FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster);
917
918 switch(FatType)
919 {
920 case FAT12:
921
922 FatOffset = Cluster + (Cluster / 2);
923 ThisFatSecNum = ActiveFatSectorStart + (FatOffset / BytesPerSector);
924 ThisFatEntOffset = (FatOffset % BytesPerSector);
925
926 DPRINTM(DPRINT_FILESYSTEM, "FatOffset: %d\n", FatOffset);
927 DPRINTM(DPRINT_FILESYSTEM, "ThisFatSecNum: %d\n", ThisFatSecNum);
928 DPRINTM(DPRINT_FILESYSTEM, "ThisFatEntOffset: %d\n", ThisFatEntOffset);
929
930 if (ThisFatEntOffset == (BytesPerSector - 1))
931 {
932 if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 2, (PVOID)FILESYSBUFFER))
933 {
934 return FALSE;
935 }
936 }
937 else
938 {
939 if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
940 {
941 return FALSE;
942 }
943 }
944
945 fat = *((USHORT *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset));
946 fat = SWAPW(fat);
947 if (Cluster & 0x0001)
948 fat = fat >> 4; /* Cluster number is ODD */
949 else
950 fat = fat & 0x0FFF; /* Cluster number is EVEN */
951
952 break;
953
954 case FAT16:
955 case FATX16:
956
957 FatOffset = (Cluster * 2);
958 ThisFatSecNum = ActiveFatSectorStart + (FatOffset / BytesPerSector);
959 ThisFatEntOffset = (FatOffset % BytesPerSector);
960
961 if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
962 {
963 return FALSE;
964 }
965
966 fat = *((USHORT *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset));
967 fat = SWAPW(fat);
968
969 break;
970
971 case FAT32:
972 case FATX32:
973
974 FatOffset = (Cluster * 4);
975 ThisFatSecNum = ActiveFatSectorStart + (FatOffset / BytesPerSector);
976 ThisFatEntOffset = (FatOffset % BytesPerSector);
977
978 if (!FatReadVolumeSectors(FatDriveNumber, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER))
979 {
980 return FALSE;
981 }
982
983 // Get the fat entry
984 fat = (*((ULONG *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset))) & 0x0FFFFFFF;
985 fat = SWAPD(fat);
986
987 break;
988
989 }
990
991 DPRINTM(DPRINT_FILESYSTEM, "FAT entry is 0x%x.\n", fat);
992
993 *ClusterPointer = fat;
994
995 return TRUE;
996 }
997
998 ULONG FatCountClustersInChain(ULONG StartCluster)
999 {
1000 ULONG ClusterCount = 0;
1001
1002 DPRINTM(DPRINT_FILESYSTEM, "FatCountClustersInChain() StartCluster = %d\n", StartCluster);
1003
1004 while (1)
1005 {
1006 //
1007 // If end of chain then break out of our cluster counting loop
1008 //
1009 if (((FatType == FAT12) && (StartCluster >= 0xff8)) ||
1010 ((FatType == FAT16 || FatType == FATX16) && (StartCluster >= 0xfff8)) ||
1011 ((FatType == FAT32 || FatType == FATX32) && (StartCluster >= 0x0ffffff8)))
1012 {
1013 break;
1014 }
1015
1016 //
1017 // Increment count
1018 //
1019 ClusterCount++;
1020
1021 //
1022 // Get next cluster
1023 //
1024 if (!FatGetFatEntry(StartCluster, &StartCluster))
1025 {
1026 return 0;
1027 }
1028 }
1029
1030 DPRINTM(DPRINT_FILESYSTEM, "FatCountClustersInChain() ClusterCount = %d\n", ClusterCount);
1031
1032 return ClusterCount;
1033 }
1034
1035 ULONG* FatGetClusterChainArray(ULONG StartCluster)
1036 {
1037 ULONG ClusterCount;
1038 ULONG ArraySize;
1039 ULONG* ArrayPointer;
1040 ULONG Idx;
1041
1042 DPRINTM(DPRINT_FILESYSTEM, "FatGetClusterChainArray() StartCluster = %d\n", StartCluster);
1043
1044 ClusterCount = FatCountClustersInChain(StartCluster) + 1; // Lets get the 0x0ffffff8 on the end of the array
1045 ArraySize = ClusterCount * sizeof(ULONG);
1046
1047 //
1048 // Allocate array memory
1049 //
1050 ArrayPointer = MmHeapAlloc(ArraySize);
1051
1052 if (ArrayPointer == NULL)
1053 {
1054 return NULL;
1055 }
1056
1057 //
1058 // Loop through and set array values
1059 //
1060 for (Idx=0; Idx<ClusterCount; Idx++)
1061 {
1062 //
1063 // Set current cluster
1064 //
1065 ArrayPointer[Idx] = StartCluster;
1066
1067 //
1068 // Don't try to get next cluster for last cluster
1069 //
1070 if (((FatType == FAT12) && (StartCluster >= 0xff8)) ||
1071 ((FatType == FAT16 || FatType == FATX16) && (StartCluster >= 0xfff8)) ||
1072 ((FatType == FAT32 || FatType == FATX32) && (StartCluster >= 0x0ffffff8)))
1073 {
1074 Idx++;
1075 break;
1076 }
1077
1078 //
1079 // Get next cluster
1080 //
1081 if (!FatGetFatEntry(StartCluster, &StartCluster))
1082 {
1083 MmHeapFree(ArrayPointer);
1084 return NULL;
1085 }
1086 }
1087
1088 return ArrayPointer;
1089 }
1090
1091 /*
1092 * FatReadCluster()
1093 * Reads the specified cluster into memory
1094 */
1095 BOOLEAN FatReadCluster(ULONG ClusterNumber, PVOID Buffer)
1096 {
1097 ULONG ClusterStartSector;
1098
1099 ClusterStartSector = ((ClusterNumber - 2) * SectorsPerCluster) + DataSectorStart;
1100
1101 DPRINTM(DPRINT_FILESYSTEM, "FatReadCluster() ClusterNumber = %d Buffer = 0x%x ClusterStartSector = %d\n", ClusterNumber, Buffer, ClusterStartSector);
1102
1103 if (!FatReadVolumeSectors(FatDriveNumber, ClusterStartSector, SectorsPerCluster, (PVOID)FILESYSBUFFER))
1104 {
1105 return FALSE;
1106 }
1107
1108 memcpy(Buffer, (PVOID)FILESYSBUFFER, SectorsPerCluster * BytesPerSector);
1109
1110 return TRUE;
1111 }
1112
1113 /*
1114 * FatReadClusterChain()
1115 * Reads the specified clusters into memory
1116 */
1117 BOOLEAN FatReadClusterChain(ULONG StartClusterNumber, ULONG NumberOfClusters, PVOID Buffer)
1118 {
1119 ULONG ClusterStartSector;
1120
1121 DPRINTM(DPRINT_FILESYSTEM, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer);
1122
1123 while (NumberOfClusters > 0)
1124 {
1125
1126 DPRINTM(DPRINT_FILESYSTEM, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer);
1127 //
1128 // Calculate starting sector for cluster
1129 //
1130 ClusterStartSector = ((StartClusterNumber - 2) * SectorsPerCluster) + DataSectorStart;
1131
1132 //
1133 // Read cluster into memory
1134 //
1135 if (!FatReadVolumeSectors(FatDriveNumber, ClusterStartSector, SectorsPerCluster, (PVOID)FILESYSBUFFER))
1136 {
1137 return FALSE;
1138 }
1139
1140 memcpy(Buffer, (PVOID)FILESYSBUFFER, SectorsPerCluster * BytesPerSector);
1141
1142 //
1143 // Decrement count of clusters left to read
1144 //
1145 NumberOfClusters--;
1146
1147 //
1148 // Increment buffer address by cluster size
1149 //
1150 Buffer = (PVOID)((ULONG_PTR)Buffer + (SectorsPerCluster * BytesPerSector));
1151
1152 //
1153 // Get next cluster
1154 //
1155 if (!FatGetFatEntry(StartClusterNumber, &StartClusterNumber))
1156 {
1157 return FALSE;
1158 }
1159
1160 //
1161 // If end of chain then break out of our cluster reading loop
1162 //
1163 if (((FatType == FAT12) && (StartClusterNumber >= 0xff8)) ||
1164 ((FatType == FAT16 || FatType == FATX16) && (StartClusterNumber >= 0xfff8)) ||
1165 ((FatType == FAT32 || FatType == FATX32) && (StartClusterNumber >= 0x0ffffff8)))
1166 {
1167 break;
1168 }
1169 }
1170
1171 return TRUE;
1172 }
1173
1174 /*
1175 * FatReadPartialCluster()
1176 * Reads part of a cluster into memory
1177 */
1178 BOOLEAN FatReadPartialCluster(ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
1179 {
1180 ULONG ClusterStartSector;
1181
1182 DPRINTM(DPRINT_FILESYSTEM, "FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber, StartingOffset, Length, Buffer);
1183
1184 ClusterStartSector = ((ClusterNumber - 2) * SectorsPerCluster) + DataSectorStart;
1185
1186 if (!FatReadVolumeSectors(FatDriveNumber, ClusterStartSector, SectorsPerCluster, (PVOID)FILESYSBUFFER))
1187 {
1188 return FALSE;
1189 }
1190
1191 memcpy(Buffer, (PVOID)((ULONG_PTR)FILESYSBUFFER + StartingOffset), Length);
1192
1193 return TRUE;
1194 }
1195
1196 /*
1197 * FatReadFile()
1198 * Reads BytesToRead from open file and
1199 * returns the number of bytes read in BytesRead
1200 */
1201 BOOLEAN FatReadFile(PFAT_FILE_INFO FatFileInfo, ULONG BytesToRead, ULONG* BytesRead, PVOID Buffer)
1202 {
1203 ULONG ClusterNumber;
1204 ULONG OffsetInCluster;
1205 ULONG LengthInCluster;
1206 ULONG NumberOfClusters;
1207 ULONG BytesPerCluster;
1208
1209 DPRINTM(DPRINT_FILESYSTEM, "FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead, Buffer);
1210
1211 if (BytesRead != NULL)
1212 {
1213 *BytesRead = 0;
1214 }
1215
1216 //
1217 // If they are trying to read past the
1218 // end of the file then return success
1219 // with BytesRead == 0
1220 //
1221 if (FatFileInfo->FilePointer >= FatFileInfo->FileSize)
1222 {
1223 return TRUE;
1224 }
1225
1226 //
1227 // If they are trying to read more than there is to read
1228 // then adjust the amount to read
1229 //
1230 if ((FatFileInfo->FilePointer + BytesToRead) > FatFileInfo->FileSize)
1231 {
1232 BytesToRead = (FatFileInfo->FileSize - FatFileInfo->FilePointer);
1233 }
1234
1235 //
1236 // Ok, now we have to perform at most 3 calculations
1237 // I'll draw you a picture (using nifty ASCII art):
1238 //
1239 // CurrentFilePointer -+
1240 // |
1241 // +----------------+
1242 // |
1243 // +-----------+-----------+-----------+-----------+
1244 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
1245 // +-----------+-----------+-----------+-----------+
1246 // | |
1247 // +---------------+--------------------+
1248 // |
1249 // BytesToRead -------+
1250 //
1251 // 1 - The first calculation (and read) will align
1252 // the file pointer with the next cluster.
1253 // boundary (if we are supposed to read that much)
1254 // 2 - The next calculation (and read) will read
1255 // in all the full clusters that the requested
1256 // amount of data would cover (in this case
1257 // clusters 2 & 3).
1258 // 3 - The last calculation (and read) would read
1259 // in the remainder of the data requested out of
1260 // the last cluster.
1261 //
1262
1263 BytesPerCluster = SectorsPerCluster * BytesPerSector;
1264
1265 //
1266 // Only do the first read if we
1267 // aren't aligned on a cluster boundary
1268 //
1269 if (FatFileInfo->FilePointer % BytesPerCluster)
1270 {
1271 //
1272 // Do the math for our first read
1273 //
1274 ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster);
1275 ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber];
1276 OffsetInCluster = (FatFileInfo->FilePointer % BytesPerCluster);
1277 LengthInCluster = (BytesToRead > (BytesPerCluster - OffsetInCluster)) ? (BytesPerCluster - OffsetInCluster) : BytesToRead;
1278
1279 //
1280 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1281 //
1282 if (!FatReadPartialCluster(ClusterNumber, OffsetInCluster, LengthInCluster, Buffer))
1283 {
1284 return FALSE;
1285 }
1286 if (BytesRead != NULL)
1287 {
1288 *BytesRead += LengthInCluster;
1289 }
1290 BytesToRead -= LengthInCluster;
1291 FatFileInfo->FilePointer += LengthInCluster;
1292 Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInCluster);
1293 }
1294
1295 //
1296 // Do the math for our second read (if any data left)
1297 //
1298 if (BytesToRead > 0)
1299 {
1300 //
1301 // Determine how many full clusters we need to read
1302 //
1303 NumberOfClusters = (BytesToRead / BytesPerCluster);
1304
1305 if (NumberOfClusters > 0)
1306 {
1307 ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster);
1308 ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber];
1309
1310 //
1311 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1312 //
1313 if (!FatReadClusterChain(ClusterNumber, NumberOfClusters, Buffer))
1314 {
1315 return FALSE;
1316 }
1317 if (BytesRead != NULL)
1318 {
1319 *BytesRead += (NumberOfClusters * BytesPerCluster);
1320 }
1321 BytesToRead -= (NumberOfClusters * BytesPerCluster);
1322 FatFileInfo->FilePointer += (NumberOfClusters * BytesPerCluster);
1323 Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfClusters * BytesPerCluster));
1324 }
1325 }
1326
1327 //
1328 // Do the math for our third read (if any data left)
1329 //
1330 if (BytesToRead > 0)
1331 {
1332 ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster);
1333 ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber];
1334
1335 //
1336 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1337 //
1338 if (!FatReadPartialCluster(ClusterNumber, 0, BytesToRead, Buffer))
1339 {
1340 return FALSE;
1341 }
1342 if (BytesRead != NULL)
1343 {
1344 *BytesRead += BytesToRead;
1345 }
1346 FatFileInfo->FilePointer += BytesToRead;
1347 BytesToRead -= BytesToRead;
1348 Buffer = (PVOID)((ULONG_PTR)Buffer + BytesToRead);
1349 }
1350
1351 return TRUE;
1352 }
1353
1354 BOOLEAN FatReadVolumeSectors(ULONG DriveNumber, ULONG SectorNumber, ULONG SectorCount, PVOID Buffer)
1355 {
1356 // Now try to read in the block
1357 if (!MachDiskReadLogicalSectors(DriveNumber, SectorNumber + FatVolumeStartSector, SectorCount, (PVOID)DISKREADBUFFER))
1358 {
1359 return FALSE;
1360 }
1361
1362 // Copy data to the caller
1363 RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, SectorCount * BytesPerSector);
1364
1365 // Return success
1366 return TRUE;
1367 }
1368
1369 LONG FatClose(ULONG FileId)
1370 {
1371 PFAT_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId);
1372
1373 MmHeapFree(FileHandle);
1374
1375 return ESUCCESS;
1376 }
1377
1378 LONG FatGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
1379 {
1380 PFAT_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId);
1381
1382 RtlZeroMemory(Information, sizeof(FILEINFORMATION));
1383 Information->EndingAddress.LowPart = FileHandle->FileSize;
1384 Information->CurrentAddress.LowPart = FileHandle->FilePointer;
1385
1386 DPRINTM(DPRINT_FILESYSTEM, "FatGetFileInformation() FileSize = %d\n",
1387 Information->EndingAddress.LowPart);
1388 DPRINTM(DPRINT_FILESYSTEM, "FatGetFileInformation() FilePointer = %d\n",
1389 Information->CurrentAddress.LowPart);
1390
1391 return ESUCCESS;
1392 }
1393
1394 LONG FatOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
1395 {
1396 FAT_FILE_INFO TempFileInfo;
1397 PFAT_FILE_INFO FileHandle;
1398 ULONG DeviceId;
1399 LONG ret;
1400
1401 if (OpenMode != OpenReadOnly)
1402 return EACCES;
1403
1404 DeviceId = FsGetDeviceId(*FileId);
1405
1406 DPRINTM(DPRINT_FILESYSTEM, "FatOpen() FileName = %s\n", Path);
1407
1408 RtlZeroMemory(&TempFileInfo, sizeof(TempFileInfo));
1409 ret = FatLookupFile(Path, DeviceId, &TempFileInfo);
1410 if (ret != ESUCCESS)
1411 return ENOENT;
1412
1413 FileHandle = MmHeapAlloc(sizeof(FAT_FILE_INFO));
1414 if (!FileHandle)
1415 return ENOMEM;
1416
1417 RtlCopyMemory(FileHandle, &TempFileInfo, sizeof(FAT_FILE_INFO));
1418
1419 FsSetDeviceSpecific(*FileId, FileHandle);
1420 return ESUCCESS;
1421 }
1422
1423 LONG FatRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
1424 {
1425 PFAT_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId);
1426 BOOLEAN ret;
1427
1428 //
1429 // Call old read method
1430 //
1431 ret = FatReadFile(FileHandle, N, Count, Buffer);
1432
1433 //
1434 // Check for success
1435 //
1436 if (ret)
1437 return ESUCCESS;
1438 else
1439 return EIO;
1440 }
1441
1442 LONG FatSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
1443 {
1444 PFAT_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId);
1445
1446 DPRINTM(DPRINT_FILESYSTEM, "FatSeek() NewFilePointer = %lu\n", Position->LowPart);
1447
1448 if (SeekMode != SeekAbsolute)
1449 return EINVAL;
1450 if (Position->HighPart != 0)
1451 return EINVAL;
1452 if (Position->LowPart >= FileHandle->FileSize)
1453 return EINVAL;
1454
1455 FileHandle->FilePointer = Position->LowPart;
1456 return ESUCCESS;
1457 }
1458
1459 const DEVVTBL FatFuncTable =
1460 {
1461 FatClose,
1462 FatGetFileInformation,
1463 FatOpen,
1464 FatRead,
1465 FatSeek,
1466 };
1467
1468 const DEVVTBL* FatMount(ULONG DeviceId)
1469 {
1470 UCHAR Buffer[512];
1471 PFAT_BOOTSECTOR BootSector = (PFAT_BOOTSECTOR)Buffer;
1472 PFAT32_BOOTSECTOR BootSector32 = (PFAT32_BOOTSECTOR)Buffer;
1473 PFATX_BOOTSECTOR BootSectorX = (PFATX_BOOTSECTOR)Buffer;
1474 LARGE_INTEGER Position;
1475 ULONG Count;
1476 LONG ret;
1477
1478 //
1479 // Read the BootSector
1480 //
1481 Position.HighPart = 0;
1482 Position.LowPart = 0;
1483 ret = ArcSeek(DeviceId, &Position, SeekAbsolute);
1484 if (ret != ESUCCESS)
1485 return NULL;
1486 ret = ArcRead(DeviceId, Buffer, sizeof(Buffer), &Count);
1487 if (ret != ESUCCESS || Count != sizeof(Buffer))
1488 return NULL;
1489
1490 //
1491 // Check if BootSector is valid. If yes, return FAT function table
1492 //
1493 if (RtlEqualMemory(BootSector->FileSystemType, "FAT12 ", 8) ||
1494 RtlEqualMemory(BootSector->FileSystemType, "FAT16 ", 8) ||
1495 RtlEqualMemory(BootSector32->FileSystemType, "FAT32 ", 8) ||
1496 RtlEqualMemory(BootSectorX->FileSystemType, "FATX", 4))
1497 {
1498 //
1499 // Compatibility hack as long as FS is not using underlying device DeviceId
1500 //
1501 ULONG DriveNumber;
1502 ULONGLONG StartSector;
1503 ULONGLONG SectorCount;
1504 int Type;
1505 if (!DiskGetBootVolume(&DriveNumber, &StartSector, &SectorCount, &Type))
1506 return NULL;
1507 FatOpenVolume(DriveNumber, StartSector, SectorCount);
1508 return &FatFuncTable;
1509 }
1510 else
1511 return NULL;
1512 }