ReactOS 0.4.15-dev-7934-g1dc8d80
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 // We found the entry, now fill in the FAT_FILE_INFO struct
674 //
675 FatFileInfoPointer->Attributes = DirEntry->Attr;
676 FatFileInfoPointer->FileSize = DirEntry->Size;
677 FatFileInfoPointer->FilePointer = 0;
678 StartCluster = ((ULONG)DirEntry->ClusterHigh << 16) + DirEntry->ClusterLow;
679 FatFileInfoPointer->CurrentCluster = StartCluster;
680 FatFileInfoPointer->StartCluster = StartCluster;
681
682 TRACE("MSDOS Directory Entry:\n");
683 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]);
684 TRACE("Attr = 0x%x\n", DirEntry->Attr);
685 TRACE("ReservedNT = 0x%x\n", DirEntry->ReservedNT);
686 TRACE("TimeInTenths = %d\n", DirEntry->TimeInTenths);
687 TRACE("CreateTime = %d\n", DirEntry->CreateTime);
688 TRACE("CreateDate = %d\n", DirEntry->CreateDate);
689 TRACE("LastAccessDate = %d\n", DirEntry->LastAccessDate);
690 TRACE("ClusterHigh = 0x%x\n", DirEntry->ClusterHigh);
691 TRACE("Time = %d\n", DirEntry->Time);
692 TRACE("Date = %d\n", DirEntry->Date);
693 TRACE("ClusterLow = 0x%x\n", DirEntry->ClusterLow);
694 TRACE("Size = %d\n", DirEntry->Size);
695 TRACE("StartCluster = 0x%x\n", StartCluster);
696
697 return TRUE;
698 }
699
700 //
701 // Nope, no match - zero buffers and continue looking
702 //
703 RtlZeroMemory(ShortNameBuffer, 13 * sizeof(UCHAR));
704 RtlZeroMemory(LfnNameBuffer, 261 * sizeof(UCHAR));
705 continue;
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 //
789 // Figure out how many sub-directories we are nested in
790 //
791 NumberOfPathParts = FsGetNumPathParts(FileName);
792
793 //
794 // Loop once for each part
795 //
796 for (i=0; i<NumberOfPathParts; i++)
797 {
798 //
799 // Get first path part
800 //
802
803 //
804 // Advance to the next part of the path
805 //
806 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
807 {
808 }
809 FileName++;
810
811 //
812 // Buffer the directory contents
813 //
814 DirectoryBuffer = FatBufferDirectory(Volume, DirectoryStartCluster, &DirectorySize, (i == 0) );
815 if (DirectoryBuffer == NULL)
816 {
817 return ENOMEM;
818 }
819
820 //
821 // Search for file name in directory
822 //
823 if (ISFATX(Volume->FatType))
824 {
825 if (!FatXSearchDirectoryBufferForFile(Volume, DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo))
826 {
827 return ENOENT;
828 }
829 }
830 else
831 {
832 if (!FatSearchDirectoryBufferForFile(Volume, DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo))
833 {
834 return ENOENT;
835 }
836 }
837
838 //
839 // If we have another sub-directory to go then
840 // grab the start cluster and free the fat chain array
841 //
842 if ((i+1) < NumberOfPathParts)
843 {
844 //
845 // Check if current entry is a directory
846 //
847 if (!(FatFileInfo.Attributes & ATTR_DIRECTORY))
848 {
849 return ENOTDIR;
850 }
851 DirectoryStartCluster = FatFileInfo.StartCluster;
852 }
853 }
854
855 RtlCopyMemory(FatFileInfoPointer, &FatFileInfo, sizeof(FAT_FILE_INFO));
856
857 return ESUCCESS;
858}
859
860/*
861 * FatParseFileName()
862 * This function parses a directory entry name which
863 * is in the form of "FILE EXT" and puts it in Buffer
864 * in the form of "file.ext"
865 */
867{
868 ULONG Idx;
869
870 Idx = 0;
872
873 //
874 // Fixup first character
875 //
876 if (DirEntry->FileName[0] == 0x05)
877 {
878 DirEntry->FileName[0] = 0xE5;
879 }
880
881 //
882 // Get the file name
883 //
884 while (Idx < 8)
885 {
886 if (DirEntry->FileName[Idx] == ' ')
887 {
888 break;
889 }
890
891 Buffer[Idx] = DirEntry->FileName[Idx];
892 Idx++;
893 }
894
895 //
896 // Get extension
897 //
898 if ((DirEntry->FileName[8] != ' '))
899 {
900 Buffer[Idx++] = '.';
901 Buffer[Idx++] = (DirEntry->FileName[8] == ' ') ? '\0' : DirEntry->FileName[8];
902 Buffer[Idx++] = (DirEntry->FileName[9] == ' ') ? '\0' : DirEntry->FileName[9];
903 Buffer[Idx++] = (DirEntry->FileName[10] == ' ') ? '\0' : DirEntry->FileName[10];
904 }
905
906 //TRACE("FatParseShortFileName() ShortName = %s\n", Buffer);
907}
908
912static
914{
915 UINT32 SectorNumAbsolute = Volume->ActiveFatSectorStart + FatSectorNumber;
916 UINT32 CacheIndex = FatSectorNumber % Volume->FatCacheSize;
917
918 ASSERT(FatSectorNumber < Volume->SectorsPerFat);
919
920 // cache miss
921 if (Volume->FatCacheIndex[CacheIndex] != SectorNumAbsolute)
922 {
923 UINT32 SectorsToRead = min(Volume->FatCacheSize - CacheIndex, min(Volume->SectorsPerFat - SectorNumAbsolute, 4));
924 UINT8 i;
925
926 if (!FatReadVolumeSectors(Volume, SectorNumAbsolute, SectorsToRead, &Volume->FatCache[CacheIndex * Volume->BytesPerSector]))
927 {
928 return NULL;
929 }
930
931 for (i = 0; i < SectorsToRead; i++)
932 {
933 Volume->FatCacheIndex[CacheIndex + i] = SectorNumAbsolute + i;
934 }
935
936 TRACE("FAT cache miss: read sector 0x%x from disk\n", SectorNumAbsolute);
937 }
938 else
939 {
940 TRACE("FAT cache hit: sector 0x%x present\n", SectorNumAbsolute);
941 }
942
943 return &Volume->FatCache[CacheIndex * Volume->BytesPerSector];
944}
945
946/*
947 * FatGetFatEntry()
948 * returns the Fat entry for a given cluster number
949 */
950static
952{
953 UINT32 FatOffset, ThisFatSecNum, ThisFatEntOffset, fat;
955
956 TRACE("FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster);
957
958 switch(Volume->FatType)
959 {
960 case FAT12:
961
962 FatOffset = Cluster + (Cluster / 2);
963 ThisFatSecNum = FatOffset / Volume->BytesPerSector;
964 ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
965
966 TRACE("FatOffset: %d\n", FatOffset);
967 TRACE("ThisFatSecNum: %d\n", ThisFatSecNum);
968 TRACE("ThisFatEntOffset: %d\n", ThisFatEntOffset);
969
970 // The cluster pointer can span within two sectors, but the FatGetFatSector function
971 // reads 4 sectors most times, except when we are at the edge of FAT cache
972 // and/or FAT region on the disk. For FAT12 the whole FAT would be cached so
973 // there will be no situation when the first sector is at the end of the cache
974 // and the next one is in the beginning
975
976 ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
977 if (!ReadBuffer)
978 {
979 return FALSE;
980 }
981
982 fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
983 fat = SWAPW(fat);
984 if (Cluster & 0x0001)
985 fat = fat >> 4; /* Cluster number is ODD */
986 else
987 fat = fat & 0x0FFF; /* Cluster number is EVEN */
988
989 break;
990
991 case FAT16:
992 case FATX16:
993
994 FatOffset = (Cluster * 2);
995 ThisFatSecNum = FatOffset / Volume->BytesPerSector;
996 ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
997
998 ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
999 if (!ReadBuffer)
1000 {
1001 return FALSE;
1002 }
1003
1004 fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
1005 fat = SWAPW(fat);
1006
1007 break;
1008
1009 case FAT32:
1010 case FATX32:
1011
1012 FatOffset = (Cluster * 4);
1013 ThisFatSecNum = FatOffset / Volume->BytesPerSector;
1014 ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
1015
1016 ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
1017 if (!ReadBuffer)
1018 {
1019 return FALSE;
1020 }
1021
1022 // Get the fat entry
1023 fat = (*((ULONG *) (ReadBuffer + ThisFatEntOffset))) & 0x0FFFFFFF;
1024 fat = SWAPD(fat);
1025
1026 break;
1027
1028 default:
1029 ERR("Unknown FAT type %d\n", Volume->FatType);
1030 return FALSE;
1031 }
1032
1033 TRACE("FAT entry is 0x%x.\n", fat);
1034
1035 *ClusterPointer = fat;
1036
1037 return TRUE;
1038}
1039
1040static
1042{
1043 ULONG ClusterCount = 0;
1044
1045 TRACE("FatCountClustersInChain() StartCluster = %d\n", StartCluster);
1046
1047 while (1)
1048 {
1049 //
1050 // If end of chain then break out of our cluster counting loop
1051 //
1052 if (FAT_IS_END_CLUSTER(StartCluster))
1053 {
1054 break;
1055 }
1056
1057 //
1058 // Increment count
1059 //
1060 ClusterCount++;
1061
1062 //
1063 // Get next cluster
1064 //
1065 if (!FatGetFatEntry(Volume, StartCluster, &StartCluster))
1066 {
1067 return 0;
1068 }
1069 }
1070
1071 TRACE("FatCountClustersInChain() ClusterCount = %d\n", ClusterCount);
1072
1073 return ClusterCount;
1074}
1075
1076static
1079 UINT32 StartClusterNumber,
1080 UINT32 MaxClusters,
1081 PVOID Buffer,
1082 PUINT32 ClustersRead,
1083 PUINT32 LastClusterNumber)
1084{
1085 UINT32 NextClusterNumber;
1086 UINT32 ClustersToRead = 1;
1087 UINT32 PrevClusterNumber = StartClusterNumber;
1088 UINT32 ClusterStartSector = ((PrevClusterNumber - 2) * Volume->SectorsPerCluster) + Volume->DataSectorStart;
1089
1090 *ClustersRead = 0;
1091 *LastClusterNumber = 0;
1092
1093 if (!FatGetFatEntry(Volume, StartClusterNumber, &NextClusterNumber))
1094 {
1095 return FALSE;
1096 }
1097
1098 // getting the number of adjacent clusters
1099 while (!FAT_IS_END_CLUSTER(NextClusterNumber) && ClustersToRead < MaxClusters && (NextClusterNumber == PrevClusterNumber + 1))
1100 {
1101 ClustersToRead++;
1102 PrevClusterNumber = NextClusterNumber;
1103 if (!FatGetFatEntry(Volume, PrevClusterNumber, &NextClusterNumber))
1104 {
1105 return FALSE;
1106 }
1107 }
1108
1109 if (!FatReadVolumeSectors(Volume, ClusterStartSector, ClustersToRead * Volume->SectorsPerCluster, Buffer))
1110 {
1111 return FALSE;
1112 }
1113
1114 *ClustersRead = ClustersToRead;
1115 *LastClusterNumber = NextClusterNumber;
1116
1117 return !FAT_IS_END_CLUSTER(NextClusterNumber) && ClustersToRead < MaxClusters;
1118}
1119
1120/*
1121 * FatReadClusterChain()
1122 * Reads the specified clusters into memory
1123 */
1124static
1125BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, UINT32 StartClusterNumber, UINT32 NumberOfClusters, PVOID Buffer, PUINT32 LastClusterNumber)
1126{
1127 UINT32 ClustersRead, NextClusterNumber, ClustersLeft = NumberOfClusters;
1128
1129 TRACE("FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer);
1130
1131 ASSERT(NumberOfClusters > 0);
1132
1133 while (FatReadAdjacentClusters(Volume, StartClusterNumber, ClustersLeft, Buffer, &ClustersRead, &NextClusterNumber))
1134 {
1135 ClustersLeft -= ClustersRead;
1136 Buffer = (PVOID)((ULONG_PTR)Buffer + (ClustersRead * Volume->SectorsPerCluster * Volume->BytesPerSector));
1137 StartClusterNumber = NextClusterNumber;
1138 }
1139
1140 if (LastClusterNumber)
1141 {
1142 *LastClusterNumber = NextClusterNumber;
1143 }
1144
1145 return (ClustersRead > 0);
1146}
1147
1148/*
1149 * FatReadPartialCluster()
1150 * Reads part of a cluster into memory
1151 */
1153{
1154 ULONG ClusterStartSector;
1155 ULONG SectorOffset, ReadSize, SectorCount;
1158
1159 //TRACE("FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber, StartingOffset, Length, Buffer);
1160
1161 ClusterStartSector = ((ClusterNumber - 2) * Volume->SectorsPerCluster) + Volume->DataSectorStart;
1162
1163 // This is the offset of the data in sectors
1164 SectorOffset = (StartingOffset / Volume->BytesPerSector);
1165 StartingOffset %= Volume->BytesPerSector;
1166
1167 // Calculate how many sectors we need to read
1168 SectorCount = (StartingOffset + Length + Volume->BytesPerSector - 1) / Volume->BytesPerSector;
1169
1170 // Calculate rounded up read size
1171 ReadSize = SectorCount * Volume->BytesPerSector;
1172
1174 if (!ReadBuffer)
1175 {
1176 return FALSE;
1177 }
1178
1179 if (FatReadVolumeSectors(Volume, ClusterStartSector + SectorOffset, SectorCount, ReadBuffer))
1180 {
1182 Success = TRUE;
1183 }
1184
1186
1187 return Success;
1188}
1189
1190/*
1191 * FatReadFile()
1192 * Reads BytesToRead from open file and
1193 * returns the number of bytes read in BytesRead
1194 */
1195static
1197{
1198 PFAT_VOLUME_INFO Volume = FatFileInfo->Volume;
1199 UINT32 NextClusterNumber, BytesPerCluster;
1200
1201 TRACE("FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead, Buffer);
1202
1203 if (BytesRead != NULL)
1204 {
1205 *BytesRead = 0;
1206 }
1207
1208 //
1209 // If the user is trying to read past the end of
1210 // the file then return success with BytesRead == 0.
1211 //
1212 if (FatFileInfo->FilePointer >= FatFileInfo->FileSize)
1213 {
1214 return TRUE;
1215 }
1216
1217 //
1218 // If the user is trying to read more than there is to read
1219 // then adjust the amount to read.
1220 //
1221 if ((FatFileInfo->FilePointer + BytesToRead) > FatFileInfo->FileSize)
1222 {
1223 BytesToRead = (FatFileInfo->FileSize - FatFileInfo->FilePointer);
1224 }
1225
1226 //
1227 // Ok, now we have to perform at most 3 calculations
1228 // I'll draw you a picture (using nifty ASCII art):
1229 //
1230 // CurrentFilePointer -+
1231 // |
1232 // +----------------+
1233 // |
1234 // +-----------+-----------+-----------+-----------+
1235 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
1236 // +-----------+-----------+-----------+-----------+
1237 // | |
1238 // +---------------+--------------------+
1239 // |
1240 // BytesToRead -------+
1241 //
1242 // 1 - The first calculation (and read) will align
1243 // the file pointer with the next cluster.
1244 // boundary (if we are supposed to read that much)
1245 // 2 - The next calculation (and read) will read
1246 // in all the full clusters that the requested
1247 // amount of data would cover (in this case
1248 // clusters 2 & 3).
1249 // 3 - The last calculation (and read) would read
1250 // in the remainder of the data requested out of
1251 // the last cluster.
1252 //
1253
1254 BytesPerCluster = Volume->SectorsPerCluster * Volume->BytesPerSector;
1255
1256 //
1257 // Only do the first read if we
1258 // aren't aligned on a cluster boundary
1259 //
1260 if (FatFileInfo->FilePointer % BytesPerCluster)
1261 {
1262 //
1263 // Do the math for our first read
1264 //
1265 UINT32 OffsetInCluster = FatFileInfo->FilePointer % BytesPerCluster;
1266 UINT32 LengthInCluster = min(BytesToRead, BytesPerCluster - OffsetInCluster);
1267
1268 ASSERT(LengthInCluster <= BytesPerCluster && LengthInCluster > 0);
1269
1270 //
1271 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1272 //
1273 if (!FatReadPartialCluster(Volume, FatFileInfo->CurrentCluster, OffsetInCluster, LengthInCluster, Buffer))
1274 {
1275 return FALSE;
1276 }
1277 if (BytesRead != NULL)
1278 {
1279 *BytesRead += LengthInCluster;
1280 }
1281 BytesToRead -= LengthInCluster;
1282 FatFileInfo->FilePointer += LengthInCluster;
1283 Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInCluster);
1284
1285 // get the next cluster if needed
1286 if ((LengthInCluster + OffsetInCluster) == BytesPerCluster)
1287 {
1288 if (!FatGetFatEntry(Volume, FatFileInfo->CurrentCluster, &NextClusterNumber))
1289 {
1290 return FALSE;
1291 }
1292
1293 FatFileInfo->CurrentCluster = NextClusterNumber;
1294 TRACE("FatReadFile() FatFileInfo->CurrentCluster = 0x%x\n", FatFileInfo->CurrentCluster);
1295 }
1296 }
1297
1298 //
1299 // Do the math for our second read (if any data left)
1300 //
1301 if (BytesToRead > 0)
1302 {
1303 //
1304 // Determine how many full clusters we need to read
1305 //
1306 UINT32 NumberOfClusters = BytesToRead / BytesPerCluster;
1307
1308 TRACE("Going to read: %u clusters\n", NumberOfClusters);
1309
1310 if (NumberOfClusters > 0)
1311 {
1312 UINT32 BytesReadHere = NumberOfClusters * BytesPerCluster;
1313
1315
1316 if (!FatReadClusterChain(Volume, FatFileInfo->CurrentCluster, NumberOfClusters, Buffer, &NextClusterNumber))
1317 {
1318 return FALSE;
1319 }
1320
1321 if (BytesRead != NULL)
1322 {
1323 *BytesRead += BytesReadHere;
1324 }
1325 BytesToRead -= BytesReadHere;
1326 Buffer = (PVOID)((ULONG_PTR)Buffer + BytesReadHere);
1327
1328 ASSERT(!FAT_IS_END_CLUSTER(NextClusterNumber) || BytesToRead == 0);
1329
1330 FatFileInfo->FilePointer += BytesReadHere;
1331 FatFileInfo->CurrentCluster = NextClusterNumber;
1332 TRACE("FatReadFile() FatFileInfo->CurrentCluster = 0x%x\n", FatFileInfo->CurrentCluster);
1333 }
1334 }
1335
1336 //
1337 // Do the math for our third read (if any data left)
1338 //
1339 if (BytesToRead > 0)
1340 {
1342
1343 //
1344 // Now do the read and update BytesRead & FilePointer
1345 //
1346 if (!FatReadPartialCluster(Volume, FatFileInfo->CurrentCluster, 0, BytesToRead, Buffer))
1347 {
1348 return FALSE;
1349 }
1350 if (BytesRead != NULL)
1351 {
1352 *BytesRead += BytesToRead;
1353 }
1354 FatFileInfo->FilePointer += BytesToRead;
1355 }
1356
1357 return TRUE;
1358}
1359
1361{
1363 ULONG Count;
1365
1366 //TRACE("FatReadVolumeSectors(): SectorNumber %d, SectorCount %d, Buffer %p\n",
1367 // SectorNumber, SectorCount, Buffer);
1368
1369 //
1370 // Seek to right position
1371 //
1372 Position.QuadPart = (ULONGLONG)SectorNumber * 512;
1373 Status = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
1374 if (Status != ESUCCESS)
1375 {
1376 TRACE("FatReadVolumeSectors() Failed to seek\n");
1377 return FALSE;
1378 }
1379
1380 //
1381 // Read data
1382 //
1383 Status = ArcRead(Volume->DeviceId, Buffer, SectorCount * 512, &Count);
1384 if (Status != ESUCCESS || Count != SectorCount * 512)
1385 {
1386 TRACE("FatReadVolumeSectors() Failed to read\n");
1387 return FALSE;
1388 }
1389
1390 // Return success
1391 return TRUE;
1392}
1393
1395{
1397
1399
1400 return ESUCCESS;
1401}
1402
1404{
1406
1408 Information->EndingAddress.LowPart = FileHandle->FileSize;
1409 Information->CurrentAddress.LowPart = FileHandle->FilePointer;
1410
1411 TRACE("FatGetFileInformation(%lu) -> FileSize = %lu, FilePointer = 0x%lx\n",
1412 FileId, Information->EndingAddress.LowPart, Information->CurrentAddress.LowPart);
1413
1414 return ESUCCESS;
1415}
1416
1418{
1419 PFAT_VOLUME_INFO FatVolume;
1420 FAT_FILE_INFO TempFileInfo;
1422 ULONG DeviceId;
1425
1426 if (OpenMode != OpenReadOnly && OpenMode != OpenDirectory)
1427 return EACCES;
1428
1429 DeviceId = FsGetDeviceId(*FileId);
1430 FatVolume = FatVolumes[DeviceId];
1431
1432 TRACE("FatOpen() FileName = %s\n", Path);
1433
1434 RtlZeroMemory(&TempFileInfo, sizeof(TempFileInfo));
1435 Status = FatLookupFile(FatVolume, Path, &TempFileInfo);
1436 if (Status != ESUCCESS)
1437 return ENOENT;
1438
1439 //
1440 // Check if caller opened what he expected (dir vs file)
1441 //
1442 IsDirectory = (TempFileInfo.Attributes & ATTR_DIRECTORY) != 0;
1443 if (IsDirectory && OpenMode != OpenDirectory)
1444 return EISDIR;
1445 else if (!IsDirectory && OpenMode != OpenReadOnly)
1446 return ENOTDIR;
1447
1449 if (!FileHandle)
1450 return ENOMEM;
1451
1452 RtlCopyMemory(FileHandle, &TempFileInfo, sizeof(FAT_FILE_INFO));
1453 FileHandle->Volume = FatVolume;
1454
1456 return ESUCCESS;
1457}
1458
1460{
1463
1464 //
1465 // Call old read method
1466 //
1468
1469 //
1470 // Check for success
1471 //
1472 if (Success)
1473 return ESUCCESS;
1474 else
1475 return EIO;
1476}
1477
1479{
1482 LARGE_INTEGER NewPosition = *Position;
1483
1484 switch (SeekMode)
1485 {
1486 case SeekAbsolute:
1487 break;
1488 case SeekRelative:
1489 NewPosition.QuadPart += (ULONGLONG)FileHandle->FilePointer;
1490 break;
1491 default:
1492 ASSERT(FALSE);
1493 return EINVAL;
1494 }
1495
1496 if (NewPosition.HighPart != 0)
1497 return EINVAL;
1498 if (NewPosition.LowPart >= FileHandle->FileSize)
1499 return EINVAL;
1500
1501 TRACE("FatSeek() NewPosition = %u, OldPointer = %u, SeekMode = %d\n", NewPosition.LowPart, FileHandle->FilePointer, SeekMode);
1502
1503 {
1504 UINT32 OldClusterIdx = FileHandle->FilePointer / (Volume->SectorsPerCluster * Volume->BytesPerSector);
1505 UINT32 NewClusterIdx = NewPosition.LowPart / (Volume->SectorsPerCluster * Volume->BytesPerSector);
1506
1507 TRACE("FatSeek() OldClusterIdx: %u, NewClusterIdx: %u\n", OldClusterIdx, NewClusterIdx);
1508
1509 if (NewClusterIdx != OldClusterIdx)
1510 {
1511 UINT32 CurrentClusterIdx, ClusterNumber;
1512
1513 if (NewClusterIdx > OldClusterIdx)
1514 {
1515 CurrentClusterIdx = OldClusterIdx;
1516 ClusterNumber = FileHandle->CurrentCluster;
1517 }
1518 else
1519 {
1520 CurrentClusterIdx = 0;
1521 ClusterNumber = FileHandle->StartCluster;
1522 }
1523
1524 for (; CurrentClusterIdx < NewClusterIdx; CurrentClusterIdx++)
1525 {
1526 if (!FatGetFatEntry(Volume, ClusterNumber, &ClusterNumber))
1527 {
1528 return EIO;
1529 }
1530 }
1531 FileHandle->CurrentCluster = ClusterNumber;
1532 }
1533 }
1534
1535 FileHandle->FilePointer = NewPosition.LowPart;
1536
1537 return ESUCCESS;
1538}
1539
1541{
1542 FatClose,
1544 FatOpen,
1545 FatRead,
1546 FatSeek,
1547 L"fastfat",
1548};
1549
1551{
1552 FatClose,
1554 FatOpen,
1555 FatRead,
1556 FatSeek,
1557 L"vfatfs",
1558};
1559
1560const DEVVTBL* FatMount(ULONG DeviceId)
1561{
1563 UCHAR Buffer[512];
1569 ULONG Count;
1572
1573 TRACE("Enter FatMount(%lu)\n", DeviceId);
1574
1575 //
1576 // Allocate data for volume information
1577 //
1579 if (!Volume)
1580 return NULL;
1582
1583 //
1584 // Read the BootSector
1585 //
1586 Position.QuadPart = 0;
1587 Status = ArcSeek(DeviceId, &Position, SeekAbsolute);
1588 if (Status != ESUCCESS)
1589 {
1591 return NULL;
1592 }
1593 Status = ArcRead(DeviceId, Buffer, sizeof(Buffer), &Count);
1594 if (Status != ESUCCESS || Count != sizeof(Buffer))
1595 {
1597 return NULL;
1598 }
1599
1600 //
1601 // Check if BootSector is valid. If no, return early
1602 //
1603 if (!RtlEqualMemory(BootSector->FileSystemType, "FAT12 ", 8) &&
1604 !RtlEqualMemory(BootSector->FileSystemType, "FAT16 ", 8) &&
1605 !RtlEqualMemory(BootSector32->FileSystemType, "FAT32 ", 8) &&
1606 !RtlEqualMemory(BootSectorX->FileSystemType, "FATX", 4))
1607 {
1609 return NULL;
1610 }
1611
1612 //
1613 // Determine sector count
1614 //
1616 if (Status != ESUCCESS)
1617 {
1619 return NULL;
1620 }
1621 SectorCount.QuadPart = (FileInformation.EndingAddress.QuadPart - FileInformation.StartingAddress.QuadPart);
1622 SectorCount.QuadPart /= SECTOR_SIZE;
1623
1624 //
1625 // Keep device id
1626 //
1627 Volume->DeviceId = DeviceId;
1628
1629 //
1630 // Really open the volume
1631 //
1632 if (!FatOpenVolume(Volume, BootSector, SectorCount.QuadPart))
1633 {
1635 return NULL;
1636 }
1637
1638 //
1639 // Remember FAT volume information
1640 //
1641 FatVolumes[DeviceId] = Volume;
1642
1643 //
1644 // Return success
1645 //
1646 TRACE("FatMount(%lu) success\n", DeviceId);
1647 return (ISFATX(Volume->FatType) ? &FatXFuncTable : &FatFuncTable);
1648}
#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
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 ERR(fmt,...)
Definition: debug.h:110
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:103
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:252
ARC_STATUS ArcSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fs.c:245
ULONG FsGetNumPathParts(PCSTR Path)
Definition: fs.c:330
VOID FileSystemError(PCSTR ErrorString)
Definition: fs.c:261
ULONG FsGetDeviceId(ULONG FileId)
Definition: fs.c:425
VOID * FsGetDeviceSpecific(ULONG FileId)
Definition: fs.c:418
#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:238
VOID FsSetDeviceSpecific(ULONG FileId, VOID *Specific)
Definition: fs.c:411
VOID FsGetFirstNameFromPath(PCHAR Buffer, PCSTR Path)
Definition: fs.c:358
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:913
static BOOLEAN FatReadAdjacentClusters(PFAT_VOLUME_INFO Volume, UINT32 StartClusterNumber, UINT32 MaxClusters, PVOID Buffer, PUINT32 ClustersRead, PUINT32 LastClusterNumber)
Definition: fat.c:1077
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:951
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:1125
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:1196
ARC_STATUS FatOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: fat.c:1417
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:1041
#define TAG_FAT_VOLUME
Definition: fat.c:33
const DEVVTBL FatXFuncTable
Definition: fat.c:1550
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:1478
BOOLEAN FatReadVolumeSectors(PFAT_VOLUME_INFO Volume, ULONG SectorNumber, ULONG SectorCount, PVOID Buffer)
Definition: fat.c:1360
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:1459
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:1540
ARC_STATUS FatGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: fat.c:1403
struct _FAT_VOLUME_INFO FAT_VOLUME_INFO
void FatParseShortFileName(PCHAR Buffer, PDIRENTRY DirEntry)
Definition: fat.c:866
LIST_ENTRY DirectoryBufferListHead
Definition: fat.c:417
ARC_STATUS FatClose(ULONG FileId)
Definition: fat.c:1394
BOOLEAN FatReadPartialCluster(PFAT_VOLUME_INFO Volume, ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
Definition: fat.c:1152
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
_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(a, b, c)
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