ReactOS 0.4.16-dev-1946-g52006dd
fat.c
Go to the documentation of this file.
1/*
2 * PROJECT: FreeLoader
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: FAT filesystem driver for FreeLoader
5 * COPYRIGHT: Copyright 1998-2003 Brian Palmer (brianp@sginet.com)
6 * Copyright 2009 Hervé Poussineau
7 * Copyright 2019 Victor Perevertkin (victor.perevertkin@reactos.org)
8 */
9
10#include <freeldr.h>
11
12#include <debug.h>
14
16PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, ULONG* EntryCountPointer, BOOLEAN RootDirectory);
19static BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, UINT32 Cluster, PUINT32 ClusterPointer);
21static BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, UINT32 StartClusterNumber, UINT32 NumberOfClusters, PVOID Buffer, PUINT32 LastClusterNumber);
24
25#define FAT_IS_END_CLUSTER(clnumber) \
26 (((Volume->FatType == FAT12) && (clnumber >= 0xff8)) || \
27 ((Volume->FatType == FAT16 || Volume->FatType == FATX16) && (clnumber >= 0xfff8)) || \
28 ((Volume->FatType == FAT32 || Volume->FatType == FATX32) && (clnumber >= 0x0ffffff8)))
29
30#define TAG_FAT_CHAIN 'CtaT'
31#define TAG_FAT_FILE 'FtaF'
32#define TAG_FAT_VOLUME 'VtaF'
33#define TAG_FAT_BUFFER 'BtaF'
34#define TAG_FAT_CACHE 'HtaF'
35
36#define FAT_MAX_CACHE_SIZE (256 * 1024) // 256 KiB, note: it should fit maximum FAT12 FAT size (6144 bytes)
37
38typedef struct _FAT_VOLUME_INFO
39{
40 PUCHAR FatCache; /* A part of 1st FAT cached in memory */
41 PULONG FatCacheIndex; /* Cached sector's indexes */
42 ULONG FatCacheSize; /* Size of the cache in sectors */
43 ULONG FatSectorStart; /* Starting sector of 1st FAT table */
44 ULONG ActiveFatSectorStart; /* Starting sector of active FAT table */
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 NumberOfClusters; /* Number of clusters of the data area */
52 ULONG TotalSectors; /* Total number of sectors on the volume */
53 UINT16 BytesPerSector; /* Number of bytes per sector */
54 UINT8 SectorsPerCluster; /* Number of sectors per cluster */
55 UINT8 NumberOfFats; /* Number of FAT tables */
56 UINT8 FatType; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
58
60
62{
63 SW(Obj, BytesPerSector);
64 SW(Obj, ReservedSectors);
65 SW(Obj, RootDirEntries);
66 SW(Obj, TotalSectors);
67 SW(Obj, SectorsPerFat);
70 SD(Obj, HiddenSectors);
71 SD(Obj, TotalSectorsBig);
72 SD(Obj, VolumeSerialNumber);
73 SW(Obj, BootSectorMagic);
74}
75
77{
78 SW(Obj, BytesPerSector);
79 SW(Obj, ReservedSectors);
80 SW(Obj, RootDirEntries);
81 SW(Obj, TotalSectors);
82 SW(Obj, SectorsPerFat);
84 SD(Obj, HiddenSectors);
85 SD(Obj, TotalSectorsBig);
86 SD(Obj, SectorsPerFatBig);
87 SW(Obj, ExtendedFlags);
88 SW(Obj, FileSystemVersion);
89 SD(Obj, RootDirStartCluster);
90 SW(Obj, FsInfo);
92 SD(Obj, VolumeSerialNumber);
93 SW(Obj, BootSectorMagic);
94}
95
97{
98 SD(Obj, VolumeSerialNumber);
99 SD(Obj, SectorsPerCluster);
100 SW(Obj, NumberOfFats);
101}
102
104{
105 SW(Obj, CreateTime);
106 SW(Obj, CreateDate);
107 SW(Obj, LastAccessDate);
108 SW(Obj, ClusterHigh);
109 SW(Obj, Time);
110 SW(Obj, Date);
111 SW(Obj, ClusterLow);
112 SD(Obj, Size);
113}
114
116{
117 int i;
118 SW(Obj, StartCluster);
119 for(i = 0; i < 5; i++)
120 Obj->Name0_4[i] = SWAPW(Obj->Name0_4[i]);
121 for(i = 0; i < 6; i++)
122 Obj->Name5_10[i] = SWAPW(Obj->Name5_10[i]);
123 for(i = 0; i < 2; i++)
124 Obj->Name11_12[i] = SWAPW(Obj->Name11_12[i]);
125}
126
128{
129 SD(Obj, StartCluster);
130 SD(Obj, Size);
131 SW(Obj, Time);
132 SW(Obj, Date);
133 SW(Obj, CreateTime);
134 SW(Obj, CreateDate);
135 SW(Obj, LastAccessTime);
136 SW(Obj, LastAccessDate);
137}
138
153ULONG
156{
157 return ((Volume->TotalSectors - Volume->DataSectorStart) / Volume->SectorsPerCluster);
158}
159
161{
162 char ErrMsg[80];
163 ULONG FatSize, i;
164 PFAT_BOOTSECTOR FatVolumeBootSector;
165 PFAT32_BOOTSECTOR Fat32VolumeBootSector;
166 PFATX_BOOTSECTOR FatXVolumeBootSector;
167
168 TRACE("FatOpenVolume() DeviceId = %d\n", Volume->DeviceId);
169
170 //
171 // Allocate the memory to hold the boot sector
172 //
173 FatVolumeBootSector = (PFAT_BOOTSECTOR)BootSector;
174 Fat32VolumeBootSector = (PFAT32_BOOTSECTOR)BootSector;
175 FatXVolumeBootSector = (PFATX_BOOTSECTOR)BootSector;
176
177 // Get the FAT type
178 Volume->FatType = FatDetermineFatType(FatVolumeBootSector, PartitionSectorCount);
179
180 // Dump boot sector (and swap it for big endian systems)
181 TRACE("Dumping boot sector:\n");
182 if (ISFATX(Volume->FatType))
183 {
184 FatSwapFatXBootSector(FatXVolumeBootSector);
185 TRACE("sizeof(FATX_BOOTSECTOR) = 0x%x.\n", sizeof(FATX_BOOTSECTOR));
186
187 TRACE("FileSystemType: %c%c%c%c.\n", FatXVolumeBootSector->FileSystemType[0], FatXVolumeBootSector->FileSystemType[1], FatXVolumeBootSector->FileSystemType[2], FatXVolumeBootSector->FileSystemType[3]);
188 TRACE("VolumeSerialNumber: 0x%x\n", FatXVolumeBootSector->VolumeSerialNumber);
189 TRACE("SectorsPerCluster: %d\n", FatXVolumeBootSector->SectorsPerCluster);
190 TRACE("NumberOfFats: %d\n", FatXVolumeBootSector->NumberOfFats);
191 TRACE("Unknown: 0x%x\n", FatXVolumeBootSector->Unknown);
192
193 TRACE("FatType %s\n", Volume->FatType == FATX16 ? "FATX16" : "FATX32");
194
195 }
196 else if (Volume->FatType == FAT32)
197 {
198 FatSwapFat32BootSector(Fat32VolumeBootSector);
199 TRACE("sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR));
200
201 TRACE("JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector->JumpBoot[0], Fat32VolumeBootSector->JumpBoot[1], Fat32VolumeBootSector->JumpBoot[2]);
202 TRACE("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]);
203 TRACE("BytesPerSector: %d\n", Fat32VolumeBootSector->BytesPerSector);
204 TRACE("SectorsPerCluster: %d\n", Fat32VolumeBootSector->SectorsPerCluster);
205 TRACE("ReservedSectors: %d\n", Fat32VolumeBootSector->ReservedSectors);
206 TRACE("NumberOfFats: %d\n", Fat32VolumeBootSector->NumberOfFats);
207 TRACE("RootDirEntries: %d\n", Fat32VolumeBootSector->RootDirEntries);
208 TRACE("TotalSectors: %d\n", Fat32VolumeBootSector->TotalSectors);
209 TRACE("MediaDescriptor: 0x%x\n", Fat32VolumeBootSector->MediaDescriptor);
210 TRACE("SectorsPerFat: %d\n", Fat32VolumeBootSector->SectorsPerFat);
211 TRACE("SectorsPerTrack: %d\n", Fat32VolumeBootSector->SectorsPerTrack);
212 TRACE("NumberOfHeads: %d\n", Fat32VolumeBootSector->NumberOfHeads);
213 TRACE("HiddenSectors: %d\n", Fat32VolumeBootSector->HiddenSectors);
214 TRACE("TotalSectorsBig: %d\n", Fat32VolumeBootSector->TotalSectorsBig);
215 TRACE("SectorsPerFatBig: %d\n", Fat32VolumeBootSector->SectorsPerFatBig);
216 TRACE("ExtendedFlags: 0x%x\n", Fat32VolumeBootSector->ExtendedFlags);
217 TRACE("FileSystemVersion: 0x%x\n", Fat32VolumeBootSector->FileSystemVersion);
218 TRACE("RootDirStartCluster: %d\n", Fat32VolumeBootSector->RootDirStartCluster);
219 TRACE("FsInfo: %d\n", Fat32VolumeBootSector->FsInfo);
220 TRACE("BackupBootSector: %d\n", Fat32VolumeBootSector->BackupBootSector);
221 TRACE("Reserved: 0x%x\n", Fat32VolumeBootSector->Reserved);
222 TRACE("DriveNumber: 0x%x\n", Fat32VolumeBootSector->DriveNumber);
223 TRACE("Reserved1: 0x%x\n", Fat32VolumeBootSector->Reserved1);
224 TRACE("BootSignature: 0x%x\n", Fat32VolumeBootSector->BootSignature);
225 TRACE("VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector->VolumeSerialNumber);
226 TRACE("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]);
227 TRACE("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]);
228 TRACE("BootSectorMagic: 0x%x\n", Fat32VolumeBootSector->BootSectorMagic);
229 }
230 else
231 {
232 FatSwapFatBootSector(FatVolumeBootSector);
233 TRACE("sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR));
234
235 TRACE("JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector->JumpBoot[0], FatVolumeBootSector->JumpBoot[1], FatVolumeBootSector->JumpBoot[2]);
236 TRACE("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]);
237 TRACE("BytesPerSector: %d\n", FatVolumeBootSector->BytesPerSector);
238 TRACE("SectorsPerCluster: %d\n", FatVolumeBootSector->SectorsPerCluster);
239 TRACE("ReservedSectors: %d\n", FatVolumeBootSector->ReservedSectors);
240 TRACE("NumberOfFats: %d\n", FatVolumeBootSector->NumberOfFats);
241 TRACE("RootDirEntries: %d\n", FatVolumeBootSector->RootDirEntries);
242 TRACE("TotalSectors: %d\n", FatVolumeBootSector->TotalSectors);
243 TRACE("MediaDescriptor: 0x%x\n", FatVolumeBootSector->MediaDescriptor);
244 TRACE("SectorsPerFat: %d\n", FatVolumeBootSector->SectorsPerFat);
245 TRACE("SectorsPerTrack: %d\n", FatVolumeBootSector->SectorsPerTrack);
246 TRACE("NumberOfHeads: %d\n", FatVolumeBootSector->NumberOfHeads);
247 TRACE("HiddenSectors: %d\n", FatVolumeBootSector->HiddenSectors);
248 TRACE("TotalSectorsBig: %d\n", FatVolumeBootSector->TotalSectorsBig);
249 TRACE("DriveNumber: 0x%x\n", FatVolumeBootSector->DriveNumber);
250 TRACE("Reserved1: 0x%x\n", FatVolumeBootSector->Reserved1);
251 TRACE("BootSignature: 0x%x\n", FatVolumeBootSector->BootSignature);
252 TRACE("VolumeSerialNumber: 0x%x\n", FatVolumeBootSector->VolumeSerialNumber);
253 TRACE("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]);
254 TRACE("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]);
255 TRACE("BootSectorMagic: 0x%x\n", FatVolumeBootSector->BootSectorMagic);
256 }
257
258 //
259 // Check the boot sector magic
260 //
261 if (! ISFATX(Volume->FatType) && FatVolumeBootSector->BootSectorMagic != 0xaa55)
262 {
263 sprintf(ErrMsg, "Invalid boot sector magic (expected 0xaa55 found 0x%x)",
264 FatVolumeBootSector->BootSectorMagic);
266 return FALSE;
267 }
268
269 //
270 // Check the FAT cluster size
271 // We do not support clusters bigger than 64k
272 //
273 if ((ISFATX(Volume->FatType) && 64 * 1024 < FatXVolumeBootSector->SectorsPerCluster * 512) ||
274 (! ISFATX(Volume->FatType) && 64 * 1024 < FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector))
275 {
276 FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
277 return FALSE;
278 }
279
280 if (ISFATX(Volume->FatType))
281 {
282 Volume->TotalSectors = PartitionSectorCount;
283 }
284 else
285 {
286 /*
287 * After DOS 4.0, at least one of TotalSectors or TotalSectorsBig will be zero.
288 * In DOS version 3.2 or before, both of these might contain some value,
289 * because, before 3.2, there was no TotalSectorsBig entry. Thus some disks
290 * might have an unexpected value in the field, and we will use TotalSectorsBig
291 * only if TotalSectors equals zero.
292 */
293 C_ASSERT(FIELD_OFFSET(FAT_BOOTSECTOR, TotalSectors) ==
294 FIELD_OFFSET(FAT32_BOOTSECTOR, TotalSectors));
295 C_ASSERT(FIELD_OFFSET(FAT_BOOTSECTOR, TotalSectorsBig) ==
296 FIELD_OFFSET(FAT32_BOOTSECTOR, TotalSectorsBig));
297 Volume->TotalSectors = (FatVolumeBootSector->TotalSectors ? FatVolumeBootSector->TotalSectors
298 : FatVolumeBootSector->TotalSectorsBig);
299 }
300
301 /* Get the sectors per FAT, root directory sector start, and data sector start */
302 if (ISFATX(Volume->FatType))
303 {
304 Volume->BytesPerSector = SECTOR_SIZE;
305 Volume->SectorsPerCluster = SWAPD(FatXVolumeBootSector->SectorsPerCluster);
306 Volume->FatSectorStart = 4096 / Volume->BytesPerSector;
307 Volume->ActiveFatSectorStart = Volume->FatSectorStart;
308 Volume->NumberOfFats = 1; // FatXVolumeBootSector->NumberOfFats;
309 FatSize = (ULONG)(PartitionSectorCount / Volume->SectorsPerCluster *
310 (Volume->FatType == FATX16 ? 2 : 4));
311 Volume->SectorsPerFat = ROUND_UP(FatSize, 4096) / Volume->BytesPerSector;
312
313 Volume->RootDirSectorStart = Volume->FatSectorStart + Volume->NumberOfFats * Volume->SectorsPerFat;
314 Volume->RootDirSectors = FatXVolumeBootSector->SectorsPerCluster;
315
316 Volume->DataSectorStart = Volume->RootDirSectorStart + Volume->RootDirSectors;
317 }
318 else if (Volume->FatType != FAT32)
319 {
320 Volume->BytesPerSector = FatVolumeBootSector->BytesPerSector;
321 Volume->SectorsPerCluster = FatVolumeBootSector->SectorsPerCluster;
322 Volume->FatSectorStart = FatVolumeBootSector->ReservedSectors;
323 Volume->ActiveFatSectorStart = Volume->FatSectorStart;
324 Volume->NumberOfFats = FatVolumeBootSector->NumberOfFats;
325 Volume->SectorsPerFat = FatVolumeBootSector->SectorsPerFat;
326
327 Volume->RootDirSectorStart = Volume->FatSectorStart + Volume->NumberOfFats * Volume->SectorsPerFat;
328 Volume->RootDirSectors = ((FatVolumeBootSector->RootDirEntries * 32) + (Volume->BytesPerSector - 1)) / Volume->BytesPerSector;
329 // Volume->RootDirSectors = (FatVolumeBootSector->RootDirEntries * sizeof(DIRENT) / Volume->BytesPerSector);
330
331 Volume->DataSectorStart = Volume->RootDirSectorStart + Volume->RootDirSectors;
332 }
333 else
334 {
335 Volume->BytesPerSector = Fat32VolumeBootSector->BytesPerSector;
336 Volume->SectorsPerCluster = Fat32VolumeBootSector->SectorsPerCluster;
337 Volume->FatSectorStart = Fat32VolumeBootSector->ReservedSectors;
338 Volume->ActiveFatSectorStart =
339 Volume->FatSectorStart + ((Fat32VolumeBootSector->ExtendedFlags & 0x80) ?
340 ((Fat32VolumeBootSector->ExtendedFlags & 0x0f) * Fat32VolumeBootSector->SectorsPerFatBig) : 0);
341 Volume->NumberOfFats = Fat32VolumeBootSector->NumberOfFats;
342 Volume->SectorsPerFat = Fat32VolumeBootSector->SectorsPerFatBig;
343 // Volume->SectorsPerFat = (Fat32VolumeBootSector->SectorsPerFat ? Fat32VolumeBootSector->SectorsPerFat : Fat32VolumeBootSector->SectorsPerFatBig);
344
345 Volume->RootDirStartCluster = Fat32VolumeBootSector->RootDirStartCluster;
346 Volume->DataSectorStart = Volume->FatSectorStart + Volume->NumberOfFats * Volume->SectorsPerFat;
347
348 //
349 // Check version
350 // we only work with version 0
351 //
352 if (Fat32VolumeBootSector->FileSystemVersion != 0)
353 {
354 FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
355 return FALSE;
356 }
357 }
358 // Volume->NumberOfClusters = FatNumberOfClusters(Volume);
359
360 Volume->FatCacheSize = min(Volume->SectorsPerFat, FAT_MAX_CACHE_SIZE / Volume->BytesPerSector);
361 TRACE("FAT cache is %d sectors, %d bytes\n", Volume->FatCacheSize, Volume->FatCacheSize * Volume->BytesPerSector);
362
363 Volume->FatCache = FrLdrTempAlloc(Volume->FatCacheSize * Volume->BytesPerSector, TAG_FAT_CACHE);
364 if (!Volume->FatCache)
365 {
366 FileSystemError("Cannot allocate memory for FAT cache");
367 return FALSE;
368 }
369
370 Volume->FatCacheIndex = FrLdrTempAlloc(Volume->FatCacheSize * sizeof(*Volume->FatCacheIndex), TAG_FAT_VOLUME);
371 if (!Volume->FatCacheIndex)
372 {
373 FileSystemError("Cannot allocate memory for FAT cache index");
375 return FALSE;
376 }
377
378 // read the beginning of the FAT (or the whole one) to cache
379 if (!FatReadVolumeSectors(Volume, Volume->ActiveFatSectorStart, Volume->FatCacheSize, Volume->FatCache))
380 {
381 FileSystemError("Error when reading FAT cache");
383 FrLdrTempFree(Volume->FatCacheIndex, TAG_FAT_VOLUME);
384 return FALSE;
385 }
386
387 // fill the index with sector numbers
388 for (i = 0; i < Volume->FatCacheSize; i++)
389 {
390 Volume->FatCacheIndex[i] = Volume->ActiveFatSectorStart + i;
391 }
392
393 return TRUE;
394}
395
397{
398 ULONG RootDirSectors;
399 ULONG DataSectorCount;
400 ULONG SectorsPerFat;
401 ULONG TotalSectors;
402 ULONG CountOfClusters;
403 PFAT32_BOOTSECTOR Fat32BootSector = (PFAT32_BOOTSECTOR)FatBootSector;
404 PFATX_BOOTSECTOR FatXBootSector = (PFATX_BOOTSECTOR)FatBootSector;
405
406 if (0 == strncmp(FatXBootSector->FileSystemType, "FATX", 4))
407 {
408 CountOfClusters = (ULONG)(PartitionSectorCount / FatXBootSector->SectorsPerCluster);
409 if (CountOfClusters < 65525)
410 {
411 /* Volume is FATX16 */
412 return FATX16;
413 }
414 else
415 {
416 /* Volume is FAT32 */
417 return FATX32;
418 }
419 }
420 else
421 {
422 RootDirSectors = ((SWAPW(FatBootSector->RootDirEntries) * 32) + (SWAPW(FatBootSector->BytesPerSector) - 1)) / SWAPW(FatBootSector->BytesPerSector);
423 SectorsPerFat = SWAPW(FatBootSector->SectorsPerFat) ? SWAPW(FatBootSector->SectorsPerFat) : SWAPD(Fat32BootSector->SectorsPerFatBig);
424 TotalSectors = SWAPW(FatBootSector->TotalSectors) ? SWAPW(FatBootSector->TotalSectors) : SWAPD(FatBootSector->TotalSectorsBig);
425 DataSectorCount = TotalSectors - (SWAPW(FatBootSector->ReservedSectors) + (FatBootSector->NumberOfFats * SectorsPerFat) + RootDirSectors);
426
427//mjl
428 if (FatBootSector->SectorsPerCluster == 0)
429 CountOfClusters = 0;
430 else
431 CountOfClusters = DataSectorCount / FatBootSector->SectorsPerCluster;
432
433 if (CountOfClusters < 4085)
434 {
435 /* Volume is FAT12 */
436 return FAT12;
437 }
438 else if (CountOfClusters < 65525)
439 {
440 /* Volume is FAT16 */
441 return FAT16;
442 }
443 else
444 {
445 /* Volume is FAT32 */
446 return FAT32;
447 }
448 }
449}
450
451typedef struct _DIRECTORY_BUFFER
452{
459
461
463{
464 PDIRECTORY_BUFFER DirectoryBuffer;
466
467 TRACE("FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster, (RootDirectory ? "TRUE" : "FALSE"));
468
469 /*
470 * For FAT32, the root directory is nothing special. We can treat it the same
471 * as a subdirectory.
472 */
473 if (RootDirectory && Volume->FatType == FAT32)
474 {
475 DirectoryStartCluster = Volume->RootDirStartCluster;
477 }
478
479 /* Search the list for a match */
482 Entry = Entry->Flink)
483 {
484 DirectoryBuffer = CONTAINING_RECORD(Entry, DIRECTORY_BUFFER, Link);
485
486 /* Check if it matches */
487 if ((DirectoryBuffer->Volume == Volume) &&
488 (DirectoryBuffer->DirectoryStartCluster == DirectoryStartCluster))
489 {
490 TRACE("Found cached buffer\n");
491 *DirectorySize = DirectoryBuffer->DirectorySize;
492 return DirectoryBuffer->Data;
493 }
494 }
495
496 //
497 // Calculate the size of the directory
498 //
499 if (RootDirectory)
500 {
501 *DirectorySize = Volume->RootDirSectors * Volume->BytesPerSector;
502 }
503 else
504 {
505 *DirectorySize = FatCountClustersInChain(Volume, DirectoryStartCluster) * Volume->SectorsPerCluster * Volume->BytesPerSector;
506 }
507
508 //
509 // Attempt to allocate memory for directory buffer
510 //
511 TRACE("Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize);
512 DirectoryBuffer = FrLdrTempAlloc(*DirectorySize + sizeof(DIRECTORY_BUFFER),
514
515 if (DirectoryBuffer == NULL)
516 {
517 return NULL;
518 }
519
520 //
521 // Now read directory contents into DirectoryBuffer
522 //
523 if (RootDirectory)
524 {
525 if (!FatReadVolumeSectors(Volume, Volume->RootDirSectorStart, Volume->RootDirSectors, DirectoryBuffer->Data))
526 {
527 FrLdrTempFree(DirectoryBuffer, TAG_FAT_BUFFER);
528 return NULL;
529 }
530 }
531 else
532 {
533 if (!FatReadClusterChain(Volume, DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer->Data, NULL))
534 {
535 FrLdrTempFree(DirectoryBuffer, TAG_FAT_BUFFER);
536 return NULL;
537 }
538 }
539
540 /* Enqueue it in the list */
541 DirectoryBuffer->Volume = Volume;
542 DirectoryBuffer->DirectoryStartCluster = DirectoryStartCluster;
543 DirectoryBuffer->DirectorySize = *DirectorySize;
544 InsertTailList(&DirectoryBufferListHead, &DirectoryBuffer->Link);
545
546 return DirectoryBuffer->Data;
547}
548
549static BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
550{
551 ULONG EntryCount;
552 ULONG CurrentEntry;
553 CHAR LfnNameBuffer[265];
554 CHAR ShortNameBuffer[20];
555 ULONG StartCluster;
556 DIRENTRY OurDirEntry;
557 LFN_DIRENTRY OurLfnDirEntry;
558 PDIRENTRY DirEntry = &OurDirEntry;
559 PLFN_DIRENTRY LfnDirEntry = &OurLfnDirEntry;
560
561 EntryCount = DirectorySize / sizeof(DIRENTRY);
562
563 TRACE("FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer, EntryCount, FileName);
564
565 RtlZeroMemory(ShortNameBuffer, 13 * sizeof(CHAR));
566 RtlZeroMemory(LfnNameBuffer, 261 * sizeof(CHAR));
567
568 for (CurrentEntry=0; CurrentEntry<EntryCount; CurrentEntry++, DirectoryBuffer = ((PDIRENTRY)DirectoryBuffer)+1)
569 {
570 OurLfnDirEntry = *((PLFN_DIRENTRY) DirectoryBuffer);
571 FatSwapLFNDirEntry(LfnDirEntry);
572 OurDirEntry = *((PDIRENTRY) DirectoryBuffer);
574
575 //TRACE("Dumping directory entry %d:\n", CurrentEntry);
576 //DbgDumpBuffer(DPRINT_FILESYSTEM, DirEntry, sizeof(DIRENTRY));
577
578 //
579 // Check if this is the last file in the directory
580 // If DirEntry[0] == 0x00 then that means all the
581 // entries after this one are unused. If this is the
582 // last entry then we didn't find the file in this directory.
583 //
584 if (DirEntry->FileName[0] == '\0')
585 {
586 return FALSE;
587 }
588
589 //
590 // Check if this is a deleted entry or not
591 //
592 if (DirEntry->FileName[0] == '\xE5')
593 {
594 RtlZeroMemory(ShortNameBuffer, 13 * sizeof(CHAR));
595 RtlZeroMemory(LfnNameBuffer, 261 * sizeof(CHAR));
596 continue;
597 }
598
599 //
600 // Check if this is a LFN entry
601 // If so it needs special handling
602 //
603 if (DirEntry->Attr == FAT_ATTR_LONG_NAME)
604 {
605 //
606 // Check to see if this is a deleted LFN entry, if so continue
607 //
608 if (LfnDirEntry->SequenceNumber & 0x80)
609 {
610 continue;
611 }
612
613 //
614 // Mask off high two bits of sequence number
615 // and make the sequence number zero-based
616 //
617 LfnDirEntry->SequenceNumber &= 0x3F;
618 LfnDirEntry->SequenceNumber--;
619
620 //
621 // Get all 13 LFN entry characters
622 //
623 if (LfnDirEntry->Name0_4[0] != 0xFFFF)
624 {
625 LfnNameBuffer[0 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[0];
626 }
627 if (LfnDirEntry->Name0_4[1] != 0xFFFF)
628 {
629 LfnNameBuffer[1 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[1];
630 }
631 if (LfnDirEntry->Name0_4[2] != 0xFFFF)
632 {
633 LfnNameBuffer[2 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[2];
634 }
635 if (LfnDirEntry->Name0_4[3] != 0xFFFF)
636 {
637 LfnNameBuffer[3 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[3];
638 }
639 if (LfnDirEntry->Name0_4[4] != 0xFFFF)
640 {
641 LfnNameBuffer[4 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[4];
642 }
643 if (LfnDirEntry->Name5_10[0] != 0xFFFF)
644 {
645 LfnNameBuffer[5 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[0];
646 }
647 if (LfnDirEntry->Name5_10[1] != 0xFFFF)
648 {
649 LfnNameBuffer[6 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[1];
650 }
651 if (LfnDirEntry->Name5_10[2] != 0xFFFF)
652 {
653 LfnNameBuffer[7 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[2];
654 }
655 if (LfnDirEntry->Name5_10[3] != 0xFFFF)
656 {
657 LfnNameBuffer[8 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[3];
658 }
659 if (LfnDirEntry->Name5_10[4] != 0xFFFF)
660 {
661 LfnNameBuffer[9 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[4];
662 }
663 if (LfnDirEntry->Name5_10[5] != 0xFFFF)
664 {
665 LfnNameBuffer[10 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[5];
666 }
667 if (LfnDirEntry->Name11_12[0] != 0xFFFF)
668 {
669 LfnNameBuffer[11 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[0];
670 }
671 if (LfnDirEntry->Name11_12[1] != 0xFFFF)
672 {
673 LfnNameBuffer[12 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[1];
674 }
675
676 //TRACE("Dumping long name buffer:\n");
677 //DbgDumpBuffer(DPRINT_FILESYSTEM, LfnNameBuffer, 260);
678
679 continue;
680 }
681
682 //
683 // Check for the volume label attribute
684 // and skip over this entry if found
685 //
686 if (DirEntry->Attr & FAT_ATTR_VOLUMENAME)
687 {
688 RtlZeroMemory(ShortNameBuffer, 13 * sizeof(UCHAR));
689 RtlZeroMemory(LfnNameBuffer, 261 * sizeof(UCHAR));
690 continue;
691 }
692
693 //
694 // If we get here then we've found a short file name
695 // entry and LfnNameBuffer contains the long file
696 // name or zeroes. All we have to do now is see if the
697 // file name matches either the short or long file name
698 // and fill in the FAT_FILE_INFO structure if it does
699 // or zero our buffers and continue looking.
700 //
701
702 //
703 // Get short file name
704 //
705 FatParseShortFileName(ShortNameBuffer, DirEntry);
706
707 //TRACE("Entry: %d LFN = %s\n", CurrentEntry, LfnNameBuffer);
708 //TRACE("Entry: %d DOS name = %s\n", CurrentEntry, ShortNameBuffer);
709
710 //
711 // See if the file name matches either the short or long name
712 //
713 if ((_stricmp(FileName, LfnNameBuffer) == 0) || (_stricmp(FileName, ShortNameBuffer) == 0))
714 {
715 //
716 // We found the entry, now fill in the FAT_FILE_INFO struct
717 //
718 FatFileInfoPointer->Attributes = DirEntry->Attr;
719 FatFileInfoPointer->FileSize = DirEntry->Size;
720 FatFileInfoPointer->FilePointer = 0;
721 StartCluster = ((ULONG)DirEntry->ClusterHigh << 16) + DirEntry->ClusterLow;
722 FatFileInfoPointer->CurrentCluster = StartCluster;
723 FatFileInfoPointer->StartCluster = StartCluster;
724
725 TRACE("MSDOS Directory Entry:\n");
726 TRACE("FileName[11] = %c%c%c%c%c%c%c%c%c%c%c\n",
727 DirEntry->FileName[0], DirEntry->FileName[1], DirEntry->FileName[2], DirEntry->FileName[3], DirEntry->FileName[4],
728 DirEntry->FileName[5], DirEntry->FileName[6], DirEntry->FileName[7], DirEntry->FileName[8], DirEntry->FileName[9], DirEntry->FileName[10]);
729 TRACE("Attr = 0x%x\n", DirEntry->Attr);
730 TRACE("ReservedNT = 0x%x\n", DirEntry->ReservedNT);
731 TRACE("TimeInTenths = %d\n", DirEntry->TimeInTenths);
732 TRACE("CreateTime = %d\n", DirEntry->CreateTime);
733 TRACE("CreateDate = %d\n", DirEntry->CreateDate);
734 TRACE("LastAccessDate = %d\n", DirEntry->LastAccessDate);
735 TRACE("ClusterHigh = 0x%x\n", DirEntry->ClusterHigh);
736 TRACE("Time = %d\n", DirEntry->Time);
737 TRACE("Date = %d\n", DirEntry->Date);
738 TRACE("ClusterLow = 0x%x\n", DirEntry->ClusterLow);
739 TRACE("Size = %d\n", DirEntry->Size);
740 TRACE("StartCluster = 0x%x\n", StartCluster);
741
742 return TRUE;
743 }
744
745 //
746 // Nope, no match - zero buffers and continue looking
747 //
748 RtlZeroMemory(ShortNameBuffer, 13 * sizeof(UCHAR));
749 RtlZeroMemory(LfnNameBuffer, 261 * sizeof(UCHAR));
750 }
751
752 return FALSE;
753}
754
755static BOOLEAN FatXSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
756{
757 ULONG EntryCount;
758 ULONG CurrentEntry;
760 FATX_DIRENTRY OurDirEntry;
761 PFATX_DIRENTRY DirEntry = &OurDirEntry;
762
763 EntryCount = DirectorySize / sizeof(FATX_DIRENTRY);
764
765 TRACE("FatXSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer, EntryCount, FileName);
766
768
769 for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++, DirectoryBuffer = ((PFATX_DIRENTRY)DirectoryBuffer)+1)
770 {
771 OurDirEntry = *(PFATX_DIRENTRY) DirectoryBuffer;
772 FatSwapFatXDirEntry(&OurDirEntry);
773 if (0xff == DirEntry->FileNameSize)
774 {
775 break;
776 }
777 if (0xe5 == DirEntry->FileNameSize)
778 {
779 continue;
780 }
781 if ((FileNameLen == DirEntry->FileNameSize) &&
782 (_strnicmp(FileName, DirEntry->FileName, FileNameLen) == 0))
783 {
784 /*
785 * We found the entry, now fill in the FAT_FILE_INFO struct
786 */
787 FatFileInfoPointer->Attributes = DirEntry->Attr;
788 FatFileInfoPointer->FileSize = DirEntry->Size;
789 FatFileInfoPointer->FilePointer = 0;
790 FatFileInfoPointer->CurrentCluster = DirEntry->StartCluster;
791 FatFileInfoPointer->StartCluster = DirEntry->StartCluster;
792
793 TRACE("FATX Directory Entry:\n");
794 TRACE("FileNameSize = %d\n", DirEntry->FileNameSize);
795 TRACE("Attr = 0x%x\n", DirEntry->Attr);
796 TRACE("StartCluster = 0x%x\n", DirEntry->StartCluster);
797 TRACE("Size = %d\n", DirEntry->Size);
798 TRACE("Time = %d\n", DirEntry->Time);
799 TRACE("Date = %d\n", DirEntry->Date);
800 TRACE("CreateTime = %d\n", DirEntry->CreateTime);
801 TRACE("CreateDate = %d\n", DirEntry->CreateDate);
802 TRACE("LastAccessTime = %d\n", DirEntry->LastAccessTime);
803 TRACE("LastAccessDate = %d\n", DirEntry->LastAccessDate);
804
805 return TRUE;
806 }
807 }
808
809 return FALSE;
810}
811
812/*
813 * FatLookupFile()
814 * This function searches the file system for the
815 * specified filename and fills in an FAT_FILE_INFO structure
816 * with info describing the file, etc. returns ARC error code
817 */
819{
820 ULONG NumberOfPathParts;
821 ULONG i;
822 CHAR PathPart[261];
823 PVOID DirectoryBuffer;
824 ULONG DirectoryStartCluster = 0;
825 ULONG DirectorySize;
826 FAT_FILE_INFO FatFileInfo;
827
828 TRACE("FatLookupFile() FileName = %s\n", FileName);
829
830 RtlZeroMemory(FatFileInfoPointer, sizeof(FAT_FILE_INFO));
831
832 /* Skip leading path separator, if any */
833 if (*FileName == '\\' || *FileName == '/')
834 ++FileName;
835 PathPart[0] = ANSI_NULL;
836
837 //
838 // Figure out how many sub-directories we are nested in
839 //
840 NumberOfPathParts = FsGetNumPathParts(FileName);
841
842 //
843 // Loop once for each part
844 //
845 for (i=0; i<NumberOfPathParts; i++)
846 {
847 //
848 // Get first path part
849 //
851
852 //
853 // Advance to the next part of the path
854 //
855 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
856 {
857 }
858 FileName++;
859
860 //
861 // Buffer the directory contents
862 //
863 DirectoryBuffer = FatBufferDirectory(Volume, DirectoryStartCluster, &DirectorySize, (i == 0) );
864 if (DirectoryBuffer == NULL)
865 {
866 return ENOMEM;
867 }
868
869 //
870 // Search for file name in directory
871 //
872 if (ISFATX(Volume->FatType))
873 {
874 if (!FatXSearchDirectoryBufferForFile(Volume, DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo))
875 {
876 return ENOENT;
877 }
878 }
879 else
880 {
881 if (!FatSearchDirectoryBufferForFile(Volume, DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo))
882 {
883 return ENOENT;
884 }
885 }
886
887 //
888 // If we have another sub-directory to go then
889 // grab the start cluster and free the fat chain array
890 //
891 if ((i+1) < NumberOfPathParts)
892 {
893 //
894 // Check if current entry is a directory
895 //
896 if (!(FatFileInfo.Attributes & FAT_ATTR_DIRECTORY))
897 {
898 return ENOTDIR;
899 }
900 DirectoryStartCluster = FatFileInfo.StartCluster;
901 }
902 }
903
904 RtlCopyMemory(FatFileInfoPointer, &FatFileInfo, sizeof(FatFileInfo));
905
906 /* Re-map the attributes to ARC file attributes */
907 FatFileInfoPointer->Attributes = 0;
908 if (FatFileInfo.Attributes & FAT_ATTR_READONLY)
909 FatFileInfoPointer->Attributes |= ReadOnlyFile;
910 if (FatFileInfo.Attributes & FAT_ATTR_HIDDEN)
911 FatFileInfoPointer->Attributes |= HiddenFile;
912 if (FatFileInfo.Attributes & FAT_ATTR_SYSTEM)
913 FatFileInfoPointer->Attributes |= SystemFile;
914 if (FatFileInfo.Attributes & FAT_ATTR_ARCHIVE)
915 FatFileInfoPointer->Attributes |= ArchiveFile;
916 if (FatFileInfo.Attributes & FAT_ATTR_DIRECTORY)
917 FatFileInfoPointer->Attributes |= DirectoryFile;
918
919 /* Copy the file name, perhaps truncated */
920 FatFileInfoPointer->FileNameLength = (ULONG)strlen(PathPart);
921 FatFileInfoPointer->FileNameLength = min(FatFileInfoPointer->FileNameLength, sizeof(FatFileInfoPointer->FileName) - 1);
922 RtlCopyMemory(FatFileInfoPointer->FileName, PathPart, FatFileInfoPointer->FileNameLength);
923
924 return ESUCCESS;
925}
926
927/*
928 * FatParseFileName()
929 * This function parses a directory entry name which
930 * is in the form of "FILE EXT" and puts it in Buffer
931 * in the form of "file.ext"
932 */
934{
935 ULONG Idx;
936
937 Idx = 0;
939
940 //
941 // Fixup first character
942 //
943 if (DirEntry->FileName[0] == 0x05)
944 {
945 DirEntry->FileName[0] = 0xE5;
946 }
947
948 //
949 // Get the file name
950 //
951 while (Idx < 8)
952 {
953 if (DirEntry->FileName[Idx] == ' ')
954 {
955 break;
956 }
957
958 Buffer[Idx] = DirEntry->FileName[Idx];
959 Idx++;
960 }
961
962 //
963 // Get extension
964 //
965 if ((DirEntry->FileName[8] != ' '))
966 {
967 Buffer[Idx++] = '.';
968 Buffer[Idx++] = (DirEntry->FileName[8] == ' ') ? '\0' : DirEntry->FileName[8];
969 Buffer[Idx++] = (DirEntry->FileName[9] == ' ') ? '\0' : DirEntry->FileName[9];
970 Buffer[Idx++] = (DirEntry->FileName[10] == ' ') ? '\0' : DirEntry->FileName[10];
971 }
972
973 //TRACE("FatParseShortFileName() ShortName = %s\n", Buffer);
974}
975
979static
981{
982 UINT32 SectorNumAbsolute = Volume->ActiveFatSectorStart + FatSectorNumber;
983 UINT32 CacheIndex = FatSectorNumber % Volume->FatCacheSize;
984
985 ASSERT(FatSectorNumber < Volume->SectorsPerFat);
986
987 // cache miss
988 if (Volume->FatCacheIndex[CacheIndex] != SectorNumAbsolute)
989 {
990 UINT32 SectorsToRead = min(Volume->FatCacheSize - CacheIndex, min(Volume->SectorsPerFat - SectorNumAbsolute, 4));
991 UINT8 i;
992
993 if (!FatReadVolumeSectors(Volume, SectorNumAbsolute, SectorsToRead, &Volume->FatCache[CacheIndex * Volume->BytesPerSector]))
994 {
995 return NULL;
996 }
997
998 for (i = 0; i < SectorsToRead; i++)
999 {
1000 Volume->FatCacheIndex[CacheIndex + i] = SectorNumAbsolute + i;
1001 }
1002
1003 TRACE("FAT cache miss: read sector 0x%x from disk\n", SectorNumAbsolute);
1004 }
1005 else
1006 {
1007 TRACE("FAT cache hit: sector 0x%x present\n", SectorNumAbsolute);
1008 }
1009
1010 return &Volume->FatCache[CacheIndex * Volume->BytesPerSector];
1011}
1012
1013/*
1014 * FatGetFatEntry()
1015 * returns the Fat entry for a given cluster number
1016 */
1017static
1019{
1020 UINT32 FatOffset, ThisFatSecNum, ThisFatEntOffset, fat;
1022
1023 TRACE("FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster);
1024
1025 switch(Volume->FatType)
1026 {
1027 case FAT12:
1028
1029 FatOffset = Cluster + (Cluster / 2);
1030 ThisFatSecNum = FatOffset / Volume->BytesPerSector;
1031 ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
1032
1033 TRACE("FatOffset: %d\n", FatOffset);
1034 TRACE("ThisFatSecNum: %d\n", ThisFatSecNum);
1035 TRACE("ThisFatEntOffset: %d\n", ThisFatEntOffset);
1036
1037 // The cluster pointer can span within two sectors, but the FatGetFatSector function
1038 // reads 4 sectors most times, except when we are at the edge of FAT cache
1039 // and/or FAT region on the disk. For FAT12 the whole FAT would be cached so
1040 // there will be no situation when the first sector is at the end of the cache
1041 // and the next one is in the beginning
1042
1043 ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
1044 if (!ReadBuffer)
1045 {
1046 return FALSE;
1047 }
1048
1049 fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
1050 fat = SWAPW(fat);
1051 if (Cluster & 0x0001)
1052 fat = fat >> 4; /* Cluster number is ODD */
1053 else
1054 fat = fat & 0x0FFF; /* Cluster number is EVEN */
1055
1056 break;
1057
1058 case FAT16:
1059 case FATX16:
1060
1061 FatOffset = (Cluster * 2);
1062 ThisFatSecNum = FatOffset / Volume->BytesPerSector;
1063 ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
1064
1065 ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
1066 if (!ReadBuffer)
1067 {
1068 return FALSE;
1069 }
1070
1071 fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
1072 fat = SWAPW(fat);
1073
1074 break;
1075
1076 case FAT32:
1077 case FATX32:
1078
1079 FatOffset = (Cluster * 4);
1080 ThisFatSecNum = FatOffset / Volume->BytesPerSector;
1081 ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
1082
1083 ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
1084 if (!ReadBuffer)
1085 {
1086 return FALSE;
1087 }
1088
1089 // Get the fat entry
1090 fat = (*((ULONG *) (ReadBuffer + ThisFatEntOffset))) & 0x0FFFFFFF;
1091 fat = SWAPD(fat);
1092
1093 break;
1094
1095 default:
1096 ERR("Unknown FAT type %d\n", Volume->FatType);
1097 return FALSE;
1098 }
1099
1100 TRACE("FAT entry is 0x%x.\n", fat);
1101
1102 *ClusterPointer = fat;
1103
1104 return TRUE;
1105}
1106
1107static
1109{
1110 ULONG ClusterCount = 0;
1111
1112 TRACE("FatCountClustersInChain() StartCluster = %d\n", StartCluster);
1113
1114 while (1)
1115 {
1116 //
1117 // If end of chain then break out of our cluster counting loop
1118 //
1119 if (FAT_IS_END_CLUSTER(StartCluster))
1120 {
1121 break;
1122 }
1123
1124 //
1125 // Increment count
1126 //
1127 ClusterCount++;
1128
1129 //
1130 // Get next cluster
1131 //
1132 if (!FatGetFatEntry(Volume, StartCluster, &StartCluster))
1133 {
1134 return 0;
1135 }
1136 }
1137
1138 TRACE("FatCountClustersInChain() ClusterCount = %d\n", ClusterCount);
1139
1140 return ClusterCount;
1141}
1142
1143static
1146 UINT32 StartClusterNumber,
1147 UINT32 MaxClusters,
1148 PVOID Buffer,
1149 PUINT32 ClustersRead,
1150 PUINT32 LastClusterNumber)
1151{
1152 UINT32 NextClusterNumber;
1153 UINT32 ClustersToRead = 1;
1154 UINT32 PrevClusterNumber = StartClusterNumber;
1155 UINT32 ClusterStartSector = ((PrevClusterNumber - 2) * Volume->SectorsPerCluster) + Volume->DataSectorStart;
1156
1157 *ClustersRead = 0;
1158 *LastClusterNumber = 0;
1159
1160 if (!FatGetFatEntry(Volume, StartClusterNumber, &NextClusterNumber))
1161 {
1162 return FALSE;
1163 }
1164
1165 // getting the number of adjacent clusters
1166 while (!FAT_IS_END_CLUSTER(NextClusterNumber) && ClustersToRead < MaxClusters && (NextClusterNumber == PrevClusterNumber + 1))
1167 {
1168 ClustersToRead++;
1169 PrevClusterNumber = NextClusterNumber;
1170 if (!FatGetFatEntry(Volume, PrevClusterNumber, &NextClusterNumber))
1171 {
1172 return FALSE;
1173 }
1174 }
1175
1176 if (!FatReadVolumeSectors(Volume, ClusterStartSector, ClustersToRead * Volume->SectorsPerCluster, Buffer))
1177 {
1178 return FALSE;
1179 }
1180
1181 *ClustersRead = ClustersToRead;
1182 *LastClusterNumber = NextClusterNumber;
1183
1184 return !FAT_IS_END_CLUSTER(NextClusterNumber) && ClustersToRead < MaxClusters;
1185}
1186
1187/*
1188 * FatReadClusterChain()
1189 * Reads the specified clusters into memory
1190 */
1191static
1192BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, UINT32 StartClusterNumber, UINT32 NumberOfClusters, PVOID Buffer, PUINT32 LastClusterNumber)
1193{
1194 UINT32 ClustersRead, NextClusterNumber, ClustersLeft = NumberOfClusters;
1195
1196 TRACE("FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer);
1197
1198 ASSERT(NumberOfClusters > 0);
1199
1200 while (FatReadAdjacentClusters(Volume, StartClusterNumber, ClustersLeft, Buffer, &ClustersRead, &NextClusterNumber))
1201 {
1202 ClustersLeft -= ClustersRead;
1203 Buffer = (PVOID)((ULONG_PTR)Buffer + (ClustersRead * Volume->SectorsPerCluster * Volume->BytesPerSector));
1204 StartClusterNumber = NextClusterNumber;
1205 }
1206
1207 if (LastClusterNumber)
1208 {
1209 *LastClusterNumber = NextClusterNumber;
1210 }
1211
1212 return (ClustersRead > 0);
1213}
1214
1215/*
1216 * FatReadPartialCluster()
1217 * Reads part of a cluster into memory
1218 */
1220{
1221 ULONG ClusterStartSector;
1222 ULONG SectorOffset, ReadSize, SectorCount;
1225
1226 //TRACE("FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber, StartingOffset, Length, Buffer);
1227
1228 ClusterStartSector = ((ClusterNumber - 2) * Volume->SectorsPerCluster) + Volume->DataSectorStart;
1229
1230 // This is the offset of the data in sectors
1231 SectorOffset = (StartingOffset / Volume->BytesPerSector);
1232 StartingOffset %= Volume->BytesPerSector;
1233
1234 // Calculate how many sectors we need to read
1235 SectorCount = (StartingOffset + Length + Volume->BytesPerSector - 1) / Volume->BytesPerSector;
1236
1237 // Calculate rounded up read size
1238 ReadSize = SectorCount * Volume->BytesPerSector;
1239
1241 if (!ReadBuffer)
1242 {
1243 return FALSE;
1244 }
1245
1246 if (FatReadVolumeSectors(Volume, ClusterStartSector + SectorOffset, SectorCount, ReadBuffer))
1247 {
1249 Success = TRUE;
1250 }
1251
1253
1254 return Success;
1255}
1256
1257/*
1258 * FatReadFile()
1259 * Reads BytesToRead from open file and
1260 * returns the number of bytes read in BytesRead
1261 */
1262static
1264{
1265 PFAT_VOLUME_INFO Volume = FatFileInfo->Volume;
1266 UINT32 NextClusterNumber, BytesPerCluster;
1267
1268 TRACE("FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead, Buffer);
1269
1270 if (BytesRead != NULL)
1271 {
1272 *BytesRead = 0;
1273 }
1274
1275 //
1276 // If the user is trying to read past the end of
1277 // the file then return success with BytesRead == 0.
1278 //
1279 if (FatFileInfo->FilePointer >= FatFileInfo->FileSize)
1280 {
1281 return TRUE;
1282 }
1283
1284 //
1285 // If the user is trying to read more than there is to read
1286 // then adjust the amount to read.
1287 //
1288 if ((FatFileInfo->FilePointer + BytesToRead) > FatFileInfo->FileSize)
1289 {
1290 BytesToRead = (FatFileInfo->FileSize - FatFileInfo->FilePointer);
1291 }
1292
1293 //
1294 // Ok, now we have to perform at most 3 calculations
1295 // I'll draw you a picture (using nifty ASCII art):
1296 //
1297 // CurrentFilePointer -+
1298 // |
1299 // +----------------+
1300 // |
1301 // +-----------+-----------+-----------+-----------+
1302 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
1303 // +-----------+-----------+-----------+-----------+
1304 // | |
1305 // +---------------+--------------------+
1306 // |
1307 // BytesToRead -------+
1308 //
1309 // 1 - The first calculation (and read) will align
1310 // the file pointer with the next cluster.
1311 // boundary (if we are supposed to read that much)
1312 // 2 - The next calculation (and read) will read
1313 // in all the full clusters that the requested
1314 // amount of data would cover (in this case
1315 // clusters 2 & 3).
1316 // 3 - The last calculation (and read) would read
1317 // in the remainder of the data requested out of
1318 // the last cluster.
1319 //
1320
1321 BytesPerCluster = Volume->SectorsPerCluster * Volume->BytesPerSector;
1322
1323 //
1324 // Only do the first read if we
1325 // aren't aligned on a cluster boundary
1326 //
1327 if (FatFileInfo->FilePointer % BytesPerCluster)
1328 {
1329 //
1330 // Do the math for our first read
1331 //
1332 UINT32 OffsetInCluster = FatFileInfo->FilePointer % BytesPerCluster;
1333 UINT32 LengthInCluster = min(BytesToRead, BytesPerCluster - OffsetInCluster);
1334
1335 ASSERT(LengthInCluster <= BytesPerCluster && LengthInCluster > 0);
1336
1337 //
1338 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1339 //
1340 if (!FatReadPartialCluster(Volume, FatFileInfo->CurrentCluster, OffsetInCluster, LengthInCluster, Buffer))
1341 {
1342 return FALSE;
1343 }
1344 if (BytesRead != NULL)
1345 {
1346 *BytesRead += LengthInCluster;
1347 }
1348 BytesToRead -= LengthInCluster;
1349 FatFileInfo->FilePointer += LengthInCluster;
1350 Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInCluster);
1351
1352 // get the next cluster if needed
1353 if ((LengthInCluster + OffsetInCluster) == BytesPerCluster)
1354 {
1355 if (!FatGetFatEntry(Volume, FatFileInfo->CurrentCluster, &NextClusterNumber))
1356 {
1357 return FALSE;
1358 }
1359
1360 FatFileInfo->CurrentCluster = NextClusterNumber;
1361 TRACE("FatReadFile() FatFileInfo->CurrentCluster = 0x%x\n", FatFileInfo->CurrentCluster);
1362 }
1363 }
1364
1365 //
1366 // Do the math for our second read (if any data left)
1367 //
1368 if (BytesToRead > 0)
1369 {
1370 //
1371 // Determine how many full clusters we need to read
1372 //
1373 UINT32 NumberOfClusters = BytesToRead / BytesPerCluster;
1374
1375 TRACE("Going to read: %u clusters\n", NumberOfClusters);
1376
1377 if (NumberOfClusters > 0)
1378 {
1379 UINT32 BytesReadHere = NumberOfClusters * BytesPerCluster;
1380
1382
1383 if (!FatReadClusterChain(Volume, FatFileInfo->CurrentCluster, NumberOfClusters, Buffer, &NextClusterNumber))
1384 {
1385 return FALSE;
1386 }
1387
1388 if (BytesRead != NULL)
1389 {
1390 *BytesRead += BytesReadHere;
1391 }
1392 BytesToRead -= BytesReadHere;
1393 Buffer = (PVOID)((ULONG_PTR)Buffer + BytesReadHere);
1394
1395 ASSERT(!FAT_IS_END_CLUSTER(NextClusterNumber) || BytesToRead == 0);
1396
1397 FatFileInfo->FilePointer += BytesReadHere;
1398 FatFileInfo->CurrentCluster = NextClusterNumber;
1399 TRACE("FatReadFile() FatFileInfo->CurrentCluster = 0x%x\n", FatFileInfo->CurrentCluster);
1400 }
1401 }
1402
1403 //
1404 // Do the math for our third read (if any data left)
1405 //
1406 if (BytesToRead > 0)
1407 {
1409
1410 //
1411 // Now do the read and update BytesRead & FilePointer
1412 //
1413 if (!FatReadPartialCluster(Volume, FatFileInfo->CurrentCluster, 0, BytesToRead, Buffer))
1414 {
1415 return FALSE;
1416 }
1417 if (BytesRead != NULL)
1418 {
1419 *BytesRead += BytesToRead;
1420 }
1421 FatFileInfo->FilePointer += BytesToRead;
1422 }
1423
1424 return TRUE;
1425}
1426
1428{
1430 ULONG Count;
1432
1433 //TRACE("FatReadVolumeSectors(): SectorNumber %d, SectorCount %d, Buffer %p\n",
1434 // SectorNumber, SectorCount, Buffer);
1435
1436 //
1437 // Seek to right position
1438 //
1439 Position.QuadPart = (ULONGLONG)SectorNumber * Volume->BytesPerSector;
1440 Status = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
1441 if (Status != ESUCCESS)
1442 {
1443 TRACE("FatReadVolumeSectors() Failed to seek\n");
1444 return FALSE;
1445 }
1446
1447 //
1448 // Read data
1449 //
1450 Status = ArcRead(Volume->DeviceId, Buffer, SectorCount * Volume->BytesPerSector, &Count);
1451 if (Status != ESUCCESS || Count != SectorCount * Volume->BytesPerSector)
1452 {
1453 TRACE("FatReadVolumeSectors() Failed to read\n");
1454 return FALSE;
1455 }
1456
1457 // Return success
1458 return TRUE;
1459}
1460
1462{
1464
1466
1467 return ESUCCESS;
1468}
1469
1471{
1473
1475 Information->EndingAddress.LowPart = FileHandle->FileSize;
1476 Information->CurrentAddress.LowPart = FileHandle->FilePointer;
1477
1478 /* Set the ARC file attributes */
1479 Information->Attributes = FileHandle->Attributes;
1480
1481 /* Copy the file name, perhaps truncated, and NUL-terminated */
1482 Information->FileNameLength = min(FileHandle->FileNameLength, sizeof(Information->FileName) - 1);
1483 RtlCopyMemory(Information->FileName, FileHandle->FileName, Information->FileNameLength);
1484 Information->FileName[Information->FileNameLength] = ANSI_NULL;
1485
1486 TRACE("FatGetFileInformation(%lu) -> FileSize = %lu, FilePointer = 0x%lx\n",
1487 FileId, Information->EndingAddress.LowPart, Information->CurrentAddress.LowPart);
1488
1489 return ESUCCESS;
1490}
1491
1493{
1494 PFAT_VOLUME_INFO FatVolume;
1495 FAT_FILE_INFO TempFileInfo;
1497 ULONG DeviceId;
1500
1501 if (OpenMode != OpenReadOnly && OpenMode != OpenDirectory)
1502 return EACCES;
1503
1504 DeviceId = FsGetDeviceId(*FileId);
1505 FatVolume = FatVolumes[DeviceId];
1506
1507 TRACE("FatOpen() FileName = %s\n", Path);
1508
1509 RtlZeroMemory(&TempFileInfo, sizeof(TempFileInfo));
1510 Status = FatLookupFile(FatVolume, Path, &TempFileInfo);
1511 if (Status != ESUCCESS)
1512 return ENOENT;
1513
1514 //
1515 // Check if caller opened what he expected (dir vs file)
1516 //
1517 IsDirectory = !!(TempFileInfo.Attributes & DirectoryFile);
1518 if (IsDirectory && OpenMode != OpenDirectory)
1519 return EISDIR;
1520 else if (!IsDirectory && OpenMode != OpenReadOnly)
1521 return ENOTDIR;
1522
1524 if (!FileHandle)
1525 return ENOMEM;
1526
1527 RtlCopyMemory(FileHandle, &TempFileInfo, sizeof(FAT_FILE_INFO));
1528 FileHandle->Volume = FatVolume;
1529
1531 return ESUCCESS;
1532}
1533
1535{
1538
1539 /* Call old read method */
1541 if (Success)
1542 return ESUCCESS;
1543 else
1544 return EIO;
1545}
1546
1548{
1551 LARGE_INTEGER NewPosition = *Position;
1552
1553 switch (SeekMode)
1554 {
1555 case SeekAbsolute:
1556 break;
1557 case SeekRelative:
1558 NewPosition.QuadPart += (ULONGLONG)FileHandle->FilePointer;
1559 break;
1560 default:
1561 ASSERT(FALSE);
1562 return EINVAL;
1563 }
1564
1565 if (NewPosition.HighPart != 0)
1566 return EINVAL;
1567 if (NewPosition.LowPart >= FileHandle->FileSize)
1568 return EINVAL;
1569
1570 TRACE("FatSeek() NewPosition = %u, OldPointer = %u, SeekMode = %d\n", NewPosition.LowPart, FileHandle->FilePointer, SeekMode);
1571
1572 {
1573 UINT32 OldClusterIdx = FileHandle->FilePointer / (Volume->SectorsPerCluster * Volume->BytesPerSector);
1574 UINT32 NewClusterIdx = NewPosition.LowPart / (Volume->SectorsPerCluster * Volume->BytesPerSector);
1575
1576 TRACE("FatSeek() OldClusterIdx: %u, NewClusterIdx: %u\n", OldClusterIdx, NewClusterIdx);
1577
1578 if (NewClusterIdx != OldClusterIdx)
1579 {
1580 UINT32 CurrentClusterIdx, ClusterNumber;
1581
1582 if (NewClusterIdx > OldClusterIdx)
1583 {
1584 CurrentClusterIdx = OldClusterIdx;
1585 ClusterNumber = FileHandle->CurrentCluster;
1586 }
1587 else
1588 {
1589 CurrentClusterIdx = 0;
1590 ClusterNumber = FileHandle->StartCluster;
1591 }
1592
1593 for (; CurrentClusterIdx < NewClusterIdx; CurrentClusterIdx++)
1594 {
1595 if (!FatGetFatEntry(Volume, ClusterNumber, &ClusterNumber))
1596 {
1597 return EIO;
1598 }
1599 }
1600 FileHandle->CurrentCluster = ClusterNumber;
1601 }
1602 }
1603
1604 FileHandle->FilePointer = NewPosition.LowPart;
1605
1606 return ESUCCESS;
1607}
1608
1609
1617 _In_ ULONG DeviceId)
1618{
1620 ASSERT(Volume);
1621 return (ULONGLONG)Volume->TotalSectors * Volume->BytesPerSector;
1622}
1623
1624
1626{
1627 FatClose,
1629 FatOpen,
1630 FatRead,
1631 FatSeek,
1632 L"fastfat",
1633};
1634
1636{
1637 FatClose,
1639 FatOpen,
1640 FatRead,
1641 FatSeek,
1642 L"vfatfs",
1643};
1644
1645const DEVVTBL* FatMount(ULONG DeviceId)
1646{
1654 ULONG Count;
1657
1658 TRACE("Enter FatMount(%lu)\n", DeviceId);
1659
1660 //
1661 // Allocate data for volume information
1662 //
1664 if (!Volume)
1665 return NULL;
1667
1668 //
1669 // Read the BootSector
1670 //
1671 Position.QuadPart = 0;
1672 Status = ArcSeek(DeviceId, &Position, SeekAbsolute);
1673 if (Status != ESUCCESS)
1674 {
1676 return NULL;
1677 }
1678 Status = ArcRead(DeviceId, Buffer, sizeof(Buffer), &Count);
1679 if (Status != ESUCCESS || Count != sizeof(Buffer))
1680 {
1682 return NULL;
1683 }
1684
1685 //
1686 // Check if BootSector is valid. If no, return early
1687 //
1688 if (!RtlEqualMemory(BootSector->FileSystemType, "FAT12 ", 8) &&
1689 !RtlEqualMemory(BootSector->FileSystemType, "FAT16 ", 8) &&
1690 !RtlEqualMemory(BootSector32->FileSystemType, "FAT32 ", 8) &&
1691 !RtlEqualMemory(BootSectorX->FileSystemType, "FATX", 4))
1692 {
1694 return NULL;
1695 }
1696
1697 //
1698 // Determine sector count
1699 //
1701 if (Status != ESUCCESS)
1702 {
1704 return NULL;
1705 }
1706 SectorCount.QuadPart = (FileInformation.EndingAddress.QuadPart - FileInformation.StartingAddress.QuadPart);
1707 SectorCount.QuadPart /= SECTOR_SIZE;
1708
1709 //
1710 // Keep device id
1711 //
1712 Volume->DeviceId = DeviceId;
1713
1714 //
1715 // Really open the volume
1716 //
1717 if (!FatOpenVolume(Volume, BootSector, SectorCount.QuadPart))
1718 {
1720 return NULL;
1721 }
1722
1723 //
1724 // Remember FAT volume information
1725 //
1726 FatVolumes[DeviceId] = Volume;
1727
1728 //
1729 // Return success
1730 //
1731 TRACE("FatMount(%lu) success\n", DeviceId);
1732 return (ISFATX(Volume->FatType) ? &FatXFuncTable : &FatFuncTable);
1733}
#define N
Definition: crc32.c:57
unsigned short UINT16
unsigned char BOOLEAN
unsigned char UINT8
unsigned int UINT32
PRTL_UNICODE_STRING_BUFFER Path
#define ENOENT
Definition: acclib.h:79
#define EINVAL
Definition: acclib.h:90
#define ENOMEM
Definition: acclib.h:84
#define EIO
Definition: acclib.h:81
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
#define EACCES
Definition: acclib.h:85
#define ReadBuffer(BaseIoAddress, Buffer, Count)
Definition: atapi.h:339
#define ERR(fmt,...)
Definition: precomp.h:57
WCHAR RootDirectory[MAX_PATH]
Definition: format.c:74
unsigned int * PUINT32
Definition: basetsd.h:119
NTSTATUS FatMount(_In_ ULONG DeviceId, _In_ ULONG Unknown, _Out_ PBL_FILE_ENTRY *FileEntry)
Definition: fat.c:23
ULONG PartitionSectorCount
Definition: partition.c:39
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
struct FATX_DIRENTRY * PFATX_DIRENTRY
#define FAT_ATTR_LONG_NAME
Definition: fat.h:153
#define FAT32
Definition: fat.h:157
#define FATX16
Definition: fat.h:158
#define FAT_ATTR_SYSTEM
Definition: fat.h:149
#define FATX32
Definition: fat.h:159
#define FAT_ATTR_READONLY
Definition: fat.h:147
#define FAT_ATTR_HIDDEN
Definition: fat.h:148
struct _FATX_BOOTSECTOR * PFATX_BOOTSECTOR
#define FAT12
Definition: fat.h:155
struct DIRENTRY * PDIRENTRY
#define FAT16
Definition: fat.h:156
#define FAT_ATTR_VOLUMENAME
Definition: fat.h:150
#define FAT_ATTR_ARCHIVE
Definition: fat.h:152
#define FAT_ATTR_DIRECTORY
Definition: fat.h:151
#define ISFATX(FT)
Definition: fat.h:161
struct LFN_DIRENTRY * PLFN_DIRENTRY
ARC_STATUS ArcGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: fs.c:462
ARC_STATUS ArcSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fs.c:455
PVOID FsGetDeviceSpecific(ULONG FileId)
Definition: fs.c:709
ULONG FsGetNumPathParts(PCSTR Path)
Definition: fs.c:617
VOID FsSetDeviceSpecific(ULONG FileId, PVOID Specific)
Definition: fs.c:702
VOID FileSystemError(PCSTR ErrorString)
Definition: fs.c:471
ULONG FsGetDeviceId(ULONG FileId)
Definition: fs.c:716
#define MAX_FDS
Definition: fs.h:34
#define SECTOR_SIZE
Definition: fs.h:22
ARC_STATUS ArcRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: fs.c:448
VOID FsGetFirstNameFromPath(PCHAR Buffer, PCSTR Path)
Definition: fs.c:645
VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: heap.c:553
PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: heap.c:545
static BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
Definition: fat.c:549
static PUCHAR FatGetFatSector(PFAT_VOLUME_INFO Volume, UINT32 FatSectorNumber)
Reads 1-4 sectors from FAT using the cache.
Definition: fat.c:980
static BOOLEAN FatReadAdjacentClusters(PFAT_VOLUME_INFO Volume, UINT32 StartClusterNumber, UINT32 MaxClusters, PVOID Buffer, PUINT32 ClustersRead, PUINT32 LastClusterNumber)
Definition: fat.c:1144
VOID FatSwapFatBootSector(PFAT_BOOTSECTOR Obj)
Definition: fat.c:61
VOID FatSwapFat32BootSector(PFAT32_BOOTSECTOR Obj)
Definition: fat.c:76
#define TAG_FAT_FILE
Definition: fat.c:31
VOID FatSwapDirEntry(PDIRENTRY Obj)
Definition: fat.c:103
ULONGLONG FatGetVolumeSize(_In_ ULONG DeviceId)
Returns the size of the FAT volume laid on the storage media device opened via DeviceId.
Definition: fat.c:1616
#define TAG_FAT_CACHE
Definition: fat.c:34
static BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, UINT32 Cluster, PUINT32 ClusterPointer)
Definition: fat.c:1018
VOID FatSwapFatXBootSector(PFATX_BOOTSECTOR Obj)
Definition: fat.c:96
ARC_STATUS FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, PFAT_FILE_INFO FatFileInfoPointer)
Definition: fat.c:818
static BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, UINT32 StartClusterNumber, UINT32 NumberOfClusters, PVOID Buffer, PUINT32 LastClusterNumber)
Definition: fat.c:1192
ULONG FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector, ULONGLONG PartitionSectorCount)
Definition: fat.c:396
struct _DIRECTORY_BUFFER DIRECTORY_BUFFER
static BOOLEAN FatReadFile(PFAT_FILE_INFO FatFileInfo, ULONG BytesToRead, ULONG *BytesRead, PVOID Buffer)
Definition: fat.c:1263
ARC_STATUS FatOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: fat.c:1492
PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, ULONG *EntryCountPointer, BOOLEAN RootDirectory)
Definition: fat.c:462
#define FAT_IS_END_CLUSTER(clnumber)
Definition: fat.c:25
static ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, UINT32 StartCluster)
Definition: fat.c:1108
#define TAG_FAT_VOLUME
Definition: fat.c:32
const DEVVTBL FatXFuncTable
Definition: fat.c:1635
static BOOLEAN FatXSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
Definition: fat.c:755
VOID FatSwapLFNDirEntry(PLFN_DIRENTRY Obj)
Definition: fat.c:115
struct _DIRECTORY_BUFFER * PDIRECTORY_BUFFER
ARC_STATUS FatSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fat.c:1547
BOOLEAN FatReadVolumeSectors(PFAT_VOLUME_INFO Volume, ULONG SectorNumber, ULONG SectorCount, PVOID Buffer)
Definition: fat.c:1427
BOOLEAN FatOpenVolume(PFAT_VOLUME_INFO Volume, PFAT_BOOTSECTOR BootSector, ULONGLONG PartitionSectorCount)
Definition: fat.c:160
#define TAG_FAT_BUFFER
Definition: fat.c:33
ARC_STATUS FatRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: fat.c:1534
PFAT_VOLUME_INFO FatVolumes[MAX_FDS]
Definition: fat.c:59
VOID FatSwapFatXDirEntry(PFATX_DIRENTRY Obj)
Definition: fat.c:127
#define FAT_MAX_CACHE_SIZE
Definition: fat.c:36
const DEVVTBL FatFuncTable
Definition: fat.c:1625
ARC_STATUS FatGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: fat.c:1470
struct _FAT_VOLUME_INFO FAT_VOLUME_INFO
void FatParseShortFileName(PCHAR Buffer, PDIRENTRY DirEntry)
Definition: fat.c:933
LIST_ENTRY DirectoryBufferListHead
Definition: fat.c:460
ARC_STATUS FatClose(ULONG FileId)
Definition: fat.c:1461
BOOLEAN FatReadPartialCluster(PFAT_VOLUME_INFO Volume, ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
Definition: fat.c:1219
BOOL BackupBootSector(LPCTSTR lpszVolumeName)
Definition: install.c:61
#define SW(Object, Field)
Definition: bytesex.h:11
#define SWAPD(x)
Definition: bytesex.h:7
#define SWAPW(x)
Definition: bytesex.h:8
#define SD(Object, Field)
Definition: bytesex.h:10
#define _stricmp
Definition: cat.c:22
Dirent FileNameLen
Definition: dirsup.c:506
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:291
#define SectorOffset(L)
Definition: cdprocs.h:1622
Definition: bufpool.h:45
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define _strnicmp(_String1, _String2, _MaxCount)
Definition: compat.h:23
#define L(x)
Definition: resources.c:13
#define ENOTDIR
Definition: errno.h:26
#define EISDIR
Definition: errno.h:27
#define FatNumberOfClusters(B)
Definition: fat.h:482
#define InsertTailList(ListHead, Entry)
@ Success
Definition: eventcreate.c:712
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
#define IsDirectory(Fcb)
Definition: ext2fs.h:283
@ DirectoryFile
Definition: fatprocs.h:1047
struct _FileName FileName
Definition: fatprocs.h:897
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE FileHandle
Definition: fltkernel.h:1231
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define C_ASSERT(e)
Definition: intsafe.h:73
#define RtlEqualMemory(dst, src, len)
Definition: kdvm.h:18
static int ErrMsg(int Error)
Definition: lnktool.cpp:123
static unsigned char * fat
Definition: mkdosfs.c:542
UNICODE_STRING Volume
Definition: fltkernel.h:1172
#define ASSERT(a)
Definition: mode.c:44
#define sprintf
Definition: sprintf.c:45
static PLARGE_INTEGER Time
Definition: time.c:105
#define min(a, b)
Definition: monoChain.cc:55
#define _In_
Definition: no_sal2.h:158
int Count
Definition: noreturn.cpp:7
#define ANSI_NULL
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
static OUT PIO_STATUS_BLOCK OUT PVOID FileInformation
Definition: pipe.c:75
ULONG SectorCount
Definition: part_xbox.c:31
unsigned short USHORT
Definition: pedump.c:61
@ ESUCCESS
Definition: arc.h:32
ULONG ARC_STATUS
Definition: arc.h:4
@ SeekRelative
Definition: arc.h:60
@ SeekAbsolute
Definition: arc.h:59
enum _OPENMODE OPENMODE
@ ReadOnlyFile
Definition: arc.h:78
@ ArchiveFile
Definition: arc.h:81
@ SystemFile
Definition: arc.h:80
@ HiddenFile
Definition: arc.h:79
enum _SEEKMODE SEEKMODE
@ OpenDirectory
Definition: arc.h:72
@ OpenReadOnly
Definition: arc.h:65
struct _FAT32_BOOTSECTOR * PFAT32_BOOTSECTOR
struct _FAT_BOOTSECTOR * PFAT_BOOTSECTOR
#define TRACE(s)
Definition: solgame.cpp:4
Definition: fat.h:103
base of all file and directory entries
Definition: entries.h:83
WCHAR Name11_12[2]
Definition: fat.h:127
UCHAR SequenceNumber
Definition: fat.h:120
WCHAR Name5_10[6]
Definition: fat.h:125
WCHAR Name0_4[5]
Definition: fat.h:121
LIST_ENTRY Link
Definition: fat.c:453
PVOID Volume
Definition: fat.c:454
ULONG DirectorySize
Definition: fat.c:456
ULONG DirectoryStartCluster
Definition: fat.c:455
UCHAR Data[]
Definition: fat.c:457
USHORT BootSectorMagic
Definition: fsutil.c:98
CHAR FileSystemType[8]
Definition: fsutil.c:94
UCHAR Reserved[12]
Definition: fsutil.c:88
UCHAR MediaDescriptor
Definition: fsutil.c:76
ULONG HiddenSectors
Definition: fsutil.c:80
UCHAR NumberOfFats
Definition: fsutil.c:73
ULONG VolumeSerialNumber
Definition: fsutil.c:92
CHAR VolumeLabel[11]
Definition: fsutil.c:93
USHORT ExtendedFlags
Definition: fsutil.c:83
ULONG SectorsPerFatBig
Definition: fsutil.c:82
UCHAR JumpBoot[3]
Definition: fsutil.c:68
CHAR OemName[8]
Definition: fsutil.c:69
USHORT NumberOfHeads
Definition: fsutil.c:79
USHORT ReservedSectors
Definition: fsutil.c:72
USHORT RootDirEntries
Definition: fsutil.c:74
USHORT FsInfo
Definition: fsutil.c:86
USHORT BytesPerSector
Definition: fsutil.c:70
USHORT FileSystemVersion
Definition: fsutil.c:84
ULONG TotalSectorsBig
Definition: fsutil.c:81
UCHAR BootSignature
Definition: fsutil.c:91
ULONG RootDirStartCluster
Definition: fsutil.c:85
UCHAR DriveNumber
Definition: fsutil.c:89
UCHAR SectorsPerCluster
Definition: fsutil.c:71
USHORT SectorsPerFat
Definition: fsutil.c:77
USHORT SectorsPerTrack
Definition: fsutil.c:78
UCHAR Reserved1
Definition: fsutil.c:90
USHORT BackupBootSector
Definition: fsutil.c:87
USHORT TotalSectors
Definition: fsutil.c:75
ULONG VolumeSerialNumber
Definition: fat.h:91
ULONG SectorsPerCluster
Definition: fat.h:92
ULONG Unknown
Definition: fat.h:94
USHORT NumberOfFats
Definition: fat.h:93
CHAR FileSystemType[4]
Definition: fat.h:90
ULONG TotalSectorsBig
Definition: fsutil.c:51
UCHAR JumpBoot[3]
Definition: fsutil.c:38
USHORT SectorsPerTrack
Definition: fsutil.c:48
USHORT TotalSectors
Definition: fsutil.c:45
UCHAR NumberOfFats
Definition: fsutil.c:43
CHAR VolumeLabel[11]
Definition: fsutil.c:56
USHORT NumberOfHeads
Definition: fsutil.c:49
USHORT SectorsPerFat
Definition: fsutil.c:47
CHAR OemName[8]
Definition: fsutil.c:39
USHORT ReservedSectors
Definition: fsutil.c:42
ULONG HiddenSectors
Definition: fsutil.c:50
CHAR FileSystemType[8]
Definition: fsutil.c:57
USHORT BytesPerSector
Definition: fsutil.c:40
USHORT RootDirEntries
Definition: fsutil.c:44
ULONG VolumeSerialNumber
Definition: fsutil.c:55
UCHAR MediaDescriptor
Definition: fsutil.c:46
USHORT BootSectorMagic
Definition: fsutil.c:61
UCHAR Reserved1
Definition: fsutil.c:53
UCHAR DriveNumber
Definition: fsutil.c:52
UCHAR BootSignature
Definition: fsutil.c:54
UCHAR SectorsPerCluster
Definition: fsutil.c:41
ULONG FileSize
Definition: fat.h:168
ULONG FileNameLength
Definition: fat.h:172
PFAT_VOLUME_INFO Volume
Definition: fat.h:167
ULONG FilePointer
Definition: fat.h:169
ULONG CurrentCluster
Definition: fat.h:170
CHAR FileName[RTL_FIELD_SIZE(FILEINFORMATION, FileName)]
Definition: fat.h:174
UCHAR Attributes
Definition: fat.h:173
ULONG StartCluster
Definition: fat.h:171
UINT16 BytesPerSector
Definition: fat.c:53
ULONG RootDirSectors
Definition: fat.c:47
ULONG FatSectorStart
Definition: fat.c:43
ULONG DataSectorStart
Definition: fat.c:49
PULONG FatCacheIndex
Definition: fat.c:41
PUCHAR FatCache
Definition: fat.c:40
ULONG RootDirSectorStart
Definition: fat.c:46
UINT8 SectorsPerCluster
Definition: fat.c:54
ULONG FatCacheSize
Definition: fat.c:42
ULONG ActiveFatSectorStart
Definition: fat.c:44
ULONG DeviceId
Definition: fat.c:51
ULONG TotalSectors
Definition: fat.c:52
ULONG SectorsPerFat
Definition: fat.c:45
ULONG RootDirStartCluster
Definition: fat.c:48
UINT8 FatType
Definition: fat.c:56
UINT8 NumberOfFats
Definition: fat.c:55
PVOID Volume
Definition: fltmgrint.h:141
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
Definition: fs.h:25
static COORD Position
Definition: mouse.c:34
uint32_t * PULONG
Definition: typedefs.h:59
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
void * PVOID
Definition: typedefs.h:50
ULONG_PTR SIZE_T
Definition: typedefs.h:80
const char * PCSTR
Definition: typedefs.h:52
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
char * PCHAR
Definition: typedefs.h:51
LONGLONG QuadPart
Definition: typedefs.h:114
ULONG LowPart
Definition: typedefs.h:106
static int Link(const char **args)
Definition: vfdcmd.c:2414
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4539
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:870
_In_ WDFREQUEST _In_ NTSTATUS _In_ ULONG_PTR Information
Definition: wdfrequest.h:1049
#define FORCEINLINE
Definition: wdftypes.h:67
_In_ ULONG _In_ ULONG _In_ ULONG NumberOfHeads
Definition: iofuncs.h:2072
_In_ ULONG _In_ ULONG SectorsPerTrack
Definition: iofuncs.h:2071
unsigned char UCHAR
Definition: xmlstorage.h:181
char CHAR
Definition: xmlstorage.h:175