3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 ULONG BytesPerSector
; /* Number of bytes per sector */
33 ULONG SectorsPerCluster
; /* Number of sectors per cluster */
34 ULONG FatVolumeStartSector
; /* Absolute starting sector of the partition */
35 ULONG FatSectorStart
; /* Starting sector of 1st FAT table */
36 ULONG ActiveFatSectorStart
; /* Starting sector of active FAT table */
37 ULONG NumberOfFats
; /* Number of FAT tables */
38 ULONG SectorsPerFat
; /* Sectors per FAT table */
39 ULONG RootDirSectorStart
; /* Starting sector of the root directory (non-fat32) */
40 ULONG RootDirSectors
; /* Number of sectors of the root directory (non-fat32) */
41 ULONG RootDirStartCluster
; /* Starting cluster number of the root directory (fat32 only) */
42 ULONG DataSectorStart
; /* Starting sector of the data area */
44 ULONG FatType
= 0; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
45 ULONG FatDriveNumber
= 0;
47 BOOL
FatOpenVolume(ULONG DriveNumber
, ULONG VolumeStartSector
, ULONG PartitionSectorCount
)
51 PFAT_BOOTSECTOR FatVolumeBootSector
;
52 PFAT32_BOOTSECTOR Fat32VolumeBootSector
;
53 PFATX_BOOTSECTOR FatXVolumeBootSector
;
55 DbgPrint((DPRINT_FILESYSTEM
, "FatOpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber
, VolumeStartSector
));
57 // Store the drive number
58 FatDriveNumber
= DriveNumber
;
61 // Allocate the memory to hold the boot sector
63 FatVolumeBootSector
= (PFAT_BOOTSECTOR
) MmAllocateMemory(512);
64 Fat32VolumeBootSector
= (PFAT32_BOOTSECTOR
) FatVolumeBootSector
;
65 FatXVolumeBootSector
= (PFATX_BOOTSECTOR
) FatVolumeBootSector
;
68 // Make sure we got the memory
70 if (FatVolumeBootSector
== NULL
)
72 FileSystemError("Out of memory.");
76 // Now try to read the boot sector
77 // If this fails then abort
78 if (!MachDiskReadLogicalSectors(DriveNumber
, VolumeStartSector
, 1, (PVOID
)DISKREADBUFFER
))
80 MmFreeMemory(FatVolumeBootSector
);
83 RtlCopyMemory(FatVolumeBootSector
, (PVOID
)DISKREADBUFFER
, 512);
86 FatType
= FatDetermineFatType(FatVolumeBootSector
, PartitionSectorCount
);
90 DbgPrint((DPRINT_FILESYSTEM
, "Dumping boot sector:\n"));
94 DbgPrint((DPRINT_FILESYSTEM
, "sizeof(FATX_BOOTSECTOR) = 0x%x.\n", sizeof(FATX_BOOTSECTOR
)));
96 DbgPrint((DPRINT_FILESYSTEM
, "FileSystemType: %c%c%c%c.\n", FatXVolumeBootSector
->FileSystemType
[0], FatXVolumeBootSector
->FileSystemType
[1], FatXVolumeBootSector
->FileSystemType
[2], FatXVolumeBootSector
->FileSystemType
[3]));
97 DbgPrint((DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", FatXVolumeBootSector
->VolumeSerialNumber
));
98 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", FatXVolumeBootSector
->SectorsPerCluster
));
99 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", FatXVolumeBootSector
->NumberOfFats
));
100 DbgPrint((DPRINT_FILESYSTEM
, "Unknown: 0x%x\n", FatXVolumeBootSector
->Unknown
));
102 DbgPrint((DPRINT_FILESYSTEM
, "FatType %s\n", FatType
== FATX16
? "FATX16" : "FATX32"));
105 else if (FatType
== FAT32
)
107 DbgPrint((DPRINT_FILESYSTEM
, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR
)));
109 DbgPrint((DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector
->JumpBoot
[0], Fat32VolumeBootSector
->JumpBoot
[1], Fat32VolumeBootSector
->JumpBoot
[2]));
110 DbgPrint((DPRINT_FILESYSTEM
, "OemName: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector
->OemName
[0], Fat32VolumeBootSector
->OemName
[1], Fat32VolumeBootSector
->OemName
[2], Fat32VolumeBootSector
->OemName
[3], Fat32VolumeBootSector
->OemName
[4], Fat32VolumeBootSector
->OemName
[5], Fat32VolumeBootSector
->OemName
[6], Fat32VolumeBootSector
->OemName
[7]));
111 DbgPrint((DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", Fat32VolumeBootSector
->BytesPerSector
));
112 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", Fat32VolumeBootSector
->SectorsPerCluster
));
113 DbgPrint((DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", Fat32VolumeBootSector
->ReservedSectors
));
114 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", Fat32VolumeBootSector
->NumberOfFats
));
115 DbgPrint((DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", Fat32VolumeBootSector
->RootDirEntries
));
116 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectors: %d\n", Fat32VolumeBootSector
->TotalSectors
));
117 DbgPrint((DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", Fat32VolumeBootSector
->MediaDescriptor
));
118 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", Fat32VolumeBootSector
->SectorsPerFat
));
119 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", Fat32VolumeBootSector
->SectorsPerTrack
));
120 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", Fat32VolumeBootSector
->NumberOfHeads
));
121 DbgPrint((DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", Fat32VolumeBootSector
->HiddenSectors
));
122 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", Fat32VolumeBootSector
->TotalSectorsBig
));
123 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFatBig: %d\n", Fat32VolumeBootSector
->SectorsPerFatBig
));
124 DbgPrint((DPRINT_FILESYSTEM
, "ExtendedFlags: 0x%x\n", Fat32VolumeBootSector
->ExtendedFlags
));
125 DbgPrint((DPRINT_FILESYSTEM
, "FileSystemVersion: 0x%x\n", Fat32VolumeBootSector
->FileSystemVersion
));
126 DbgPrint((DPRINT_FILESYSTEM
, "RootDirStartCluster: %d\n", Fat32VolumeBootSector
->RootDirStartCluster
));
127 DbgPrint((DPRINT_FILESYSTEM
, "FsInfo: %d\n", Fat32VolumeBootSector
->FsInfo
));
128 DbgPrint((DPRINT_FILESYSTEM
, "BackupBootSector: %d\n", Fat32VolumeBootSector
->BackupBootSector
));
129 DbgPrint((DPRINT_FILESYSTEM
, "Reserved: 0x%x\n", Fat32VolumeBootSector
->Reserved
));
130 DbgPrint((DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", Fat32VolumeBootSector
->DriveNumber
));
131 DbgPrint((DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", Fat32VolumeBootSector
->Reserved1
));
132 DbgPrint((DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", Fat32VolumeBootSector
->BootSignature
));
133 DbgPrint((DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector
->VolumeSerialNumber
));
134 DbgPrint((DPRINT_FILESYSTEM
, "VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector
->VolumeLabel
[0], Fat32VolumeBootSector
->VolumeLabel
[1], Fat32VolumeBootSector
->VolumeLabel
[2], Fat32VolumeBootSector
->VolumeLabel
[3], Fat32VolumeBootSector
->VolumeLabel
[4], Fat32VolumeBootSector
->VolumeLabel
[5], Fat32VolumeBootSector
->VolumeLabel
[6], Fat32VolumeBootSector
->VolumeLabel
[7], Fat32VolumeBootSector
->VolumeLabel
[8], Fat32VolumeBootSector
->VolumeLabel
[9], Fat32VolumeBootSector
->VolumeLabel
[10]));
135 DbgPrint((DPRINT_FILESYSTEM
, "FileSystemType: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector
->FileSystemType
[0], Fat32VolumeBootSector
->FileSystemType
[1], Fat32VolumeBootSector
->FileSystemType
[2], Fat32VolumeBootSector
->FileSystemType
[3], Fat32VolumeBootSector
->FileSystemType
[4], Fat32VolumeBootSector
->FileSystemType
[5], Fat32VolumeBootSector
->FileSystemType
[6], Fat32VolumeBootSector
->FileSystemType
[7]));
136 DbgPrint((DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", Fat32VolumeBootSector
->BootSectorMagic
));
140 DbgPrint((DPRINT_FILESYSTEM
, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR
)));
142 DbgPrint((DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector
->JumpBoot
[0], FatVolumeBootSector
->JumpBoot
[1], FatVolumeBootSector
->JumpBoot
[2]));
143 DbgPrint((DPRINT_FILESYSTEM
, "OemName: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector
->OemName
[0], FatVolumeBootSector
->OemName
[1], FatVolumeBootSector
->OemName
[2], FatVolumeBootSector
->OemName
[3], FatVolumeBootSector
->OemName
[4], FatVolumeBootSector
->OemName
[5], FatVolumeBootSector
->OemName
[6], FatVolumeBootSector
->OemName
[7]));
144 DbgPrint((DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", FatVolumeBootSector
->BytesPerSector
));
145 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", FatVolumeBootSector
->SectorsPerCluster
));
146 DbgPrint((DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", FatVolumeBootSector
->ReservedSectors
));
147 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", FatVolumeBootSector
->NumberOfFats
));
148 DbgPrint((DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", FatVolumeBootSector
->RootDirEntries
));
149 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectors: %d\n", FatVolumeBootSector
->TotalSectors
));
150 DbgPrint((DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", FatVolumeBootSector
->MediaDescriptor
));
151 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", FatVolumeBootSector
->SectorsPerFat
));
152 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", FatVolumeBootSector
->SectorsPerTrack
));
153 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", FatVolumeBootSector
->NumberOfHeads
));
154 DbgPrint((DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", FatVolumeBootSector
->HiddenSectors
));
155 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", FatVolumeBootSector
->TotalSectorsBig
));
156 DbgPrint((DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", FatVolumeBootSector
->DriveNumber
));
157 DbgPrint((DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", FatVolumeBootSector
->Reserved1
));
158 DbgPrint((DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", FatVolumeBootSector
->BootSignature
));
159 DbgPrint((DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector
->VolumeSerialNumber
));
160 DbgPrint((DPRINT_FILESYSTEM
, "VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", FatVolumeBootSector
->VolumeLabel
[0], FatVolumeBootSector
->VolumeLabel
[1], FatVolumeBootSector
->VolumeLabel
[2], FatVolumeBootSector
->VolumeLabel
[3], FatVolumeBootSector
->VolumeLabel
[4], FatVolumeBootSector
->VolumeLabel
[5], FatVolumeBootSector
->VolumeLabel
[6], FatVolumeBootSector
->VolumeLabel
[7], FatVolumeBootSector
->VolumeLabel
[8], FatVolumeBootSector
->VolumeLabel
[9], FatVolumeBootSector
->VolumeLabel
[10]));
161 DbgPrint((DPRINT_FILESYSTEM
, "FileSystemType: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector
->FileSystemType
[0], FatVolumeBootSector
->FileSystemType
[1], FatVolumeBootSector
->FileSystemType
[2], FatVolumeBootSector
->FileSystemType
[3], FatVolumeBootSector
->FileSystemType
[4], FatVolumeBootSector
->FileSystemType
[5], FatVolumeBootSector
->FileSystemType
[6], FatVolumeBootSector
->FileSystemType
[7]));
162 DbgPrint((DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", FatVolumeBootSector
->BootSectorMagic
));
165 #endif // defined DEBUG
168 // Set the correct partition offset
170 FatVolumeStartSector
= VolumeStartSector
;
173 // Check the boot sector magic
175 if (! ISFATX(FatType
) && FatVolumeBootSector
->BootSectorMagic
!= 0xaa55)
177 sprintf(ErrMsg
, "Invalid boot sector magic on drive 0x%x (expected 0xaa55 found 0x%x)",
178 DriveNumber
, FatVolumeBootSector
->BootSectorMagic
);
179 FileSystemError(ErrMsg
);
180 MmFreeMemory(FatVolumeBootSector
);
185 // Check the FAT cluster size
186 // We do not support clusters bigger than 64k
188 if ((ISFATX(FatType
) && 64 * 1024 < FatXVolumeBootSector
->SectorsPerCluster
* 512) ||
189 (! ISFATX(FatType
) && 64 * 1024 < FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
))
191 FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
192 MmFreeMemory(FatVolumeBootSector
);
197 // Clear our variables
200 ActiveFatSectorStart
= 0;
202 RootDirSectorStart
= 0;
208 // Get the sectors per FAT,
209 // root directory starting sector,
210 // and data sector start
214 BytesPerSector
= 512;
215 SectorsPerCluster
= FatXVolumeBootSector
->SectorsPerCluster
;
216 FatSectorStart
= (4096 / BytesPerSector
);
217 ActiveFatSectorStart
= FatSectorStart
;
219 FatSize
= PartitionSectorCount
/ SectorsPerCluster
*
220 (FATX16
== FatType
? 2 : 4);
221 SectorsPerFat
= (((FatSize
+ 4095) / 4096) * 4096) / BytesPerSector
;
223 RootDirSectorStart
= FatSectorStart
+ NumberOfFats
* SectorsPerFat
;
224 RootDirSectors
= FatXVolumeBootSector
->SectorsPerCluster
;
226 DataSectorStart
= RootDirSectorStart
+ RootDirSectors
;
228 else if (FatType
!= FAT32
)
230 BytesPerSector
= FatVolumeBootSector
->BytesPerSector
;
231 SectorsPerCluster
= FatVolumeBootSector
->SectorsPerCluster
;
232 FatSectorStart
= FatVolumeBootSector
->ReservedSectors
;
233 ActiveFatSectorStart
= FatSectorStart
;
234 NumberOfFats
= FatVolumeBootSector
->NumberOfFats
;
235 SectorsPerFat
= FatVolumeBootSector
->SectorsPerFat
;
237 RootDirSectorStart
= FatSectorStart
+ NumberOfFats
* SectorsPerFat
;
238 RootDirSectors
= ((FatVolumeBootSector
->RootDirEntries
* 32) + (BytesPerSector
- 1)) / BytesPerSector
;
240 DataSectorStart
= RootDirSectorStart
+ RootDirSectors
;
244 BytesPerSector
= Fat32VolumeBootSector
->BytesPerSector
;
245 SectorsPerCluster
= Fat32VolumeBootSector
->SectorsPerCluster
;
246 FatSectorStart
= Fat32VolumeBootSector
->ReservedSectors
;
247 ActiveFatSectorStart
= FatSectorStart
+
248 ((Fat32VolumeBootSector
->ExtendedFlags
& 0x80) ? ((Fat32VolumeBootSector
->ExtendedFlags
& 0x0f) * Fat32VolumeBootSector
->SectorsPerFatBig
) : 0);
249 NumberOfFats
= Fat32VolumeBootSector
->NumberOfFats
;
250 SectorsPerFat
= Fat32VolumeBootSector
->SectorsPerFatBig
;
252 RootDirStartCluster
= Fat32VolumeBootSector
->RootDirStartCluster
;
253 DataSectorStart
= FatSectorStart
+ NumberOfFats
* SectorsPerFat
;
257 // we only work with version 0
259 if (Fat32VolumeBootSector
->FileSystemVersion
!= 0)
261 FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
265 MmFreeMemory(FatVolumeBootSector
);
268 // Initialize the disk cache for this drive
270 if (!CacheInitializeDrive(DriveNumber
))
276 // Force the FAT sectors into the cache
277 // as long as it is FAT12 or FAT16. FAT32 can
278 // have a multi-megabyte FAT so we don't want that.
280 if (FatType
!= FAT32
&& FatType
!= FATX32
)
282 if (!CacheForceDiskSectorsIntoCache(DriveNumber
, ActiveFatSectorStart
, SectorsPerFat
))
291 ULONG
FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector
, ULONG PartitionSectorCount
)
293 ULONG RootDirSectors
;
294 ULONG DataSectorCount
;
297 ULONG CountOfClusters
;
298 PFAT32_BOOTSECTOR Fat32BootSector
= (PFAT32_BOOTSECTOR
)FatBootSector
;
299 PFATX_BOOTSECTOR FatXBootSector
= (PFATX_BOOTSECTOR
)FatBootSector
;
301 if (0 == strncmp(FatXBootSector
->FileSystemType
, "FATX", 4))
303 CountOfClusters
= PartitionSectorCount
/ FatXBootSector
->SectorsPerCluster
;
304 if (CountOfClusters
< 65525)
306 /* Volume is FATX16 */
311 /* Volume is FAT32 */
317 RootDirSectors
= ((FatBootSector
->RootDirEntries
* 32) + (FatBootSector
->BytesPerSector
- 1)) / FatBootSector
->BytesPerSector
;
318 SectorsPerFat
= FatBootSector
->SectorsPerFat
? FatBootSector
->SectorsPerFat
: Fat32BootSector
->SectorsPerFatBig
;
319 TotalSectors
= FatBootSector
->TotalSectors
? FatBootSector
->TotalSectors
: FatBootSector
->TotalSectorsBig
;
320 DataSectorCount
= TotalSectors
- (FatBootSector
->ReservedSectors
+ (FatBootSector
->NumberOfFats
* SectorsPerFat
) + RootDirSectors
);
323 if (FatBootSector
->SectorsPerCluster
== 0)
326 CountOfClusters
= DataSectorCount
/ FatBootSector
->SectorsPerCluster
;
328 if (CountOfClusters
< 4085)
330 /* Volume is FAT12 */
333 else if (CountOfClusters
< 65525)
335 /* Volume is FAT16 */
340 /* Volume is FAT32 */
346 PVOID
FatBufferDirectory(ULONG DirectoryStartCluster
, ULONG
*DirectorySize
, BOOL RootDirectory
)
348 PVOID DirectoryBuffer
;
350 DbgPrint((DPRINT_FILESYSTEM
, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster
, (RootDirectory
? "TRUE" : "FALSE")));
353 * For FAT32, the root directory is nothing special. We can treat it the same
356 if (RootDirectory
&& FAT32
== FatType
)
358 DirectoryStartCluster
= RootDirStartCluster
;
359 RootDirectory
= FALSE
;
363 // Calculate the size of the directory
367 *DirectorySize
= RootDirSectors
* BytesPerSector
;
371 *DirectorySize
= FatCountClustersInChain(DirectoryStartCluster
) * SectorsPerCluster
* BytesPerSector
;
375 // Attempt to allocate memory for directory buffer
377 DbgPrint((DPRINT_FILESYSTEM
, "Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize
));
378 DirectoryBuffer
= MmAllocateMemory(*DirectorySize
);
380 if (DirectoryBuffer
== NULL
)
386 // Now read directory contents into DirectoryBuffer
390 if (!FatReadVolumeSectors(FatDriveNumber
, RootDirSectorStart
, RootDirSectors
, DirectoryBuffer
))
392 MmFreeMemory(DirectoryBuffer
);
398 if (!FatReadClusterChain(DirectoryStartCluster
, 0xFFFFFFFF, DirectoryBuffer
))
400 MmFreeMemory(DirectoryBuffer
);
405 return DirectoryBuffer
;
408 BOOL
FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
413 PLFN_DIRENTRY LfnDirEntry
;
414 CHAR LfnNameBuffer
[265];
415 CHAR ShortNameBuffer
[20];
418 EntryCount
= DirectorySize
/ sizeof(DIRENTRY
);
420 DbgPrint((DPRINT_FILESYSTEM
, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
));
422 memset(ShortNameBuffer
, 0, 13 * sizeof(CHAR
));
423 memset(LfnNameBuffer
, 0, 261 * sizeof(CHAR
));
425 DirEntry
= (PDIRENTRY
) DirectoryBuffer
;
426 for (CurrentEntry
=0; CurrentEntry
<EntryCount
; CurrentEntry
++, DirEntry
++)
428 LfnDirEntry
= (PLFN_DIRENTRY
)DirEntry
;
430 //DbgPrint((DPRINT_FILESYSTEM, "Dumping directory entry %d:\n", CurrentEntry));
431 //DbgDumpBuffer(DPRINT_FILESYSTEM, DirEntry, sizeof(DIRENTRY));
434 // Check if this is the last file in the directory
435 // If DirEntry[0] == 0x00 then that means all the
436 // entries after this one are unused. If this is the
437 // last entry then we didn't find the file in this directory.
439 if (DirEntry
->FileName
[0] == '\0')
445 // Check if this is a deleted entry or not
447 if (DirEntry
->FileName
[0] == '\xE5')
449 memset(ShortNameBuffer
, 0, 13 * sizeof(CHAR
));
450 memset(LfnNameBuffer
, 0, 261 * sizeof(CHAR
));
455 // Check if this is a LFN entry
456 // If so it needs special handling
458 if (DirEntry
->Attr
== ATTR_LONG_NAME
)
461 // Check to see if this is a deleted LFN entry, if so continue
463 if (LfnDirEntry
->SequenceNumber
& 0x80)
469 // Mask off high two bits of sequence number
470 // and make the sequence number zero-based
472 LfnDirEntry
->SequenceNumber
&= 0x3F;
473 LfnDirEntry
->SequenceNumber
--;
476 // Get all 13 LFN entry characters
478 if (LfnDirEntry
->Name0_4
[0] != 0xFFFF)
480 LfnNameBuffer
[0 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[0];
482 if (LfnDirEntry
->Name0_4
[1] != 0xFFFF)
484 LfnNameBuffer
[1 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[1];
486 if (LfnDirEntry
->Name0_4
[2] != 0xFFFF)
488 LfnNameBuffer
[2 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[2];
490 if (LfnDirEntry
->Name0_4
[3] != 0xFFFF)
492 LfnNameBuffer
[3 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[3];
494 if (LfnDirEntry
->Name0_4
[4] != 0xFFFF)
496 LfnNameBuffer
[4 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[4];
498 if (LfnDirEntry
->Name5_10
[0] != 0xFFFF)
500 LfnNameBuffer
[5 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[0];
502 if (LfnDirEntry
->Name5_10
[1] != 0xFFFF)
504 LfnNameBuffer
[6 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[1];
506 if (LfnDirEntry
->Name5_10
[2] != 0xFFFF)
508 LfnNameBuffer
[7 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[2];
510 if (LfnDirEntry
->Name5_10
[3] != 0xFFFF)
512 LfnNameBuffer
[8 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[3];
514 if (LfnDirEntry
->Name5_10
[4] != 0xFFFF)
516 LfnNameBuffer
[9 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[4];
518 if (LfnDirEntry
->Name5_10
[5] != 0xFFFF)
520 LfnNameBuffer
[10 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[5];
522 if (LfnDirEntry
->Name11_12
[0] != 0xFFFF)
524 LfnNameBuffer
[11 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[0];
526 if (LfnDirEntry
->Name11_12
[1] != 0xFFFF)
528 LfnNameBuffer
[12 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[1];
531 //DbgPrint((DPRINT_FILESYSTEM, "Dumping long name buffer:\n"));
532 //DbgDumpBuffer(DPRINT_FILESYSTEM, LfnNameBuffer, 260);
538 // Check for the volume label attribute
539 // and skip over this entry if found
541 if (DirEntry
->Attr
& ATTR_VOLUMENAME
)
543 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
544 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
549 // If we get here then we've found a short file name
550 // entry and LfnNameBuffer contains the long file
551 // name or zeroes. All we have to do now is see if the
552 // file name matches either the short or long file name
553 // and fill in the FAT_FILE_INFO structure if it does
554 // or zero our buffers and continue looking.
558 // Get short file name
560 FatParseShortFileName(ShortNameBuffer
, DirEntry
);
562 DbgPrint((DPRINT_FILESYSTEM
, "Entry: %d LFN = %s\n", CurrentEntry
, LfnNameBuffer
));
563 DbgPrint((DPRINT_FILESYSTEM
, "Entry: %d DOS name = %s\n", CurrentEntry
, ShortNameBuffer
));
566 // See if the file name matches either the short or long name
568 if (((strlen(FileName
) == strlen(LfnNameBuffer
)) && (stricmp(FileName
, LfnNameBuffer
) == 0)) ||
569 ((strlen(FileName
) == strlen(ShortNameBuffer
)) && (stricmp(FileName
, ShortNameBuffer
) == 0))) {
571 // We found the entry, now fill in the FAT_FILE_INFO struct
573 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
574 FatFileInfoPointer
->FilePointer
= 0;
576 DbgPrint((DPRINT_FILESYSTEM
, "MSDOS Directory Entry:\n"));
577 DbgPrint((DPRINT_FILESYSTEM
, "FileName[11] = %c%c%c%c%c%c%c%c%c%c%c\n", DirEntry
->FileName
[0], DirEntry
->FileName
[1], DirEntry
->FileName
[2], DirEntry
->FileName
[3], DirEntry
->FileName
[4], DirEntry
->FileName
[5], DirEntry
->FileName
[6], DirEntry
->FileName
[7], DirEntry
->FileName
[8], DirEntry
->FileName
[9], DirEntry
->FileName
[10]));
578 DbgPrint((DPRINT_FILESYSTEM
, "Attr = 0x%x\n", DirEntry
->Attr
));
579 DbgPrint((DPRINT_FILESYSTEM
, "ReservedNT = 0x%x\n", DirEntry
->ReservedNT
));
580 DbgPrint((DPRINT_FILESYSTEM
, "TimeInTenths = %d\n", DirEntry
->TimeInTenths
));
581 DbgPrint((DPRINT_FILESYSTEM
, "CreateTime = %d\n", DirEntry
->CreateTime
));
582 DbgPrint((DPRINT_FILESYSTEM
, "CreateDate = %d\n", DirEntry
->CreateDate
));
583 DbgPrint((DPRINT_FILESYSTEM
, "LastAccessDate = %d\n", DirEntry
->LastAccessDate
));
584 DbgPrint((DPRINT_FILESYSTEM
, "ClusterHigh = 0x%x\n", DirEntry
->ClusterHigh
));
585 DbgPrint((DPRINT_FILESYSTEM
, "Time = %d\n", DirEntry
->Time
));
586 DbgPrint((DPRINT_FILESYSTEM
, "Date = %d\n", DirEntry
->Date
));
587 DbgPrint((DPRINT_FILESYSTEM
, "ClusterLow = 0x%x\n", DirEntry
->ClusterLow
));
588 DbgPrint((DPRINT_FILESYSTEM
, "Size = %d\n", DirEntry
->Size
));
591 // Get the cluster chain
593 StartCluster
= ((ULONG
)DirEntry
->ClusterHigh
<< 16) + DirEntry
->ClusterLow
;
594 DbgPrint((DPRINT_FILESYSTEM
, "StartCluster = 0x%x\n", StartCluster
));
595 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(StartCluster
);
598 // See if memory allocation failed
600 if (FatFileInfoPointer
->FileFatChain
== NULL
)
609 // Nope, no match - zero buffers and continue looking
611 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
612 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
619 static BOOL
FatXSearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
623 PFATX_DIRENTRY DirEntry
;
626 EntryCount
= DirectorySize
/ sizeof(FATX_DIRENTRY
);
628 DbgPrint((DPRINT_FILESYSTEM
, "FatXSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
));
630 FileNameLen
= strlen(FileName
);
631 DirEntry
= (PFATX_DIRENTRY
) DirectoryBuffer
;
632 for (CurrentEntry
= 0; CurrentEntry
< EntryCount
; CurrentEntry
++, DirEntry
++)
634 if (0xff == DirEntry
->FileNameSize
)
638 if (0xe5 == DirEntry
->FileNameSize
)
642 if (FileNameLen
== DirEntry
->FileNameSize
&&
643 0 == strnicmp(FileName
, DirEntry
->FileName
, FileNameLen
))
646 * We found the entry, now fill in the FAT_FILE_INFO struct
648 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
649 FatFileInfoPointer
->FilePointer
= 0;
651 DbgPrint((DPRINT_FILESYSTEM
, "FATX Directory Entry:\n"));
652 DbgPrint((DPRINT_FILESYSTEM
, "FileNameSize = %d\n", DirEntry
->FileNameSize
));
653 DbgPrint((DPRINT_FILESYSTEM
, "Attr = 0x%x\n", DirEntry
->Attr
));
654 DbgPrint((DPRINT_FILESYSTEM
, "StartCluster = 0x%x\n", DirEntry
->StartCluster
));
655 DbgPrint((DPRINT_FILESYSTEM
, "Size = %d\n", DirEntry
->Size
));
656 DbgPrint((DPRINT_FILESYSTEM
, "Time = %d\n", DirEntry
->Time
));
657 DbgPrint((DPRINT_FILESYSTEM
, "Date = %d\n", DirEntry
->Date
));
658 DbgPrint((DPRINT_FILESYSTEM
, "CreateTime = %d\n", DirEntry
->CreateTime
));
659 DbgPrint((DPRINT_FILESYSTEM
, "CreateDate = %d\n", DirEntry
->CreateDate
));
660 DbgPrint((DPRINT_FILESYSTEM
, "LastAccessTime = %d\n", DirEntry
->LastAccessTime
));
661 DbgPrint((DPRINT_FILESYSTEM
, "LastAccessDate = %d\n", DirEntry
->LastAccessDate
));
664 * Get the cluster chain
666 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(DirEntry
->StartCluster
);
669 * See if memory allocation failed
671 if (NULL
== FatFileInfoPointer
->FileFatChain
)
685 * This function searches the file system for the
686 * specified filename and fills in a FAT_FILE_INFO structure
687 * with info describing the file, etc. returns true
688 * if the file exists or false otherwise
690 BOOL
FatLookupFile(PCSTR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
693 ULONG NumberOfPathParts
;
695 PVOID DirectoryBuffer
;
696 ULONG DirectoryStartCluster
= 0;
698 FAT_FILE_INFO FatFileInfo
;
700 DbgPrint((DPRINT_FILESYSTEM
, "FatLookupFile() FileName = %s\n", FileName
));
702 memset(FatFileInfoPointer
, 0, sizeof(FAT_FILE_INFO
));
705 // Figure out how many sub-directories we are nested in
707 NumberOfPathParts
= FsGetNumPathParts(FileName
);
710 // Loop once for each part
712 for (i
=0; i
<NumberOfPathParts
; i
++)
715 // Get first path part
717 FsGetFirstNameFromPath(PathPart
, FileName
);
720 // Advance to the next part of the path
722 for (; (*FileName
!= '\\') && (*FileName
!= '/') && (*FileName
!= '\0'); FileName
++)
728 // Buffer the directory contents
730 DirectoryBuffer
= FatBufferDirectory(DirectoryStartCluster
, &DirectorySize
, (i
== 0) );
731 if (DirectoryBuffer
== NULL
)
737 // Search for file name in directory
741 if (!FatXSearchDirectoryBufferForFile(DirectoryBuffer
, DirectorySize
, PathPart
, &FatFileInfo
))
743 MmFreeMemory(DirectoryBuffer
);
749 if (!FatSearchDirectoryBufferForFile(DirectoryBuffer
, DirectorySize
, PathPart
, &FatFileInfo
))
751 MmFreeMemory(DirectoryBuffer
);
756 MmFreeMemory(DirectoryBuffer
);
759 // If we have another sub-directory to go then
760 // grab the start cluster and free the fat chain array
762 if ((i
+1) < NumberOfPathParts
)
764 DirectoryStartCluster
= FatFileInfo
.FileFatChain
[0];
765 MmFreeMemory(FatFileInfo
.FileFatChain
);
769 memcpy(FatFileInfoPointer
, &FatFileInfo
, sizeof(FAT_FILE_INFO
));
776 * This function parses a directory entry name which
777 * is in the form of "FILE EXT" and puts it in Buffer
778 * in the form of "file.ext"
780 void FatParseShortFileName(PCHAR Buffer
, PDIRENTRY DirEntry
)
785 RtlZeroMemory(Buffer
, 13);
788 // Fixup first character
790 if (DirEntry
->FileName
[0] == 0x05)
792 DirEntry
->FileName
[0] = 0xE5;
800 if (DirEntry
->FileName
[Idx
] == ' ')
805 Buffer
[Idx
] = DirEntry
->FileName
[Idx
];
812 if ((DirEntry
->FileName
[8] != ' '))
815 Buffer
[Idx
++] = (DirEntry
->FileName
[8] == ' ') ? '\0' : DirEntry
->FileName
[8];
816 Buffer
[Idx
++] = (DirEntry
->FileName
[9] == ' ') ? '\0' : DirEntry
->FileName
[9];
817 Buffer
[Idx
++] = (DirEntry
->FileName
[10] == ' ') ? '\0' : DirEntry
->FileName
[10];
820 DbgPrint((DPRINT_FILESYSTEM
, "FatParseShortFileName() ShortName = %s\n", Buffer
));
825 * returns the Fat entry for a given cluster number
827 BOOL
FatGetFatEntry(ULONG Cluster
, ULONG
* ClusterPointer
)
832 UINT ThisFatEntOffset
;
834 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster
));
840 FatOffset
= Cluster
+ (Cluster
/ 2);
841 ThisFatSecNum
= ActiveFatSectorStart
+ (FatOffset
/ BytesPerSector
);
842 ThisFatEntOffset
= (FatOffset
% BytesPerSector
);
844 DbgPrint((DPRINT_FILESYSTEM
, "FatOffset: %d\n", FatOffset
));
845 DbgPrint((DPRINT_FILESYSTEM
, "ThisFatSecNum: %d\n", ThisFatSecNum
));
846 DbgPrint((DPRINT_FILESYSTEM
, "ThisFatEntOffset: %d\n", ThisFatEntOffset
));
848 if (ThisFatEntOffset
== (BytesPerSector
- 1))
850 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 2, (PVOID
)FILESYSBUFFER
))
857 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
863 fat
= *((USHORT
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
));
864 if (Cluster
& 0x0001)
865 fat
= fat
>> 4; /* Cluster number is ODD */
867 fat
= fat
& 0x0FFF; /* Cluster number is EVEN */
874 FatOffset
= (Cluster
* 2);
875 ThisFatSecNum
= ActiveFatSectorStart
+ (FatOffset
/ BytesPerSector
);
876 ThisFatEntOffset
= (FatOffset
% BytesPerSector
);
878 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
883 fat
= *((USHORT
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
));
890 FatOffset
= (Cluster
* 4);
891 ThisFatSecNum
= ActiveFatSectorStart
+ (FatOffset
/ BytesPerSector
);
892 ThisFatEntOffset
= (FatOffset
% BytesPerSector
);
894 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
900 fat
= (*((ULONG
*) ((ULONG_PTR
)FILESYSBUFFER
+ ThisFatEntOffset
))) & 0x0FFFFFFF;
906 DbgPrint((DPRINT_FILESYSTEM
, "FAT entry is 0x%x.\n", fat
));
908 *ClusterPointer
= fat
;
915 * Tries to open the file 'name' and returns true or false
916 * for success and failure respectively
918 FILE* FatOpenFile(PCSTR FileName
)
920 FAT_FILE_INFO TempFatFileInfo
;
921 PFAT_FILE_INFO FileHandle
;
923 DbgPrint((DPRINT_FILESYSTEM
, "FatOpenFile() FileName = %s\n", FileName
));
925 if (!FatLookupFile(FileName
, &TempFatFileInfo
))
930 FileHandle
= MmAllocateMemory(sizeof(FAT_FILE_INFO
));
932 if (FileHandle
== NULL
)
937 memcpy(FileHandle
, &TempFatFileInfo
, sizeof(FAT_FILE_INFO
));
939 return (FILE*)FileHandle
;
942 ULONG
FatCountClustersInChain(ULONG StartCluster
)
944 ULONG ClusterCount
= 0;
946 DbgPrint((DPRINT_FILESYSTEM
, "FatCountClustersInChain() StartCluster = %d\n", StartCluster
));
951 // If end of chain then break out of our cluster counting loop
953 if (((FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
954 ((FatType
== FAT16
|| FatType
== FATX16
) && (StartCluster
>= 0xfff8)) ||
955 ((FatType
== FAT32
|| FatType
== FATX32
) && (StartCluster
>= 0x0ffffff8)))
968 if (!FatGetFatEntry(StartCluster
, &StartCluster
))
974 DbgPrint((DPRINT_FILESYSTEM
, "FatCountClustersInChain() ClusterCount = %d\n", ClusterCount
));
979 ULONG
* FatGetClusterChainArray(ULONG StartCluster
)
986 DbgPrint((DPRINT_FILESYSTEM
, "FatGetClusterChainArray() StartCluster = %d\n", StartCluster
));
988 ClusterCount
= FatCountClustersInChain(StartCluster
) + 1; // Lets get the 0x0ffffff8 on the end of the array
989 ArraySize
= ClusterCount
* sizeof(ULONG
);
992 // Allocate array memory
994 ArrayPointer
= MmAllocateMemory(ArraySize
);
996 if (ArrayPointer
== NULL
)
1002 // Loop through and set array values
1004 for (Idx
=0; Idx
<ClusterCount
; Idx
++)
1007 // Set current cluster
1009 ArrayPointer
[Idx
] = StartCluster
;
1012 // Don't try to get next cluster for last cluster
1014 if (((FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
1015 ((FatType
== FAT16
|| FatType
== FATX16
) && (StartCluster
>= 0xfff8)) ||
1016 ((FatType
== FAT32
|| FatType
== FATX32
) && (StartCluster
>= 0x0ffffff8)))
1025 if (!FatGetFatEntry(StartCluster
, &StartCluster
))
1027 MmFreeMemory(ArrayPointer
);
1032 return ArrayPointer
;
1037 * Reads the specified cluster into memory
1039 BOOL
FatReadCluster(ULONG ClusterNumber
, PVOID Buffer
)
1041 ULONG ClusterStartSector
;
1043 ClusterStartSector
= ((ClusterNumber
- 2) * SectorsPerCluster
) + DataSectorStart
;
1045 DbgPrint((DPRINT_FILESYSTEM
, "FatReadCluster() ClusterNumber = %d Buffer = 0x%x ClusterStartSector = %d\n", ClusterNumber
, Buffer
, ClusterStartSector
));
1047 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1052 memcpy(Buffer
, (PVOID
)FILESYSBUFFER
, SectorsPerCluster
* BytesPerSector
);
1058 * FatReadClusterChain()
1059 * Reads the specified clusters into memory
1061 BOOL
FatReadClusterChain(ULONG StartClusterNumber
, ULONG NumberOfClusters
, PVOID Buffer
)
1063 ULONG ClusterStartSector
;
1065 DbgPrint((DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
));
1067 while (NumberOfClusters
> 0)
1070 DbgPrint((DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
));
1072 // Calculate starting sector for cluster
1074 ClusterStartSector
= ((StartClusterNumber
- 2) * SectorsPerCluster
) + DataSectorStart
;
1077 // Read cluster into memory
1079 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1084 memcpy(Buffer
, (PVOID
)FILESYSBUFFER
, SectorsPerCluster
* BytesPerSector
);
1087 // Decrement count of clusters left to read
1092 // Increment buffer address by cluster size
1094 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (SectorsPerCluster
* BytesPerSector
));
1099 if (!FatGetFatEntry(StartClusterNumber
, &StartClusterNumber
))
1105 // If end of chain then break out of our cluster reading loop
1107 if (((FatType
== FAT12
) && (StartClusterNumber
>= 0xff8)) ||
1108 ((FatType
== FAT16
|| FatType
== FATX16
) && (StartClusterNumber
>= 0xfff8)) ||
1109 ((FatType
== FAT32
|| FatType
== FATX32
) && (StartClusterNumber
>= 0x0ffffff8)))
1119 * FatReadPartialCluster()
1120 * Reads part of a cluster into memory
1122 BOOL
FatReadPartialCluster(ULONG ClusterNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
)
1124 ULONG ClusterStartSector
;
1126 DbgPrint((DPRINT_FILESYSTEM
, "FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber
, StartingOffset
, Length
, Buffer
));
1128 ClusterStartSector
= ((ClusterNumber
- 2) * SectorsPerCluster
) + DataSectorStart
;
1130 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1135 memcpy(Buffer
, (PVOID
)((ULONG_PTR
)FILESYSBUFFER
+ StartingOffset
), Length
);
1142 * Reads BytesToRead from open file and
1143 * returns the number of bytes read in BytesRead
1145 BOOL
FatReadFile(FILE *FileHandle
, ULONG BytesToRead
, ULONG
* BytesRead
, PVOID Buffer
)
1147 PFAT_FILE_INFO FatFileInfo
= (PFAT_FILE_INFO
)FileHandle
;
1148 ULONG ClusterNumber
;
1149 ULONG OffsetInCluster
;
1150 ULONG LengthInCluster
;
1151 ULONG NumberOfClusters
;
1152 ULONG BytesPerCluster
;
1154 DbgPrint((DPRINT_FILESYSTEM
, "FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead
, Buffer
));
1156 if (BytesRead
!= NULL
)
1162 // If they are trying to read past the
1163 // end of the file then return success
1164 // with BytesRead == 0
1166 if (FatFileInfo
->FilePointer
>= FatFileInfo
->FileSize
)
1172 // If they are trying to read more than there is to read
1173 // then adjust the amount to read
1175 if ((FatFileInfo
->FilePointer
+ BytesToRead
) > FatFileInfo
->FileSize
)
1177 BytesToRead
= (FatFileInfo
->FileSize
- FatFileInfo
->FilePointer
);
1181 // Ok, now we have to perform at most 3 calculations
1182 // I'll draw you a picture (using nifty ASCII art):
1184 // CurrentFilePointer -+
1186 // +----------------+
1188 // +-----------+-----------+-----------+-----------+
1189 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
1190 // +-----------+-----------+-----------+-----------+
1192 // +---------------+--------------------+
1194 // BytesToRead -------+
1196 // 1 - The first calculation (and read) will align
1197 // the file pointer with the next cluster.
1198 // boundary (if we are supposed to read that much)
1199 // 2 - The next calculation (and read) will read
1200 // in all the full clusters that the requested
1201 // amount of data would cover (in this case
1203 // 3 - The last calculation (and read) would read
1204 // in the remainder of the data requested out of
1205 // the last cluster.
1208 BytesPerCluster
= SectorsPerCluster
* BytesPerSector
;
1211 // Only do the first read if we
1212 // aren't aligned on a cluster boundary
1214 if (FatFileInfo
->FilePointer
% BytesPerCluster
)
1217 // Do the math for our first read
1219 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1220 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1221 OffsetInCluster
= (FatFileInfo
->FilePointer
% BytesPerCluster
);
1222 LengthInCluster
= (BytesToRead
> (BytesPerCluster
- OffsetInCluster
)) ? (BytesPerCluster
- OffsetInCluster
) : BytesToRead
;
1225 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1227 if (!FatReadPartialCluster(ClusterNumber
, OffsetInCluster
, LengthInCluster
, Buffer
))
1231 if (BytesRead
!= NULL
)
1233 *BytesRead
+= LengthInCluster
;
1235 BytesToRead
-= LengthInCluster
;
1236 FatFileInfo
->FilePointer
+= LengthInCluster
;
1237 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ LengthInCluster
);
1241 // Do the math for our second read (if any data left)
1243 if (BytesToRead
> 0)
1246 // Determine how many full clusters we need to read
1248 NumberOfClusters
= (BytesToRead
/ BytesPerCluster
);
1250 if (NumberOfClusters
> 0)
1252 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1253 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1256 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1258 if (!FatReadClusterChain(ClusterNumber
, NumberOfClusters
, Buffer
))
1262 if (BytesRead
!= NULL
)
1264 *BytesRead
+= (NumberOfClusters
* BytesPerCluster
);
1266 BytesToRead
-= (NumberOfClusters
* BytesPerCluster
);
1267 FatFileInfo
->FilePointer
+= (NumberOfClusters
* BytesPerCluster
);
1268 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (NumberOfClusters
* BytesPerCluster
));
1273 // Do the math for our third read (if any data left)
1275 if (BytesToRead
> 0)
1277 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1278 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1281 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1283 if (!FatReadPartialCluster(ClusterNumber
, 0, BytesToRead
, Buffer
))
1287 if (BytesRead
!= NULL
)
1289 *BytesRead
+= BytesToRead
;
1291 FatFileInfo
->FilePointer
+= BytesToRead
;
1292 BytesToRead
-= BytesToRead
;
1293 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ BytesToRead
);
1299 ULONG
FatGetFileSize(FILE *FileHandle
)
1301 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1303 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFileSize() FileSize = %d\n", FatFileHandle
->FileSize
));
1305 return FatFileHandle
->FileSize
;
1308 VOID
FatSetFilePointer(FILE *FileHandle
, ULONG NewFilePointer
)
1310 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1312 DbgPrint((DPRINT_FILESYSTEM
, "FatSetFilePointer() NewFilePointer = %d\n", NewFilePointer
));
1314 FatFileHandle
->FilePointer
= NewFilePointer
;
1317 ULONG
FatGetFilePointer(FILE *FileHandle
)
1319 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1321 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFilePointer() FilePointer = %d\n", FatFileHandle
->FilePointer
));
1323 return FatFileHandle
->FilePointer
;
1326 BOOL
FatReadVolumeSectors(ULONG DriveNumber
, ULONG SectorNumber
, ULONG SectorCount
, PVOID Buffer
)
1328 return CacheReadDiskSectors(DriveNumber
, SectorNumber
+ FatVolumeStartSector
, SectorCount
, Buffer
);