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