ReactOS  0.4.14-dev-55-g2da92ac
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>
13 DBG_DEFAULT_CHANNEL(FILESYSTEM);
14 
16 PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, ULONG* EntryCountPointer, BOOLEAN RootDirectory);
17 BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG EntryCount, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer);
20 static BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, UINT32 Cluster, PUINT32 ClusterPointer);
22 static 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 
39 typedef 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);
243  FileSystemError(ErrMsg);
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");
331  FrLdrTempFree(Volume->FatCache, TAG_FAT_CACHE);
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");
339  FrLdrTempFree(Volume->FatCache, TAG_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 
408 typedef 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  memset(ShortNameBuffer, 0, 13 * sizeof(CHAR));
523  memset(LfnNameBuffer, 0, 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  memset(ShortNameBuffer, 0, 13 * sizeof(CHAR));
552  memset(LfnNameBuffer, 0, 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  memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR));
646  memset(LfnNameBuffer, 0, 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  memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR));
704  memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR));
705  continue;
706  }
707 
708  return FALSE;
709 }
710 
711 static 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  memset(FatFileInfoPointer, 0, 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  //
801  FsGetFirstNameFromPath(PathPart, FileName);
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  memcpy(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;
871  RtlZeroMemory(Buffer, 13);
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 
912 static
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  */
950 static
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 
1040 static
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 
1076 static
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  */
1124 static
1125 BOOLEAN 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;
1157  BOOLEAN Success = FALSE;
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  */
1195 static
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 
1314  ASSERT(!FAT_IS_END_CLUSTER(FatFileInfo->CurrentCluster));
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  {
1341  ASSERT(!FAT_IS_END_CLUSTER(FatFileInfo->CurrentCluster));
1342 
1343  //
1344  // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
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  BytesToRead -= BytesToRead;
1356  Buffer = (PVOID)((ULONG_PTR)Buffer + BytesToRead);
1357  }
1358 
1359  return TRUE;
1360 }
1361 
1363 {
1365  ULONG Count;
1367 
1368  //TRACE("FatReadVolumeSectors(): SectorNumber %d, SectorCount %d, Buffer %p\n",
1369  // SectorNumber, SectorCount, Buffer);
1370 
1371  //
1372  // Seek to right position
1373  //
1374  Position.QuadPart = (ULONGLONG)SectorNumber * 512;
1375  Status = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
1376  if (Status != ESUCCESS)
1377  {
1378  TRACE("FatReadVolumeSectors() Failed to seek\n");
1379  return FALSE;
1380  }
1381 
1382  //
1383  // Read data
1384  //
1385  Status = ArcRead(Volume->DeviceId, Buffer, SectorCount * 512, &Count);
1386  if (Status != ESUCCESS || Count != SectorCount * 512)
1387  {
1388  TRACE("FatReadVolumeSectors() Failed to read\n");
1389  return FALSE;
1390  }
1391 
1392  // Return success
1393  return TRUE;
1394 }
1395 
1397 {
1399 
1401 
1402  return ESUCCESS;
1403 }
1404 
1406 {
1408 
1410  Information->EndingAddress.LowPart = FileHandle->FileSize;
1411  Information->CurrentAddress.LowPart = FileHandle->FilePointer;
1412 
1413  TRACE("FatGetFileInformation(%lu) -> FileSize = %lu, FilePointer = 0x%lx\n",
1414  FileId, Information->EndingAddress.LowPart, Information->CurrentAddress.LowPart);
1415 
1416  return ESUCCESS;
1417 }
1418 
1420 {
1421  PFAT_VOLUME_INFO FatVolume;
1422  FAT_FILE_INFO TempFileInfo;
1424  ULONG DeviceId;
1427 
1428  if (OpenMode != OpenReadOnly && OpenMode != OpenDirectory)
1429  return EACCES;
1430 
1431  DeviceId = FsGetDeviceId(*FileId);
1432  FatVolume = FatVolumes[DeviceId];
1433 
1434  TRACE("FatOpen() FileName = %s\n", Path);
1435 
1436  RtlZeroMemory(&TempFileInfo, sizeof(TempFileInfo));
1437  Status = FatLookupFile(FatVolume, Path, &TempFileInfo);
1438  if (Status != ESUCCESS)
1439  return ENOENT;
1440 
1441  //
1442  // Check if caller opened what he expected (dir vs file)
1443  //
1444  IsDirectory = (TempFileInfo.Attributes & ATTR_DIRECTORY) != 0;
1445  if (IsDirectory && OpenMode != OpenDirectory)
1446  return EISDIR;
1447  else if (!IsDirectory && OpenMode != OpenReadOnly)
1448  return ENOTDIR;
1449 
1451  if (!FileHandle)
1452  return ENOMEM;
1453 
1454  RtlCopyMemory(FileHandle, &TempFileInfo, sizeof(FAT_FILE_INFO));
1455  FileHandle->Volume = FatVolume;
1456 
1457  FsSetDeviceSpecific(*FileId, FileHandle);
1458  return ESUCCESS;
1459 }
1460 
1462 {
1464  BOOLEAN Success;
1465 
1466  //
1467  // Call old read method
1468  //
1470 
1471  //
1472  // Check for success
1473  //
1474  if (Success)
1475  return ESUCCESS;
1476  else
1477  return EIO;
1478 }
1479 
1481 {
1484  LARGE_INTEGER NewPosition = *Position;
1485 
1486  switch (SeekMode)
1487  {
1488  case SeekAbsolute:
1489  break;
1490  case SeekRelative:
1491  NewPosition.QuadPart += (ULONGLONG)FileHandle->FilePointer;
1492  break;
1493  default:
1494  ASSERT(FALSE);
1495  return EINVAL;
1496  }
1497 
1498  if (NewPosition.HighPart != 0)
1499  return EINVAL;
1500  if (NewPosition.LowPart >= FileHandle->FileSize)
1501  return EINVAL;
1502 
1503  TRACE("FatSeek() NewPosition = %u, OldPointer = %u, SeekMode = %d\n", NewPosition.LowPart, FileHandle->FilePointer, SeekMode);
1504 
1505  {
1506  UINT32 OldClusterIdx = FileHandle->FilePointer / (Volume->SectorsPerCluster * Volume->BytesPerSector);
1507  UINT32 NewClusterIdx = NewPosition.LowPart / (Volume->SectorsPerCluster * Volume->BytesPerSector);
1508 
1509  TRACE("FatSeek() OldClusterIdx: %u, NewClusterIdx: %u\n", OldClusterIdx, NewClusterIdx);
1510 
1511  if (NewClusterIdx != OldClusterIdx)
1512  {
1513  UINT32 CurrentClusterIdx, ClusterNumber;
1514 
1515  if (NewClusterIdx > OldClusterIdx)
1516  {
1517  CurrentClusterIdx = OldClusterIdx;
1518  ClusterNumber = FileHandle->CurrentCluster;
1519  }
1520  else
1521  {
1522  CurrentClusterIdx = 0;
1523  ClusterNumber = FileHandle->StartCluster;
1524  }
1525 
1526  for (; CurrentClusterIdx < NewClusterIdx; CurrentClusterIdx++)
1527  {
1528  if (!FatGetFatEntry(Volume, ClusterNumber, &ClusterNumber))
1529  {
1530  return EIO;
1531  }
1532  }
1533  FileHandle->CurrentCluster = ClusterNumber;
1534  }
1535  }
1536 
1537  FileHandle->FilePointer = NewPosition.LowPart;
1538 
1539  return ESUCCESS;
1540 }
1541 
1543 {
1544  FatClose,
1546  FatOpen,
1547  FatRead,
1548  FatSeek,
1549  L"fastfat",
1550 };
1551 
1552 const DEVVTBL* FatMount(ULONG DeviceId)
1553 {
1555  UCHAR Buffer[512];
1558  PFATX_BOOTSECTOR BootSectorX = (PFATX_BOOTSECTOR)Buffer;
1561  ULONG Count;
1564 
1565  TRACE("Enter FatMount(%lu)\n", DeviceId);
1566 
1567  //
1568  // Allocate data for volume information
1569  //
1571  if (!Volume)
1572  return NULL;
1574 
1575  //
1576  // Read the BootSector
1577  //
1578  Position.QuadPart = 0;
1579  Status = ArcSeek(DeviceId, &Position, SeekAbsolute);
1580  if (Status != ESUCCESS)
1581  {
1583  return NULL;
1584  }
1585  Status = ArcRead(DeviceId, Buffer, sizeof(Buffer), &Count);
1586  if (Status != ESUCCESS || Count != sizeof(Buffer))
1587  {
1589  return NULL;
1590  }
1591 
1592  //
1593  // Check if BootSector is valid. If no, return early
1594  //
1595  if (!RtlEqualMemory(BootSector->FileSystemType, "FAT12 ", 8) &&
1596  !RtlEqualMemory(BootSector->FileSystemType, "FAT16 ", 8) &&
1597  !RtlEqualMemory(BootSector32->FileSystemType, "FAT32 ", 8) &&
1598  !RtlEqualMemory(BootSectorX->FileSystemType, "FATX", 4))
1599  {
1601  return NULL;
1602  }
1603 
1604  //
1605  // Determine sector count
1606  //
1608  if (Status != ESUCCESS)
1609  {
1611  return NULL;
1612  }
1613  SectorCount.QuadPart = (FileInformation.EndingAddress.QuadPart - FileInformation.StartingAddress.QuadPart);
1614  SectorCount.QuadPart /= SECTOR_SIZE;
1615 
1616  //
1617  // Keep device id
1618  //
1619  Volume->DeviceId = DeviceId;
1620 
1621  //
1622  // Really open the volume
1623  //
1624  if (!FatOpenVolume(Volume, BootSector, SectorCount.QuadPart))
1625  {
1627  return NULL;
1628  }
1629 
1630  //
1631  // Remember FAT volume information
1632  //
1633  FatVolumes[DeviceId] = Volume;
1634 
1635  //
1636  // Return success
1637  //
1638  TRACE("FatMount(%lu) success\n", DeviceId);
1639  return &FatFuncTable;
1640 }
USHORT BytesPerSector
Definition: bootsup.c:79
UCHAR SectorsPerCluster
Definition: bootsup.c:51
signed char * PCHAR
Definition: retypes.h:7
#define FAT12
Definition: fat.h:167
#define SD(Object, Field)
Definition: bytesex.h:10
struct DIRENTRY * PDIRENTRY
UINT8 NumberOfFats
Definition: fat.c:54
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, ULONG *EntryCountPointer, BOOLEAN RootDirectory)
Definition: fat.c:419
VOID FatSwapFatXBootSector(PFATX_BOOTSECTOR Obj)
Definition: fat.c:95
#define FAT_MAX_CACHE_SIZE
Definition: fat.c:37
#define ROUND_UP(n, align)
Definition: eventvwr.h:31
VOID FsGetFirstNameFromPath(PCHAR Buffer, PCSTR Path)
Definition: fs.c:356
#define SWAPW(x)
Definition: bytesex.h:8
WCHAR RootDirectory[MAX_PATH]
Definition: format.c:74
UCHAR SectorsPerCluster
Definition: bootsup.c:80
UCHAR SequenceNumber
Definition: fat.h:120
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:282
USHORT TotalSectors
Definition: bootsup.c:55
struct _Entry Entry
Definition: kefuncs.h:640
VOID FatSwapDirEntry(PDIRENTRY Obj)
Definition: fat.c:102
UCHAR Reserved1
Definition: bootsup.c:99
ULONG FatSectorStart
Definition: fat.c:44
#define TAG_FAT_BUFFER
Definition: fat.c:34
Definition: arc.h:32
NTSTATUS FatMount(_In_ ULONG DeviceId, _In_ ULONG Unknown, _Out_ PBL_FILE_ENTRY *FileEntry)
Definition: fat.c:23
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
USHORT BootSectorMagic
Definition: bootsup.c:107
unsigned int * PUINT32
Definition: basetsd.h:127
static BOOLEAN FatXSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
Definition: fat.c:711
Definition: arc.h:39
static COORD Position
Definition: mouse.c:34
unsigned char * PUCHAR
Definition: retypes.h:3
char CHAR
Definition: xmlstorage.h:175
#define ReadBuffer(BaseIoAddress, Buffer, Count)
Definition: atapi.h:339
UCHAR JumpBoot[3]
Definition: bootsup.c:77
Definition: fs.h:24
ULONG StartCluster
Definition: fat.h:154
PFAT_VOLUME_INFO Volume
Definition: fat.h:150
#define ISFATX(FT)
Definition: fat.h:173
UINT8 FatType
Definition: fat.c:53
VOID FatSwapFatXDirEntry(PFATX_DIRENTRY Obj)
Definition: fat.c:126
#define SWAPD(x)
Definition: bytesex.h:7
struct _FAT_VOLUME_INFO FAT_VOLUME_INFO
ULONG FsGetNumPathParts(PCSTR Path)
Definition: fs.c:328
static OUT PIO_STATUS_BLOCK OUT PVOID FileInformation
Definition: pipe.c:75
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
ULONG TotalSectorsBig
Definition: bootsup.c:90
#define SW(Object, Field)
Definition: bytesex.h:11
static BOOLEAN FatReadAdjacentClusters(PFAT_VOLUME_INFO Volume, UINT32 StartClusterNumber, UINT32 MaxClusters, PVOID Buffer, PUINT32 ClustersRead, PUINT32 LastClusterNumber)
Definition: fat.c:1077
ULONG ARC_STATUS
Definition: arc.h:4
_In_ ULONG _In_ ULONG _In_ ULONG NumberOfHeads
Definition: iofuncs.h:2066
#define InsertTailList(ListHead, Entry)
struct FATX_DIRENTRY * PFATX_DIRENTRY
#define ATTR_LONG_NAME
Definition: fat.h:165
#define _stricmp
Definition: cat.c:22
VOID * FsGetDeviceSpecific(ULONG FileId)
Definition: fs.c:416
static BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, UINT32 StartClusterNumber, UINT32 NumberOfClusters, PVOID Buffer, PUINT32 LastClusterNumber)
Definition: fat.c:1125
Definition: arc.h:48
static int Link(const char **args)
Definition: vfdcmd.c:2414
PVOID Volume
Definition: fat.c:411
LIST_ENTRY Link
Definition: fat.c:410
static PUCHAR FatGetFatSector(PFAT_VOLUME_INFO Volume, UINT32 FatSectorNumber)
Reads 1-4 sectors from FAT using the cache.
Definition: fat.c:913
static BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, UINT32 Cluster, PUINT32 ClusterPointer)
Definition: fat.c:951
BOOL BackupBootSector(LPCTSTR lpszVolumeName)
Definition: install.c:61
ULONG VolumeSerialNumber
Definition: bootsup.c:101
DBG_DEFAULT_CHANNEL(FILESYSTEM)
uint32_t ULONG_PTR
Definition: typedefs.h:63
USHORT BytesPerSector
Definition: bootsup.c:50
CHAR VolumeLabel[11]
Definition: bootsup.c:66
#define sprintf(buf, format,...)
Definition: sprintf.c:55
#define ATTR_VOLUMENAME
Definition: fat.h:162
HANDLE FileHandle
Definition: stats.c:38
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 FAT_IS_END_CLUSTER(clnumber)
Definition: fat.c:26
ULONG FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector, ULONGLONG PartitionSectorCount)
Definition: fat.c:353
_In_ ULONG _In_ ULONG SectorsPerTrack
Definition: iofuncs.h:2066
struct LFN_DIRENTRY * PLFN_DIRENTRY
ULONG PartitionSectorCount
Definition: partition.c:39
unsigned int UINT32
VOID FileSystemError(PCSTR ErrorString)
Definition: fs.c:259
#define FATX32
Definition: fat.h:171
struct _FAT32_BOOTSECTOR * PFAT32_BOOTSECTOR
ULONG SectorsPerFatBig
Definition: bootsup.c:91
USHORT RootDirEntries
Definition: bootsup.c:54
ULONG DirectorySize
Definition: fat.c:413
struct _DIRECTORY_BUFFER * PDIRECTORY_BUFFER
_Check_return_ _CRTIMP int __cdecl _strnicmp(_In_reads_or_z_(_MaxCount) const char *_Str1, _In_reads_or_z_(_MaxCount) const char *_Str2, _In_ size_t _MaxCount)
CHAR OemName[8]
Definition: bootsup.c:49
UCHAR JumpBoot[3]
Definition: bootsup.c:48
FORCEINLINE PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: mm.h:177
#define SectorOffset(L)
Definition: cdprocs.h:1632
unsigned char BOOLEAN
ULONG FilePointer
Definition: fat.h:152
smooth NULL
Definition: ftsmooth.c:416
ARC_STATUS FatGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: fat.c:1405
USHORT NumberOfHeads
Definition: bootsup.c:59
struct tagDIRENTRY DIRENTRY
enum _SEEKMODE SEEKMODE
Definition: bufpool.h:45
USHORT NumberOfFats
Definition: fat.h:93
ULONG FatCacheSize
Definition: fat.c:43
void * PVOID
Definition: retypes.h:9
#define TAG_FAT_CACHE
Definition: fat.c:35
WCHAR Name5_10[6]
Definition: fat.h:125
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
ULONG DirectoryStartCluster
Definition: fat.c:412
ULONG SectorsPerFat
Definition: fat.c:46
CHAR FileSystemType[8]
Definition: bootsup.c:103
UCHAR BootSignature
Definition: bootsup.c:64
Definition: arc.h:50
USHORT RootDirEntries
Definition: bootsup.c:83
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
VOID FatSwapFatBootSector(PFAT_BOOTSECTOR Obj)
Definition: fat.c:60
#define TRACE(s)
Definition: solgame.cpp:4
static ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, UINT32 StartCluster)
Definition: fat.c:1041
Dirent FileNameLen
Definition: dirsup.c:506
NTSYSAPI ULONG NTAPI RtlEqualMemory(CONST VOID *Source1, CONST VOID *Source2, ULONG Length)
USHORT ReservedSectors
Definition: bootsup.c:52
USHORT ReservedSectors
Definition: bootsup.c:81
PFAT_VOLUME_INFO FatVolumes[MAX_FDS]
Definition: fat.c:58
CHAR OemName[8]
Definition: bootsup.c:78
uint64_t ULONGLONG
Definition: typedefs.h:65
WCHAR Name0_4[5]
Definition: fat.h:121
ULONG CurrentCluster
Definition: fat.h:153
#define TAG_FAT_VOLUME
Definition: fat.c:33
UCHAR Reserved1
Definition: bootsup.c:63
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
USHORT SectorsPerFat
Definition: bootsup.c:57
VOID FsSetDeviceSpecific(ULONG FileId, VOID *Specific)
Definition: fs.c:409
ARC_STATUS FatRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: fat.c:1461
UCHAR BootSignature
Definition: bootsup.c:100
USHORT BackupBootSector
Definition: bootsup.c:96
BOOLEAN FatReadVolumeSectors(PFAT_VOLUME_INFO Volume, ULONG SectorNumber, ULONG SectorCount, PVOID Buffer)
Definition: fat.c:1362
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
USHORT BootSectorMagic
Definition: bootsup.c:71
#define MAX_FDS
Definition: fs.h:34
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
UCHAR NumberOfFats
Definition: bootsup.c:53
ARC_STATUS ArcRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: fs.c:236
CHAR VolumeLabel[11]
Definition: bootsup.c:102
struct _FAT_BOOTSECTOR * PFAT_BOOTSECTOR
UCHAR DriveNumber
Definition: bootsup.c:98
unsigned char UCHAR
Definition: xmlstorage.h:181
ULONG DeviceId
Definition: fat.c:51
Definition: arc.h:34
static const WCHAR L[]
Definition: oid.c:1250
void FatParseShortFileName(PCHAR Buffer, PDIRENTRY DirEntry)
Definition: fat.c:866
_Must_inspect_result_ _In_ PFLT_INSTANCE _Out_ PBOOLEAN IsDirectory
Definition: fltkernel.h:1139
USHORT TotalSectors
Definition: bootsup.c:84
ARC_STATUS ArcSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fs.c:243
const DEVVTBL FatFuncTable
Definition: fat.c:1542
ULONG LowPart
Definition: typedefs.h:104
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
USHORT SectorsPerTrack
Definition: bootsup.c:87
ULONG VolumeSerialNumber
Definition: bootsup.c:65
ULONG Unknown
Definition: fat.h:94
Definition: fat.h:102
Definition: typedefs.h:117
ARC_STATUS FatOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: fat.c:1419
UCHAR MediaDescriptor
Definition: bootsup.c:85
#define ATTR_DIRECTORY
Definition: fat.h:163
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:359
UCHAR Data[]
Definition: fat.c:414
ULONG SectorCount
Definition: part_xbox.c:32
BOOLEAN FatOpenVolume(PFAT_VOLUME_INFO Volume, PFAT_BOOTSECTOR BootSector, ULONGLONG PartitionSectorCount)
Definition: fat.c:138
USHORT SectorsPerTrack
Definition: bootsup.c:58
#define FAT16
Definition: fat.h:168
Status
Definition: gdiplustypes.h:24
#define ERR(fmt,...)
Definition: debug.h:109
USHORT FileSystemVersion
Definition: bootsup.c:93
ULONG_PTR SIZE_T
Definition: typedefs.h:78
#define TAG_FAT_FILE
Definition: fat.c:32
USHORT FsInfo
Definition: bootsup.c:95
VOID FatSwapFat32BootSector(PFAT32_BOOTSECTOR Obj)
Definition: fat.c:75
PRTL_UNICODE_STRING_BUFFER Path
ULONG RootDirSectors
Definition: fat.c:48
ULONG FileSize
Definition: fat.h:151
unsigned short USHORT
Definition: pedump.c:61
ULONG RootDirStartCluster
Definition: fat.c:49
UCHAR MediaDescriptor
Definition: bootsup.c:56
CHAR FileSystemType[8]
Definition: bootsup.c:67
ULONG VolumeSerialNumber
Definition: fat.h:91
USHORT SectorsPerFat
Definition: bootsup.c:86
UCHAR NumberOfFats
Definition: bootsup.c:82
ULONG SectorsPerCluster
Definition: fat.h:92
#define FATX16
Definition: fat.h:170
unsigned short UINT16
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
Definition: arc.h:46
ULONG ActiveFatSectorStart
Definition: fat.c:45
UINT8 SectorsPerCluster
Definition: fat.c:55
PUCHAR FatCache
Definition: fat.c:41
BOOLEAN FatReadPartialCluster(PFAT_VOLUME_INFO Volume, ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
Definition: fat.c:1152
Definition: arc.h:40
Definition: arc.h:41
#define FAT32
Definition: fat.h:169
VOID FatSwapLFNDirEntry(PLFN_DIRENTRY Obj)
Definition: fat.c:114
WCHAR Name11_12[2]
Definition: fat.h:127
USHORT NumberOfHeads
Definition: bootsup.c:88
ARC_STATUS FatSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fat.c:1480
ULONG TotalSectorsBig
Definition: bootsup.c:61
ARC_STATUS FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, PFAT_FILE_INFO FatFileInfoPointer)
Definition: fat.c:774
ULONG HiddenSectors
Definition: bootsup.c:60
ARC_STATUS ArcGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: fs.c:250
ULONG HiddenSectors
Definition: bootsup.c:89
ULONG FsGetDeviceId(ULONG FileId)
Definition: fs.c:423
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
struct _DIRECTORY_BUFFER DIRECTORY_BUFFER
ARC_STATUS FatClose(ULONG FileId)
Definition: fat.c:1396
UCHAR Reserved[12]
Definition: bootsup.c:97
#define SECTOR_SIZE
Definition: fs.h:22
const char * PCSTR
Definition: typedefs.h:51
CHAR FileSystemType[4]
Definition: fat.h:90
UINT16 BytesPerSector
Definition: fat.c:52
ULONG RootDirSectorStart
Definition: fat.c:47
struct _FATX_BOOTSECTOR * PFATX_BOOTSECTOR
UCHAR Attributes
Definition: fat.h:155
enum _OPENMODE OPENMODE
PULONG FatCacheIndex
Definition: fat.c:42
unsigned char UINT8
#define memset(x, y, z)
Definition: compat.h:39
BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG EntryCount, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
Definition: fat.c:506
LIST_ENTRY DirectoryBufferListHead
Definition: fat.c:417
static unsigned char * fat
Definition: mkdosfs.c:542
static BOOLEAN FatReadFile(PFAT_FILE_INFO FatFileInfo, ULONG BytesToRead, ULONG *BytesRead, PVOID Buffer)
Definition: fat.c:1196
ULONG DataSectorStart
Definition: fat.c:50
static PLARGE_INTEGER Time
Definition: time.c:105
base of all file and directory entries
Definition: entries.h:82
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesRead
Definition: fltkernel.h:1255
Iosb Information
Definition: create.c:4377
UCHAR DriveNumber
Definition: bootsup.c:62
LONGLONG QuadPart
Definition: typedefs.h:112
ULONG RootDirStartCluster
Definition: bootsup.c:94
USHORT ExtendedFlags
Definition: bootsup.c:92
FORCEINLINE VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: mm.h:186