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(PFAT_VOLUME_INFO Volume
, ULONG DirectoryStartCluster
, ULONG
* EntryCountPointer
, BOOLEAN RootDirectory
);
27 BOOLEAN
FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume
, PVOID DirectoryBuffer
, ULONG EntryCount
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
);
28 LONG
FatLookupFile(PFAT_VOLUME_INFO Volume
, PCSTR FileName
, ULONG DeviceId
, PFAT_FILE_INFO FatFileInfoPointer
);
29 void FatParseShortFileName(PCHAR Buffer
, PDIRENTRY DirEntry
);
30 BOOLEAN
FatGetFatEntry(PFAT_VOLUME_INFO Volume
, ULONG Cluster
, ULONG
* ClusterPointer
);
31 ULONG
FatCountClustersInChain(PFAT_VOLUME_INFO Volume
, ULONG StartCluster
);
32 ULONG
* FatGetClusterChainArray(PFAT_VOLUME_INFO Volume
, ULONG StartCluster
);
33 BOOLEAN
FatReadClusterChain(PFAT_VOLUME_INFO Volume
, ULONG StartClusterNumber
, ULONG NumberOfClusters
, PVOID Buffer
);
34 BOOLEAN
FatReadPartialCluster(PFAT_VOLUME_INFO Volume
, ULONG ClusterNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
);
35 BOOLEAN
FatReadVolumeSectors(PFAT_VOLUME_INFO Volume
, ULONG SectorNumber
, ULONG SectorCount
, PVOID Buffer
);
37 typedef struct _FAT_VOLUME_INFO
39 ULONG BytesPerSector
; /* Number of bytes per sector */
40 ULONG SectorsPerCluster
; /* Number of sectors per cluster */
41 ULONG FatSectorStart
; /* Starting sector of 1st FAT table */
42 ULONG ActiveFatSectorStart
; /* Starting sector of active FAT table */
43 ULONG NumberOfFats
; /* Number of FAT tables */
44 ULONG SectorsPerFat
; /* Sectors per FAT table */
45 ULONG RootDirSectorStart
; /* Starting sector of the root directory (non-fat32) */
46 ULONG RootDirSectors
; /* Number of sectors of the root directory (non-fat32) */
47 ULONG RootDirStartCluster
; /* Starting cluster number of the root directory (fat32 only) */
48 ULONG DataSectorStart
; /* Starting sector of the data area */
49 ULONG FatType
; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
53 static PFAT_VOLUME_INFO FatVolume
= NULL
;
55 VOID
FatSwapFatBootSector(PFAT_BOOTSECTOR Obj
)
57 SW(Obj
, BytesPerSector
);
58 SW(Obj
, ReservedSectors
);
59 SW(Obj
, RootDirEntries
);
60 SW(Obj
, TotalSectors
);
61 SW(Obj
, SectorsPerFat
);
62 SW(Obj
, SectorsPerTrack
);
63 SW(Obj
, NumberOfHeads
);
64 SD(Obj
, HiddenSectors
);
65 SD(Obj
, TotalSectorsBig
);
66 SD(Obj
, VolumeSerialNumber
);
67 SW(Obj
, BootSectorMagic
);
70 VOID
FatSwapFat32BootSector(PFAT32_BOOTSECTOR Obj
)
72 SW(Obj
, BytesPerSector
);
73 SW(Obj
, ReservedSectors
);
74 SW(Obj
, RootDirEntries
);
75 SW(Obj
, TotalSectors
);
76 SW(Obj
, SectorsPerFat
);
77 SW(Obj
, NumberOfHeads
);
78 SD(Obj
, HiddenSectors
);
79 SD(Obj
, TotalSectorsBig
);
80 SD(Obj
, SectorsPerFatBig
);
81 SW(Obj
, ExtendedFlags
);
82 SW(Obj
, FileSystemVersion
);
83 SD(Obj
, RootDirStartCluster
);
85 SW(Obj
, BackupBootSector
);
86 SD(Obj
, VolumeSerialNumber
);
87 SW(Obj
, BootSectorMagic
);
90 VOID
FatSwapFatXBootSector(PFATX_BOOTSECTOR Obj
)
92 SD(Obj
, VolumeSerialNumber
);
93 SD(Obj
, SectorsPerCluster
);
94 SW(Obj
, NumberOfFats
);
97 VOID
FatSwapDirEntry(PDIRENTRY Obj
)
101 SW(Obj
, LastAccessDate
);
102 SW(Obj
, ClusterHigh
);
109 VOID
FatSwapLFNDirEntry(PLFN_DIRENTRY Obj
)
112 SW(Obj
, StartCluster
);
113 for(i
= 0; i
< 5; i
++)
114 Obj
->Name0_4
[i
] = SWAPW(Obj
->Name0_4
[i
]);
115 for(i
= 0; i
< 6; i
++)
116 Obj
->Name5_10
[i
] = SWAPW(Obj
->Name5_10
[i
]);
117 for(i
= 0; i
< 2; i
++)
118 Obj
->Name11_12
[i
] = SWAPW(Obj
->Name11_12
[i
]);
121 VOID
FatSwapFatXDirEntry(PFATX_DIRENTRY Obj
)
123 SD(Obj
, StartCluster
);
129 SW(Obj
, LastAccessTime
);
130 SW(Obj
, LastAccessDate
);
133 BOOLEAN
FatOpenVolume(PFAT_VOLUME_INFO Volume
, PFAT_BOOTSECTOR BootSector
, ULONGLONG PartitionSectorCount
)
137 PFAT_BOOTSECTOR FatVolumeBootSector
;
138 PFAT32_BOOTSECTOR Fat32VolumeBootSector
;
139 PFATX_BOOTSECTOR FatXVolumeBootSector
;
141 DPRINTM(DPRINT_FILESYSTEM
, "FatOpenVolume() DeviceId = %d\n", Volume
->DeviceId
);
144 // Allocate the memory to hold the boot sector
146 FatVolumeBootSector
= (PFAT_BOOTSECTOR
)BootSector
;
147 Fat32VolumeBootSector
= (PFAT32_BOOTSECTOR
)BootSector
;
148 FatXVolumeBootSector
= (PFATX_BOOTSECTOR
)BootSector
;
151 Volume
->FatType
= FatDetermineFatType(FatVolumeBootSector
, PartitionSectorCount
);
153 // Dump boot sector (and swap it for big endian systems)
154 DPRINTM(DPRINT_FILESYSTEM
, "Dumping boot sector:\n");
155 if (ISFATX(Volume
->FatType
))
157 FatSwapFatXBootSector(FatXVolumeBootSector
);
158 DPRINTM(DPRINT_FILESYSTEM
, "sizeof(FATX_BOOTSECTOR) = 0x%x.\n", sizeof(FATX_BOOTSECTOR
));
160 DPRINTM(DPRINT_FILESYSTEM
, "FileSystemType: %c%c%c%c.\n", FatXVolumeBootSector
->FileSystemType
[0], FatXVolumeBootSector
->FileSystemType
[1], FatXVolumeBootSector
->FileSystemType
[2], FatXVolumeBootSector
->FileSystemType
[3]);
161 DPRINTM(DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", FatXVolumeBootSector
->VolumeSerialNumber
);
162 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", FatXVolumeBootSector
->SectorsPerCluster
);
163 DPRINTM(DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", FatXVolumeBootSector
->NumberOfFats
);
164 DPRINTM(DPRINT_FILESYSTEM
, "Unknown: 0x%x\n", FatXVolumeBootSector
->Unknown
);
166 DPRINTM(DPRINT_FILESYSTEM
, "FatType %s\n", Volume
->FatType
== FATX16
? "FATX16" : "FATX32");
169 else if (Volume
->FatType
== FAT32
)
171 FatSwapFat32BootSector(Fat32VolumeBootSector
);
172 DPRINTM(DPRINT_FILESYSTEM
, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR
));
174 DPRINTM(DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector
->JumpBoot
[0], Fat32VolumeBootSector
->JumpBoot
[1], Fat32VolumeBootSector
->JumpBoot
[2]);
175 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]);
176 DPRINTM(DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", Fat32VolumeBootSector
->BytesPerSector
);
177 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", Fat32VolumeBootSector
->SectorsPerCluster
);
178 DPRINTM(DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", Fat32VolumeBootSector
->ReservedSectors
);
179 DPRINTM(DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", Fat32VolumeBootSector
->NumberOfFats
);
180 DPRINTM(DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", Fat32VolumeBootSector
->RootDirEntries
);
181 DPRINTM(DPRINT_FILESYSTEM
, "TotalSectors: %d\n", Fat32VolumeBootSector
->TotalSectors
);
182 DPRINTM(DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", Fat32VolumeBootSector
->MediaDescriptor
);
183 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", Fat32VolumeBootSector
->SectorsPerFat
);
184 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", Fat32VolumeBootSector
->SectorsPerTrack
);
185 DPRINTM(DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", Fat32VolumeBootSector
->NumberOfHeads
);
186 DPRINTM(DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", Fat32VolumeBootSector
->HiddenSectors
);
187 DPRINTM(DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", Fat32VolumeBootSector
->TotalSectorsBig
);
188 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerFatBig: %d\n", Fat32VolumeBootSector
->SectorsPerFatBig
);
189 DPRINTM(DPRINT_FILESYSTEM
, "ExtendedFlags: 0x%x\n", Fat32VolumeBootSector
->ExtendedFlags
);
190 DPRINTM(DPRINT_FILESYSTEM
, "FileSystemVersion: 0x%x\n", Fat32VolumeBootSector
->FileSystemVersion
);
191 DPRINTM(DPRINT_FILESYSTEM
, "RootDirStartCluster: %d\n", Fat32VolumeBootSector
->RootDirStartCluster
);
192 DPRINTM(DPRINT_FILESYSTEM
, "FsInfo: %d\n", Fat32VolumeBootSector
->FsInfo
);
193 DPRINTM(DPRINT_FILESYSTEM
, "BackupBootSector: %d\n", Fat32VolumeBootSector
->BackupBootSector
);
194 DPRINTM(DPRINT_FILESYSTEM
, "Reserved: 0x%x\n", Fat32VolumeBootSector
->Reserved
);
195 DPRINTM(DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", Fat32VolumeBootSector
->DriveNumber
);
196 DPRINTM(DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", Fat32VolumeBootSector
->Reserved1
);
197 DPRINTM(DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", Fat32VolumeBootSector
->BootSignature
);
198 DPRINTM(DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector
->VolumeSerialNumber
);
199 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]);
200 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]);
201 DPRINTM(DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", Fat32VolumeBootSector
->BootSectorMagic
);
205 FatSwapFatBootSector(FatVolumeBootSector
);
206 DPRINTM(DPRINT_FILESYSTEM
, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR
));
208 DPRINTM(DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector
->JumpBoot
[0], FatVolumeBootSector
->JumpBoot
[1], FatVolumeBootSector
->JumpBoot
[2]);
209 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]);
210 DPRINTM(DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", FatVolumeBootSector
->BytesPerSector
);
211 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", FatVolumeBootSector
->SectorsPerCluster
);
212 DPRINTM(DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", FatVolumeBootSector
->ReservedSectors
);
213 DPRINTM(DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", FatVolumeBootSector
->NumberOfFats
);
214 DPRINTM(DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", FatVolumeBootSector
->RootDirEntries
);
215 DPRINTM(DPRINT_FILESYSTEM
, "TotalSectors: %d\n", FatVolumeBootSector
->TotalSectors
);
216 DPRINTM(DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", FatVolumeBootSector
->MediaDescriptor
);
217 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", FatVolumeBootSector
->SectorsPerFat
);
218 DPRINTM(DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", FatVolumeBootSector
->SectorsPerTrack
);
219 DPRINTM(DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", FatVolumeBootSector
->NumberOfHeads
);
220 DPRINTM(DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", FatVolumeBootSector
->HiddenSectors
);
221 DPRINTM(DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", FatVolumeBootSector
->TotalSectorsBig
);
222 DPRINTM(DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", FatVolumeBootSector
->DriveNumber
);
223 DPRINTM(DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", FatVolumeBootSector
->Reserved1
);
224 DPRINTM(DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", FatVolumeBootSector
->BootSignature
);
225 DPRINTM(DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector
->VolumeSerialNumber
);
226 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]);
227 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]);
228 DPRINTM(DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", FatVolumeBootSector
->BootSectorMagic
);
232 // Check the boot sector magic
234 if (! ISFATX(Volume
->FatType
) && FatVolumeBootSector
->BootSectorMagic
!= 0xaa55)
236 sprintf(ErrMsg
, "Invalid boot sector magic (expected 0xaa55 found 0x%x)",
237 FatVolumeBootSector
->BootSectorMagic
);
238 FileSystemError(ErrMsg
);
243 // Check the FAT cluster size
244 // We do not support clusters bigger than 64k
246 if ((ISFATX(Volume
->FatType
) && 64 * 1024 < FatXVolumeBootSector
->SectorsPerCluster
* 512) ||
247 (! ISFATX(Volume
->FatType
) && 64 * 1024 < FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
))
249 FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
254 // Get the sectors per FAT,
255 // root directory starting sector,
256 // and data sector start
258 if (ISFATX(Volume
->FatType
))
260 Volume
->BytesPerSector
= 512;
261 Volume
->SectorsPerCluster
= SWAPD(FatXVolumeBootSector
->SectorsPerCluster
);
262 Volume
->FatSectorStart
= (4096 / Volume
->BytesPerSector
);
263 Volume
->ActiveFatSectorStart
= Volume
->FatSectorStart
;
264 Volume
->NumberOfFats
= 1;
265 FatSize
= PartitionSectorCount
/ Volume
->SectorsPerCluster
*
266 (Volume
->FatType
== FATX16
? 2 : 4);
267 Volume
->SectorsPerFat
= (((FatSize
+ 4095) / 4096) * 4096) / Volume
->BytesPerSector
;
269 Volume
->RootDirSectorStart
= Volume
->FatSectorStart
+ Volume
->NumberOfFats
* Volume
->SectorsPerFat
;
270 Volume
->RootDirSectors
= FatXVolumeBootSector
->SectorsPerCluster
;
272 Volume
->DataSectorStart
= Volume
->RootDirSectorStart
+ Volume
->RootDirSectors
;
274 else if (Volume
->FatType
!= FAT32
)
276 Volume
->BytesPerSector
= FatVolumeBootSector
->BytesPerSector
;
277 Volume
->SectorsPerCluster
= FatVolumeBootSector
->SectorsPerCluster
;
278 Volume
->FatSectorStart
= FatVolumeBootSector
->ReservedSectors
;
279 Volume
->ActiveFatSectorStart
= Volume
->FatSectorStart
;
280 Volume
->NumberOfFats
= FatVolumeBootSector
->NumberOfFats
;
281 Volume
->SectorsPerFat
= FatVolumeBootSector
->SectorsPerFat
;
283 Volume
->RootDirSectorStart
= Volume
->FatSectorStart
+ Volume
->NumberOfFats
* Volume
->SectorsPerFat
;
284 Volume
->RootDirSectors
= ((FatVolumeBootSector
->RootDirEntries
* 32) + (Volume
->BytesPerSector
- 1)) / Volume
->BytesPerSector
;
286 Volume
->DataSectorStart
= Volume
->RootDirSectorStart
+ Volume
->RootDirSectors
;
290 Volume
->BytesPerSector
= Fat32VolumeBootSector
->BytesPerSector
;
291 Volume
->SectorsPerCluster
= Fat32VolumeBootSector
->SectorsPerCluster
;
292 Volume
->FatSectorStart
= Fat32VolumeBootSector
->ReservedSectors
;
293 Volume
->ActiveFatSectorStart
= Volume
->FatSectorStart
+
294 ((Fat32VolumeBootSector
->ExtendedFlags
& 0x80) ? ((Fat32VolumeBootSector
->ExtendedFlags
& 0x0f) * Fat32VolumeBootSector
->SectorsPerFatBig
) : 0);
295 Volume
->NumberOfFats
= Fat32VolumeBootSector
->NumberOfFats
;
296 Volume
->SectorsPerFat
= Fat32VolumeBootSector
->SectorsPerFatBig
;
298 Volume
->RootDirStartCluster
= Fat32VolumeBootSector
->RootDirStartCluster
;
299 Volume
->DataSectorStart
= Volume
->FatSectorStart
+ Volume
->NumberOfFats
* Volume
->SectorsPerFat
;
303 // we only work with version 0
305 if (Fat32VolumeBootSector
->FileSystemVersion
!= 0)
307 FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
315 ULONG
FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector
, ULONG PartitionSectorCount
)
317 ULONG RootDirSectors
;
318 ULONG DataSectorCount
;
321 ULONG CountOfClusters
;
322 PFAT32_BOOTSECTOR Fat32BootSector
= (PFAT32_BOOTSECTOR
)FatBootSector
;
323 PFATX_BOOTSECTOR FatXBootSector
= (PFATX_BOOTSECTOR
)FatBootSector
;
325 if (0 == strncmp(FatXBootSector
->FileSystemType
, "FATX", 4))
327 CountOfClusters
= PartitionSectorCount
/ FatXBootSector
->SectorsPerCluster
;
328 if (CountOfClusters
< 65525)
330 /* Volume is FATX16 */
335 /* Volume is FAT32 */
341 RootDirSectors
= ((SWAPW(FatBootSector
->RootDirEntries
) * 32) + (SWAPW(FatBootSector
->BytesPerSector
) - 1)) / SWAPW(FatBootSector
->BytesPerSector
);
342 SectorsPerFat
= SWAPW(FatBootSector
->SectorsPerFat
) ? SWAPW(FatBootSector
->SectorsPerFat
) : SWAPD(Fat32BootSector
->SectorsPerFatBig
);
343 TotalSectors
= SWAPW(FatBootSector
->TotalSectors
) ? SWAPW(FatBootSector
->TotalSectors
) : SWAPD(FatBootSector
->TotalSectorsBig
);
344 DataSectorCount
= TotalSectors
- (SWAPW(FatBootSector
->ReservedSectors
) + (FatBootSector
->NumberOfFats
* SectorsPerFat
) + RootDirSectors
);
347 if (FatBootSector
->SectorsPerCluster
== 0)
350 CountOfClusters
= DataSectorCount
/ FatBootSector
->SectorsPerCluster
;
352 if (CountOfClusters
< 4085)
354 /* Volume is FAT12 */
357 else if (CountOfClusters
< 65525)
359 /* Volume is FAT16 */
364 /* Volume is FAT32 */
370 PVOID
FatBufferDirectory(PFAT_VOLUME_INFO Volume
, ULONG DirectoryStartCluster
, ULONG
*DirectorySize
, BOOLEAN RootDirectory
)
372 PVOID DirectoryBuffer
;
374 DPRINTM(DPRINT_FILESYSTEM
, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster
, (RootDirectory
? "TRUE" : "FALSE"));
377 * For FAT32, the root directory is nothing special. We can treat it the same
380 if (RootDirectory
&& Volume
->FatType
== FAT32
)
382 DirectoryStartCluster
= Volume
->RootDirStartCluster
;
383 RootDirectory
= FALSE
;
387 // Calculate the size of the directory
391 *DirectorySize
= Volume
->RootDirSectors
* Volume
->BytesPerSector
;
395 *DirectorySize
= FatCountClustersInChain(Volume
, DirectoryStartCluster
) * Volume
->SectorsPerCluster
* Volume
->BytesPerSector
;
399 // Attempt to allocate memory for directory buffer
401 DPRINTM(DPRINT_FILESYSTEM
, "Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize
);
402 DirectoryBuffer
= MmHeapAlloc(*DirectorySize
);
404 if (DirectoryBuffer
== NULL
)
410 // Now read directory contents into DirectoryBuffer
414 if (!FatReadVolumeSectors(Volume
, Volume
->RootDirSectorStart
, Volume
->RootDirSectors
, DirectoryBuffer
))
416 MmHeapFree(DirectoryBuffer
);
422 if (!FatReadClusterChain(Volume
, DirectoryStartCluster
, 0xFFFFFFFF, DirectoryBuffer
))
424 MmHeapFree(DirectoryBuffer
);
429 return DirectoryBuffer
;
432 BOOLEAN
FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume
, PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
436 CHAR LfnNameBuffer
[265];
437 CHAR ShortNameBuffer
[20];
439 DIRENTRY OurDirEntry
;
440 LFN_DIRENTRY OurLfnDirEntry
;
441 PDIRENTRY DirEntry
= &OurDirEntry
;
442 PLFN_DIRENTRY LfnDirEntry
= &OurLfnDirEntry
;
444 EntryCount
= DirectorySize
/ sizeof(DIRENTRY
);
446 DPRINTM(DPRINT_FILESYSTEM
, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
);
448 memset(ShortNameBuffer
, 0, 13 * sizeof(CHAR
));
449 memset(LfnNameBuffer
, 0, 261 * sizeof(CHAR
));
451 for (CurrentEntry
=0; CurrentEntry
<EntryCount
; CurrentEntry
++, DirectoryBuffer
= ((PDIRENTRY
)DirectoryBuffer
)+1)
453 OurLfnDirEntry
= *((PLFN_DIRENTRY
) DirectoryBuffer
);
454 FatSwapLFNDirEntry(LfnDirEntry
);
455 OurDirEntry
= *((PDIRENTRY
) DirectoryBuffer
);
456 FatSwapDirEntry(DirEntry
);
458 //DPRINTM(DPRINT_FILESYSTEM, "Dumping directory entry %d:\n", CurrentEntry);
459 //DbgDumpBuffer(DPRINT_FILESYSTEM, DirEntry, sizeof(DIRENTRY));
462 // Check if this is the last file in the directory
463 // If DirEntry[0] == 0x00 then that means all the
464 // entries after this one are unused. If this is the
465 // last entry then we didn't find the file in this directory.
467 if (DirEntry
->FileName
[0] == '\0')
473 // Check if this is a deleted entry or not
475 if (DirEntry
->FileName
[0] == '\xE5')
477 memset(ShortNameBuffer
, 0, 13 * sizeof(CHAR
));
478 memset(LfnNameBuffer
, 0, 261 * sizeof(CHAR
));
483 // Check if this is a LFN entry
484 // If so it needs special handling
486 if (DirEntry
->Attr
== ATTR_LONG_NAME
)
489 // Check to see if this is a deleted LFN entry, if so continue
491 if (LfnDirEntry
->SequenceNumber
& 0x80)
497 // Mask off high two bits of sequence number
498 // and make the sequence number zero-based
500 LfnDirEntry
->SequenceNumber
&= 0x3F;
501 LfnDirEntry
->SequenceNumber
--;
504 // Get all 13 LFN entry characters
506 if (LfnDirEntry
->Name0_4
[0] != 0xFFFF)
508 LfnNameBuffer
[0 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[0];
510 if (LfnDirEntry
->Name0_4
[1] != 0xFFFF)
512 LfnNameBuffer
[1 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[1];
514 if (LfnDirEntry
->Name0_4
[2] != 0xFFFF)
516 LfnNameBuffer
[2 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[2];
518 if (LfnDirEntry
->Name0_4
[3] != 0xFFFF)
520 LfnNameBuffer
[3 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[3];
522 if (LfnDirEntry
->Name0_4
[4] != 0xFFFF)
524 LfnNameBuffer
[4 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[4];
526 if (LfnDirEntry
->Name5_10
[0] != 0xFFFF)
528 LfnNameBuffer
[5 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[0];
530 if (LfnDirEntry
->Name5_10
[1] != 0xFFFF)
532 LfnNameBuffer
[6 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[1];
534 if (LfnDirEntry
->Name5_10
[2] != 0xFFFF)
536 LfnNameBuffer
[7 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[2];
538 if (LfnDirEntry
->Name5_10
[3] != 0xFFFF)
540 LfnNameBuffer
[8 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[3];
542 if (LfnDirEntry
->Name5_10
[4] != 0xFFFF)
544 LfnNameBuffer
[9 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[4];
546 if (LfnDirEntry
->Name5_10
[5] != 0xFFFF)
548 LfnNameBuffer
[10 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[5];
550 if (LfnDirEntry
->Name11_12
[0] != 0xFFFF)
552 LfnNameBuffer
[11 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[0];
554 if (LfnDirEntry
->Name11_12
[1] != 0xFFFF)
556 LfnNameBuffer
[12 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[1];
559 //DPRINTM(DPRINT_FILESYSTEM, "Dumping long name buffer:\n");
560 //DbgDumpBuffer(DPRINT_FILESYSTEM, LfnNameBuffer, 260);
566 // Check for the volume label attribute
567 // and skip over this entry if found
569 if (DirEntry
->Attr
& ATTR_VOLUMENAME
)
571 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
572 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
577 // If we get here then we've found a short file name
578 // entry and LfnNameBuffer contains the long file
579 // name or zeroes. All we have to do now is see if the
580 // file name matches either the short or long file name
581 // and fill in the FAT_FILE_INFO structure if it does
582 // or zero our buffers and continue looking.
586 // Get short file name
588 FatParseShortFileName(ShortNameBuffer
, DirEntry
);
590 DPRINTM(DPRINT_FILESYSTEM
, "Entry: %d LFN = %s\n", CurrentEntry
, LfnNameBuffer
);
591 DPRINTM(DPRINT_FILESYSTEM
, "Entry: %d DOS name = %s\n", CurrentEntry
, ShortNameBuffer
);
594 // See if the file name matches either the short or long name
596 if (((strlen(FileName
) == strlen(LfnNameBuffer
)) && (_stricmp(FileName
, LfnNameBuffer
) == 0)) ||
597 ((strlen(FileName
) == strlen(ShortNameBuffer
)) && (_stricmp(FileName
, ShortNameBuffer
) == 0))) {
599 // We found the entry, now fill in the FAT_FILE_INFO struct
601 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
602 FatFileInfoPointer
->FilePointer
= 0;
604 DPRINTM(DPRINT_FILESYSTEM
, "MSDOS Directory Entry:\n");
605 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]);
606 DPRINTM(DPRINT_FILESYSTEM
, "Attr = 0x%x\n", DirEntry
->Attr
);
607 DPRINTM(DPRINT_FILESYSTEM
, "ReservedNT = 0x%x\n", DirEntry
->ReservedNT
);
608 DPRINTM(DPRINT_FILESYSTEM
, "TimeInTenths = %d\n", DirEntry
->TimeInTenths
);
609 DPRINTM(DPRINT_FILESYSTEM
, "CreateTime = %d\n", DirEntry
->CreateTime
);
610 DPRINTM(DPRINT_FILESYSTEM
, "CreateDate = %d\n", DirEntry
->CreateDate
);
611 DPRINTM(DPRINT_FILESYSTEM
, "LastAccessDate = %d\n", DirEntry
->LastAccessDate
);
612 DPRINTM(DPRINT_FILESYSTEM
, "ClusterHigh = 0x%x\n", DirEntry
->ClusterHigh
);
613 DPRINTM(DPRINT_FILESYSTEM
, "Time = %d\n", DirEntry
->Time
);
614 DPRINTM(DPRINT_FILESYSTEM
, "Date = %d\n", DirEntry
->Date
);
615 DPRINTM(DPRINT_FILESYSTEM
, "ClusterLow = 0x%x\n", DirEntry
->ClusterLow
);
616 DPRINTM(DPRINT_FILESYSTEM
, "Size = %d\n", DirEntry
->Size
);
619 // Get the cluster chain
621 StartCluster
= ((ULONG
)DirEntry
->ClusterHigh
<< 16) + DirEntry
->ClusterLow
;
622 DPRINTM(DPRINT_FILESYSTEM
, "StartCluster = 0x%x\n", StartCluster
);
623 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(Volume
, StartCluster
);
626 // See if memory allocation failed
628 if (FatFileInfoPointer
->FileFatChain
== NULL
)
637 // Nope, no match - zero buffers and continue looking
639 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
640 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
647 static BOOLEAN
FatXSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume
, PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
652 FATX_DIRENTRY OurDirEntry
;
653 PFATX_DIRENTRY DirEntry
= &OurDirEntry
;
655 EntryCount
= DirectorySize
/ sizeof(FATX_DIRENTRY
);
657 DPRINTM(DPRINT_FILESYSTEM
, "FatXSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
);
659 FileNameLen
= strlen(FileName
);
661 for (CurrentEntry
= 0; CurrentEntry
< EntryCount
; CurrentEntry
++, DirectoryBuffer
= ((PFATX_DIRENTRY
)DirectoryBuffer
)+1)
663 OurDirEntry
= *(PFATX_DIRENTRY
) DirectoryBuffer
;
664 FatSwapFatXDirEntry(&OurDirEntry
);
665 if (0xff == DirEntry
->FileNameSize
)
669 if (0xe5 == DirEntry
->FileNameSize
)
673 if (FileNameLen
== DirEntry
->FileNameSize
&&
674 0 == _strnicmp(FileName
, DirEntry
->FileName
, FileNameLen
))
677 * We found the entry, now fill in the FAT_FILE_INFO struct
679 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
680 FatFileInfoPointer
->FilePointer
= 0;
682 DPRINTM(DPRINT_FILESYSTEM
, "FATX Directory Entry:\n");
683 DPRINTM(DPRINT_FILESYSTEM
, "FileNameSize = %d\n", DirEntry
->FileNameSize
);
684 DPRINTM(DPRINT_FILESYSTEM
, "Attr = 0x%x\n", DirEntry
->Attr
);
685 DPRINTM(DPRINT_FILESYSTEM
, "StartCluster = 0x%x\n", DirEntry
->StartCluster
);
686 DPRINTM(DPRINT_FILESYSTEM
, "Size = %d\n", DirEntry
->Size
);
687 DPRINTM(DPRINT_FILESYSTEM
, "Time = %d\n", DirEntry
->Time
);
688 DPRINTM(DPRINT_FILESYSTEM
, "Date = %d\n", DirEntry
->Date
);
689 DPRINTM(DPRINT_FILESYSTEM
, "CreateTime = %d\n", DirEntry
->CreateTime
);
690 DPRINTM(DPRINT_FILESYSTEM
, "CreateDate = %d\n", DirEntry
->CreateDate
);
691 DPRINTM(DPRINT_FILESYSTEM
, "LastAccessTime = %d\n", DirEntry
->LastAccessTime
);
692 DPRINTM(DPRINT_FILESYSTEM
, "LastAccessDate = %d\n", DirEntry
->LastAccessDate
);
695 * Get the cluster chain
697 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(Volume
, DirEntry
->StartCluster
);
700 * See if memory allocation failed
702 if (NULL
== FatFileInfoPointer
->FileFatChain
)
716 * This function searches the file system for the
717 * specified filename and fills in an FAT_FILE_INFO structure
718 * with info describing the file, etc. returns ARC error code
720 LONG
FatLookupFile(PFAT_VOLUME_INFO Volume
, PCSTR FileName
, ULONG DeviceId
, PFAT_FILE_INFO FatFileInfoPointer
)
723 ULONG NumberOfPathParts
;
725 PVOID DirectoryBuffer
;
726 ULONG DirectoryStartCluster
= 0;
728 FAT_FILE_INFO FatFileInfo
;
730 DPRINTM(DPRINT_FILESYSTEM
, "FatLookupFile() FileName = %s\n", FileName
);
732 memset(FatFileInfoPointer
, 0, sizeof(FAT_FILE_INFO
));
735 // Figure out how many sub-directories we are nested in
737 NumberOfPathParts
= FsGetNumPathParts(FileName
);
740 // Loop once for each part
742 for (i
=0; i
<NumberOfPathParts
; i
++)
745 // Get first path part
747 FsGetFirstNameFromPath(PathPart
, FileName
);
750 // Advance to the next part of the path
752 for (; (*FileName
!= '\\') && (*FileName
!= '/') && (*FileName
!= '\0'); FileName
++)
758 // Buffer the directory contents
760 DirectoryBuffer
= FatBufferDirectory(Volume
, DirectoryStartCluster
, &DirectorySize
, (i
== 0) );
761 if (DirectoryBuffer
== NULL
)
767 // Search for file name in directory
769 if (ISFATX(Volume
->FatType
))
771 if (!FatXSearchDirectoryBufferForFile(Volume
, DirectoryBuffer
, DirectorySize
, PathPart
, &FatFileInfo
))
773 MmHeapFree(DirectoryBuffer
);
779 if (!FatSearchDirectoryBufferForFile(Volume
, DirectoryBuffer
, DirectorySize
, PathPart
, &FatFileInfo
))
781 MmHeapFree(DirectoryBuffer
);
786 MmHeapFree(DirectoryBuffer
);
789 // If we have another sub-directory to go then
790 // grab the start cluster and free the fat chain array
792 if ((i
+1) < NumberOfPathParts
)
794 DirectoryStartCluster
= FatFileInfo
.FileFatChain
[0];
795 MmHeapFree(FatFileInfo
.FileFatChain
);
799 memcpy(FatFileInfoPointer
, &FatFileInfo
, sizeof(FAT_FILE_INFO
));
806 * This function parses a directory entry name which
807 * is in the form of "FILE EXT" and puts it in Buffer
808 * in the form of "file.ext"
810 void FatParseShortFileName(PCHAR Buffer
, PDIRENTRY DirEntry
)
815 RtlZeroMemory(Buffer
, 13);
818 // Fixup first character
820 if (DirEntry
->FileName
[0] == 0x05)
822 DirEntry
->FileName
[0] = 0xE5;
830 if (DirEntry
->FileName
[Idx
] == ' ')
835 Buffer
[Idx
] = DirEntry
->FileName
[Idx
];
842 if ((DirEntry
->FileName
[8] != ' '))
845 Buffer
[Idx
++] = (DirEntry
->FileName
[8] == ' ') ? '\0' : DirEntry
->FileName
[8];
846 Buffer
[Idx
++] = (DirEntry
->FileName
[9] == ' ') ? '\0' : DirEntry
->FileName
[9];
847 Buffer
[Idx
++] = (DirEntry
->FileName
[10] == ' ') ? '\0' : DirEntry
->FileName
[10];
850 DPRINTM(DPRINT_FILESYSTEM
, "FatParseShortFileName() ShortName = %s\n", Buffer
);
855 * returns the Fat entry for a given cluster number
857 BOOLEAN
FatGetFatEntry(PFAT_VOLUME_INFO Volume
, ULONG Cluster
, ULONG
* ClusterPointer
)
861 UINT32 ThisFatSecNum
;
862 UINT32 ThisFatEntOffset
;
864 DPRINTM(DPRINT_FILESYSTEM
, "FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster
);
866 switch(Volume
->FatType
)
870 FatOffset
= Cluster
+ (Cluster
/ 2);
871 ThisFatSecNum
= Volume
->ActiveFatSectorStart
+ (FatOffset
/ Volume
->BytesPerSector
);
872 ThisFatEntOffset
= (FatOffset
% Volume
->BytesPerSector
);
874 DPRINTM(DPRINT_FILESYSTEM
, "FatOffset: %d\n", FatOffset
);
875 DPRINTM(DPRINT_FILESYSTEM
, "ThisFatSecNum: %d\n", ThisFatSecNum
);
876 DPRINTM(DPRINT_FILESYSTEM
, "ThisFatEntOffset: %d\n", ThisFatEntOffset
);
878 if (ThisFatEntOffset
== (Volume
->BytesPerSector
- 1))
880 if (!FatReadVolumeSectors(Volume
, ThisFatSecNum
, 2, (PVOID
)FILESYSBUFFER
))
887 if (!FatReadVolumeSectors(Volume
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
893 fat
= *((USHORT
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
));
895 if (Cluster
& 0x0001)
896 fat
= fat
>> 4; /* Cluster number is ODD */
898 fat
= fat
& 0x0FFF; /* Cluster number is EVEN */
905 FatOffset
= (Cluster
* 2);
906 ThisFatSecNum
= Volume
->ActiveFatSectorStart
+ (FatOffset
/ Volume
->BytesPerSector
);
907 ThisFatEntOffset
= (FatOffset
% Volume
->BytesPerSector
);
909 if (!FatReadVolumeSectors(Volume
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
914 fat
= *((USHORT
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
));
922 FatOffset
= (Cluster
* 4);
923 ThisFatSecNum
= Volume
->ActiveFatSectorStart
+ (FatOffset
/ Volume
->BytesPerSector
);
924 ThisFatEntOffset
= (FatOffset
% Volume
->BytesPerSector
);
926 if (!FatReadVolumeSectors(Volume
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
932 fat
= (*((ULONG
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
))) & 0x0FFFFFFF;
938 DPRINTM(DPRINT_FILESYSTEM
, "Unknown FAT type %d\n", Volume
->FatType
);
943 DPRINTM(DPRINT_FILESYSTEM
, "FAT entry is 0x%x.\n", fat
);
945 *ClusterPointer
= fat
;
950 ULONG
FatCountClustersInChain(PFAT_VOLUME_INFO Volume
, ULONG StartCluster
)
952 ULONG ClusterCount
= 0;
954 DPRINTM(DPRINT_FILESYSTEM
, "FatCountClustersInChain() StartCluster = %d\n", StartCluster
);
959 // If end of chain then break out of our cluster counting loop
961 if (((Volume
->FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
962 ((Volume
->FatType
== FAT16
|| Volume
->FatType
== FATX16
) && (StartCluster
>= 0xfff8)) ||
963 ((Volume
->FatType
== FAT32
|| Volume
->FatType
== FATX32
) && (StartCluster
>= 0x0ffffff8)))
976 if (!FatGetFatEntry(Volume
, StartCluster
, &StartCluster
))
982 DPRINTM(DPRINT_FILESYSTEM
, "FatCountClustersInChain() ClusterCount = %d\n", ClusterCount
);
987 ULONG
* FatGetClusterChainArray(PFAT_VOLUME_INFO Volume
, ULONG StartCluster
)
994 DPRINTM(DPRINT_FILESYSTEM
, "FatGetClusterChainArray() StartCluster = %d\n", StartCluster
);
996 ClusterCount
= FatCountClustersInChain(Volume
, StartCluster
) + 1; // Lets get the 0x0ffffff8 on the end of the array
997 ArraySize
= ClusterCount
* sizeof(ULONG
);
1000 // Allocate array memory
1002 ArrayPointer
= MmHeapAlloc(ArraySize
);
1004 if (ArrayPointer
== NULL
)
1010 // Loop through and set array values
1012 for (Idx
=0; Idx
<ClusterCount
; Idx
++)
1015 // Set current cluster
1017 ArrayPointer
[Idx
] = StartCluster
;
1020 // Don't try to get next cluster for last cluster
1022 if (((Volume
->FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
1023 ((Volume
->FatType
== FAT16
|| Volume
->FatType
== FATX16
) && (StartCluster
>= 0xfff8)) ||
1024 ((Volume
->FatType
== FAT32
|| Volume
->FatType
== FATX32
) && (StartCluster
>= 0x0ffffff8)))
1033 if (!FatGetFatEntry(Volume
, StartCluster
, &StartCluster
))
1035 MmHeapFree(ArrayPointer
);
1040 return ArrayPointer
;
1044 * FatReadClusterChain()
1045 * Reads the specified clusters into memory
1047 BOOLEAN
FatReadClusterChain(PFAT_VOLUME_INFO Volume
, ULONG StartClusterNumber
, ULONG NumberOfClusters
, PVOID Buffer
)
1049 ULONG ClusterStartSector
;
1051 DPRINTM(DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
);
1053 while (NumberOfClusters
> 0)
1056 DPRINTM(DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
);
1058 // Calculate starting sector for cluster
1060 ClusterStartSector
= ((StartClusterNumber
- 2) * Volume
->SectorsPerCluster
) + Volume
->DataSectorStart
;
1063 // Read cluster into memory
1065 if (!FatReadVolumeSectors(Volume
, ClusterStartSector
, Volume
->SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1070 memcpy(Buffer
, (PVOID
)FILESYSBUFFER
, Volume
->SectorsPerCluster
* Volume
->BytesPerSector
);
1073 // Decrement count of clusters left to read
1078 // Increment buffer address by cluster size
1080 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (Volume
->SectorsPerCluster
* Volume
->BytesPerSector
));
1085 if (!FatGetFatEntry(Volume
, StartClusterNumber
, &StartClusterNumber
))
1091 // If end of chain then break out of our cluster reading loop
1093 if (((Volume
->FatType
== FAT12
) && (StartClusterNumber
>= 0xff8)) ||
1094 ((Volume
->FatType
== FAT16
|| Volume
->FatType
== FATX16
) && (StartClusterNumber
>= 0xfff8)) ||
1095 ((Volume
->FatType
== FAT32
|| Volume
->FatType
== FATX32
) && (StartClusterNumber
>= 0x0ffffff8)))
1105 * FatReadPartialCluster()
1106 * Reads part of a cluster into memory
1108 BOOLEAN
FatReadPartialCluster(PFAT_VOLUME_INFO Volume
, ULONG ClusterNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
)
1110 ULONG ClusterStartSector
;
1112 DPRINTM(DPRINT_FILESYSTEM
, "FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber
, StartingOffset
, Length
, Buffer
);
1114 ClusterStartSector
= ((ClusterNumber
- 2) * Volume
->SectorsPerCluster
) + Volume
->DataSectorStart
;
1116 if (!FatReadVolumeSectors(Volume
, ClusterStartSector
, Volume
->SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1121 memcpy(Buffer
, (PVOID
)((ULONG_PTR
)FILESYSBUFFER
+ StartingOffset
), Length
);
1128 * Reads BytesToRead from open file and
1129 * returns the number of bytes read in BytesRead
1131 BOOLEAN
FatReadFile(PFAT_FILE_INFO FatFileInfo
, ULONG BytesToRead
, ULONG
* BytesRead
, PVOID Buffer
)
1133 PFAT_VOLUME_INFO Volume
= FatFileInfo
->Volume
;
1134 ULONG ClusterNumber
;
1135 ULONG OffsetInCluster
;
1136 ULONG LengthInCluster
;
1137 ULONG NumberOfClusters
;
1138 ULONG BytesPerCluster
;
1140 DPRINTM(DPRINT_FILESYSTEM
, "FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead
, Buffer
);
1142 if (BytesRead
!= NULL
)
1148 // If they are trying to read past the
1149 // end of the file then return success
1150 // with BytesRead == 0
1152 if (FatFileInfo
->FilePointer
>= FatFileInfo
->FileSize
)
1158 // If they are trying to read more than there is to read
1159 // then adjust the amount to read
1161 if ((FatFileInfo
->FilePointer
+ BytesToRead
) > FatFileInfo
->FileSize
)
1163 BytesToRead
= (FatFileInfo
->FileSize
- FatFileInfo
->FilePointer
);
1167 // Ok, now we have to perform at most 3 calculations
1168 // I'll draw you a picture (using nifty ASCII art):
1170 // CurrentFilePointer -+
1172 // +----------------+
1174 // +-----------+-----------+-----------+-----------+
1175 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
1176 // +-----------+-----------+-----------+-----------+
1178 // +---------------+--------------------+
1180 // BytesToRead -------+
1182 // 1 - The first calculation (and read) will align
1183 // the file pointer with the next cluster.
1184 // boundary (if we are supposed to read that much)
1185 // 2 - The next calculation (and read) will read
1186 // in all the full clusters that the requested
1187 // amount of data would cover (in this case
1189 // 3 - The last calculation (and read) would read
1190 // in the remainder of the data requested out of
1191 // the last cluster.
1194 BytesPerCluster
= Volume
->SectorsPerCluster
* Volume
->BytesPerSector
;
1197 // Only do the first read if we
1198 // aren't aligned on a cluster boundary
1200 if (FatFileInfo
->FilePointer
% BytesPerCluster
)
1203 // Do the math for our first read
1205 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1206 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1207 OffsetInCluster
= (FatFileInfo
->FilePointer
% BytesPerCluster
);
1208 LengthInCluster
= (BytesToRead
> (BytesPerCluster
- OffsetInCluster
)) ? (BytesPerCluster
- OffsetInCluster
) : BytesToRead
;
1211 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1213 if (!FatReadPartialCluster(Volume
, ClusterNumber
, OffsetInCluster
, LengthInCluster
, Buffer
))
1217 if (BytesRead
!= NULL
)
1219 *BytesRead
+= LengthInCluster
;
1221 BytesToRead
-= LengthInCluster
;
1222 FatFileInfo
->FilePointer
+= LengthInCluster
;
1223 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ LengthInCluster
);
1227 // Do the math for our second read (if any data left)
1229 if (BytesToRead
> 0)
1232 // Determine how many full clusters we need to read
1234 NumberOfClusters
= (BytesToRead
/ BytesPerCluster
);
1236 if (NumberOfClusters
> 0)
1238 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1239 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1242 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1244 if (!FatReadClusterChain(Volume
, ClusterNumber
, NumberOfClusters
, Buffer
))
1248 if (BytesRead
!= NULL
)
1250 *BytesRead
+= (NumberOfClusters
* BytesPerCluster
);
1252 BytesToRead
-= (NumberOfClusters
* BytesPerCluster
);
1253 FatFileInfo
->FilePointer
+= (NumberOfClusters
* BytesPerCluster
);
1254 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (NumberOfClusters
* BytesPerCluster
));
1259 // Do the math for our third read (if any data left)
1261 if (BytesToRead
> 0)
1263 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1264 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1267 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1269 if (!FatReadPartialCluster(Volume
, ClusterNumber
, 0, BytesToRead
, Buffer
))
1273 if (BytesRead
!= NULL
)
1275 *BytesRead
+= BytesToRead
;
1277 FatFileInfo
->FilePointer
+= BytesToRead
;
1278 BytesToRead
-= BytesToRead
;
1279 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ BytesToRead
);
1285 BOOLEAN
FatReadVolumeSectors(PFAT_VOLUME_INFO Volume
, ULONG SectorNumber
, ULONG SectorCount
, PVOID Buffer
)
1287 LARGE_INTEGER Position
;
1291 DPRINTM(DPRINT_FILESYSTEM
, "FatReadVolumeSectors(): SectorNumber %d, SectorCount %d, Buffer %p\n",
1292 SectorNumber
, SectorCount
, Buffer
);
1295 // Seek to right position
1297 Position
.QuadPart
= SectorNumber
* 512;
1298 ret
= ArcSeek(Volume
->DeviceId
, &Position
, SeekAbsolute
);
1299 if (ret
!= ESUCCESS
)
1301 DPRINTM(DPRINT_FILESYSTEM
, "FatReadVolumeSectors() Failed to seek\n");
1308 ret
= ArcRead(Volume
->DeviceId
, Buffer
, SectorCount
* 512, &Count
);
1309 if (ret
!= ESUCCESS
|| Count
!= SectorCount
* 512)
1311 DPRINTM(DPRINT_FILESYSTEM
, "FatReadVolumeSectors() Failed to read\n");
1319 LONG
FatClose(ULONG FileId
)
1321 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1323 MmHeapFree(FileHandle
);
1328 LONG
FatGetFileInformation(ULONG FileId
, FILEINFORMATION
* Information
)
1330 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1332 RtlZeroMemory(Information
, sizeof(FILEINFORMATION
));
1333 Information
->EndingAddress
.LowPart
= FileHandle
->FileSize
;
1334 Information
->CurrentAddress
.LowPart
= FileHandle
->FilePointer
;
1336 DPRINTM(DPRINT_FILESYSTEM
, "FatGetFileInformation() FileSize = %d\n",
1337 Information
->EndingAddress
.LowPart
);
1338 DPRINTM(DPRINT_FILESYSTEM
, "FatGetFileInformation() FilePointer = %d\n",
1339 Information
->CurrentAddress
.LowPart
);
1344 LONG
FatOpen(CHAR
* Path
, OPENMODE OpenMode
, ULONG
* FileId
)
1346 FAT_FILE_INFO TempFileInfo
;
1347 PFAT_FILE_INFO FileHandle
;
1351 if (OpenMode
!= OpenReadOnly
)
1354 DeviceId
= FsGetDeviceId(*FileId
);
1356 DPRINTM(DPRINT_FILESYSTEM
, "FatOpen() FileName = %s\n", Path
);
1358 RtlZeroMemory(&TempFileInfo
, sizeof(TempFileInfo
));
1359 ret
= FatLookupFile(FatVolume
, Path
, DeviceId
, &TempFileInfo
);
1360 if (ret
!= ESUCCESS
)
1363 FileHandle
= MmHeapAlloc(sizeof(FAT_FILE_INFO
));
1367 RtlCopyMemory(FileHandle
, &TempFileInfo
, sizeof(FAT_FILE_INFO
));
1368 FileHandle
->Volume
= FatVolume
;
1370 FsSetDeviceSpecific(*FileId
, FileHandle
);
1374 LONG
FatRead(ULONG FileId
, VOID
* Buffer
, ULONG N
, ULONG
* Count
)
1376 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1380 // Call old read method
1382 ret
= FatReadFile(FileHandle
, N
, Count
, Buffer
);
1385 // Check for success
1393 LONG
FatSeek(ULONG FileId
, LARGE_INTEGER
* Position
, SEEKMODE SeekMode
)
1395 PFAT_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1397 DPRINTM(DPRINT_FILESYSTEM
, "FatSeek() NewFilePointer = %lu\n", Position
->LowPart
);
1399 if (SeekMode
!= SeekAbsolute
)
1401 if (Position
->HighPart
!= 0)
1403 if (Position
->LowPart
>= FileHandle
->FileSize
)
1406 FileHandle
->FilePointer
= Position
->LowPart
;
1410 const DEVVTBL FatFuncTable
=
1413 FatGetFileInformation
,
1419 const DEVVTBL
* FatMount(ULONG DeviceId
)
1421 PFAT_VOLUME_INFO Volume
;
1423 PFAT_BOOTSECTOR BootSector
= (PFAT_BOOTSECTOR
)Buffer
;
1424 PFAT32_BOOTSECTOR BootSector32
= (PFAT32_BOOTSECTOR
)Buffer
;
1425 PFATX_BOOTSECTOR BootSectorX
= (PFATX_BOOTSECTOR
)Buffer
;
1426 FILEINFORMATION FileInformation
;
1427 LARGE_INTEGER Position
;
1429 ULARGE_INTEGER SectorCount
;
1433 // Allocate data for volume information
1435 Volume
= MmHeapAlloc(sizeof(FAT_VOLUME_INFO
));
1438 RtlZeroMemory(Volume
, sizeof(FAT_VOLUME_INFO
));
1441 // Read the BootSector
1443 Position
.HighPart
= 0;
1444 Position
.LowPart
= 0;
1445 ret
= ArcSeek(DeviceId
, &Position
, SeekAbsolute
);
1446 if (ret
!= ESUCCESS
)
1451 ret
= ArcRead(DeviceId
, Buffer
, sizeof(Buffer
), &Count
);
1452 if (ret
!= ESUCCESS
|| Count
!= sizeof(Buffer
))
1459 // Check if BootSector is valid. If no, return early
1461 if (!RtlEqualMemory(BootSector
->FileSystemType
, "FAT12 ", 8) &&
1462 !RtlEqualMemory(BootSector
->FileSystemType
, "FAT16 ", 8) &&
1463 !RtlEqualMemory(BootSector32
->FileSystemType
, "FAT32 ", 8) &&
1464 !RtlEqualMemory(BootSectorX
->FileSystemType
, "FATX", 4))
1471 // Determine sector count
1473 ret
= ArcGetFileInformation(DeviceId
, &FileInformation
);
1474 if (ret
!= ESUCCESS
)
1479 SectorCount
.HighPart
= FileInformation
.EndingAddress
.HighPart
;
1480 SectorCount
.LowPart
= FileInformation
.EndingAddress
.LowPart
;
1481 SectorCount
.QuadPart
/= SECTOR_SIZE
;
1486 Volume
->DeviceId
= DeviceId
;
1489 // Really open the volume
1491 if (!FatOpenVolume(Volume
, BootSector
, SectorCount
.QuadPart
))
1498 // HACK: for now, only support one FAT volume
1510 return &FatFuncTable
;