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