3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
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.
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.
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.
25 BOOLEAN gCacheEnabled
= FALSE
;
27 ULONG BytesPerSector
; /* Number of bytes per sector */
28 ULONG SectorsPerCluster
; /* Number of sectors per cluster */
29 ULONG FatVolumeStartSector
; /* Absolute starting sector of the partition */
30 ULONG FatSectorStart
; /* Starting sector of 1st FAT table */
31 ULONG ActiveFatSectorStart
; /* Starting sector of active FAT table */
32 ULONG NumberOfFats
; /* Number of FAT tables */
33 ULONG SectorsPerFat
; /* Sectors per FAT table */
34 ULONG RootDirSectorStart
; /* Starting sector of the root directory (non-fat32) */
35 ULONG RootDirSectors
; /* Number of sectors of the root directory (non-fat32) */
36 ULONG RootDirStartCluster
; /* Starting cluster number of the root directory (fat32 only) */
37 ULONG DataSectorStart
; /* Starting sector of the data area */
39 ULONG FatType
= 0; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
40 ULONG FatDriveNumber
= 0;
42 VOID
FatSwapFatBootSector(PFAT_BOOTSECTOR Obj
)
44 SW(Obj
, BytesPerSector
);
45 SW(Obj
, ReservedSectors
);
46 SW(Obj
, RootDirEntries
);
47 SW(Obj
, TotalSectors
);
48 SW(Obj
, SectorsPerFat
);
49 SW(Obj
, SectorsPerTrack
);
50 SW(Obj
, NumberOfHeads
);
51 SD(Obj
, HiddenSectors
);
52 SD(Obj
, TotalSectorsBig
);
53 SD(Obj
, VolumeSerialNumber
);
54 SW(Obj
, BootSectorMagic
);
57 VOID
FatSwapFat32BootSector(PFAT32_BOOTSECTOR Obj
)
59 SW(Obj
, BytesPerSector
);
60 SW(Obj
, ReservedSectors
);
61 SW(Obj
, RootDirEntries
);
62 SW(Obj
, TotalSectors
);
63 SW(Obj
, SectorsPerFat
);
64 SW(Obj
, NumberOfHeads
);
65 SD(Obj
, HiddenSectors
);
66 SD(Obj
, TotalSectorsBig
);
67 SD(Obj
, SectorsPerFatBig
);
68 SW(Obj
, ExtendedFlags
);
69 SW(Obj
, FileSystemVersion
);
70 SD(Obj
, RootDirStartCluster
);
72 SW(Obj
, BackupBootSector
);
73 SD(Obj
, VolumeSerialNumber
);
74 SW(Obj
, BootSectorMagic
);
77 VOID
FatSwapFatXBootSector(PFATX_BOOTSECTOR Obj
)
79 SD(Obj
, VolumeSerialNumber
);
80 SD(Obj
, SectorsPerCluster
);
81 SW(Obj
, NumberOfFats
);
84 VOID
FatSwapDirEntry(PDIRENTRY Obj
)
88 SW(Obj
, LastAccessDate
);
96 VOID
FatSwapLFNDirEntry(PLFN_DIRENTRY Obj
)
99 SW(Obj
, StartCluster
);
100 for(i
= 0; i
< 5; i
++)
101 Obj
->Name0_4
[i
] = SWAPW(Obj
->Name0_4
[i
]);
102 for(i
= 0; i
< 6; i
++)
103 Obj
->Name5_10
[i
] = SWAPW(Obj
->Name5_10
[i
]);
104 for(i
= 0; i
< 2; i
++)
105 Obj
->Name11_12
[i
] = SWAPW(Obj
->Name11_12
[i
]);
108 VOID
FatSwapFatXDirEntry(PFATX_DIRENTRY Obj
)
110 SD(Obj
, StartCluster
);
116 SW(Obj
, LastAccessTime
);
117 SW(Obj
, LastAccessDate
);
120 BOOLEAN
FatOpenVolume(UCHAR DriveNumber
, ULONGLONG VolumeStartSector
, ULONGLONG PartitionSectorCount
)
124 PFAT_BOOTSECTOR FatVolumeBootSector
;
125 PFAT32_BOOTSECTOR Fat32VolumeBootSector
;
126 PFATX_BOOTSECTOR FatXVolumeBootSector
;
128 DbgPrint((DPRINT_FILESYSTEM
, "FatOpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber
, VolumeStartSector
));
130 // Store the drive number
131 FatDriveNumber
= DriveNumber
;
134 // Allocate the memory to hold the boot sector
136 FatVolumeBootSector
= (PFAT_BOOTSECTOR
) MmHeapAlloc(512);
137 Fat32VolumeBootSector
= (PFAT32_BOOTSECTOR
) FatVolumeBootSector
;
138 FatXVolumeBootSector
= (PFATX_BOOTSECTOR
) FatVolumeBootSector
;
141 // Make sure we got the memory
143 if (FatVolumeBootSector
== NULL
)
145 FileSystemError("Out of memory.");
149 // Now try to read the boot sector
150 // If this fails then abort
151 if (!MachDiskReadLogicalSectors(DriveNumber
, VolumeStartSector
, 1, (PVOID
)DISKREADBUFFER
))
153 MmHeapFree(FatVolumeBootSector
);
156 RtlCopyMemory(FatVolumeBootSector
, (PVOID
)DISKREADBUFFER
, 512);
159 FatType
= FatDetermineFatType(FatVolumeBootSector
, PartitionSectorCount
);
161 // Dump boot sector (and swap it for big endian systems)
162 DbgPrint((DPRINT_FILESYSTEM
, "Dumping boot sector:\n"));
165 FatSwapFatXBootSector(FatXVolumeBootSector
);
166 DbgPrint((DPRINT_FILESYSTEM
, "sizeof(FATX_BOOTSECTOR) = 0x%x.\n", sizeof(FATX_BOOTSECTOR
)));
168 DbgPrint((DPRINT_FILESYSTEM
, "FileSystemType: %c%c%c%c.\n", FatXVolumeBootSector
->FileSystemType
[0], FatXVolumeBootSector
->FileSystemType
[1], FatXVolumeBootSector
->FileSystemType
[2], FatXVolumeBootSector
->FileSystemType
[3]));
169 DbgPrint((DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", FatXVolumeBootSector
->VolumeSerialNumber
));
170 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", FatXVolumeBootSector
->SectorsPerCluster
));
171 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", FatXVolumeBootSector
->NumberOfFats
));
172 DbgPrint((DPRINT_FILESYSTEM
, "Unknown: 0x%x\n", FatXVolumeBootSector
->Unknown
));
174 DbgPrint((DPRINT_FILESYSTEM
, "FatType %s\n", FatType
== FATX16
? "FATX16" : "FATX32"));
177 else if (FatType
== FAT32
)
179 FatSwapFat32BootSector(Fat32VolumeBootSector
);
180 DbgPrint((DPRINT_FILESYSTEM
, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR
)));
182 DbgPrint((DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector
->JumpBoot
[0], Fat32VolumeBootSector
->JumpBoot
[1], Fat32VolumeBootSector
->JumpBoot
[2]));
183 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]));
184 DbgPrint((DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", Fat32VolumeBootSector
->BytesPerSector
));
185 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", Fat32VolumeBootSector
->SectorsPerCluster
));
186 DbgPrint((DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", Fat32VolumeBootSector
->ReservedSectors
));
187 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", Fat32VolumeBootSector
->NumberOfFats
));
188 DbgPrint((DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", Fat32VolumeBootSector
->RootDirEntries
));
189 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectors: %d\n", Fat32VolumeBootSector
->TotalSectors
));
190 DbgPrint((DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", Fat32VolumeBootSector
->MediaDescriptor
));
191 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", Fat32VolumeBootSector
->SectorsPerFat
));
192 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", Fat32VolumeBootSector
->SectorsPerTrack
));
193 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", Fat32VolumeBootSector
->NumberOfHeads
));
194 DbgPrint((DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", Fat32VolumeBootSector
->HiddenSectors
));
195 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", Fat32VolumeBootSector
->TotalSectorsBig
));
196 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFatBig: %d\n", Fat32VolumeBootSector
->SectorsPerFatBig
));
197 DbgPrint((DPRINT_FILESYSTEM
, "ExtendedFlags: 0x%x\n", Fat32VolumeBootSector
->ExtendedFlags
));
198 DbgPrint((DPRINT_FILESYSTEM
, "FileSystemVersion: 0x%x\n", Fat32VolumeBootSector
->FileSystemVersion
));
199 DbgPrint((DPRINT_FILESYSTEM
, "RootDirStartCluster: %d\n", Fat32VolumeBootSector
->RootDirStartCluster
));
200 DbgPrint((DPRINT_FILESYSTEM
, "FsInfo: %d\n", Fat32VolumeBootSector
->FsInfo
));
201 DbgPrint((DPRINT_FILESYSTEM
, "BackupBootSector: %d\n", Fat32VolumeBootSector
->BackupBootSector
));
202 DbgPrint((DPRINT_FILESYSTEM
, "Reserved: 0x%x\n", Fat32VolumeBootSector
->Reserved
));
203 DbgPrint((DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", Fat32VolumeBootSector
->DriveNumber
));
204 DbgPrint((DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", Fat32VolumeBootSector
->Reserved1
));
205 DbgPrint((DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", Fat32VolumeBootSector
->BootSignature
));
206 DbgPrint((DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector
->VolumeSerialNumber
));
207 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]));
208 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]));
209 DbgPrint((DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", Fat32VolumeBootSector
->BootSectorMagic
));
213 FatSwapFatBootSector(FatVolumeBootSector
);
214 DbgPrint((DPRINT_FILESYSTEM
, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR
)));
216 DbgPrint((DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector
->JumpBoot
[0], FatVolumeBootSector
->JumpBoot
[1], FatVolumeBootSector
->JumpBoot
[2]));
217 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]));
218 DbgPrint((DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", FatVolumeBootSector
->BytesPerSector
));
219 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", FatVolumeBootSector
->SectorsPerCluster
));
220 DbgPrint((DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", FatVolumeBootSector
->ReservedSectors
));
221 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", FatVolumeBootSector
->NumberOfFats
));
222 DbgPrint((DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", FatVolumeBootSector
->RootDirEntries
));
223 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectors: %d\n", FatVolumeBootSector
->TotalSectors
));
224 DbgPrint((DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", FatVolumeBootSector
->MediaDescriptor
));
225 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", FatVolumeBootSector
->SectorsPerFat
));
226 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", FatVolumeBootSector
->SectorsPerTrack
));
227 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", FatVolumeBootSector
->NumberOfHeads
));
228 DbgPrint((DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", FatVolumeBootSector
->HiddenSectors
));
229 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", FatVolumeBootSector
->TotalSectorsBig
));
230 DbgPrint((DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", FatVolumeBootSector
->DriveNumber
));
231 DbgPrint((DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", FatVolumeBootSector
->Reserved1
));
232 DbgPrint((DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", FatVolumeBootSector
->BootSignature
));
233 DbgPrint((DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector
->VolumeSerialNumber
));
234 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]));
235 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]));
236 DbgPrint((DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", FatVolumeBootSector
->BootSectorMagic
));
240 // Set the correct partition offset
242 FatVolumeStartSector
= VolumeStartSector
;
245 // Check the boot sector magic
247 if (! ISFATX(FatType
) && FatVolumeBootSector
->BootSectorMagic
!= 0xaa55)
249 sprintf(ErrMsg
, "Invalid boot sector magic on drive 0x%x (expected 0xaa55 found 0x%x)",
250 DriveNumber
, FatVolumeBootSector
->BootSectorMagic
);
251 FileSystemError(ErrMsg
);
252 MmHeapFree(FatVolumeBootSector
);
257 // Check the FAT cluster size
258 // We do not support clusters bigger than 64k
260 if ((ISFATX(FatType
) && 64 * 1024 < FatXVolumeBootSector
->SectorsPerCluster
* 512) ||
261 (! ISFATX(FatType
) && 64 * 1024 < FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
))
263 FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
264 MmHeapFree(FatVolumeBootSector
);
269 // Clear our variables
272 ActiveFatSectorStart
= 0;
274 RootDirSectorStart
= 0;
280 // Get the sectors per FAT,
281 // root directory starting sector,
282 // and data sector start
286 BytesPerSector
= 512;
287 SectorsPerCluster
= SWAPD(FatXVolumeBootSector
->SectorsPerCluster
);
288 FatSectorStart
= (4096 / BytesPerSector
);
289 ActiveFatSectorStart
= FatSectorStart
;
291 FatSize
= PartitionSectorCount
/ SectorsPerCluster
*
292 (FATX16
== FatType
? 2 : 4);
293 SectorsPerFat
= (((FatSize
+ 4095) / 4096) * 4096) / BytesPerSector
;
295 RootDirSectorStart
= FatSectorStart
+ NumberOfFats
* SectorsPerFat
;
296 RootDirSectors
= FatXVolumeBootSector
->SectorsPerCluster
;
298 DataSectorStart
= RootDirSectorStart
+ RootDirSectors
;
300 else if (FatType
!= FAT32
)
302 BytesPerSector
= FatVolumeBootSector
->BytesPerSector
;
303 SectorsPerCluster
= FatVolumeBootSector
->SectorsPerCluster
;
304 FatSectorStart
= FatVolumeBootSector
->ReservedSectors
;
305 ActiveFatSectorStart
= FatSectorStart
;
306 NumberOfFats
= FatVolumeBootSector
->NumberOfFats
;
307 SectorsPerFat
= FatVolumeBootSector
->SectorsPerFat
;
309 RootDirSectorStart
= FatSectorStart
+ NumberOfFats
* SectorsPerFat
;
310 RootDirSectors
= ((FatVolumeBootSector
->RootDirEntries
* 32) + (BytesPerSector
- 1)) / BytesPerSector
;
312 DataSectorStart
= RootDirSectorStart
+ RootDirSectors
;
316 BytesPerSector
= Fat32VolumeBootSector
->BytesPerSector
;
317 SectorsPerCluster
= Fat32VolumeBootSector
->SectorsPerCluster
;
318 FatSectorStart
= Fat32VolumeBootSector
->ReservedSectors
;
319 ActiveFatSectorStart
= FatSectorStart
+
320 ((Fat32VolumeBootSector
->ExtendedFlags
& 0x80) ? ((Fat32VolumeBootSector
->ExtendedFlags
& 0x0f) * Fat32VolumeBootSector
->SectorsPerFatBig
) : 0);
321 NumberOfFats
= Fat32VolumeBootSector
->NumberOfFats
;
322 SectorsPerFat
= Fat32VolumeBootSector
->SectorsPerFatBig
;
324 RootDirStartCluster
= Fat32VolumeBootSector
->RootDirStartCluster
;
325 DataSectorStart
= FatSectorStart
+ NumberOfFats
* SectorsPerFat
;
329 // we only work with version 0
331 if (Fat32VolumeBootSector
->FileSystemVersion
!= 0)
333 FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
337 MmHeapFree(FatVolumeBootSector
);
342 // Initialize the disk cache for this drive
344 if (!CacheInitializeDrive(DriveNumber
))
350 // Force the FAT sectors into the cache
351 // as long as it is FAT12 or FAT16. FAT32 can
352 // have a multi-megabyte FAT so we don't want that.
354 if (FatType
!= FAT32
&& FatType
!= FATX32
)
356 if (!CacheForceDiskSectorsIntoCache(DriveNumber
, ActiveFatSectorStart
, SectorsPerFat
))
364 GEOMETRY DriveGeometry
;
367 // Initialize drive by getting its geometry
368 if (!MachDiskGetDriveGeometry(DriveNumber
, &DriveGeometry
))
373 BlockSize
= MachDiskGetCacheableBlockCount(DriveNumber
);
379 ULONG
FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector
, ULONG PartitionSectorCount
)
381 ULONG RootDirSectors
;
382 ULONG DataSectorCount
;
385 ULONG CountOfClusters
;
386 PFAT32_BOOTSECTOR Fat32BootSector
= (PFAT32_BOOTSECTOR
)FatBootSector
;
387 PFATX_BOOTSECTOR FatXBootSector
= (PFATX_BOOTSECTOR
)FatBootSector
;
389 if (0 == strncmp(FatXBootSector
->FileSystemType
, "FATX", 4))
391 CountOfClusters
= PartitionSectorCount
/ FatXBootSector
->SectorsPerCluster
;
392 if (CountOfClusters
< 65525)
394 /* Volume is FATX16 */
399 /* Volume is FAT32 */
405 RootDirSectors
= ((SWAPW(FatBootSector
->RootDirEntries
) * 32) + (SWAPW(FatBootSector
->BytesPerSector
) - 1)) / SWAPW(FatBootSector
->BytesPerSector
);
406 SectorsPerFat
= SWAPW(FatBootSector
->SectorsPerFat
) ? SWAPW(FatBootSector
->SectorsPerFat
) : SWAPD(Fat32BootSector
->SectorsPerFatBig
);
407 TotalSectors
= SWAPW(FatBootSector
->TotalSectors
) ? SWAPW(FatBootSector
->TotalSectors
) : SWAPD(FatBootSector
->TotalSectorsBig
);
408 DataSectorCount
= TotalSectors
- (SWAPW(FatBootSector
->ReservedSectors
) + (FatBootSector
->NumberOfFats
* SectorsPerFat
) + RootDirSectors
);
411 if (FatBootSector
->SectorsPerCluster
== 0)
414 CountOfClusters
= DataSectorCount
/ FatBootSector
->SectorsPerCluster
;
416 if (CountOfClusters
< 4085)
418 /* Volume is FAT12 */
421 else if (CountOfClusters
< 65525)
423 /* Volume is FAT16 */
428 /* Volume is FAT32 */
434 PVOID
FatBufferDirectory(ULONG DirectoryStartCluster
, ULONG
*DirectorySize
, BOOLEAN RootDirectory
)
436 PVOID DirectoryBuffer
;
438 DbgPrint((DPRINT_FILESYSTEM
, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster
, (RootDirectory
? "TRUE" : "FALSE")));
441 * For FAT32, the root directory is nothing special. We can treat it the same
444 if (RootDirectory
&& FAT32
== FatType
)
446 DirectoryStartCluster
= RootDirStartCluster
;
447 RootDirectory
= FALSE
;
451 // Calculate the size of the directory
455 *DirectorySize
= RootDirSectors
* BytesPerSector
;
459 *DirectorySize
= FatCountClustersInChain(DirectoryStartCluster
) * SectorsPerCluster
* BytesPerSector
;
463 // Attempt to allocate memory for directory buffer
465 DbgPrint((DPRINT_FILESYSTEM
, "Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize
));
466 DirectoryBuffer
= MmHeapAlloc(*DirectorySize
);
468 if (DirectoryBuffer
== NULL
)
474 // Now read directory contents into DirectoryBuffer
478 if (!FatReadVolumeSectors(FatDriveNumber
, RootDirSectorStart
, RootDirSectors
, DirectoryBuffer
))
480 MmHeapFree(DirectoryBuffer
);
486 if (!FatReadClusterChain(DirectoryStartCluster
, 0xFFFFFFFF, DirectoryBuffer
))
488 MmHeapFree(DirectoryBuffer
);
493 return DirectoryBuffer
;
496 BOOLEAN
FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
500 CHAR LfnNameBuffer
[265];
501 CHAR ShortNameBuffer
[20];
503 DIRENTRY OurDirEntry
;
504 LFN_DIRENTRY OurLfnDirEntry
;
505 PDIRENTRY DirEntry
= &OurDirEntry
;
506 PLFN_DIRENTRY LfnDirEntry
= &OurLfnDirEntry
;
508 EntryCount
= DirectorySize
/ sizeof(DIRENTRY
);
510 DbgPrint((DPRINT_FILESYSTEM
, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
));
512 memset(ShortNameBuffer
, 0, 13 * sizeof(CHAR
));
513 memset(LfnNameBuffer
, 0, 261 * sizeof(CHAR
));
515 for (CurrentEntry
=0; CurrentEntry
<EntryCount
; CurrentEntry
++, DirectoryBuffer
= ((PDIRENTRY
)DirectoryBuffer
)+1)
517 OurLfnDirEntry
= *((PLFN_DIRENTRY
) DirectoryBuffer
);
518 FatSwapLFNDirEntry(LfnDirEntry
);
519 OurDirEntry
= *((PDIRENTRY
) DirectoryBuffer
);
520 FatSwapDirEntry(DirEntry
);
522 //DbgPrint((DPRINT_FILESYSTEM, "Dumping directory entry %d:\n", CurrentEntry));
523 //DbgDumpBuffer(DPRINT_FILESYSTEM, DirEntry, sizeof(DIRENTRY));
526 // Check if this is the last file in the directory
527 // If DirEntry[0] == 0x00 then that means all the
528 // entries after this one are unused. If this is the
529 // last entry then we didn't find the file in this directory.
531 if (DirEntry
->FileName
[0] == '\0')
537 // Check if this is a deleted entry or not
539 if (DirEntry
->FileName
[0] == '\xE5')
541 memset(ShortNameBuffer
, 0, 13 * sizeof(CHAR
));
542 memset(LfnNameBuffer
, 0, 261 * sizeof(CHAR
));
547 // Check if this is a LFN entry
548 // If so it needs special handling
550 if (DirEntry
->Attr
== ATTR_LONG_NAME
)
553 // Check to see if this is a deleted LFN entry, if so continue
555 if (LfnDirEntry
->SequenceNumber
& 0x80)
561 // Mask off high two bits of sequence number
562 // and make the sequence number zero-based
564 LfnDirEntry
->SequenceNumber
&= 0x3F;
565 LfnDirEntry
->SequenceNumber
--;
568 // Get all 13 LFN entry characters
570 if (LfnDirEntry
->Name0_4
[0] != 0xFFFF)
572 LfnNameBuffer
[0 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[0];
574 if (LfnDirEntry
->Name0_4
[1] != 0xFFFF)
576 LfnNameBuffer
[1 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[1];
578 if (LfnDirEntry
->Name0_4
[2] != 0xFFFF)
580 LfnNameBuffer
[2 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[2];
582 if (LfnDirEntry
->Name0_4
[3] != 0xFFFF)
584 LfnNameBuffer
[3 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[3];
586 if (LfnDirEntry
->Name0_4
[4] != 0xFFFF)
588 LfnNameBuffer
[4 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[4];
590 if (LfnDirEntry
->Name5_10
[0] != 0xFFFF)
592 LfnNameBuffer
[5 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[0];
594 if (LfnDirEntry
->Name5_10
[1] != 0xFFFF)
596 LfnNameBuffer
[6 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[1];
598 if (LfnDirEntry
->Name5_10
[2] != 0xFFFF)
600 LfnNameBuffer
[7 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[2];
602 if (LfnDirEntry
->Name5_10
[3] != 0xFFFF)
604 LfnNameBuffer
[8 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[3];
606 if (LfnDirEntry
->Name5_10
[4] != 0xFFFF)
608 LfnNameBuffer
[9 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[4];
610 if (LfnDirEntry
->Name5_10
[5] != 0xFFFF)
612 LfnNameBuffer
[10 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[5];
614 if (LfnDirEntry
->Name11_12
[0] != 0xFFFF)
616 LfnNameBuffer
[11 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[0];
618 if (LfnDirEntry
->Name11_12
[1] != 0xFFFF)
620 LfnNameBuffer
[12 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[1];
623 //DbgPrint((DPRINT_FILESYSTEM, "Dumping long name buffer:\n"));
624 //DbgDumpBuffer(DPRINT_FILESYSTEM, LfnNameBuffer, 260);
630 // Check for the volume label attribute
631 // and skip over this entry if found
633 if (DirEntry
->Attr
& ATTR_VOLUMENAME
)
635 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
636 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
641 // If we get here then we've found a short file name
642 // entry and LfnNameBuffer contains the long file
643 // name or zeroes. All we have to do now is see if the
644 // file name matches either the short or long file name
645 // and fill in the FAT_FILE_INFO structure if it does
646 // or zero our buffers and continue looking.
650 // Get short file name
652 FatParseShortFileName(ShortNameBuffer
, DirEntry
);
654 DbgPrint((DPRINT_FILESYSTEM
, "Entry: %d LFN = %s\n", CurrentEntry
, LfnNameBuffer
));
655 DbgPrint((DPRINT_FILESYSTEM
, "Entry: %d DOS name = %s\n", CurrentEntry
, ShortNameBuffer
));
658 // See if the file name matches either the short or long name
660 if (((strlen(FileName
) == strlen(LfnNameBuffer
)) && (_stricmp(FileName
, LfnNameBuffer
) == 0)) ||
661 ((strlen(FileName
) == strlen(ShortNameBuffer
)) && (_stricmp(FileName
, ShortNameBuffer
) == 0))) {
663 // We found the entry, now fill in the FAT_FILE_INFO struct
665 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
666 FatFileInfoPointer
->FilePointer
= 0;
668 DbgPrint((DPRINT_FILESYSTEM
, "MSDOS Directory Entry:\n"));
669 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]));
670 DbgPrint((DPRINT_FILESYSTEM
, "Attr = 0x%x\n", DirEntry
->Attr
));
671 DbgPrint((DPRINT_FILESYSTEM
, "ReservedNT = 0x%x\n", DirEntry
->ReservedNT
));
672 DbgPrint((DPRINT_FILESYSTEM
, "TimeInTenths = %d\n", DirEntry
->TimeInTenths
));
673 DbgPrint((DPRINT_FILESYSTEM
, "CreateTime = %d\n", DirEntry
->CreateTime
));
674 DbgPrint((DPRINT_FILESYSTEM
, "CreateDate = %d\n", DirEntry
->CreateDate
));
675 DbgPrint((DPRINT_FILESYSTEM
, "LastAccessDate = %d\n", DirEntry
->LastAccessDate
));
676 DbgPrint((DPRINT_FILESYSTEM
, "ClusterHigh = 0x%x\n", DirEntry
->ClusterHigh
));
677 DbgPrint((DPRINT_FILESYSTEM
, "Time = %d\n", DirEntry
->Time
));
678 DbgPrint((DPRINT_FILESYSTEM
, "Date = %d\n", DirEntry
->Date
));
679 DbgPrint((DPRINT_FILESYSTEM
, "ClusterLow = 0x%x\n", DirEntry
->ClusterLow
));
680 DbgPrint((DPRINT_FILESYSTEM
, "Size = %d\n", DirEntry
->Size
));
683 // Get the cluster chain
685 StartCluster
= ((ULONG
)DirEntry
->ClusterHigh
<< 16) + DirEntry
->ClusterLow
;
686 DbgPrint((DPRINT_FILESYSTEM
, "StartCluster = 0x%x\n", StartCluster
));
687 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(StartCluster
);
690 // See if memory allocation failed
692 if (FatFileInfoPointer
->FileFatChain
== NULL
)
701 // Nope, no match - zero buffers and continue looking
703 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
704 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
711 static BOOLEAN
FatXSearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
716 FATX_DIRENTRY OurDirEntry
;
717 PFATX_DIRENTRY DirEntry
= &OurDirEntry
;
719 EntryCount
= DirectorySize
/ sizeof(FATX_DIRENTRY
);
721 DbgPrint((DPRINT_FILESYSTEM
, "FatXSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
));
723 FileNameLen
= strlen(FileName
);
725 for (CurrentEntry
= 0; CurrentEntry
< EntryCount
; CurrentEntry
++, DirectoryBuffer
= ((PFATX_DIRENTRY
)DirectoryBuffer
)+1)
727 OurDirEntry
= *(PFATX_DIRENTRY
) DirectoryBuffer
;
728 FatSwapFatXDirEntry(&OurDirEntry
);
729 if (0xff == DirEntry
->FileNameSize
)
733 if (0xe5 == DirEntry
->FileNameSize
)
737 if (FileNameLen
== DirEntry
->FileNameSize
&&
738 0 == _strnicmp(FileName
, DirEntry
->FileName
, FileNameLen
))
741 * We found the entry, now fill in the FAT_FILE_INFO struct
743 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
744 FatFileInfoPointer
->FilePointer
= 0;
746 DbgPrint((DPRINT_FILESYSTEM
, "FATX Directory Entry:\n"));
747 DbgPrint((DPRINT_FILESYSTEM
, "FileNameSize = %d\n", DirEntry
->FileNameSize
));
748 DbgPrint((DPRINT_FILESYSTEM
, "Attr = 0x%x\n", DirEntry
->Attr
));
749 DbgPrint((DPRINT_FILESYSTEM
, "StartCluster = 0x%x\n", DirEntry
->StartCluster
));
750 DbgPrint((DPRINT_FILESYSTEM
, "Size = %d\n", DirEntry
->Size
));
751 DbgPrint((DPRINT_FILESYSTEM
, "Time = %d\n", DirEntry
->Time
));
752 DbgPrint((DPRINT_FILESYSTEM
, "Date = %d\n", DirEntry
->Date
));
753 DbgPrint((DPRINT_FILESYSTEM
, "CreateTime = %d\n", DirEntry
->CreateTime
));
754 DbgPrint((DPRINT_FILESYSTEM
, "CreateDate = %d\n", DirEntry
->CreateDate
));
755 DbgPrint((DPRINT_FILESYSTEM
, "LastAccessTime = %d\n", DirEntry
->LastAccessTime
));
756 DbgPrint((DPRINT_FILESYSTEM
, "LastAccessDate = %d\n", DirEntry
->LastAccessDate
));
759 * Get the cluster chain
761 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(DirEntry
->StartCluster
);
764 * See if memory allocation failed
766 if (NULL
== FatFileInfoPointer
->FileFatChain
)
780 * This function searches the file system for the
781 * specified filename and fills in a FAT_FILE_INFO structure
782 * with info describing the file, etc. returns true
783 * if the file exists or false otherwise
785 BOOLEAN
FatLookupFile(PCSTR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
788 ULONG NumberOfPathParts
;
790 PVOID DirectoryBuffer
;
791 ULONG DirectoryStartCluster
= 0;
793 FAT_FILE_INFO FatFileInfo
;
795 DbgPrint((DPRINT_FILESYSTEM
, "FatLookupFile() FileName = %s\n", FileName
));
797 memset(FatFileInfoPointer
, 0, sizeof(FAT_FILE_INFO
));
800 // Figure out how many sub-directories we are nested in
802 NumberOfPathParts
= FsGetNumPathParts(FileName
);
805 // Loop once for each part
807 for (i
=0; i
<NumberOfPathParts
; i
++)
810 // Get first path part
812 FsGetFirstNameFromPath(PathPart
, FileName
);
815 // Advance to the next part of the path
817 for (; (*FileName
!= '\\') && (*FileName
!= '/') && (*FileName
!= '\0'); FileName
++)
823 // Buffer the directory contents
825 DirectoryBuffer
= FatBufferDirectory(DirectoryStartCluster
, &DirectorySize
, (i
== 0) );
826 if (DirectoryBuffer
== NULL
)
832 // Search for file name in directory
836 if (!FatXSearchDirectoryBufferForFile(DirectoryBuffer
, DirectorySize
, PathPart
, &FatFileInfo
))
838 MmHeapFree(DirectoryBuffer
);
844 if (!FatSearchDirectoryBufferForFile(DirectoryBuffer
, DirectorySize
, PathPart
, &FatFileInfo
))
846 MmHeapFree(DirectoryBuffer
);
851 MmHeapFree(DirectoryBuffer
);
854 // If we have another sub-directory to go then
855 // grab the start cluster and free the fat chain array
857 if ((i
+1) < NumberOfPathParts
)
859 DirectoryStartCluster
= FatFileInfo
.FileFatChain
[0];
860 MmHeapFree(FatFileInfo
.FileFatChain
);
864 memcpy(FatFileInfoPointer
, &FatFileInfo
, sizeof(FAT_FILE_INFO
));
871 * This function parses a directory entry name which
872 * is in the form of "FILE EXT" and puts it in Buffer
873 * in the form of "file.ext"
875 void FatParseShortFileName(PCHAR Buffer
, PDIRENTRY DirEntry
)
880 RtlZeroMemory(Buffer
, 13);
883 // Fixup first character
885 if (DirEntry
->FileName
[0] == 0x05)
887 DirEntry
->FileName
[0] = 0xE5;
895 if (DirEntry
->FileName
[Idx
] == ' ')
900 Buffer
[Idx
] = DirEntry
->FileName
[Idx
];
907 if ((DirEntry
->FileName
[8] != ' '))
910 Buffer
[Idx
++] = (DirEntry
->FileName
[8] == ' ') ? '\0' : DirEntry
->FileName
[8];
911 Buffer
[Idx
++] = (DirEntry
->FileName
[9] == ' ') ? '\0' : DirEntry
->FileName
[9];
912 Buffer
[Idx
++] = (DirEntry
->FileName
[10] == ' ') ? '\0' : DirEntry
->FileName
[10];
915 DbgPrint((DPRINT_FILESYSTEM
, "FatParseShortFileName() ShortName = %s\n", Buffer
));
920 * returns the Fat entry for a given cluster number
922 BOOLEAN
FatGetFatEntry(ULONG Cluster
, ULONG
* ClusterPointer
)
926 UINT32 ThisFatSecNum
;
927 UINT32 ThisFatEntOffset
;
929 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster
));
935 FatOffset
= Cluster
+ (Cluster
/ 2);
936 ThisFatSecNum
= ActiveFatSectorStart
+ (FatOffset
/ BytesPerSector
);
937 ThisFatEntOffset
= (FatOffset
% BytesPerSector
);
939 DbgPrint((DPRINT_FILESYSTEM
, "FatOffset: %d\n", FatOffset
));
940 DbgPrint((DPRINT_FILESYSTEM
, "ThisFatSecNum: %d\n", ThisFatSecNum
));
941 DbgPrint((DPRINT_FILESYSTEM
, "ThisFatEntOffset: %d\n", ThisFatEntOffset
));
943 if (ThisFatEntOffset
== (BytesPerSector
- 1))
945 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 2, (PVOID
)FILESYSBUFFER
))
952 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
958 fat
= *((USHORT
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
));
960 if (Cluster
& 0x0001)
961 fat
= fat
>> 4; /* Cluster number is ODD */
963 fat
= fat
& 0x0FFF; /* Cluster number is EVEN */
970 FatOffset
= (Cluster
* 2);
971 ThisFatSecNum
= ActiveFatSectorStart
+ (FatOffset
/ BytesPerSector
);
972 ThisFatEntOffset
= (FatOffset
% BytesPerSector
);
974 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
979 fat
= *((USHORT
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
));
987 FatOffset
= (Cluster
* 4);
988 ThisFatSecNum
= ActiveFatSectorStart
+ (FatOffset
/ BytesPerSector
);
989 ThisFatEntOffset
= (FatOffset
% BytesPerSector
);
991 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
997 fat
= (*((ULONG
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
))) & 0x0FFFFFFF;
1004 DbgPrint((DPRINT_FILESYSTEM
, "FAT entry is 0x%x.\n", fat
));
1006 *ClusterPointer
= fat
;
1013 * Tries to open the file 'name' and returns true or false
1014 * for success and failure respectively
1016 FILE* FatOpenFile(PCSTR FileName
)
1018 FAT_FILE_INFO TempFatFileInfo
;
1019 PFAT_FILE_INFO FileHandle
;
1021 DbgPrint((DPRINT_FILESYSTEM
, "FatOpenFile() FileName = %s\n", FileName
));
1023 if (!FatLookupFile(FileName
, &TempFatFileInfo
))
1028 FileHandle
= MmHeapAlloc(sizeof(FAT_FILE_INFO
));
1030 if (FileHandle
== NULL
)
1035 memcpy(FileHandle
, &TempFatFileInfo
, sizeof(FAT_FILE_INFO
));
1037 return (FILE*)FileHandle
;
1040 ULONG
FatCountClustersInChain(ULONG StartCluster
)
1042 ULONG ClusterCount
= 0;
1044 DbgPrint((DPRINT_FILESYSTEM
, "FatCountClustersInChain() StartCluster = %d\n", StartCluster
));
1049 // If end of chain then break out of our cluster counting loop
1051 if (((FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
1052 ((FatType
== FAT16
|| FatType
== FATX16
) && (StartCluster
>= 0xfff8)) ||
1053 ((FatType
== FAT32
|| FatType
== FATX32
) && (StartCluster
>= 0x0ffffff8)))
1066 if (!FatGetFatEntry(StartCluster
, &StartCluster
))
1072 DbgPrint((DPRINT_FILESYSTEM
, "FatCountClustersInChain() ClusterCount = %d\n", ClusterCount
));
1074 return ClusterCount
;
1077 ULONG
* FatGetClusterChainArray(ULONG StartCluster
)
1081 ULONG
* ArrayPointer
;
1084 DbgPrint((DPRINT_FILESYSTEM
, "FatGetClusterChainArray() StartCluster = %d\n", StartCluster
));
1086 ClusterCount
= FatCountClustersInChain(StartCluster
) + 1; // Lets get the 0x0ffffff8 on the end of the array
1087 ArraySize
= ClusterCount
* sizeof(ULONG
);
1090 // Allocate array memory
1092 ArrayPointer
= MmHeapAlloc(ArraySize
);
1094 if (ArrayPointer
== NULL
)
1100 // Loop through and set array values
1102 for (Idx
=0; Idx
<ClusterCount
; Idx
++)
1105 // Set current cluster
1107 ArrayPointer
[Idx
] = StartCluster
;
1110 // Don't try to get next cluster for last cluster
1112 if (((FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
1113 ((FatType
== FAT16
|| FatType
== FATX16
) && (StartCluster
>= 0xfff8)) ||
1114 ((FatType
== FAT32
|| FatType
== FATX32
) && (StartCluster
>= 0x0ffffff8)))
1123 if (!FatGetFatEntry(StartCluster
, &StartCluster
))
1125 MmHeapFree(ArrayPointer
);
1130 return ArrayPointer
;
1135 * Reads the specified cluster into memory
1137 BOOLEAN
FatReadCluster(ULONG ClusterNumber
, PVOID Buffer
)
1139 ULONG ClusterStartSector
;
1141 ClusterStartSector
= ((ClusterNumber
- 2) * SectorsPerCluster
) + DataSectorStart
;
1143 DbgPrint((DPRINT_FILESYSTEM
, "FatReadCluster() ClusterNumber = %d Buffer = 0x%x ClusterStartSector = %d\n", ClusterNumber
, Buffer
, ClusterStartSector
));
1145 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1150 memcpy(Buffer
, (PVOID
)FILESYSBUFFER
, SectorsPerCluster
* BytesPerSector
);
1156 * FatReadClusterChain()
1157 * Reads the specified clusters into memory
1159 BOOLEAN
FatReadClusterChain(ULONG StartClusterNumber
, ULONG NumberOfClusters
, PVOID Buffer
)
1161 ULONG ClusterStartSector
;
1163 DbgPrint((DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
));
1165 while (NumberOfClusters
> 0)
1168 DbgPrint((DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
));
1170 // Calculate starting sector for cluster
1172 ClusterStartSector
= ((StartClusterNumber
- 2) * SectorsPerCluster
) + DataSectorStart
;
1175 // Read cluster into memory
1177 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1182 memcpy(Buffer
, (PVOID
)FILESYSBUFFER
, SectorsPerCluster
* BytesPerSector
);
1185 // Decrement count of clusters left to read
1190 // Increment buffer address by cluster size
1192 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (SectorsPerCluster
* BytesPerSector
));
1197 if (!FatGetFatEntry(StartClusterNumber
, &StartClusterNumber
))
1203 // If end of chain then break out of our cluster reading loop
1205 if (((FatType
== FAT12
) && (StartClusterNumber
>= 0xff8)) ||
1206 ((FatType
== FAT16
|| FatType
== FATX16
) && (StartClusterNumber
>= 0xfff8)) ||
1207 ((FatType
== FAT32
|| FatType
== FATX32
) && (StartClusterNumber
>= 0x0ffffff8)))
1217 * FatReadPartialCluster()
1218 * Reads part of a cluster into memory
1220 BOOLEAN
FatReadPartialCluster(ULONG ClusterNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
)
1222 ULONG ClusterStartSector
;
1224 DbgPrint((DPRINT_FILESYSTEM
, "FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber
, StartingOffset
, Length
, Buffer
));
1226 ClusterStartSector
= ((ClusterNumber
- 2) * SectorsPerCluster
) + DataSectorStart
;
1228 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1233 memcpy(Buffer
, (PVOID
)((ULONG_PTR
)FILESYSBUFFER
+ StartingOffset
), Length
);
1240 * Reads BytesToRead from open file and
1241 * returns the number of bytes read in BytesRead
1243 BOOLEAN
FatReadFile(FILE *FileHandle
, ULONG BytesToRead
, ULONG
* BytesRead
, PVOID Buffer
)
1245 PFAT_FILE_INFO FatFileInfo
= (PFAT_FILE_INFO
)FileHandle
;
1246 ULONG ClusterNumber
;
1247 ULONG OffsetInCluster
;
1248 ULONG LengthInCluster
;
1249 ULONG NumberOfClusters
;
1250 ULONG BytesPerCluster
;
1252 DbgPrint((DPRINT_FILESYSTEM
, "FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead
, Buffer
));
1254 if (BytesRead
!= NULL
)
1260 // If they are trying to read past the
1261 // end of the file then return success
1262 // with BytesRead == 0
1264 if (FatFileInfo
->FilePointer
>= FatFileInfo
->FileSize
)
1270 // If they are trying to read more than there is to read
1271 // then adjust the amount to read
1273 if ((FatFileInfo
->FilePointer
+ BytesToRead
) > FatFileInfo
->FileSize
)
1275 BytesToRead
= (FatFileInfo
->FileSize
- FatFileInfo
->FilePointer
);
1279 // Ok, now we have to perform at most 3 calculations
1280 // I'll draw you a picture (using nifty ASCII art):
1282 // CurrentFilePointer -+
1284 // +----------------+
1286 // +-----------+-----------+-----------+-----------+
1287 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
1288 // +-----------+-----------+-----------+-----------+
1290 // +---------------+--------------------+
1292 // BytesToRead -------+
1294 // 1 - The first calculation (and read) will align
1295 // the file pointer with the next cluster.
1296 // boundary (if we are supposed to read that much)
1297 // 2 - The next calculation (and read) will read
1298 // in all the full clusters that the requested
1299 // amount of data would cover (in this case
1301 // 3 - The last calculation (and read) would read
1302 // in the remainder of the data requested out of
1303 // the last cluster.
1306 BytesPerCluster
= SectorsPerCluster
* BytesPerSector
;
1309 // Only do the first read if we
1310 // aren't aligned on a cluster boundary
1312 if (FatFileInfo
->FilePointer
% BytesPerCluster
)
1315 // Do the math for our first read
1317 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1318 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1319 OffsetInCluster
= (FatFileInfo
->FilePointer
% BytesPerCluster
);
1320 LengthInCluster
= (BytesToRead
> (BytesPerCluster
- OffsetInCluster
)) ? (BytesPerCluster
- OffsetInCluster
) : BytesToRead
;
1323 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1325 if (!FatReadPartialCluster(ClusterNumber
, OffsetInCluster
, LengthInCluster
, Buffer
))
1329 if (BytesRead
!= NULL
)
1331 *BytesRead
+= LengthInCluster
;
1333 BytesToRead
-= LengthInCluster
;
1334 FatFileInfo
->FilePointer
+= LengthInCluster
;
1335 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ LengthInCluster
);
1339 // Do the math for our second read (if any data left)
1341 if (BytesToRead
> 0)
1344 // Determine how many full clusters we need to read
1346 NumberOfClusters
= (BytesToRead
/ BytesPerCluster
);
1348 if (NumberOfClusters
> 0)
1350 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1351 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1354 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1356 if (!FatReadClusterChain(ClusterNumber
, NumberOfClusters
, Buffer
))
1360 if (BytesRead
!= NULL
)
1362 *BytesRead
+= (NumberOfClusters
* BytesPerCluster
);
1364 BytesToRead
-= (NumberOfClusters
* BytesPerCluster
);
1365 FatFileInfo
->FilePointer
+= (NumberOfClusters
* BytesPerCluster
);
1366 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (NumberOfClusters
* BytesPerCluster
));
1371 // Do the math for our third read (if any data left)
1373 if (BytesToRead
> 0)
1375 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1376 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1379 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1381 if (!FatReadPartialCluster(ClusterNumber
, 0, BytesToRead
, Buffer
))
1385 if (BytesRead
!= NULL
)
1387 *BytesRead
+= BytesToRead
;
1389 FatFileInfo
->FilePointer
+= BytesToRead
;
1390 BytesToRead
-= BytesToRead
;
1391 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ BytesToRead
);
1397 ULONG
FatGetFileSize(FILE *FileHandle
)
1399 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1401 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFileSize() FileSize = %d\n", FatFileHandle
->FileSize
));
1403 return FatFileHandle
->FileSize
;
1406 VOID
FatSetFilePointer(FILE *FileHandle
, ULONG NewFilePointer
)
1408 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1410 DbgPrint((DPRINT_FILESYSTEM
, "FatSetFilePointer() NewFilePointer = %d\n", NewFilePointer
));
1412 FatFileHandle
->FilePointer
= NewFilePointer
;
1415 ULONG
FatGetFilePointer(FILE *FileHandle
)
1417 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1419 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFilePointer() FilePointer = %d\n", FatFileHandle
->FilePointer
));
1421 return FatFileHandle
->FilePointer
;
1424 BOOLEAN
FatReadVolumeSectors(ULONG DriveNumber
, ULONG SectorNumber
, ULONG SectorCount
, PVOID Buffer
)
1428 return CacheReadDiskSectors(DriveNumber
, SectorNumber
+ FatVolumeStartSector
, SectorCount
, Buffer
);
1432 // Now try to read in the block
1433 if (!MachDiskReadLogicalSectors(DriveNumber
, SectorNumber
+ FatVolumeStartSector
, SectorCount
, (PVOID
)DISKREADBUFFER
))
1438 // Copy data to the caller
1439 RtlCopyMemory(Buffer
, (PVOID
)DISKREADBUFFER
, SectorCount
* BytesPerSector
);
1446 const FS_VTBL FatVtbl
= {