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