3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2009 Hervé Poussineau
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 ULONG
FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector
, ULONG PartitionSectorCount
);
27 PVOID
FatBufferDirectory(PFAT_VOLUME_INFO Volume
, ULONG DirectoryStartCluster
, ULONG
* EntryCountPointer
, BOOLEAN RootDirectory
);
28 BOOLEAN
FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume
, PVOID DirectoryBuffer
, ULONG EntryCount
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
);
29 LONG
FatLookupFile(PFAT_VOLUME_INFO Volume
, PCSTR FileName
, ULONG DeviceId
, PFAT_FILE_INFO FatFileInfoPointer
);
30 void FatParseShortFileName(PCHAR Buffer
, PDIRENTRY DirEntry
);
31 BOOLEAN
FatGetFatEntry(PFAT_VOLUME_INFO Volume
, ULONG Cluster
, ULONG
* ClusterPointer
);
32 ULONG
FatCountClustersInChain(PFAT_VOLUME_INFO Volume
, ULONG StartCluster
);
33 ULONG
* FatGetClusterChainArray(PFAT_VOLUME_INFO Volume
, ULONG StartCluster
);
34 BOOLEAN
FatReadClusterChain(PFAT_VOLUME_INFO Volume
, ULONG StartClusterNumber
, ULONG NumberOfClusters
, PVOID Buffer
);
35 BOOLEAN
FatReadPartialCluster(PFAT_VOLUME_INFO Volume
, ULONG ClusterNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
);
36 BOOLEAN
FatReadVolumeSectors(PFAT_VOLUME_INFO Volume
, ULONG SectorNumber
, ULONG SectorCount
, PVOID Buffer
);
38 typedef struct _FAT_VOLUME_INFO
40 ULONG BytesPerSector
; /* Number of bytes per sector */
41 ULONG SectorsPerCluster
; /* Number of sectors per cluster */
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 ULONG FatType
; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
54 PFAT_VOLUME_INFO FatVolumes
[MAX_FDS
];
56 VOID
FatSwapFatBootSector(PFAT_BOOTSECTOR Obj
)
58 SW(Obj
, BytesPerSector
);
59 SW(Obj
, ReservedSectors
);
60 SW(Obj
, RootDirEntries
);
61 SW(Obj
, TotalSectors
);
62 SW(Obj
, SectorsPerFat
);
63 SW(Obj
, SectorsPerTrack
);
64 SW(Obj
, NumberOfHeads
);
65 SD(Obj
, HiddenSectors
);
66 SD(Obj
, TotalSectorsBig
);
67 SD(Obj
, VolumeSerialNumber
);
68 SW(Obj
, BootSectorMagic
);
71 VOID
FatSwapFat32BootSector(PFAT32_BOOTSECTOR Obj
)
73 SW(Obj
, BytesPerSector
);
74 SW(Obj
, ReservedSectors
);
75 SW(Obj
, RootDirEntries
);
76 SW(Obj
, TotalSectors
);
77 SW(Obj
, SectorsPerFat
);
78 SW(Obj
, NumberOfHeads
);
79 SD(Obj
, HiddenSectors
);
80 SD(Obj
, TotalSectorsBig
);
81 SD(Obj
, SectorsPerFatBig
);
82 SW(Obj
, ExtendedFlags
);
83 SW(Obj
, FileSystemVersion
);
84 SD(Obj
, RootDirStartCluster
);
86 SW(Obj
, BackupBootSector
);
87 SD(Obj
, VolumeSerialNumber
);
88 SW(Obj
, BootSectorMagic
);
91 VOID
FatSwapFatXBootSector(PFATX_BOOTSECTOR Obj
)
93 SD(Obj
, VolumeSerialNumber
);
94 SD(Obj
, SectorsPerCluster
);
95 SW(Obj
, NumberOfFats
);
98 VOID
FatSwapDirEntry(PDIRENTRY Obj
)
102 SW(Obj
, LastAccessDate
);
103 SW(Obj
, ClusterHigh
);
110 VOID
FatSwapLFNDirEntry(PLFN_DIRENTRY Obj
)
113 SW(Obj
, StartCluster
);
114 for(i
= 0; i
< 5; i
++)
115 Obj
->Name0_4
[i
] = SWAPW(Obj
->Name0_4
[i
]);
116 for(i
= 0; i
< 6; i
++)
117 Obj
->Name5_10
[i
] = SWAPW(Obj
->Name5_10
[i
]);
118 for(i
= 0; i
< 2; i
++)
119 Obj
->Name11_12
[i
] = SWAPW(Obj
->Name11_12
[i
]);
122 VOID
FatSwapFatXDirEntry(PFATX_DIRENTRY Obj
)
124 SD(Obj
, StartCluster
);
130 SW(Obj
, LastAccessTime
);
131 SW(Obj
, LastAccessDate
);
134 BOOLEAN
FatOpenVolume(PFAT_VOLUME_INFO Volume
, PFAT_BOOTSECTOR BootSector
, ULONGLONG PartitionSectorCount
)
138 PFAT_BOOTSECTOR FatVolumeBootSector
;
139 PFAT32_BOOTSECTOR Fat32VolumeBootSector
;
140 PFATX_BOOTSECTOR FatXVolumeBootSector
;
142 DPRINTM(DPRINT_FILESYSTEM
, "FatOpenVolume() DeviceId = %d\n", Volume
->DeviceId
);
145 // Allocate the memory to hold the boot sector
147 FatVolumeBootSector
= (PFAT_BOOTSECTOR
)BootSector
;
148 Fat32VolumeBootSector
= (PFAT32_BOOTSECTOR
)BootSector
;
149 FatXVolumeBootSector
= (PFATX_BOOTSECTOR
)BootSector
;
152 Volume
->FatType
= FatDetermineFatType(FatVolumeBootSector
, PartitionSectorCount
);
154 // Dump boot sector (and swap it for big endian systems)
155 DPRINTM(DPRINT_FILESYSTEM
, "Dumping boot sector:\n");
156 if (ISFATX(Volume
->FatType
))
158 FatSwapFatXBootSector(FatXVolumeBootSector
);
159 DPRINTM(DPRINT_FILESYSTEM
, "sizeof(FATX_BOOTSECTOR) = 0x%x.\n", sizeof(FATX_BOOTSECTOR
));
161 DPRINTM(DPRINT_FILESYSTEM
, "FileSystemType: %c%c%c%c.\n", FatXVolumeBootSector
->FileSystemType
[0], FatXVolumeBootSector
->FileSystemType
[1], FatXVolumeBootSector
->FileSystemType
[2], FatXVolumeBootSector
->FileSystemType
[3]);
162 DPRINTM(DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", FatXVolumeBootSector
->VolumeSerialNumber
);
163 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", FatXVolumeBootSector
->SectorsPerCluster
);
164 DPRINTM(DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", FatXVolumeBootSector
->NumberOfFats
);
165 DPRINTM(DPRINT_FILESYSTEM
, "Unknown: 0x%x\n", FatXVolumeBootSector
->Unknown
);
167 DPRINTM(DPRINT_FILESYSTEM
, "FatType %s\n", Volume
->FatType
== FATX16
? "FATX16" : "FATX32");
170 else if (Volume
->FatType
== FAT32
)
172 FatSwapFat32BootSector(Fat32VolumeBootSector
);
173 DPRINTM(DPRINT_FILESYSTEM
, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR
));
175 DPRINTM(DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector
->JumpBoot
[0], Fat32VolumeBootSector
->JumpBoot
[1], Fat32VolumeBootSector
->JumpBoot
[2]);
176 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]);
177 DPRINTM(DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", Fat32VolumeBootSector
->BytesPerSector
);
178 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", Fat32VolumeBootSector
->SectorsPerCluster
);
179 DPRINTM(DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", Fat32VolumeBootSector
->ReservedSectors
);
180 DPRINTM(DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", Fat32VolumeBootSector
->NumberOfFats
);
181 DPRINTM(DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", Fat32VolumeBootSector
->RootDirEntries
);
182 DPRINTM(DPRINT_FILESYSTEM
, "TotalSectors: %d\n", Fat32VolumeBootSector
->TotalSectors
);
183 DPRINTM(DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", Fat32VolumeBootSector
->MediaDescriptor
);
184 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", Fat32VolumeBootSector
->SectorsPerFat
);
185 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", Fat32VolumeBootSector
->SectorsPerTrack
);
186 DPRINTM(DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", Fat32VolumeBootSector
->NumberOfHeads
);
187 DPRINTM(DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", Fat32VolumeBootSector
->HiddenSectors
);
188 DPRINTM(DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", Fat32VolumeBootSector
->TotalSectorsBig
);
189 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerFatBig: %d\n", Fat32VolumeBootSector
->SectorsPerFatBig
);
190 DPRINTM(DPRINT_FILESYSTEM
, "ExtendedFlags: 0x%x\n", Fat32VolumeBootSector
->ExtendedFlags
);
191 DPRINTM(DPRINT_FILESYSTEM
, "FileSystemVersion: 0x%x\n", Fat32VolumeBootSector
->FileSystemVersion
);
192 DPRINTM(DPRINT_FILESYSTEM
, "RootDirStartCluster: %d\n", Fat32VolumeBootSector
->RootDirStartCluster
);
193 DPRINTM(DPRINT_FILESYSTEM
, "FsInfo: %d\n", Fat32VolumeBootSector
->FsInfo
);
194 DPRINTM(DPRINT_FILESYSTEM
, "BackupBootSector: %d\n", Fat32VolumeBootSector
->BackupBootSector
);
195 DPRINTM(DPRINT_FILESYSTEM
, "Reserved: 0x%x\n", Fat32VolumeBootSector
->Reserved
);
196 DPRINTM(DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", Fat32VolumeBootSector
->DriveNumber
);
197 DPRINTM(DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", Fat32VolumeBootSector
->Reserved1
);
198 DPRINTM(DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", Fat32VolumeBootSector
->BootSignature
);
199 DPRINTM(DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector
->VolumeSerialNumber
);
200 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]);
201 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]);
202 DPRINTM(DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", Fat32VolumeBootSector
->BootSectorMagic
);
206 FatSwapFatBootSector(FatVolumeBootSector
);
207 DPRINTM(DPRINT_FILESYSTEM
, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR
));
209 DPRINTM(DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector
->JumpBoot
[0], FatVolumeBootSector
->JumpBoot
[1], FatVolumeBootSector
->JumpBoot
[2]);
210 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]);
211 DPRINTM(DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", FatVolumeBootSector
->BytesPerSector
);
212 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", FatVolumeBootSector
->SectorsPerCluster
);
213 DPRINTM(DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", FatVolumeBootSector
->ReservedSectors
);
214 DPRINTM(DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", FatVolumeBootSector
->NumberOfFats
);
215 DPRINTM(DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", FatVolumeBootSector
->RootDirEntries
);
216 DPRINTM(DPRINT_FILESYSTEM
, "TotalSectors: %d\n", FatVolumeBootSector
->TotalSectors
);
217 DPRINTM(DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", FatVolumeBootSector
->MediaDescriptor
);
218 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", FatVolumeBootSector
->SectorsPerFat
);
219 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", FatVolumeBootSector
->SectorsPerTrack
);
220 DPRINTM(DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", FatVolumeBootSector
->NumberOfHeads
);
221 DPRINTM(DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", FatVolumeBootSector
->HiddenSectors
);
222 DPRINTM(DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", FatVolumeBootSector
->TotalSectorsBig
);
223 DPRINTM(DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", FatVolumeBootSector
->DriveNumber
);
224 DPRINTM(DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", FatVolumeBootSector
->Reserved1
);
225 DPRINTM(DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", FatVolumeBootSector
->BootSignature
);
226 DPRINTM(DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector
->VolumeSerialNumber
);
227 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]);
228 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]);
229 DPRINTM(DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", FatVolumeBootSector
->BootSectorMagic
);
233 // Check the boot sector magic
235 if (! ISFATX(Volume
->FatType
) && FatVolumeBootSector
->BootSectorMagic
!= 0xaa55)
237 sprintf(ErrMsg
, "Invalid boot sector magic (expected 0xaa55 found 0x%x)",
238 FatVolumeBootSector
->BootSectorMagic
);
239 FileSystemError(ErrMsg
);
244 // Check the FAT cluster size
245 // We do not support clusters bigger than 64k
247 if ((ISFATX(Volume
->FatType
) && 64 * 1024 < FatXVolumeBootSector
->SectorsPerCluster
* 512) ||
248 (! ISFATX(Volume
->FatType
) && 64 * 1024 < FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
))
250 FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
255 // Get the sectors per FAT,
256 // root directory starting sector,
257 // and data sector start
259 if (ISFATX(Volume
->FatType
))
261 Volume
->BytesPerSector
= 512;
262 Volume
->SectorsPerCluster
= SWAPD(FatXVolumeBootSector
->SectorsPerCluster
);
263 Volume
->FatSectorStart
= (4096 / Volume
->BytesPerSector
);
264 Volume
->ActiveFatSectorStart
= Volume
->FatSectorStart
;
265 Volume
->NumberOfFats
= 1;
266 FatSize
= PartitionSectorCount
/ Volume
->SectorsPerCluster
*
267 (Volume
->FatType
== FATX16
? 2 : 4);
268 Volume
->SectorsPerFat
= (((FatSize
+ 4095) / 4096) * 4096) / Volume
->BytesPerSector
;
270 Volume
->RootDirSectorStart
= Volume
->FatSectorStart
+ Volume
->NumberOfFats
* Volume
->SectorsPerFat
;
271 Volume
->RootDirSectors
= FatXVolumeBootSector
->SectorsPerCluster
;
273 Volume
->DataSectorStart
= Volume
->RootDirSectorStart
+ Volume
->RootDirSectors
;
275 else if (Volume
->FatType
!= FAT32
)
277 Volume
->BytesPerSector
= FatVolumeBootSector
->BytesPerSector
;
278 Volume
->SectorsPerCluster
= FatVolumeBootSector
->SectorsPerCluster
;
279 Volume
->FatSectorStart
= FatVolumeBootSector
->ReservedSectors
;
280 Volume
->ActiveFatSectorStart
= Volume
->FatSectorStart
;
281 Volume
->NumberOfFats
= FatVolumeBootSector
->NumberOfFats
;
282 Volume
->SectorsPerFat
= FatVolumeBootSector
->SectorsPerFat
;
284 Volume
->RootDirSectorStart
= Volume
->FatSectorStart
+ Volume
->NumberOfFats
* Volume
->SectorsPerFat
;
285 Volume
->RootDirSectors
= ((FatVolumeBootSector
->RootDirEntries
* 32) + (Volume
->BytesPerSector
- 1)) / Volume
->BytesPerSector
;
287 Volume
->DataSectorStart
= Volume
->RootDirSectorStart
+ Volume
->RootDirSectors
;
291 Volume
->BytesPerSector
= Fat32VolumeBootSector
->BytesPerSector
;
292 Volume
->SectorsPerCluster
= Fat32VolumeBootSector
->SectorsPerCluster
;
293 Volume
->FatSectorStart
= Fat32VolumeBootSector
->ReservedSectors
;
294 Volume
->ActiveFatSectorStart
= Volume
->FatSectorStart
+
295 ((Fat32VolumeBootSector
->ExtendedFlags
& 0x80) ? ((Fat32VolumeBootSector
->ExtendedFlags
& 0x0f) * Fat32VolumeBootSector
->SectorsPerFatBig
) : 0);
296 Volume
->NumberOfFats
= Fat32VolumeBootSector
->NumberOfFats
;
297 Volume
->SectorsPerFat
= Fat32VolumeBootSector
->SectorsPerFatBig
;
299 Volume
->RootDirStartCluster
= Fat32VolumeBootSector
->RootDirStartCluster
;
300 Volume
->DataSectorStart
= Volume
->FatSectorStart
+ Volume
->NumberOfFats
* Volume
->SectorsPerFat
;
304 // we only work with version 0
306 if (Fat32VolumeBootSector
->FileSystemVersion
!= 0)
308 FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
316 ULONG
FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector
, ULONG PartitionSectorCount
)
318 ULONG RootDirSectors
;
319 ULONG DataSectorCount
;
322 ULONG CountOfClusters
;
323 PFAT32_BOOTSECTOR Fat32BootSector
= (PFAT32_BOOTSECTOR
)FatBootSector
;
324 PFATX_BOOTSECTOR FatXBootSector
= (PFATX_BOOTSECTOR
)FatBootSector
;
326 if (0 == strncmp(FatXBootSector
->FileSystemType
, "FATX", 4))
328 CountOfClusters
= PartitionSectorCount
/ FatXBootSector
->SectorsPerCluster
;
329 if (CountOfClusters
< 65525)
331 /* Volume is FATX16 */
336 /* Volume is FAT32 */
342 RootDirSectors
= ((SWAPW(FatBootSector
->RootDirEntries
) * 32) + (SWAPW(FatBootSector
->BytesPerSector
) - 1)) / SWAPW(FatBootSector
->BytesPerSector
);
343 SectorsPerFat
= SWAPW(FatBootSector
->SectorsPerFat
) ? SWAPW(FatBootSector
->SectorsPerFat
) : SWAPD(Fat32BootSector
->SectorsPerFatBig
);
344 TotalSectors
= SWAPW(FatBootSector
->TotalSectors
) ? SWAPW(FatBootSector
->TotalSectors
) : SWAPD(FatBootSector
->TotalSectorsBig
);
345 DataSectorCount
= TotalSectors
- (SWAPW(FatBootSector
->ReservedSectors
) + (FatBootSector
->NumberOfFats
* SectorsPerFat
) + RootDirSectors
);
348 if (FatBootSector
->SectorsPerCluster
== 0)
351 CountOfClusters
= DataSectorCount
/ FatBootSector
->SectorsPerCluster
;
353 if (CountOfClusters
< 4085)
355 /* Volume is FAT12 */
358 else if (CountOfClusters
< 65525)
360 /* Volume is FAT16 */
365 /* Volume is FAT32 */
371 PVOID
FatBufferDirectory(PFAT_VOLUME_INFO Volume
, ULONG DirectoryStartCluster
, ULONG
*DirectorySize
, BOOLEAN RootDirectory
)
373 PVOID DirectoryBuffer
;
375 DPRINTM(DPRINT_FILESYSTEM
, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster
, (RootDirectory
? "TRUE" : "FALSE"));
378 * For FAT32, the root directory is nothing special. We can treat it the same
381 if (RootDirectory
&& Volume
->FatType
== FAT32
)
383 DirectoryStartCluster
= Volume
->RootDirStartCluster
;
384 RootDirectory
= FALSE
;
388 // Calculate the size of the directory
392 *DirectorySize
= Volume
->RootDirSectors
* Volume
->BytesPerSector
;
396 *DirectorySize
= FatCountClustersInChain(Volume
, DirectoryStartCluster
) * Volume
->SectorsPerCluster
* Volume
->BytesPerSector
;
400 // Attempt to allocate memory for directory buffer
402 DPRINTM(DPRINT_FILESYSTEM
, "Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize
);
403 DirectoryBuffer
= MmAllocateMemory(*DirectorySize
);
405 if (DirectoryBuffer
== NULL
)
411 // Now read directory contents into DirectoryBuffer
415 if (!FatReadVolumeSectors(Volume
, Volume
->RootDirSectorStart
, Volume
->RootDirSectors
, DirectoryBuffer
))
417 MmFreeMemory(DirectoryBuffer
);
423 if (!FatReadClusterChain(Volume
, DirectoryStartCluster
, 0xFFFFFFFF, DirectoryBuffer
))
425 MmFreeMemory(DirectoryBuffer
);
430 return DirectoryBuffer
;
433 BOOLEAN
FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume
, PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
437 CHAR LfnNameBuffer
[265];
438 CHAR ShortNameBuffer
[20];
440 DIRENTRY OurDirEntry
;
441 LFN_DIRENTRY OurLfnDirEntry
;
442 PDIRENTRY DirEntry
= &OurDirEntry
;
443 PLFN_DIRENTRY LfnDirEntry
= &OurLfnDirEntry
;
445 EntryCount
= DirectorySize
/ sizeof(DIRENTRY
);
447 DPRINTM(DPRINT_FILESYSTEM
, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
);
449 memset(ShortNameBuffer
, 0, 13 * sizeof(CHAR
));
450 memset(LfnNameBuffer
, 0, 261 * sizeof(CHAR
));
452 for (CurrentEntry
=0; CurrentEntry
<EntryCount
; CurrentEntry
++, DirectoryBuffer
= ((PDIRENTRY
)DirectoryBuffer
)+1)
454 OurLfnDirEntry
= *((PLFN_DIRENTRY
) DirectoryBuffer
);
455 FatSwapLFNDirEntry(LfnDirEntry
);
456 OurDirEntry
= *((PDIRENTRY
) DirectoryBuffer
);
457 FatSwapDirEntry(DirEntry
);
459 //DPRINTM(DPRINT_FILESYSTEM, "Dumping directory entry %d:\n", CurrentEntry);
460 //DbgDumpBuffer(DPRINT_FILESYSTEM, DirEntry, sizeof(DIRENTRY));
463 // Check if this is the last file in the directory
464 // If DirEntry[0] == 0x00 then that means all the
465 // entries after this one are unused. If this is the
466 // last entry then we didn't find the file in this directory.
468 if (DirEntry
->FileName
[0] == '\0')
474 // Check if this is a deleted entry or not
476 if (DirEntry
->FileName
[0] == '\xE5')
478 memset(ShortNameBuffer
, 0, 13 * sizeof(CHAR
));
479 memset(LfnNameBuffer
, 0, 261 * sizeof(CHAR
));
484 // Check if this is a LFN entry
485 // If so it needs special handling
487 if (DirEntry
->Attr
== ATTR_LONG_NAME
)
490 // Check to see if this is a deleted LFN entry, if so continue
492 if (LfnDirEntry
->SequenceNumber
& 0x80)
498 // Mask off high two bits of sequence number
499 // and make the sequence number zero-based
501 LfnDirEntry
->SequenceNumber
&= 0x3F;
502 LfnDirEntry
->SequenceNumber
--;
505 // Get all 13 LFN entry characters
507 if (LfnDirEntry
->Name0_4
[0] != 0xFFFF)
509 LfnNameBuffer
[0 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[0];
511 if (LfnDirEntry
->Name0_4
[1] != 0xFFFF)
513 LfnNameBuffer
[1 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[1];
515 if (LfnDirEntry
->Name0_4
[2] != 0xFFFF)
517 LfnNameBuffer
[2 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[2];
519 if (LfnDirEntry
->Name0_4
[3] != 0xFFFF)
521 LfnNameBuffer
[3 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[3];
523 if (LfnDirEntry
->Name0_4
[4] != 0xFFFF)
525 LfnNameBuffer
[4 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[4];
527 if (LfnDirEntry
->Name5_10
[0] != 0xFFFF)
529 LfnNameBuffer
[5 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[0];
531 if (LfnDirEntry
->Name5_10
[1] != 0xFFFF)
533 LfnNameBuffer
[6 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[1];
535 if (LfnDirEntry
->Name5_10
[2] != 0xFFFF)
537 LfnNameBuffer
[7 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[2];
539 if (LfnDirEntry
->Name5_10
[3] != 0xFFFF)
541 LfnNameBuffer
[8 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[3];
543 if (LfnDirEntry
->Name5_10
[4] != 0xFFFF)
545 LfnNameBuffer
[9 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[4];
547 if (LfnDirEntry
->Name5_10
[5] != 0xFFFF)
549 LfnNameBuffer
[10 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[5];
551 if (LfnDirEntry
->Name11_12
[0] != 0xFFFF)
553 LfnNameBuffer
[11 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[0];
555 if (LfnDirEntry
->Name11_12
[1] != 0xFFFF)
557 LfnNameBuffer
[12 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[1];
560 //DPRINTM(DPRINT_FILESYSTEM, "Dumping long name buffer:\n");
561 //DbgDumpBuffer(DPRINT_FILESYSTEM, LfnNameBuffer, 260);
567 // Check for the volume label attribute
568 // and skip over this entry if found
570 if (DirEntry
->Attr
& ATTR_VOLUMENAME
)
572 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
573 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
578 // If we get here then we've found a short file name
579 // entry and LfnNameBuffer contains the long file
580 // name or zeroes. All we have to do now is see if the
581 // file name matches either the short or long file name
582 // and fill in the FAT_FILE_INFO structure if it does
583 // or zero our buffers and continue looking.
587 // Get short file name
589 FatParseShortFileName(ShortNameBuffer
, DirEntry
);
591 //DPRINTM(DPRINT_FILESYSTEM, "Entry: %d LFN = %s\n", CurrentEntry, LfnNameBuffer);
592 //DPRINTM(DPRINT_FILESYSTEM, "Entry: %d DOS name = %s\n", CurrentEntry, ShortNameBuffer);
595 // See if the file name matches either the short or long name
597 if (((strlen(FileName
) == strlen(LfnNameBuffer
)) && (_stricmp(FileName
, LfnNameBuffer
) == 0)) ||
598 ((strlen(FileName
) == strlen(ShortNameBuffer
)) && (_stricmp(FileName
, ShortNameBuffer
) == 0))) {
600 // We found the entry, now fill in the FAT_FILE_INFO struct
602 FatFileInfoPointer
->Attributes
= DirEntry
->Attr
;
603 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
604 FatFileInfoPointer
->FilePointer
= 0;
606 DPRINTM(DPRINT_FILESYSTEM
, "MSDOS Directory Entry:\n");
607 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]);
608 DPRINTM(DPRINT_FILESYSTEM
, "Attr = 0x%x\n", DirEntry
->Attr
);
609 DPRINTM(DPRINT_FILESYSTEM
, "ReservedNT = 0x%x\n", DirEntry
->ReservedNT
);
610 DPRINTM(DPRINT_FILESYSTEM
, "TimeInTenths = %d\n", DirEntry
->TimeInTenths
);
611 DPRINTM(DPRINT_FILESYSTEM
, "CreateTime = %d\n", DirEntry
->CreateTime
);
612 DPRINTM(DPRINT_FILESYSTEM
, "CreateDate = %d\n", DirEntry
->CreateDate
);
613 DPRINTM(DPRINT_FILESYSTEM
, "LastAccessDate = %d\n", DirEntry
->LastAccessDate
);
614 DPRINTM(DPRINT_FILESYSTEM
, "ClusterHigh = 0x%x\n", DirEntry
->ClusterHigh
);
615 DPRINTM(DPRINT_FILESYSTEM
, "Time = %d\n", DirEntry
->Time
);
616 DPRINTM(DPRINT_FILESYSTEM
, "Date = %d\n", DirEntry
->Date
);
617 DPRINTM(DPRINT_FILESYSTEM
, "ClusterLow = 0x%x\n", DirEntry
->ClusterLow
);
618 DPRINTM(DPRINT_FILESYSTEM
, "Size = %d\n", DirEntry
->Size
);
621 // Get the cluster chain
623 StartCluster
= ((ULONG
)DirEntry
->ClusterHigh
<< 16) + DirEntry
->ClusterLow
;
624 DPRINTM(DPRINT_FILESYSTEM
, "StartCluster = 0x%x\n", StartCluster
);
625 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(Volume
, StartCluster
);
628 // See if memory allocation failed
630 if (FatFileInfoPointer
->FileFatChain
== NULL
)
639 // Nope, no match - zero buffers and continue looking
641 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
642 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
649 static BOOLEAN
FatXSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume
, PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
654 FATX_DIRENTRY OurDirEntry
;
655 PFATX_DIRENTRY DirEntry
= &OurDirEntry
;
657 EntryCount
= DirectorySize
/ sizeof(FATX_DIRENTRY
);
659 DPRINTM(DPRINT_FILESYSTEM
, "FatXSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
);
661 FileNameLen
= strlen(FileName
);
663 for (CurrentEntry
= 0; CurrentEntry
< EntryCount
; CurrentEntry
++, DirectoryBuffer
= ((PFATX_DIRENTRY
)DirectoryBuffer
)+1)
665 OurDirEntry
= *(PFATX_DIRENTRY
) DirectoryBuffer
;
666 FatSwapFatXDirEntry(&OurDirEntry
);
667 if (0xff == DirEntry
->FileNameSize
)
671 if (0xe5 == DirEntry
->FileNameSize
)
675 if (FileNameLen
== DirEntry
->FileNameSize
&&
676 0 == _strnicmp(FileName
, DirEntry
->FileName
, FileNameLen
))
679 * We found the entry, now fill in the FAT_FILE_INFO struct
681 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
682 FatFileInfoPointer
->FilePointer
= 0;
684 DPRINTM(DPRINT_FILESYSTEM
, "FATX Directory Entry:\n");
685 DPRINTM(DPRINT_FILESYSTEM
, "FileNameSize = %d\n", DirEntry
->FileNameSize
);
686 DPRINTM(DPRINT_FILESYSTEM
, "Attr = 0x%x\n", DirEntry
->Attr
);
687 DPRINTM(DPRINT_FILESYSTEM
, "StartCluster = 0x%x\n", DirEntry
->StartCluster
);
688 DPRINTM(DPRINT_FILESYSTEM
, "Size = %d\n", DirEntry
->Size
);
689 DPRINTM(DPRINT_FILESYSTEM
, "Time = %d\n", DirEntry
->Time
);
690 DPRINTM(DPRINT_FILESYSTEM
, "Date = %d\n", DirEntry
->Date
);
691 DPRINTM(DPRINT_FILESYSTEM
, "CreateTime = %d\n", DirEntry
->CreateTime
);
692 DPRINTM(DPRINT_FILESYSTEM
, "CreateDate = %d\n", DirEntry
->CreateDate
);
693 DPRINTM(DPRINT_FILESYSTEM
, "LastAccessTime = %d\n", DirEntry
->LastAccessTime
);
694 DPRINTM(DPRINT_FILESYSTEM
, "LastAccessDate = %d\n", DirEntry
->LastAccessDate
);
697 * Get the cluster chain
699 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(Volume
, DirEntry
->StartCluster
);
702 * See if memory allocation failed
704 if (NULL
== FatFileInfoPointer
->FileFatChain
)
718 * This function searches the file system for the
719 * specified filename and fills in an FAT_FILE_INFO structure
720 * with info describing the file, etc. returns ARC error code
722 LONG
FatLookupFile(PFAT_VOLUME_INFO Volume
, PCSTR FileName
, ULONG DeviceId
, PFAT_FILE_INFO FatFileInfoPointer
)
725 ULONG NumberOfPathParts
;
727 PVOID DirectoryBuffer
;
728 ULONG DirectoryStartCluster
= 0;
730 FAT_FILE_INFO FatFileInfo
;
732 DPRINTM(DPRINT_FILESYSTEM
, "FatLookupFile() FileName = %s\n", FileName
);
734 memset(FatFileInfoPointer
, 0, sizeof(FAT_FILE_INFO
));
737 // Figure out how many sub-directories we are nested in
739 NumberOfPathParts
= FsGetNumPathParts(FileName
);
742 // Loop once for each part
744 for (i
=0; i
<NumberOfPathParts
; i
++)
747 // Get first path part
749 FsGetFirstNameFromPath(PathPart
, FileName
);
752 // Advance to the next part of the path
754 for (; (*FileName
!= '\\') && (*FileName
!= '/') && (*FileName
!= '\0'); FileName
++)
760 // Buffer the directory contents
762 DirectoryBuffer
= FatBufferDirectory(Volume
, DirectoryStartCluster
, &DirectorySize
, (i
== 0) );
763 if (DirectoryBuffer
== NULL
)
769 // Search for file name in directory
771 if (ISFATX(Volume
->FatType
))
773 if (!FatXSearchDirectoryBufferForFile(Volume
, DirectoryBuffer
, DirectorySize
, PathPart
, &FatFileInfo
))
775 MmFreeMemory(DirectoryBuffer
);
781 if (!FatSearchDirectoryBufferForFile(Volume
, DirectoryBuffer
, DirectorySize
, PathPart
, &FatFileInfo
))
783 MmFreeMemory(DirectoryBuffer
);
788 MmFreeMemory(DirectoryBuffer
);
791 // If we have another sub-directory to go then
792 // grab the start cluster and free the fat chain array
794 if ((i
+1) < NumberOfPathParts
)
797 // Check if current entry is a directory
799 if (!(FatFileInfo
.Attributes
& ATTR_DIRECTORY
))
801 MmFreeMemory(FatFileInfo
.FileFatChain
);
804 DirectoryStartCluster
= FatFileInfo
.FileFatChain
[0];
806 MmFreeMemory(FatFileInfo
.FileFatChain
);
809 memcpy(FatFileInfoPointer
, &FatFileInfo
, sizeof(FAT_FILE_INFO
));
816 * This function parses a directory entry name which
817 * is in the form of "FILE EXT" and puts it in Buffer
818 * in the form of "file.ext"
820 void FatParseShortFileName(PCHAR Buffer
, PDIRENTRY DirEntry
)
825 RtlZeroMemory(Buffer
, 13);
828 // Fixup first character
830 if (DirEntry
->FileName
[0] == 0x05)
832 DirEntry
->FileName
[0] = 0xE5;
840 if (DirEntry
->FileName
[Idx
] == ' ')
845 Buffer
[Idx
] = DirEntry
->FileName
[Idx
];
852 if ((DirEntry
->FileName
[8] != ' '))
855 Buffer
[Idx
++] = (DirEntry
->FileName
[8] == ' ') ? '\0' : DirEntry
->FileName
[8];
856 Buffer
[Idx
++] = (DirEntry
->FileName
[9] == ' ') ? '\0' : DirEntry
->FileName
[9];
857 Buffer
[Idx
++] = (DirEntry
->FileName
[10] == ' ') ? '\0' : DirEntry
->FileName
[10];
860 //DPRINTM(DPRINT_FILESYSTEM, "FatParseShortFileName() ShortName = %s\n", Buffer);
865 * returns the Fat entry for a given cluster number
867 BOOLEAN
FatGetFatEntry(PFAT_VOLUME_INFO Volume
, ULONG Cluster
, ULONG
* ClusterPointer
)
871 UINT32 ThisFatSecNum
;
872 UINT32 ThisFatEntOffset
;
874 //DPRINTM(DPRINT_FILESYSTEM, "FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster);
876 switch(Volume
->FatType
)
880 FatOffset
= Cluster
+ (Cluster
/ 2);
881 ThisFatSecNum
= Volume
->ActiveFatSectorStart
+ (FatOffset
/ Volume
->BytesPerSector
);
882 ThisFatEntOffset
= (FatOffset
% Volume
->BytesPerSector
);
884 DPRINTM(DPRINT_FILESYSTEM
, "FatOffset: %d\n", FatOffset
);
885 DPRINTM(DPRINT_FILESYSTEM
, "ThisFatSecNum: %d\n", ThisFatSecNum
);
886 DPRINTM(DPRINT_FILESYSTEM
, "ThisFatEntOffset: %d\n", ThisFatEntOffset
);
888 if (ThisFatEntOffset
== (Volume
->BytesPerSector
- 1))
890 if (!FatReadVolumeSectors(Volume
, ThisFatSecNum
, 2, (PVOID
)FILESYSBUFFER
))
897 if (!FatReadVolumeSectors(Volume
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
903 fat
= *((USHORT
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
));
905 if (Cluster
& 0x0001)
906 fat
= fat
>> 4; /* Cluster number is ODD */
908 fat
= fat
& 0x0FFF; /* Cluster number is EVEN */
915 FatOffset
= (Cluster
* 2);
916 ThisFatSecNum
= Volume
->ActiveFatSectorStart
+ (FatOffset
/ Volume
->BytesPerSector
);
917 ThisFatEntOffset
= (FatOffset
% Volume
->BytesPerSector
);
919 if (!FatReadVolumeSectors(Volume
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
924 fat
= *((USHORT
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
));
932 FatOffset
= (Cluster
* 4);
933 ThisFatSecNum
= Volume
->ActiveFatSectorStart
+ (FatOffset
/ Volume
->BytesPerSector
);
934 ThisFatEntOffset
= (FatOffset
% Volume
->BytesPerSector
);
936 if (!FatReadVolumeSectors(Volume
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
942 fat
= (*((ULONG
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
))) & 0x0FFFFFFF;
948 DPRINTM(DPRINT_FILESYSTEM
, "Unknown FAT type %d\n", Volume
->FatType
);
953 //DPRINTM(DPRINT_FILESYSTEM, "FAT entry is 0x%x.\n", fat);
955 *ClusterPointer
= fat
;
960 ULONG
FatCountClustersInChain(PFAT_VOLUME_INFO Volume
, ULONG StartCluster
)
962 ULONG ClusterCount
= 0;
964 DPRINTM(DPRINT_FILESYSTEM
, "FatCountClustersInChain() StartCluster = %d\n", StartCluster
);
969 // If end of chain then break out of our cluster counting loop
971 if (((Volume
->FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
972 ((Volume
->FatType
== FAT16
|| Volume
->FatType
== FATX16
) && (StartCluster
>= 0xfff8)) ||
973 ((Volume
->FatType
== FAT32
|| Volume
->FatType
== FATX32
) && (StartCluster
>= 0x0ffffff8)))
986 if (!FatGetFatEntry(Volume
, StartCluster
, &StartCluster
))
992 DPRINTM(DPRINT_FILESYSTEM
, "FatCountClustersInChain() ClusterCount = %d\n", ClusterCount
);
997 ULONG
* FatGetClusterChainArray(PFAT_VOLUME_INFO Volume
, ULONG StartCluster
)
1001 ULONG
* ArrayPointer
;
1004 DPRINTM(DPRINT_FILESYSTEM
, "FatGetClusterChainArray() StartCluster = %d\n", StartCluster
);
1006 ClusterCount
= FatCountClustersInChain(Volume
, StartCluster
) + 1; // Lets get the 0x0ffffff8 on the end of the array
1007 ArraySize
= ClusterCount
* sizeof(ULONG
);
1010 // Allocate array memory
1012 ArrayPointer
= MmAllocateMemory(ArraySize
);
1014 if (ArrayPointer
== NULL
)
1020 // Loop through and set array values
1022 for (Idx
=0; Idx
<ClusterCount
; Idx
++)
1025 // Set current cluster
1027 ArrayPointer
[Idx
] = StartCluster
;
1030 // Don't try to get next cluster for last cluster
1032 if (((Volume
->FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
1033 ((Volume
->FatType
== FAT16
|| Volume
->FatType
== FATX16
) && (StartCluster
>= 0xfff8)) ||
1034 ((Volume
->FatType
== FAT32
|| Volume
->FatType
== FATX32
) && (StartCluster
>= 0x0ffffff8)))
1043 if (!FatGetFatEntry(Volume
, StartCluster
, &StartCluster
))
1045 MmFreeMemory(ArrayPointer
);
1050 return ArrayPointer
;
1054 * FatReadClusterChain()
1055 * Reads the specified clusters into memory
1057 BOOLEAN
FatReadClusterChain(PFAT_VOLUME_INFO Volume
, ULONG StartClusterNumber
, ULONG NumberOfClusters
, PVOID Buffer
)
1059 ULONG ClusterStartSector
;
1061 DPRINTM(DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
);
1063 while (NumberOfClusters
> 0)
1066 //DPRINTM(DPRINT_FILESYSTEM, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer);
1068 // Calculate starting sector for cluster
1070 ClusterStartSector
= ((StartClusterNumber
- 2) * Volume
->SectorsPerCluster
) + Volume
->DataSectorStart
;
1073 // Read cluster into memory
1075 if (!FatReadVolumeSectors(Volume
, ClusterStartSector
, Volume
->SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1080 memcpy(Buffer
, (PVOID
)FILESYSBUFFER
, Volume
->SectorsPerCluster
* Volume
->BytesPerSector
);
1083 // Decrement count of clusters left to read
1088 // Increment buffer address by cluster size
1090 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (Volume
->SectorsPerCluster
* Volume
->BytesPerSector
));
1095 if (!FatGetFatEntry(Volume
, StartClusterNumber
, &StartClusterNumber
))
1101 // If end of chain then break out of our cluster reading loop
1103 if (((Volume
->FatType
== FAT12
) && (StartClusterNumber
>= 0xff8)) ||
1104 ((Volume
->FatType
== FAT16
|| Volume
->FatType
== FATX16
) && (StartClusterNumber
>= 0xfff8)) ||
1105 ((Volume
->FatType
== FAT32
|| Volume
->FatType
== FATX32
) && (StartClusterNumber
>= 0x0ffffff8)))
1115 * FatReadPartialCluster()
1116 * Reads part of a cluster into memory
1118 BOOLEAN
FatReadPartialCluster(PFAT_VOLUME_INFO Volume
, ULONG ClusterNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
)
1120 ULONG ClusterStartSector
;
1122 //DPRINTM(DPRINT_FILESYSTEM, "FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber, StartingOffset, Length, Buffer);
1124 ClusterStartSector
= ((ClusterNumber
- 2) * Volume
->SectorsPerCluster
) + Volume
->DataSectorStart
;
1126 if (!FatReadVolumeSectors(Volume
, ClusterStartSector
, Volume
->SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1131 memcpy(Buffer
, (PVOID
)((ULONG_PTR
)FILESYSBUFFER
+ StartingOffset
), Length
);
1138 * Reads BytesToRead from open file and
1139 * returns the number of bytes read in BytesRead
1141 BOOLEAN
FatReadFile(PFAT_FILE_INFO FatFileInfo
, ULONG BytesToRead
, ULONG
* BytesRead
, PVOID Buffer
)
1143 PFAT_VOLUME_INFO Volume
= FatFileInfo
->Volume
;
1144 ULONG ClusterNumber
;
1145 ULONG OffsetInCluster
;
1146 ULONG LengthInCluster
;
1147 ULONG NumberOfClusters
;
1148 ULONG BytesPerCluster
;
1150 DPRINTM(DPRINT_FILESYSTEM
, "FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead
, Buffer
);
1152 if (BytesRead
!= NULL
)
1158 // If they are trying to read past the
1159 // end of the file then return success
1160 // with BytesRead == 0
1162 if (FatFileInfo
->FilePointer
>= FatFileInfo
->FileSize
)
1168 // If they are trying to read more than there is to read
1169 // then adjust the amount to read
1171 if ((FatFileInfo
->FilePointer
+ BytesToRead
) > FatFileInfo
->FileSize
)
1173 BytesToRead
= (FatFileInfo
->FileSize
- FatFileInfo
->FilePointer
);
1177 // Ok, now we have to perform at most 3 calculations
1178 // I'll draw you a picture (using nifty ASCII art):
1180 // CurrentFilePointer -+
1182 // +----------------+
1184 // +-----------+-----------+-----------+-----------+
1185 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
1186 // +-----------+-----------+-----------+-----------+
1188 // +---------------+--------------------+
1190 // BytesToRead -------+
1192 // 1 - The first calculation (and read) will align
1193 // the file pointer with the next cluster.
1194 // boundary (if we are supposed to read that much)
1195 // 2 - The next calculation (and read) will read
1196 // in all the full clusters that the requested
1197 // amount of data would cover (in this case
1199 // 3 - The last calculation (and read) would read
1200 // in the remainder of the data requested out of
1201 // the last cluster.
1204 BytesPerCluster
= Volume
->SectorsPerCluster
* Volume
->BytesPerSector
;
1207 // Only do the first read if we
1208 // aren't aligned on a cluster boundary
1210 if (FatFileInfo
->FilePointer
% BytesPerCluster
)
1213 // Do the math for our first read
1215 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1216 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1217 OffsetInCluster
= (FatFileInfo
->FilePointer
% BytesPerCluster
);
1218 LengthInCluster
= (BytesToRead
> (BytesPerCluster
- OffsetInCluster
)) ? (BytesPerCluster
- OffsetInCluster
) : BytesToRead
;
1221 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1223 if (!FatReadPartialCluster(Volume
, ClusterNumber
, OffsetInCluster
, LengthInCluster
, Buffer
))
1227 if (BytesRead
!= NULL
)
1229 *BytesRead
+= LengthInCluster
;
1231 BytesToRead
-= LengthInCluster
;
1232 FatFileInfo
->FilePointer
+= LengthInCluster
;
1233 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ LengthInCluster
);
1237 // Do the math for our second read (if any data left)
1239 if (BytesToRead
> 0)
1242 // Determine how many full clusters we need to read
1244 NumberOfClusters
= (BytesToRead
/ BytesPerCluster
);
1246 if (NumberOfClusters
> 0)
1248 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1249 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1252 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1254 if (!FatReadClusterChain(Volume
, ClusterNumber
, NumberOfClusters
, Buffer
))
1258 if (BytesRead
!= NULL
)
1260 *BytesRead
+= (NumberOfClusters
* BytesPerCluster
);
1262 BytesToRead
-= (NumberOfClusters
* BytesPerCluster
);
1263 FatFileInfo
->FilePointer
+= (NumberOfClusters
* BytesPerCluster
);
1264 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (NumberOfClusters
* BytesPerCluster
));
1269 // Do the math for our third read (if any data left)
1271 if (BytesToRead
> 0)
1273 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1274 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1277 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1279 if (!FatReadPartialCluster(Volume
, ClusterNumber
, 0, BytesToRead
, Buffer
))
1283 if (BytesRead
!= NULL
)
1285 *BytesRead
+= BytesToRead
;
1287 FatFileInfo
->FilePointer
+= BytesToRead
;
1288 BytesToRead
-= BytesToRead
;
1289 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ BytesToRead
);
1295 BOOLEAN
FatReadVolumeSectors(PFAT_VOLUME_INFO Volume
, ULONG SectorNumber
, ULONG SectorCount
, PVOID Buffer
)
1297 LARGE_INTEGER Position
;
1301 //DPRINTM(DPRINT_FILESYSTEM, "FatReadVolumeSectors(): SectorNumber %d, SectorCount %d, Buffer %p\n",
1302 // SectorNumber, SectorCount, Buffer);
1305 // Seek to right position
1307 Position
.QuadPart
= SectorNumber
* 512;
1308 ret
= ArcSeek(Volume
->DeviceId
, &Position
, SeekAbsolute
);
1309 if (ret
!= ESUCCESS
)
1311 DPRINTM(DPRINT_FILESYSTEM
, "FatReadVolumeSectors() Failed to seek\n");
1318 ret
= ArcRead(Volume
->DeviceId
, Buffer
, SectorCount
* 512, &Count
);
1319 if (ret
!= ESUCCESS
|| Count
!= SectorCount
* 512)
1321 DPRINTM(DPRINT_FILESYSTEM
, "FatReadVolumeSectors() Failed to read\n");
1329 LONG
FatClose(ULONG FileId
)
1331 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1333 MmHeapFree(FileHandle
);
1338 LONG
FatGetFileInformation(ULONG FileId
, FILEINFORMATION
* Information
)
1340 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1342 RtlZeroMemory(Information
, sizeof(FILEINFORMATION
));
1343 Information
->EndingAddress
.LowPart
= FileHandle
->FileSize
;
1344 Information
->CurrentAddress
.LowPart
= FileHandle
->FilePointer
;
1346 DPRINTM(DPRINT_FILESYSTEM
, "FatGetFileInformation() FileSize = %d\n",
1347 Information
->EndingAddress
.LowPart
);
1348 DPRINTM(DPRINT_FILESYSTEM
, "FatGetFileInformation() FilePointer = %d\n",
1349 Information
->CurrentAddress
.LowPart
);
1354 LONG
FatOpen(CHAR
* Path
, OPENMODE OpenMode
, ULONG
* FileId
)
1356 PFAT_VOLUME_INFO FatVolume
;
1357 FAT_FILE_INFO TempFileInfo
;
1358 PFAT_FILE_INFO FileHandle
;
1360 BOOLEAN IsDirectory
;
1363 if (OpenMode
!= OpenReadOnly
&& OpenMode
!= OpenDirectory
)
1366 DeviceId
= FsGetDeviceId(*FileId
);
1367 FatVolume
= FatVolumes
[DeviceId
];
1369 DPRINTM(DPRINT_FILESYSTEM
, "FatOpen() FileName = %s\n", Path
);
1371 RtlZeroMemory(&TempFileInfo
, sizeof(TempFileInfo
));
1372 ret
= FatLookupFile(FatVolume
, Path
, DeviceId
, &TempFileInfo
);
1373 if (ret
!= ESUCCESS
)
1377 // Check if caller opened what he expected (dir vs file)
1379 IsDirectory
= (TempFileInfo
.Attributes
& ATTR_DIRECTORY
) != 0;
1380 if (IsDirectory
&& OpenMode
!= OpenDirectory
)
1382 else if (!IsDirectory
&& OpenMode
!= OpenReadOnly
)
1385 FileHandle
= MmHeapAlloc(sizeof(FAT_FILE_INFO
));
1389 RtlCopyMemory(FileHandle
, &TempFileInfo
, sizeof(FAT_FILE_INFO
));
1390 FileHandle
->Volume
= FatVolume
;
1392 FsSetDeviceSpecific(*FileId
, FileHandle
);
1396 LONG
FatRead(ULONG FileId
, VOID
* Buffer
, ULONG N
, ULONG
* Count
)
1398 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1402 // Call old read method
1404 ret
= FatReadFile(FileHandle
, N
, Count
, Buffer
);
1407 // Check for success
1415 LONG
FatSeek(ULONG FileId
, LARGE_INTEGER
* Position
, SEEKMODE SeekMode
)
1417 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1419 DPRINTM(DPRINT_FILESYSTEM
, "FatSeek() NewFilePointer = %lu\n", Position
->LowPart
);
1421 if (SeekMode
!= SeekAbsolute
)
1423 if (Position
->HighPart
!= 0)
1425 if (Position
->LowPart
>= FileHandle
->FileSize
)
1428 FileHandle
->FilePointer
= Position
->LowPart
;
1432 const DEVVTBL FatFuncTable
=
1435 FatGetFileInformation
,
1442 const DEVVTBL
* FatMount(ULONG DeviceId
)
1444 PFAT_VOLUME_INFO Volume
;
1446 PFAT_BOOTSECTOR BootSector
= (PFAT_BOOTSECTOR
)Buffer
;
1447 PFAT32_BOOTSECTOR BootSector32
= (PFAT32_BOOTSECTOR
)Buffer
;
1448 PFATX_BOOTSECTOR BootSectorX
= (PFATX_BOOTSECTOR
)Buffer
;
1449 FILEINFORMATION FileInformation
;
1450 LARGE_INTEGER Position
;
1452 ULARGE_INTEGER SectorCount
;
1456 // Allocate data for volume information
1458 Volume
= MmHeapAlloc(sizeof(FAT_VOLUME_INFO
));
1461 RtlZeroMemory(Volume
, sizeof(FAT_VOLUME_INFO
));
1464 // Read the BootSector
1466 Position
.HighPart
= 0;
1467 Position
.LowPart
= 0;
1468 ret
= ArcSeek(DeviceId
, &Position
, SeekAbsolute
);
1469 if (ret
!= ESUCCESS
)
1474 ret
= ArcRead(DeviceId
, Buffer
, sizeof(Buffer
), &Count
);
1475 if (ret
!= ESUCCESS
|| Count
!= sizeof(Buffer
))
1482 // Check if BootSector is valid. If no, return early
1484 if (!RtlEqualMemory(BootSector
->FileSystemType
, "FAT12 ", 8) &&
1485 !RtlEqualMemory(BootSector
->FileSystemType
, "FAT16 ", 8) &&
1486 !RtlEqualMemory(BootSector32
->FileSystemType
, "FAT32 ", 8) &&
1487 !RtlEqualMemory(BootSectorX
->FileSystemType
, "FATX", 4))
1494 // Determine sector count
1496 ret
= ArcGetFileInformation(DeviceId
, &FileInformation
);
1497 if (ret
!= ESUCCESS
)
1502 SectorCount
.HighPart
= FileInformation
.EndingAddress
.HighPart
;
1503 SectorCount
.LowPart
= FileInformation
.EndingAddress
.LowPart
;
1504 SectorCount
.QuadPart
/= SECTOR_SIZE
;
1509 Volume
->DeviceId
= DeviceId
;
1512 // Really open the volume
1514 if (!FatOpenVolume(Volume
, BootSector
, SectorCount
.QuadPart
))
1521 // Remember FAT volume information
1523 FatVolumes
[DeviceId
] = Volume
;
1528 return &FatFuncTable
;