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 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
);
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 */
51 ULONG FatType
= 0; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
52 ULONG FatDriveNumber
= 0;
54 VOID
FatSwapFatBootSector(PFAT_BOOTSECTOR Obj
)
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
);
69 VOID
FatSwapFat32BootSector(PFAT32_BOOTSECTOR Obj
)
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
);
84 SW(Obj
, BackupBootSector
);
85 SD(Obj
, VolumeSerialNumber
);
86 SW(Obj
, BootSectorMagic
);
89 VOID
FatSwapFatXBootSector(PFATX_BOOTSECTOR Obj
)
91 SD(Obj
, VolumeSerialNumber
);
92 SD(Obj
, SectorsPerCluster
);
93 SW(Obj
, NumberOfFats
);
96 VOID
FatSwapDirEntry(PDIRENTRY Obj
)
100 SW(Obj
, LastAccessDate
);
101 SW(Obj
, ClusterHigh
);
108 VOID
FatSwapLFNDirEntry(PLFN_DIRENTRY Obj
)
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
]);
120 VOID
FatSwapFatXDirEntry(PFATX_DIRENTRY Obj
)
122 SD(Obj
, StartCluster
);
128 SW(Obj
, LastAccessTime
);
129 SW(Obj
, LastAccessDate
);
132 BOOLEAN
FatOpenVolume(UCHAR DriveNumber
, ULONGLONG VolumeStartSector
, ULONGLONG PartitionSectorCount
)
136 PFAT_BOOTSECTOR FatVolumeBootSector
;
137 PFAT32_BOOTSECTOR Fat32VolumeBootSector
;
138 PFATX_BOOTSECTOR FatXVolumeBootSector
;
140 DPRINTM(DPRINT_FILESYSTEM
, "FatOpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber
, VolumeStartSector
);
142 // Store the drive number
143 FatDriveNumber
= DriveNumber
;
146 // Allocate the memory to hold the boot sector
148 FatVolumeBootSector
= (PFAT_BOOTSECTOR
) MmHeapAlloc(512);
149 Fat32VolumeBootSector
= (PFAT32_BOOTSECTOR
) FatVolumeBootSector
;
150 FatXVolumeBootSector
= (PFATX_BOOTSECTOR
) FatVolumeBootSector
;
153 // Make sure we got the memory
155 if (FatVolumeBootSector
== NULL
)
157 FileSystemError("Out of memory.");
161 // Now try to read the boot sector
162 // If this fails then abort
163 if (!MachDiskReadLogicalSectors(DriveNumber
, VolumeStartSector
, 1, (PVOID
)DISKREADBUFFER
))
165 MmHeapFree(FatVolumeBootSector
);
168 RtlCopyMemory(FatVolumeBootSector
, (PVOID
)DISKREADBUFFER
, 512);
171 FatType
= FatDetermineFatType(FatVolumeBootSector
, PartitionSectorCount
);
173 // Dump boot sector (and swap it for big endian systems)
174 DPRINTM(DPRINT_FILESYSTEM
, "Dumping boot sector:\n");
177 FatSwapFatXBootSector(FatXVolumeBootSector
);
178 DPRINTM(DPRINT_FILESYSTEM
, "sizeof(FATX_BOOTSECTOR) = 0x%x.\n", sizeof(FATX_BOOTSECTOR
));
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
);
186 DPRINTM(DPRINT_FILESYSTEM
, "FatType %s\n", FatType
== FATX16
? "FATX16" : "FATX32");
189 else if (FatType
== FAT32
)
191 FatSwapFat32BootSector(Fat32VolumeBootSector
);
192 DPRINTM(DPRINT_FILESYSTEM
, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR
));
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
);
225 FatSwapFatBootSector(FatVolumeBootSector
);
226 DPRINTM(DPRINT_FILESYSTEM
, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR
));
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
);
252 // Set the correct partition offset
254 FatVolumeStartSector
= VolumeStartSector
;
257 // Check the boot sector magic
259 if (! ISFATX(FatType
) && FatVolumeBootSector
->BootSectorMagic
!= 0xaa55)
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
);
269 // Check the FAT cluster size
270 // We do not support clusters bigger than 64k
272 if ((ISFATX(FatType
) && 64 * 1024 < FatXVolumeBootSector
->SectorsPerCluster
* 512) ||
273 (! ISFATX(FatType
) && 64 * 1024 < FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
))
275 FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
276 MmHeapFree(FatVolumeBootSector
);
281 // Clear our variables
284 ActiveFatSectorStart
= 0;
286 RootDirSectorStart
= 0;
292 // Get the sectors per FAT,
293 // root directory starting sector,
294 // and data sector start
298 BytesPerSector
= 512;
299 SectorsPerCluster
= SWAPD(FatXVolumeBootSector
->SectorsPerCluster
);
300 FatSectorStart
= (4096 / BytesPerSector
);
301 ActiveFatSectorStart
= FatSectorStart
;
303 FatSize
= PartitionSectorCount
/ SectorsPerCluster
*
304 (FATX16
== FatType
? 2 : 4);
305 SectorsPerFat
= (((FatSize
+ 4095) / 4096) * 4096) / BytesPerSector
;
307 RootDirSectorStart
= FatSectorStart
+ NumberOfFats
* SectorsPerFat
;
308 RootDirSectors
= FatXVolumeBootSector
->SectorsPerCluster
;
310 DataSectorStart
= RootDirSectorStart
+ RootDirSectors
;
312 else if (FatType
!= FAT32
)
314 BytesPerSector
= FatVolumeBootSector
->BytesPerSector
;
315 SectorsPerCluster
= FatVolumeBootSector
->SectorsPerCluster
;
316 FatSectorStart
= FatVolumeBootSector
->ReservedSectors
;
317 ActiveFatSectorStart
= FatSectorStart
;
318 NumberOfFats
= FatVolumeBootSector
->NumberOfFats
;
319 SectorsPerFat
= FatVolumeBootSector
->SectorsPerFat
;
321 RootDirSectorStart
= FatSectorStart
+ NumberOfFats
* SectorsPerFat
;
322 RootDirSectors
= ((FatVolumeBootSector
->RootDirEntries
* 32) + (BytesPerSector
- 1)) / BytesPerSector
;
324 DataSectorStart
= RootDirSectorStart
+ RootDirSectors
;
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
;
336 RootDirStartCluster
= Fat32VolumeBootSector
->RootDirStartCluster
;
337 DataSectorStart
= FatSectorStart
+ NumberOfFats
* SectorsPerFat
;
341 // we only work with version 0
343 if (Fat32VolumeBootSector
->FileSystemVersion
!= 0)
345 FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
349 MmHeapFree(FatVolumeBootSector
);
352 GEOMETRY DriveGeometry
;
355 // Initialize drive by getting its geometry
356 if (!MachDiskGetDriveGeometry(DriveNumber
, &DriveGeometry
))
361 BlockSize
= MachDiskGetCacheableBlockCount(DriveNumber
);
367 ULONG
FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector
, ULONG PartitionSectorCount
)
369 ULONG RootDirSectors
;
370 ULONG DataSectorCount
;
373 ULONG CountOfClusters
;
374 PFAT32_BOOTSECTOR Fat32BootSector
= (PFAT32_BOOTSECTOR
)FatBootSector
;
375 PFATX_BOOTSECTOR FatXBootSector
= (PFATX_BOOTSECTOR
)FatBootSector
;
377 if (0 == strncmp(FatXBootSector
->FileSystemType
, "FATX", 4))
379 CountOfClusters
= PartitionSectorCount
/ FatXBootSector
->SectorsPerCluster
;
380 if (CountOfClusters
< 65525)
382 /* Volume is FATX16 */
387 /* Volume is FAT32 */
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
);
399 if (FatBootSector
->SectorsPerCluster
== 0)
402 CountOfClusters
= DataSectorCount
/ FatBootSector
->SectorsPerCluster
;
404 if (CountOfClusters
< 4085)
406 /* Volume is FAT12 */
409 else if (CountOfClusters
< 65525)
411 /* Volume is FAT16 */
416 /* Volume is FAT32 */
422 PVOID
FatBufferDirectory(ULONG DirectoryStartCluster
, ULONG
*DirectorySize
, BOOLEAN RootDirectory
)
424 PVOID DirectoryBuffer
;
426 DPRINTM(DPRINT_FILESYSTEM
, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster
, (RootDirectory
? "TRUE" : "FALSE"));
429 * For FAT32, the root directory is nothing special. We can treat it the same
432 if (RootDirectory
&& FAT32
== FatType
)
434 DirectoryStartCluster
= RootDirStartCluster
;
435 RootDirectory
= FALSE
;
439 // Calculate the size of the directory
443 *DirectorySize
= RootDirSectors
* BytesPerSector
;
447 *DirectorySize
= FatCountClustersInChain(DirectoryStartCluster
) * SectorsPerCluster
* BytesPerSector
;
451 // Attempt to allocate memory for directory buffer
453 DPRINTM(DPRINT_FILESYSTEM
, "Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize
);
454 DirectoryBuffer
= MmHeapAlloc(*DirectorySize
);
456 if (DirectoryBuffer
== NULL
)
462 // Now read directory contents into DirectoryBuffer
466 if (!FatReadVolumeSectors(FatDriveNumber
, RootDirSectorStart
, RootDirSectors
, DirectoryBuffer
))
468 MmHeapFree(DirectoryBuffer
);
474 if (!FatReadClusterChain(DirectoryStartCluster
, 0xFFFFFFFF, DirectoryBuffer
))
476 MmHeapFree(DirectoryBuffer
);
481 return DirectoryBuffer
;
484 BOOLEAN
FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
488 CHAR LfnNameBuffer
[265];
489 CHAR ShortNameBuffer
[20];
491 DIRENTRY OurDirEntry
;
492 LFN_DIRENTRY OurLfnDirEntry
;
493 PDIRENTRY DirEntry
= &OurDirEntry
;
494 PLFN_DIRENTRY LfnDirEntry
= &OurLfnDirEntry
;
496 EntryCount
= DirectorySize
/ sizeof(DIRENTRY
);
498 DPRINTM(DPRINT_FILESYSTEM
, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
);
500 memset(ShortNameBuffer
, 0, 13 * sizeof(CHAR
));
501 memset(LfnNameBuffer
, 0, 261 * sizeof(CHAR
));
503 for (CurrentEntry
=0; CurrentEntry
<EntryCount
; CurrentEntry
++, DirectoryBuffer
= ((PDIRENTRY
)DirectoryBuffer
)+1)
505 OurLfnDirEntry
= *((PLFN_DIRENTRY
) DirectoryBuffer
);
506 FatSwapLFNDirEntry(LfnDirEntry
);
507 OurDirEntry
= *((PDIRENTRY
) DirectoryBuffer
);
508 FatSwapDirEntry(DirEntry
);
510 //DPRINTM(DPRINT_FILESYSTEM, "Dumping directory entry %d:\n", CurrentEntry);
511 //DbgDumpBuffer(DPRINT_FILESYSTEM, DirEntry, sizeof(DIRENTRY));
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.
519 if (DirEntry
->FileName
[0] == '\0')
525 // Check if this is a deleted entry or not
527 if (DirEntry
->FileName
[0] == '\xE5')
529 memset(ShortNameBuffer
, 0, 13 * sizeof(CHAR
));
530 memset(LfnNameBuffer
, 0, 261 * sizeof(CHAR
));
535 // Check if this is a LFN entry
536 // If so it needs special handling
538 if (DirEntry
->Attr
== ATTR_LONG_NAME
)
541 // Check to see if this is a deleted LFN entry, if so continue
543 if (LfnDirEntry
->SequenceNumber
& 0x80)
549 // Mask off high two bits of sequence number
550 // and make the sequence number zero-based
552 LfnDirEntry
->SequenceNumber
&= 0x3F;
553 LfnDirEntry
->SequenceNumber
--;
556 // Get all 13 LFN entry characters
558 if (LfnDirEntry
->Name0_4
[0] != 0xFFFF)
560 LfnNameBuffer
[0 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[0];
562 if (LfnDirEntry
->Name0_4
[1] != 0xFFFF)
564 LfnNameBuffer
[1 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[1];
566 if (LfnDirEntry
->Name0_4
[2] != 0xFFFF)
568 LfnNameBuffer
[2 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[2];
570 if (LfnDirEntry
->Name0_4
[3] != 0xFFFF)
572 LfnNameBuffer
[3 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[3];
574 if (LfnDirEntry
->Name0_4
[4] != 0xFFFF)
576 LfnNameBuffer
[4 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[4];
578 if (LfnDirEntry
->Name5_10
[0] != 0xFFFF)
580 LfnNameBuffer
[5 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[0];
582 if (LfnDirEntry
->Name5_10
[1] != 0xFFFF)
584 LfnNameBuffer
[6 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[1];
586 if (LfnDirEntry
->Name5_10
[2] != 0xFFFF)
588 LfnNameBuffer
[7 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[2];
590 if (LfnDirEntry
->Name5_10
[3] != 0xFFFF)
592 LfnNameBuffer
[8 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[3];
594 if (LfnDirEntry
->Name5_10
[4] != 0xFFFF)
596 LfnNameBuffer
[9 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[4];
598 if (LfnDirEntry
->Name5_10
[5] != 0xFFFF)
600 LfnNameBuffer
[10 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[5];
602 if (LfnDirEntry
->Name11_12
[0] != 0xFFFF)
604 LfnNameBuffer
[11 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[0];
606 if (LfnDirEntry
->Name11_12
[1] != 0xFFFF)
608 LfnNameBuffer
[12 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[1];
611 //DPRINTM(DPRINT_FILESYSTEM, "Dumping long name buffer:\n");
612 //DbgDumpBuffer(DPRINT_FILESYSTEM, LfnNameBuffer, 260);
618 // Check for the volume label attribute
619 // and skip over this entry if found
621 if (DirEntry
->Attr
& ATTR_VOLUMENAME
)
623 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
624 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
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.
638 // Get short file name
640 FatParseShortFileName(ShortNameBuffer
, DirEntry
);
642 DPRINTM(DPRINT_FILESYSTEM
, "Entry: %d LFN = %s\n", CurrentEntry
, LfnNameBuffer
);
643 DPRINTM(DPRINT_FILESYSTEM
, "Entry: %d DOS name = %s\n", CurrentEntry
, ShortNameBuffer
);
646 // See if the file name matches either the short or long name
648 if (((strlen(FileName
) == strlen(LfnNameBuffer
)) && (_stricmp(FileName
, LfnNameBuffer
) == 0)) ||
649 ((strlen(FileName
) == strlen(ShortNameBuffer
)) && (_stricmp(FileName
, ShortNameBuffer
) == 0))) {
651 // We found the entry, now fill in the FAT_FILE_INFO struct
653 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
654 FatFileInfoPointer
->FilePointer
= 0;
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
);
671 // Get the cluster chain
673 StartCluster
= ((ULONG
)DirEntry
->ClusterHigh
<< 16) + DirEntry
->ClusterLow
;
674 DPRINTM(DPRINT_FILESYSTEM
, "StartCluster = 0x%x\n", StartCluster
);
675 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(StartCluster
);
678 // See if memory allocation failed
680 if (FatFileInfoPointer
->FileFatChain
== NULL
)
689 // Nope, no match - zero buffers and continue looking
691 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
692 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
699 static BOOLEAN
FatXSearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
704 FATX_DIRENTRY OurDirEntry
;
705 PFATX_DIRENTRY DirEntry
= &OurDirEntry
;
707 EntryCount
= DirectorySize
/ sizeof(FATX_DIRENTRY
);
709 DPRINTM(DPRINT_FILESYSTEM
, "FatXSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
);
711 FileNameLen
= strlen(FileName
);
713 for (CurrentEntry
= 0; CurrentEntry
< EntryCount
; CurrentEntry
++, DirectoryBuffer
= ((PFATX_DIRENTRY
)DirectoryBuffer
)+1)
715 OurDirEntry
= *(PFATX_DIRENTRY
) DirectoryBuffer
;
716 FatSwapFatXDirEntry(&OurDirEntry
);
717 if (0xff == DirEntry
->FileNameSize
)
721 if (0xe5 == DirEntry
->FileNameSize
)
725 if (FileNameLen
== DirEntry
->FileNameSize
&&
726 0 == _strnicmp(FileName
, DirEntry
->FileName
, FileNameLen
))
729 * We found the entry, now fill in the FAT_FILE_INFO struct
731 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
732 FatFileInfoPointer
->FilePointer
= 0;
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
);
747 * Get the cluster chain
749 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(DirEntry
->StartCluster
);
752 * See if memory allocation failed
754 if (NULL
== FatFileInfoPointer
->FileFatChain
)
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
772 LONG
FatLookupFile(PCSTR FileName
, ULONG DeviceId
, PFAT_FILE_INFO FatFileInfoPointer
)
775 ULONG NumberOfPathParts
;
777 PVOID DirectoryBuffer
;
778 ULONG DirectoryStartCluster
= 0;
780 FAT_FILE_INFO FatFileInfo
;
782 DPRINTM(DPRINT_FILESYSTEM
, "FatLookupFile() FileName = %s\n", FileName
);
784 memset(FatFileInfoPointer
, 0, sizeof(FAT_FILE_INFO
));
787 // Figure out how many sub-directories we are nested in
789 NumberOfPathParts
= FsGetNumPathParts(FileName
);
792 // Loop once for each part
794 for (i
=0; i
<NumberOfPathParts
; i
++)
797 // Get first path part
799 FsGetFirstNameFromPath(PathPart
, FileName
);
802 // Advance to the next part of the path
804 for (; (*FileName
!= '\\') && (*FileName
!= '/') && (*FileName
!= '\0'); FileName
++)
810 // Buffer the directory contents
812 DirectoryBuffer
= FatBufferDirectory(DirectoryStartCluster
, &DirectorySize
, (i
== 0) );
813 if (DirectoryBuffer
== NULL
)
819 // Search for file name in directory
823 if (!FatXSearchDirectoryBufferForFile(DirectoryBuffer
, DirectorySize
, PathPart
, &FatFileInfo
))
825 MmHeapFree(DirectoryBuffer
);
831 if (!FatSearchDirectoryBufferForFile(DirectoryBuffer
, DirectorySize
, PathPart
, &FatFileInfo
))
833 MmHeapFree(DirectoryBuffer
);
838 MmHeapFree(DirectoryBuffer
);
841 // If we have another sub-directory to go then
842 // grab the start cluster and free the fat chain array
844 if ((i
+1) < NumberOfPathParts
)
846 DirectoryStartCluster
= FatFileInfo
.FileFatChain
[0];
847 MmHeapFree(FatFileInfo
.FileFatChain
);
851 memcpy(FatFileInfoPointer
, &FatFileInfo
, sizeof(FAT_FILE_INFO
));
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"
862 void FatParseShortFileName(PCHAR Buffer
, PDIRENTRY DirEntry
)
867 RtlZeroMemory(Buffer
, 13);
870 // Fixup first character
872 if (DirEntry
->FileName
[0] == 0x05)
874 DirEntry
->FileName
[0] = 0xE5;
882 if (DirEntry
->FileName
[Idx
] == ' ')
887 Buffer
[Idx
] = DirEntry
->FileName
[Idx
];
894 if ((DirEntry
->FileName
[8] != ' '))
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];
902 DPRINTM(DPRINT_FILESYSTEM
, "FatParseShortFileName() ShortName = %s\n", Buffer
);
907 * returns the Fat entry for a given cluster number
909 BOOLEAN
FatGetFatEntry(ULONG Cluster
, ULONG
* ClusterPointer
)
913 UINT32 ThisFatSecNum
;
914 UINT32 ThisFatEntOffset
;
916 DPRINTM(DPRINT_FILESYSTEM
, "FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster
);
922 FatOffset
= Cluster
+ (Cluster
/ 2);
923 ThisFatSecNum
= ActiveFatSectorStart
+ (FatOffset
/ BytesPerSector
);
924 ThisFatEntOffset
= (FatOffset
% BytesPerSector
);
926 DPRINTM(DPRINT_FILESYSTEM
, "FatOffset: %d\n", FatOffset
);
927 DPRINTM(DPRINT_FILESYSTEM
, "ThisFatSecNum: %d\n", ThisFatSecNum
);
928 DPRINTM(DPRINT_FILESYSTEM
, "ThisFatEntOffset: %d\n", ThisFatEntOffset
);
930 if (ThisFatEntOffset
== (BytesPerSector
- 1))
932 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 2, (PVOID
)FILESYSBUFFER
))
939 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
945 fat
= *((USHORT
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
));
947 if (Cluster
& 0x0001)
948 fat
= fat
>> 4; /* Cluster number is ODD */
950 fat
= fat
& 0x0FFF; /* Cluster number is EVEN */
957 FatOffset
= (Cluster
* 2);
958 ThisFatSecNum
= ActiveFatSectorStart
+ (FatOffset
/ BytesPerSector
);
959 ThisFatEntOffset
= (FatOffset
% BytesPerSector
);
961 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
966 fat
= *((USHORT
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
));
974 FatOffset
= (Cluster
* 4);
975 ThisFatSecNum
= ActiveFatSectorStart
+ (FatOffset
/ BytesPerSector
);
976 ThisFatEntOffset
= (FatOffset
% BytesPerSector
);
978 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
984 fat
= (*((ULONG
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
))) & 0x0FFFFFFF;
991 DPRINTM(DPRINT_FILESYSTEM
, "FAT entry is 0x%x.\n", fat
);
993 *ClusterPointer
= fat
;
998 ULONG
FatCountClustersInChain(ULONG StartCluster
)
1000 ULONG ClusterCount
= 0;
1002 DPRINTM(DPRINT_FILESYSTEM
, "FatCountClustersInChain() StartCluster = %d\n", StartCluster
);
1007 // If end of chain then break out of our cluster counting loop
1009 if (((FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
1010 ((FatType
== FAT16
|| FatType
== FATX16
) && (StartCluster
>= 0xfff8)) ||
1011 ((FatType
== FAT32
|| FatType
== FATX32
) && (StartCluster
>= 0x0ffffff8)))
1024 if (!FatGetFatEntry(StartCluster
, &StartCluster
))
1030 DPRINTM(DPRINT_FILESYSTEM
, "FatCountClustersInChain() ClusterCount = %d\n", ClusterCount
);
1032 return ClusterCount
;
1035 ULONG
* FatGetClusterChainArray(ULONG StartCluster
)
1039 ULONG
* ArrayPointer
;
1042 DPRINTM(DPRINT_FILESYSTEM
, "FatGetClusterChainArray() StartCluster = %d\n", StartCluster
);
1044 ClusterCount
= FatCountClustersInChain(StartCluster
) + 1; // Lets get the 0x0ffffff8 on the end of the array
1045 ArraySize
= ClusterCount
* sizeof(ULONG
);
1048 // Allocate array memory
1050 ArrayPointer
= MmHeapAlloc(ArraySize
);
1052 if (ArrayPointer
== NULL
)
1058 // Loop through and set array values
1060 for (Idx
=0; Idx
<ClusterCount
; Idx
++)
1063 // Set current cluster
1065 ArrayPointer
[Idx
] = StartCluster
;
1068 // Don't try to get next cluster for last cluster
1070 if (((FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
1071 ((FatType
== FAT16
|| FatType
== FATX16
) && (StartCluster
>= 0xfff8)) ||
1072 ((FatType
== FAT32
|| FatType
== FATX32
) && (StartCluster
>= 0x0ffffff8)))
1081 if (!FatGetFatEntry(StartCluster
, &StartCluster
))
1083 MmHeapFree(ArrayPointer
);
1088 return ArrayPointer
;
1093 * Reads the specified cluster into memory
1095 BOOLEAN
FatReadCluster(ULONG ClusterNumber
, PVOID Buffer
)
1097 ULONG ClusterStartSector
;
1099 ClusterStartSector
= ((ClusterNumber
- 2) * SectorsPerCluster
) + DataSectorStart
;
1101 DPRINTM(DPRINT_FILESYSTEM
, "FatReadCluster() ClusterNumber = %d Buffer = 0x%x ClusterStartSector = %d\n", ClusterNumber
, Buffer
, ClusterStartSector
);
1103 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1108 memcpy(Buffer
, (PVOID
)FILESYSBUFFER
, SectorsPerCluster
* BytesPerSector
);
1114 * FatReadClusterChain()
1115 * Reads the specified clusters into memory
1117 BOOLEAN
FatReadClusterChain(ULONG StartClusterNumber
, ULONG NumberOfClusters
, PVOID Buffer
)
1119 ULONG ClusterStartSector
;
1121 DPRINTM(DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
);
1123 while (NumberOfClusters
> 0)
1126 DPRINTM(DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
);
1128 // Calculate starting sector for cluster
1130 ClusterStartSector
= ((StartClusterNumber
- 2) * SectorsPerCluster
) + DataSectorStart
;
1133 // Read cluster into memory
1135 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1140 memcpy(Buffer
, (PVOID
)FILESYSBUFFER
, SectorsPerCluster
* BytesPerSector
);
1143 // Decrement count of clusters left to read
1148 // Increment buffer address by cluster size
1150 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (SectorsPerCluster
* BytesPerSector
));
1155 if (!FatGetFatEntry(StartClusterNumber
, &StartClusterNumber
))
1161 // If end of chain then break out of our cluster reading loop
1163 if (((FatType
== FAT12
) && (StartClusterNumber
>= 0xff8)) ||
1164 ((FatType
== FAT16
|| FatType
== FATX16
) && (StartClusterNumber
>= 0xfff8)) ||
1165 ((FatType
== FAT32
|| FatType
== FATX32
) && (StartClusterNumber
>= 0x0ffffff8)))
1175 * FatReadPartialCluster()
1176 * Reads part of a cluster into memory
1178 BOOLEAN
FatReadPartialCluster(ULONG ClusterNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
)
1180 ULONG ClusterStartSector
;
1182 DPRINTM(DPRINT_FILESYSTEM
, "FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber
, StartingOffset
, Length
, Buffer
);
1184 ClusterStartSector
= ((ClusterNumber
- 2) * SectorsPerCluster
) + DataSectorStart
;
1186 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1191 memcpy(Buffer
, (PVOID
)((ULONG_PTR
)FILESYSBUFFER
+ StartingOffset
), Length
);
1198 * Reads BytesToRead from open file and
1199 * returns the number of bytes read in BytesRead
1201 BOOLEAN
FatReadFile(PFAT_FILE_INFO FatFileInfo
, ULONG BytesToRead
, ULONG
* BytesRead
, PVOID Buffer
)
1203 ULONG ClusterNumber
;
1204 ULONG OffsetInCluster
;
1205 ULONG LengthInCluster
;
1206 ULONG NumberOfClusters
;
1207 ULONG BytesPerCluster
;
1209 DPRINTM(DPRINT_FILESYSTEM
, "FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead
, Buffer
);
1211 if (BytesRead
!= NULL
)
1217 // If they are trying to read past the
1218 // end of the file then return success
1219 // with BytesRead == 0
1221 if (FatFileInfo
->FilePointer
>= FatFileInfo
->FileSize
)
1227 // If they are trying to read more than there is to read
1228 // then adjust the amount to read
1230 if ((FatFileInfo
->FilePointer
+ BytesToRead
) > FatFileInfo
->FileSize
)
1232 BytesToRead
= (FatFileInfo
->FileSize
- FatFileInfo
->FilePointer
);
1236 // Ok, now we have to perform at most 3 calculations
1237 // I'll draw you a picture (using nifty ASCII art):
1239 // CurrentFilePointer -+
1241 // +----------------+
1243 // +-----------+-----------+-----------+-----------+
1244 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
1245 // +-----------+-----------+-----------+-----------+
1247 // +---------------+--------------------+
1249 // BytesToRead -------+
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
1258 // 3 - The last calculation (and read) would read
1259 // in the remainder of the data requested out of
1260 // the last cluster.
1263 BytesPerCluster
= SectorsPerCluster
* BytesPerSector
;
1266 // Only do the first read if we
1267 // aren't aligned on a cluster boundary
1269 if (FatFileInfo
->FilePointer
% BytesPerCluster
)
1272 // Do the math for our first read
1274 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1275 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1276 OffsetInCluster
= (FatFileInfo
->FilePointer
% BytesPerCluster
);
1277 LengthInCluster
= (BytesToRead
> (BytesPerCluster
- OffsetInCluster
)) ? (BytesPerCluster
- OffsetInCluster
) : BytesToRead
;
1280 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1282 if (!FatReadPartialCluster(ClusterNumber
, OffsetInCluster
, LengthInCluster
, Buffer
))
1286 if (BytesRead
!= NULL
)
1288 *BytesRead
+= LengthInCluster
;
1290 BytesToRead
-= LengthInCluster
;
1291 FatFileInfo
->FilePointer
+= LengthInCluster
;
1292 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ LengthInCluster
);
1296 // Do the math for our second read (if any data left)
1298 if (BytesToRead
> 0)
1301 // Determine how many full clusters we need to read
1303 NumberOfClusters
= (BytesToRead
/ BytesPerCluster
);
1305 if (NumberOfClusters
> 0)
1307 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1308 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1311 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1313 if (!FatReadClusterChain(ClusterNumber
, NumberOfClusters
, Buffer
))
1317 if (BytesRead
!= NULL
)
1319 *BytesRead
+= (NumberOfClusters
* BytesPerCluster
);
1321 BytesToRead
-= (NumberOfClusters
* BytesPerCluster
);
1322 FatFileInfo
->FilePointer
+= (NumberOfClusters
* BytesPerCluster
);
1323 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (NumberOfClusters
* BytesPerCluster
));
1328 // Do the math for our third read (if any data left)
1330 if (BytesToRead
> 0)
1332 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1333 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1336 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1338 if (!FatReadPartialCluster(ClusterNumber
, 0, BytesToRead
, Buffer
))
1342 if (BytesRead
!= NULL
)
1344 *BytesRead
+= BytesToRead
;
1346 FatFileInfo
->FilePointer
+= BytesToRead
;
1347 BytesToRead
-= BytesToRead
;
1348 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ BytesToRead
);
1354 BOOLEAN
FatReadVolumeSectors(ULONG DriveNumber
, ULONG SectorNumber
, ULONG SectorCount
, PVOID Buffer
)
1356 // Now try to read in the block
1357 if (!MachDiskReadLogicalSectors(DriveNumber
, SectorNumber
+ FatVolumeStartSector
, SectorCount
, (PVOID
)DISKREADBUFFER
))
1362 // Copy data to the caller
1363 RtlCopyMemory(Buffer
, (PVOID
)DISKREADBUFFER
, SectorCount
* BytesPerSector
);
1369 LONG
FatClose(ULONG FileId
)
1371 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1373 MmHeapFree(FileHandle
);
1378 LONG
FatGetFileInformation(ULONG FileId
, FILEINFORMATION
* Information
)
1380 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1382 RtlZeroMemory(Information
, sizeof(FILEINFORMATION
));
1383 Information
->EndingAddress
.LowPart
= FileHandle
->FileSize
;
1384 Information
->CurrentAddress
.LowPart
= FileHandle
->FilePointer
;
1386 DPRINTM(DPRINT_FILESYSTEM
, "FatGetFileInformation() FileSize = %d\n",
1387 Information
->EndingAddress
.LowPart
);
1388 DPRINTM(DPRINT_FILESYSTEM
, "FatGetFileInformation() FilePointer = %d\n",
1389 Information
->CurrentAddress
.LowPart
);
1394 LONG
FatOpen(CHAR
* Path
, OPENMODE OpenMode
, ULONG
* FileId
)
1396 FAT_FILE_INFO TempFileInfo
;
1397 PFAT_FILE_INFO FileHandle
;
1401 if (OpenMode
!= OpenReadOnly
)
1404 DeviceId
= FsGetDeviceId(*FileId
);
1406 DPRINTM(DPRINT_FILESYSTEM
, "FatOpen() FileName = %s\n", Path
);
1408 RtlZeroMemory(&TempFileInfo
, sizeof(TempFileInfo
));
1409 ret
= FatLookupFile(Path
, DeviceId
, &TempFileInfo
);
1410 if (ret
!= ESUCCESS
)
1413 FileHandle
= MmHeapAlloc(sizeof(FAT_FILE_INFO
));
1417 RtlCopyMemory(FileHandle
, &TempFileInfo
, sizeof(FAT_FILE_INFO
));
1419 FsSetDeviceSpecific(*FileId
, FileHandle
);
1423 LONG
FatRead(ULONG FileId
, VOID
* Buffer
, ULONG N
, ULONG
* Count
)
1425 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1429 // Call old read method
1431 ret
= FatReadFile(FileHandle
, N
, Count
, Buffer
);
1434 // Check for success
1442 LONG
FatSeek(ULONG FileId
, LARGE_INTEGER
* Position
, SEEKMODE SeekMode
)
1444 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1446 DPRINTM(DPRINT_FILESYSTEM
, "FatSeek() NewFilePointer = %lu\n", Position
->LowPart
);
1448 if (SeekMode
!= SeekAbsolute
)
1450 if (Position
->HighPart
!= 0)
1452 if (Position
->LowPart
>= FileHandle
->FileSize
)
1455 FileHandle
->FilePointer
= Position
->LowPart
;
1459 const DEVVTBL FatFuncTable
=
1462 FatGetFileInformation
,
1468 const DEVVTBL
* FatMount(ULONG DeviceId
)
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
;
1479 // Read the BootSector
1481 Position
.HighPart
= 0;
1482 Position
.LowPart
= 0;
1483 ret
= ArcSeek(DeviceId
, &Position
, SeekAbsolute
);
1484 if (ret
!= ESUCCESS
)
1486 ret
= ArcRead(DeviceId
, Buffer
, sizeof(Buffer
), &Count
);
1487 if (ret
!= ESUCCESS
|| Count
!= sizeof(Buffer
))
1491 // Check if BootSector is valid. If yes, return FAT function table
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))
1499 // Compatibility hack as long as FS is not using underlying device DeviceId
1502 ULONGLONG StartSector
;
1503 ULONGLONG SectorCount
;
1505 if (!DiskGetBootVolume(&DriveNumber
, &StartSector
, &SectorCount
, &Type
))
1507 FatOpenVolume(DriveNumber
, StartSector
, SectorCount
);
1508 return &FatFuncTable
;