3 * Copyright (C) 1998-2002 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 PFAT_BOOTSECTOR FatVolumeBootSector
= NULL
;
33 PFAT32_BOOTSECTOR Fat32VolumeBootSector
= NULL
;
35 ULONG RootDirSectorStart
; // Starting sector of the root directory (fat12/16)
36 ULONG DataSectorStart
; // Starting sector of the data area
37 ULONG SectorsPerFat
; // Sectors per FAT table
38 ULONG RootDirSectors
; // Number of sectors of the root directory (fat32)
40 ULONG FatType
= 0; // FAT12, FAT16, or FAT32
41 ULONG FatDriveNumber
= 0;
43 BOOL
FatOpenVolume(ULONG DriveNumber
, ULONG VolumeStartSector
)
46 DbgPrint((DPRINT_FILESYSTEM
, "FatOpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber
, VolumeStartSector
));
48 // Store the drive number
49 FatDriveNumber
= DriveNumber
;
52 // Free any memory previously allocated
54 if (FatVolumeBootSector
!= NULL
)
56 FreeMemory(FatVolumeBootSector
);
58 FatVolumeBootSector
= NULL
;
59 Fat32VolumeBootSector
= NULL
;
63 // Now allocate the memory to hold the boot sector
65 FatVolumeBootSector
= (PFAT_BOOTSECTOR
) AllocateMemory(512);
66 Fat32VolumeBootSector
= (PFAT32_BOOTSECTOR
) FatVolumeBootSector
;
69 // Make sure we got the memory
71 if (FatVolumeBootSector
== NULL
)
73 FileSystemError("Out of memory.");
77 // Now try to read the boot sector
78 // If this fails then abort
79 if (!DiskReadLogicalSectors(DriveNumber
, VolumeStartSector
, 1, FatVolumeBootSector
))
85 FatType
= FatDetermineFatType(FatVolumeBootSector
);
89 DbgPrint((DPRINT_FILESYSTEM
, "Dumping boot sector:\n"));
93 DbgPrint((DPRINT_FILESYSTEM
, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR
)));
95 DbgPrint((DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector
->JumpBoot
[0], Fat32VolumeBootSector
->JumpBoot
[1], Fat32VolumeBootSector
->JumpBoot
[2]));
96 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]));
97 DbgPrint((DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", Fat32VolumeBootSector
->BytesPerSector
));
98 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", Fat32VolumeBootSector
->SectorsPerCluster
));
99 DbgPrint((DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", Fat32VolumeBootSector
->ReservedSectors
));
100 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", Fat32VolumeBootSector
->NumberOfFats
));
101 DbgPrint((DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", Fat32VolumeBootSector
->RootDirEntries
));
102 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectors: %d\n", Fat32VolumeBootSector
->TotalSectors
));
103 DbgPrint((DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", Fat32VolumeBootSector
->MediaDescriptor
));
104 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", Fat32VolumeBootSector
->SectorsPerFat
));
105 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", Fat32VolumeBootSector
->SectorsPerTrack
));
106 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", Fat32VolumeBootSector
->NumberOfHeads
));
107 DbgPrint((DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", Fat32VolumeBootSector
->HiddenSectors
));
108 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", Fat32VolumeBootSector
->TotalSectorsBig
));
109 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFatBig: %d\n", Fat32VolumeBootSector
->SectorsPerFatBig
));
110 DbgPrint((DPRINT_FILESYSTEM
, "ExtendedFlags: 0x%x\n", Fat32VolumeBootSector
->ExtendedFlags
));
111 DbgPrint((DPRINT_FILESYSTEM
, "FileSystemVersion: 0x%x\n", Fat32VolumeBootSector
->FileSystemVersion
));
112 DbgPrint((DPRINT_FILESYSTEM
, "RootDirStartCluster: %d\n", Fat32VolumeBootSector
->RootDirStartCluster
));
113 DbgPrint((DPRINT_FILESYSTEM
, "FsInfo: %d\n", Fat32VolumeBootSector
->FsInfo
));
114 DbgPrint((DPRINT_FILESYSTEM
, "BackupBootSector: %d\n", Fat32VolumeBootSector
->BackupBootSector
));
115 DbgPrint((DPRINT_FILESYSTEM
, "Reserved: 0x%x\n", Fat32VolumeBootSector
->Reserved
));
116 DbgPrint((DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", Fat32VolumeBootSector
->DriveNumber
));
117 DbgPrint((DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", Fat32VolumeBootSector
->Reserved1
));
118 DbgPrint((DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", Fat32VolumeBootSector
->BootSignature
));
119 DbgPrint((DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector
->VolumeSerialNumber
));
120 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]));
121 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]));
122 DbgPrint((DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", Fat32VolumeBootSector
->BootSectorMagic
));
126 DbgPrint((DPRINT_FILESYSTEM
, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR
)));
128 DbgPrint((DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector
->JumpBoot
[0], FatVolumeBootSector
->JumpBoot
[1], FatVolumeBootSector
->JumpBoot
[2]));
129 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]));
130 DbgPrint((DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", FatVolumeBootSector
->BytesPerSector
));
131 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", FatVolumeBootSector
->SectorsPerCluster
));
132 DbgPrint((DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", FatVolumeBootSector
->ReservedSectors
));
133 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", FatVolumeBootSector
->NumberOfFats
));
134 DbgPrint((DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", FatVolumeBootSector
->RootDirEntries
));
135 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectors: %d\n", FatVolumeBootSector
->TotalSectors
));
136 DbgPrint((DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", FatVolumeBootSector
->MediaDescriptor
));
137 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", FatVolumeBootSector
->SectorsPerFat
));
138 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", FatVolumeBootSector
->SectorsPerTrack
));
139 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", FatVolumeBootSector
->NumberOfHeads
));
140 DbgPrint((DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", FatVolumeBootSector
->HiddenSectors
));
141 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", FatVolumeBootSector
->TotalSectorsBig
));
142 DbgPrint((DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", FatVolumeBootSector
->DriveNumber
));
143 DbgPrint((DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", FatVolumeBootSector
->Reserved1
));
144 DbgPrint((DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", FatVolumeBootSector
->BootSignature
));
145 DbgPrint((DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector
->VolumeSerialNumber
));
146 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]));
147 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]));
148 DbgPrint((DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", FatVolumeBootSector
->BootSectorMagic
));
151 #endif // defined DEBUG
154 // Check the boot sector magic
156 if (FatVolumeBootSector
->BootSectorMagic
!= 0xaa55)
158 FileSystemError("Invalid boot sector magic (0xaa55)");
163 // Check the FAT cluster size
164 // We do not support clusters bigger than 64k
166 if ((FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
) > (64 * 1024))
168 FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
173 // Clear our variables
175 RootDirSectorStart
= 0;
181 // Get the sectors per FAT,
182 // root directory starting sector,
183 // and data sector start
185 if (FatType
!= FAT32
)
187 SectorsPerFat
= FatVolumeBootSector
->SectorsPerFat
;
189 RootDirSectorStart
= (FatVolumeBootSector
->NumberOfFats
* SectorsPerFat
) + FatVolumeBootSector
->ReservedSectors
;
190 RootDirSectors
= ((FatVolumeBootSector
->RootDirEntries
* 32) + (FatVolumeBootSector
->BytesPerSector
- 1)) / FatVolumeBootSector
->BytesPerSector
;
192 DataSectorStart
= FatVolumeBootSector
->ReservedSectors
+ (FatVolumeBootSector
->NumberOfFats
* FatVolumeBootSector
->SectorsPerFat
) + RootDirSectors
;
196 SectorsPerFat
= Fat32VolumeBootSector
->SectorsPerFatBig
;
198 DataSectorStart
= FatVolumeBootSector
->ReservedSectors
+ (FatVolumeBootSector
->NumberOfFats
* Fat32VolumeBootSector
->SectorsPerFatBig
) + RootDirSectors
;
203 // we only work with version 0
205 if (Fat32VolumeBootSector
->FileSystemVersion
!= 0)
207 FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
213 // Initialize the disk cache for this drive
215 if (!CacheInitializeDrive(DriveNumber
))
221 // Force the FAT sectors into the cache
222 // as long as it is FAT12 or FAT16. FAT32 can
223 // have a multi-megabyte FAT so we don't want that.
225 if (FatType
!= FAT32
)
227 if (!CacheForceDiskSectorsIntoCache(DriveNumber
, FatVolumeBootSector
->HiddenSectors
+ FatVolumeBootSector
->ReservedSectors
, FatVolumeBootSector
->SectorsPerFat
))
236 ULONG
FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector
)
238 ULONG RootDirSectors
;
239 ULONG DataSectorCount
;
242 ULONG CountOfClusters
;
243 PFAT32_BOOTSECTOR Fat32BootSector
= (PFAT32_BOOTSECTOR
)FatBootSector
;
245 RootDirSectors
= ((FatBootSector
->RootDirEntries
* 32) + (FatBootSector
->BytesPerSector
- 1)) / FatBootSector
->BytesPerSector
;
246 SectorsPerFat
= FatBootSector
->SectorsPerFat
? FatBootSector
->SectorsPerFat
: Fat32BootSector
->SectorsPerFatBig
;
247 TotalSectors
= FatBootSector
->TotalSectors
? FatBootSector
->TotalSectors
: FatBootSector
->TotalSectorsBig
;
248 DataSectorCount
= TotalSectors
- (FatBootSector
->ReservedSectors
+ (FatBootSector
->NumberOfFats
* SectorsPerFat
) + RootDirSectors
);
251 if (FatBootSector
->SectorsPerCluster
== 0)
254 CountOfClusters
= DataSectorCount
/ FatBootSector
->SectorsPerCluster
;
256 if (CountOfClusters
< 4085)
258 /* Volume is FAT12 */
261 else if (CountOfClusters
< 65525)
263 /* Volume is FAT16 */
268 /* Volume is FAT32 */
273 PVOID
FatBufferDirectory(UINT32 DirectoryStartCluster
, PUINT32 EntryCountPointer
, BOOL RootDirectory
)
275 UINT32 RootDirectoryStartSector
;
276 UINT32 RootDirectorySectorCount
;
277 PVOID DirectoryBuffer
;
278 UINT32 DirectorySize
;
280 DbgPrint((DPRINT_FILESYSTEM
, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster
, (RootDirectory
? "TRUE" : "FALSE")));
283 // Calculate the size of the directory
285 if ((RootDirectory
) && (FatType
!= FAT32
))
287 DbgPrint((DPRINT_FILESYSTEM
, "We are here.\n"));
288 /*DbgPrint((DPRINT_FILESYSTEM, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR)));
290 DbgPrint((DPRINT_FILESYSTEM, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector->JumpBoot[0], FatVolumeBootSector->JumpBoot[1], FatVolumeBootSector->JumpBoot[2]));
291 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]));*/
292 DbgPrint((DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", FatVolumeBootSector
->BytesPerSector
));
293 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", FatVolumeBootSector
->SectorsPerCluster
));
294 DbgPrint((DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", FatVolumeBootSector
->ReservedSectors
));
295 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", FatVolumeBootSector
->NumberOfFats
));
296 DbgPrint((DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", FatVolumeBootSector
->RootDirEntries
));
297 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectors: %d\n", FatVolumeBootSector
->TotalSectors
));
298 DbgPrint((DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", FatVolumeBootSector
->MediaDescriptor
));
299 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", FatVolumeBootSector
->SectorsPerFat
));
300 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", FatVolumeBootSector
->SectorsPerTrack
));
301 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", FatVolumeBootSector
->NumberOfHeads
));
302 DbgPrint((DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", FatVolumeBootSector
->HiddenSectors
));
303 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", FatVolumeBootSector
->TotalSectorsBig
));
304 DbgPrint((DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", FatVolumeBootSector
->DriveNumber
));
305 DbgPrint((DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", FatVolumeBootSector
->Reserved1
));
306 DbgPrint((DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", FatVolumeBootSector
->BootSignature
));
307 DbgPrint((DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector
->VolumeSerialNumber
));
308 /*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]));
309 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]));*/
310 DbgPrint((DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", FatVolumeBootSector
->BootSectorMagic
));
311 DirectorySize
= ROUND_UP((FatVolumeBootSector
->RootDirEntries
* 32), FatVolumeBootSector
->BytesPerSector
);
315 DbgPrint((DPRINT_FILESYSTEM
, "No we are here.\n"));
318 DirectorySize
= (FatCountClustersInChain(Fat32VolumeBootSector
->RootDirStartCluster
) * Fat32VolumeBootSector
->SectorsPerCluster
) * Fat32VolumeBootSector
->BytesPerSector
;
322 DirectorySize
= (FatCountClustersInChain(DirectoryStartCluster
) * FatVolumeBootSector
->SectorsPerCluster
) * FatVolumeBootSector
->BytesPerSector
;
327 // Attempt to allocate memory for directory buffer
329 DbgPrint((DPRINT_FILESYSTEM
, "Trying to allocate (DirectorySize) %d bytes.\n", DirectorySize
));
330 DirectoryBuffer
= AllocateMemory(DirectorySize
);
332 if (DirectoryBuffer
== NULL
)
338 // Now read directory contents into DirectoryBuffer
342 if (FatType
== FAT32
)
344 if (!FatReadClusterChain(Fat32VolumeBootSector
->RootDirStartCluster
, 0xFFFFFFFF, DirectoryBuffer
))
346 FreeMemory(DirectoryBuffer
);
353 // FAT type is not FAT32 so the root directory comes right after the fat table
355 RootDirectoryStartSector
= FatVolumeBootSector
->ReservedSectors
+ (FatVolumeBootSector
->NumberOfFats
* FatVolumeBootSector
->SectorsPerFat
);
356 RootDirectorySectorCount
= (DirectorySize
/ FatVolumeBootSector
->BytesPerSector
);
358 if (!FatReadVolumeSectors(FatDriveNumber
, RootDirectoryStartSector
, RootDirectorySectorCount
, DirectoryBuffer
))
360 FreeMemory(DirectoryBuffer
);
367 if (!FatReadClusterChain(DirectoryStartCluster
, 0xFFFFFFFF, DirectoryBuffer
))
369 FreeMemory(DirectoryBuffer
);
374 *EntryCountPointer
= (DirectorySize
/ 32);
376 return DirectoryBuffer
;
379 BOOL
FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer
, UINT32 EntryCount
, PUCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
383 PLFN_DIRENTRY LfnDirEntry
;
384 UCHAR LfnNameBuffer
[261];
385 UCHAR ShortNameBuffer
[13];
388 DbgPrint((DPRINT_FILESYSTEM
, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
));
390 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
391 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
393 for (CurrentEntry
=0; CurrentEntry
<EntryCount
; CurrentEntry
++)
395 DirEntry
= (PDIRENTRY
)(DirectoryBuffer
+ (CurrentEntry
* 32) );
396 LfnDirEntry
= (PLFN_DIRENTRY
)DirEntry
;
399 // Check if this is the last file in the directory
400 // If DirEntry[0] == 0x00 then that means all the
401 // entries after this one are unused. If this is the
402 // last entry then we didn't find the file in this directory.
404 if (DirEntry
->FileName
[0] == 0x00)
410 // Check if this is a deleted entry or not
412 if (DirEntry
->FileName
[0] == 0xE5)
414 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
415 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
420 // Check if this is a LFN entry
421 // If so it needs special handling
423 if (DirEntry
->Attr
== ATTR_LONG_NAME
)
426 // Check to see if this is a deleted LFN entry, if so continue
428 if (LfnDirEntry
->SequenceNumber
& 0x80)
434 // Mask off high two bits of sequence number
435 // and make the sequence number zero-based
437 LfnDirEntry
->SequenceNumber
&= 0x3F;
438 LfnDirEntry
->SequenceNumber
--;
441 // Get all 13 LFN entry characters
443 if (LfnDirEntry
->Name0_4
[0] != 0xFFFF)
445 LfnNameBuffer
[0 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[0];
447 if (LfnDirEntry
->Name0_4
[1] != 0xFFFF)
449 LfnNameBuffer
[1 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[1];
451 if (LfnDirEntry
->Name0_4
[2] != 0xFFFF)
453 LfnNameBuffer
[2 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[2];
455 if (LfnDirEntry
->Name0_4
[3] != 0xFFFF)
457 LfnNameBuffer
[3 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[3];
459 if (LfnDirEntry
->Name0_4
[4] != 0xFFFF)
461 LfnNameBuffer
[4 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[4];
463 if (LfnDirEntry
->Name5_10
[0] != 0xFFFF)
465 LfnNameBuffer
[5 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[0];
467 if (LfnDirEntry
->Name5_10
[1] != 0xFFFF)
469 LfnNameBuffer
[6 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[1];
471 if (LfnDirEntry
->Name5_10
[2] != 0xFFFF)
473 LfnNameBuffer
[7 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[2];
475 if (LfnDirEntry
->Name5_10
[3] != 0xFFFF)
477 LfnNameBuffer
[8 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[3];
479 if (LfnDirEntry
->Name5_10
[4] != 0xFFFF)
481 LfnNameBuffer
[9 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[4];
483 if (LfnDirEntry
->Name5_10
[5] != 0xFFFF)
485 LfnNameBuffer
[10 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[5];
487 if (LfnDirEntry
->Name11_12
[0] != 0xFFFF)
489 LfnNameBuffer
[11 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[0];
491 if (LfnDirEntry
->Name11_12
[1] != 0xFFFF)
493 LfnNameBuffer
[12 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[1];
500 // Check for the volume label attribute
501 // and skip over this entry if found
503 if (DirEntry
->Attr
& ATTR_VOLUMENAME
)
505 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
506 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
511 // If we get here then we've found a short file name
512 // entry and LfnNameBuffer contains the long file
513 // name or zeroes. All we have to do now is see if the
514 // file name matches either the short or long file name
515 // and fill in the FAT_FILE_INFO structure if it does
516 // or zero our buffers and continue looking.
520 // Get short file name
522 FatParseShortFileName(ShortNameBuffer
, DirEntry
);
524 DbgPrint((DPRINT_FILESYSTEM
, "Entry: %d LFN = %s\n", CurrentEntry
, LfnNameBuffer
));
525 DbgPrint((DPRINT_FILESYSTEM
, "Entry: %d DOS name = %s\n", CurrentEntry
, ShortNameBuffer
));
528 // See if the file name matches either the short or long name
530 if (((strlen(FileName
) == strlen(LfnNameBuffer
)) && (stricmp(FileName
, LfnNameBuffer
) == 0)) ||
531 ((strlen(FileName
) == strlen(ShortNameBuffer
)) && (stricmp(FileName
, ShortNameBuffer
) == 0)))
534 // We found the entry, now fill in the FAT_FILE_INFO struct
536 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
537 FatFileInfoPointer
->FilePointer
= 0;
539 DbgPrint((DPRINT_FILESYSTEM
, "MSDOS Directory Entry:\n"));
540 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]));
541 DbgPrint((DPRINT_FILESYSTEM
, "Attr = 0x%x\n", DirEntry
->Attr
));
542 DbgPrint((DPRINT_FILESYSTEM
, "ReservedNT = 0x%x\n", DirEntry
->ReservedNT
));
543 DbgPrint((DPRINT_FILESYSTEM
, "TimeInTenths = %d\n", DirEntry
->TimeInTenths
));
544 DbgPrint((DPRINT_FILESYSTEM
, "CreateTime = %d\n", DirEntry
->CreateTime
));
545 DbgPrint((DPRINT_FILESYSTEM
, "CreateDate = %d\n", DirEntry
->CreateDate
));
546 DbgPrint((DPRINT_FILESYSTEM
, "LastAccessDate = %d\n", DirEntry
->LastAccessDate
));
547 DbgPrint((DPRINT_FILESYSTEM
, "ClusterHigh = 0x%x\n", DirEntry
->ClusterHigh
));
548 DbgPrint((DPRINT_FILESYSTEM
, "Time = %d\n", DirEntry
->Time
));
549 DbgPrint((DPRINT_FILESYSTEM
, "Date = %d\n", DirEntry
->Date
));
550 DbgPrint((DPRINT_FILESYSTEM
, "ClusterLow = 0x%x\n", DirEntry
->ClusterLow
));
551 DbgPrint((DPRINT_FILESYSTEM
, "Size = %d\n", DirEntry
->Size
));
554 // Get the cluster chain
556 StartCluster
= ((UINT32
)DirEntry
->ClusterHigh
<< 16) + DirEntry
->ClusterLow
;
557 DbgPrint((DPRINT_FILESYSTEM
, "StartCluster = 0x%x\n", StartCluster
));
558 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(StartCluster
);
561 // See if memory allocation failed
563 if (FatFileInfoPointer
->FileFatChain
== NULL
)
572 // Nope, no match - zero buffers and continue looking
574 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
575 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
584 * This function searches the file system for the
585 * specified filename and fills in a FAT_STRUCT structure
586 * with info describing the file, etc. returns true
587 * if the file exists or false otherwise
589 BOOL
FatLookupFile(PUCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
592 ULONG NumberOfPathParts
;
594 PVOID DirectoryBuffer
;
595 UINT32 DirectoryStartCluster
= 0;
596 ULONG DirectoryEntryCount
;
597 FAT_FILE_INFO FatFileInfo
;
599 DbgPrint((DPRINT_FILESYSTEM
, "FatLookupFile() FileName = %s\n", FileName
));
601 memset(FatFileInfoPointer
, 0, sizeof(FAT_FILE_INFO
));
604 // Check and see if the first character is '\' and remove it if so
606 while (*FileName
== '\\')
612 // Figure out how many sub-directories we are nested in
614 NumberOfPathParts
= FatGetNumPathParts(FileName
);
617 // Loop once for each part
619 for (i
=0; i
<NumberOfPathParts
; i
++)
622 // Get first path part
624 FatGetFirstNameFromPath(PathPart
, FileName
);
627 // Advance to the next part of the path
629 for (; (*FileName
!= '\\') && (*FileName
!= '\0'); FileName
++)
635 // Buffer the directory contents
637 DirectoryBuffer
= FatBufferDirectory(DirectoryStartCluster
, &DirectoryEntryCount
, (i
== 0) );
638 if (DirectoryBuffer
== NULL
)
644 // Search for file name in directory
646 if (!FatSearchDirectoryBufferForFile(DirectoryBuffer
, DirectoryEntryCount
, PathPart
, &FatFileInfo
))
648 FreeMemory(DirectoryBuffer
);
652 FreeMemory(DirectoryBuffer
);
655 // If we have another sub-directory to go then
656 // grab the start cluster and free the fat chain array
658 if ((i
+1) < NumberOfPathParts
)
660 DirectoryStartCluster
= FatFileInfo
.FileFatChain
[0];
661 FreeMemory(FatFileInfo
.FileFatChain
);
665 memcpy(FatFileInfoPointer
, &FatFileInfo
, sizeof(FAT_FILE_INFO
));
671 * FatGetNumPathParts()
672 * This function parses a path in the form of dir1\dir2\file1.ext
673 * and returns the number of parts it has (i.e. 3 - dir1,dir2,file1.ext)
675 ULONG
FatGetNumPathParts(PUCHAR Path
)
680 for (i
=0,num
=0; i
<(int)strlen(Path
); i
++)
689 DbgPrint((DPRINT_FILESYSTEM
, "FatGetNumPathParts() Path = %s NumPathParts = %d\n", Path
, num
));
695 * FatGetFirstNameFromPath()
696 * This function parses a path in the form of dir1\dir2\file1.ext
697 * and puts the first name of the path (e.g. "dir1") in buffer
698 * compatible with the MSDOS directory structure
700 VOID
FatGetFirstNameFromPath(PUCHAR Buffer
, PUCHAR Path
)
704 // Copy all the characters up to the end of the
705 // string or until we hit a '\' character
706 // and put them in Buffer
707 for (i
=0; i
<(int)strlen(Path
); i
++)
721 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFirstNameFromPath() Path = %s FirstName = %s\n", Path
, Buffer
));
726 * This function parses a directory entry name which
727 * is in the form of "FILE EXT" and puts it in Buffer
728 * in the form of "file.ext"
730 void FatParseShortFileName(PUCHAR Buffer
, PDIRENTRY DirEntry
)
737 // Fixup first character
739 if (DirEntry
->FileName
[0] == 0x05)
741 DirEntry
->FileName
[0] = 0xE5;
749 if (DirEntry
->FileName
[Idx
] == ' ')
754 Buffer
[Idx
] = DirEntry
->FileName
[Idx
];
761 if ((DirEntry
->FileName
[8] != ' '))
764 Buffer
[Idx
++] = (DirEntry
->FileName
[8] == ' ') ? '\0' : DirEntry
->FileName
[8];
765 Buffer
[Idx
++] = (DirEntry
->FileName
[9] == ' ') ? '\0' : DirEntry
->FileName
[9];
766 Buffer
[Idx
++] = (DirEntry
->FileName
[10] == ' ') ? '\0' : DirEntry
->FileName
[10];
770 // Null-Terminate string
772 Buffer
[Idx
+ 4] = '\0';
774 DbgPrint((DPRINT_FILESYSTEM
, "FatParseShortFileName() ShortName = %s\n", Buffer
));
779 * returns the Fat entry for a given cluster number
781 BOOL
FatGetFatEntry(UINT32 Cluster
, PUINT32 ClusterPointer
)
786 int ThisFatEntOffset
;
788 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster
));
794 FatOffset
= Cluster
+ (Cluster
/ 2);
795 ThisFatSecNum
= FatVolumeBootSector
->ReservedSectors
+ (FatOffset
/ FatVolumeBootSector
->BytesPerSector
);
796 ThisFatEntOffset
= (FatOffset
% FatVolumeBootSector
->BytesPerSector
);
798 DbgPrint((DPRINT_FILESYSTEM
, "FatOffset: %d\n", FatOffset
));
799 DbgPrint((DPRINT_FILESYSTEM
, "ThisFatSecNum: %d\n", ThisFatSecNum
));
800 DbgPrint((DPRINT_FILESYSTEM
, "ThisFatEntOffset: %d\n", ThisFatEntOffset
));
802 if (ThisFatEntOffset
== (FatVolumeBootSector
->BytesPerSector
- 1))
804 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 2, (PVOID
)FILESYSBUFFER
))
811 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
817 fat
= *((WORD
*) ((PVOID
)FILESYSBUFFER
+ ThisFatEntOffset
));
818 if (Cluster
& 0x0001)
819 fat
= fat
>> 4; /* Cluster number is ODD */
821 fat
= fat
& 0x0FFF; /* Cluster number is EVEN */
827 FatOffset
= (Cluster
* 2);
828 ThisFatSecNum
= FatVolumeBootSector
->ReservedSectors
+ (FatOffset
/ FatVolumeBootSector
->BytesPerSector
);
829 ThisFatEntOffset
= (FatOffset
% FatVolumeBootSector
->BytesPerSector
);
831 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
836 fat
= *((WORD
*) ((PVOID
)FILESYSBUFFER
+ ThisFatEntOffset
));
842 FatOffset
= (Cluster
* 4);
843 ThisFatSecNum
= (Fat32VolumeBootSector
->ExtendedFlags
& 0x80) ? ((Fat32VolumeBootSector
->ExtendedFlags
& 0x0f) * Fat32VolumeBootSector
->SectorsPerFatBig
) : 0; // Get the active fat sector offset
844 ThisFatSecNum
+= FatVolumeBootSector
->ReservedSectors
+ (FatOffset
/ FatVolumeBootSector
->BytesPerSector
);
845 ThisFatEntOffset
= (FatOffset
% FatVolumeBootSector
->BytesPerSector
);
847 if (!FatReadVolumeSectors(FatDriveNumber
, ThisFatSecNum
, 1, (PVOID
)FILESYSBUFFER
))
853 fat
= (*((DWORD
*) ((PVOID
)FILESYSBUFFER
+ ThisFatEntOffset
))) & 0x0FFFFFFF;
859 DbgPrint((DPRINT_FILESYSTEM
, "FAT entry is 0x%x.\n", fat
));
861 *ClusterPointer
= fat
;
868 * Tries to open the file 'name' and returns true or false
869 * for success and failure respectively
871 FILE* FatOpenFile(PUCHAR FileName
)
873 FAT_FILE_INFO TempFatFileInfo
;
874 PFAT_FILE_INFO FileHandle
;
876 DbgPrint((DPRINT_FILESYSTEM
, "FatOpenFile() FileName = %s\n", FileName
));
878 if (!FatLookupFile(FileName
, &TempFatFileInfo
))
883 FileHandle
= AllocateMemory(sizeof(FAT_FILE_INFO
));
885 if (FileHandle
== NULL
)
890 memcpy(FileHandle
, &TempFatFileInfo
, sizeof(FAT_FILE_INFO
));
892 return (FILE*)FileHandle
;
895 UINT32
FatCountClustersInChain(UINT32 StartCluster
)
897 UINT32 ClusterCount
= 0;
899 DbgPrint((DPRINT_FILESYSTEM
, "FatCountClustersInChain() StartCluster = %d\n", StartCluster
));
904 // If end of chain then break out of our cluster counting loop
906 if (((FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
907 ((FatType
== FAT16
) && (StartCluster
>= 0xfff8)) ||
908 ((FatType
== FAT32
) && (StartCluster
>= 0x0ffffff8)))
921 if (!FatGetFatEntry(StartCluster
, &StartCluster
))
927 DbgPrint((DPRINT_FILESYSTEM
, "FatCountClustersInChain() ClusterCount = %d\n", ClusterCount
));
932 PUINT32
FatGetClusterChainArray(UINT32 StartCluster
)
936 PUINT32 ArrayPointer
;
939 DbgPrint((DPRINT_FILESYSTEM
, "FatGetClusterChainArray() StartCluster = %d\n", StartCluster
));
941 ClusterCount
= FatCountClustersInChain(StartCluster
) + 1; // Lets get the 0x0ffffff8 on the end of the array
942 ArraySize
= ClusterCount
* sizeof(UINT32
);
945 // Allocate array memory
947 ArrayPointer
= AllocateMemory(ArraySize
);
949 if (ArrayPointer
== NULL
)
955 // Loop through and set array values
957 for (Idx
=0; Idx
<ClusterCount
; Idx
++)
960 // Set current cluster
962 ArrayPointer
[Idx
] = StartCluster
;
965 // Don't try to get next cluster for last cluster
967 if (((FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
968 ((FatType
== FAT16
) && (StartCluster
>= 0xfff8)) ||
969 ((FatType
== FAT32
) && (StartCluster
>= 0x0ffffff8)))
978 if (!FatGetFatEntry(StartCluster
, &StartCluster
))
980 FreeMemory(ArrayPointer
);
990 * Reads the specified cluster into memory
991 * and returns the number of bytes read
993 BOOL
FatReadCluster(ULONG ClusterNumber
, PVOID Buffer
)
995 ULONG ClusterStartSector
;
997 ClusterStartSector
= ((ClusterNumber
- 2) * FatVolumeBootSector
->SectorsPerCluster
) + DataSectorStart
;
999 DbgPrint((DPRINT_FILESYSTEM
, "FatReadCluster() ClusterNumber = %d Buffer = 0x%x ClusterStartSector = %d\n", ClusterNumber
, Buffer
, ClusterStartSector
));
1001 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, FatVolumeBootSector
->SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1006 memcpy(Buffer
, (PVOID
)FILESYSBUFFER
, FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
);
1012 * FatReadClusterChain()
1013 * Reads the specified clusters into memory
1015 BOOL
FatReadClusterChain(ULONG StartClusterNumber
, ULONG NumberOfClusters
, PVOID Buffer
)
1017 ULONG ClusterStartSector
;
1019 DbgPrint((DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
));
1021 while (NumberOfClusters
> 0)
1024 DbgPrint((DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
));
1026 // Calculate starting sector for cluster
1028 ClusterStartSector
= ((StartClusterNumber
- 2) * FatVolumeBootSector
->SectorsPerCluster
) + DataSectorStart
;
1031 // Read cluster into memory
1033 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, FatVolumeBootSector
->SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1038 memcpy(Buffer
, (PVOID
)FILESYSBUFFER
, FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
);
1041 // Decrement count of clusters left to read
1046 // Increment buffer address by cluster size
1048 Buffer
+= (FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
);
1053 if (!FatGetFatEntry(StartClusterNumber
, &StartClusterNumber
))
1059 // If end of chain then break out of our cluster reading loop
1061 if (((FatType
== FAT12
) && (StartClusterNumber
>= 0xff8)) ||
1062 ((FatType
== FAT16
) && (StartClusterNumber
>= 0xfff8)) ||
1063 ((FatType
== FAT32
) && (StartClusterNumber
>= 0x0ffffff8)))
1073 * FatReadPartialCluster()
1074 * Reads part of a cluster into memory
1076 BOOL
FatReadPartialCluster(ULONG ClusterNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
)
1078 ULONG ClusterStartSector
;
1080 DbgPrint((DPRINT_FILESYSTEM
, "FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber
, StartingOffset
, Length
, Buffer
));
1082 ClusterStartSector
= ((ClusterNumber
- 2) * FatVolumeBootSector
->SectorsPerCluster
) + DataSectorStart
;
1084 if (!FatReadVolumeSectors(FatDriveNumber
, ClusterStartSector
, FatVolumeBootSector
->SectorsPerCluster
, (PVOID
)FILESYSBUFFER
))
1089 memcpy(Buffer
, ((PVOID
)FILESYSBUFFER
+ StartingOffset
), Length
);
1096 * Reads BytesToRead from open file and
1097 * returns the number of bytes read in BytesRead
1099 BOOL
FatReadFile(FILE *FileHandle
, ULONG BytesToRead
, PULONG BytesRead
, PVOID Buffer
)
1101 PFAT_FILE_INFO FatFileInfo
= (PFAT_FILE_INFO
)FileHandle
;
1102 UINT32 ClusterNumber
;
1103 UINT32 OffsetInCluster
;
1104 UINT32 LengthInCluster
;
1105 UINT32 NumberOfClusters
;
1106 UINT32 BytesPerCluster
;
1108 DbgPrint((DPRINT_FILESYSTEM
, "FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead
, Buffer
));
1110 if (BytesRead
!= NULL
)
1116 // If they are trying to read past the
1117 // end of the file then return success
1118 // with BytesRead == 0
1120 if (FatFileInfo
->FilePointer
>= FatFileInfo
->FileSize
)
1126 // If they are trying to read more than there is to read
1127 // then adjust the amount to read
1129 if ((FatFileInfo
->FilePointer
+ BytesToRead
) > FatFileInfo
->FileSize
)
1131 BytesToRead
= (FatFileInfo
->FileSize
- FatFileInfo
->FilePointer
);
1135 // Ok, now we have to perform at most 3 calculations
1136 // I'll draw you a picture (using nifty ASCII art):
1138 // CurrentFilePointer -+
1140 // +----------------+
1142 // +-----------+-----------+-----------+-----------+
1143 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
1144 // +-----------+-----------+-----------+-----------+
1146 // +---------------+--------------------+
1148 // BytesToRead -------+
1150 // 1 - The first calculation (and read) will align
1151 // the file pointer with the next cluster.
1152 // boundary (if we are supposed to read that much)
1153 // 2 - The next calculation (and read) will read
1154 // in all the full clusters that the requested
1155 // amount of data would cover (in this case
1157 // 3 - The last calculation (and read) would read
1158 // in the remainder of the data requested out of
1159 // the last cluster.
1162 BytesPerCluster
= (FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
);
1165 // Only do the first read if we
1166 // aren't aligned on a cluster boundary
1168 if (FatFileInfo
->FilePointer
% BytesPerCluster
)
1171 // Do the math for our first read
1173 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1174 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1175 OffsetInCluster
= (FatFileInfo
->FilePointer
% BytesPerCluster
);
1176 LengthInCluster
= (BytesToRead
> (BytesPerCluster
- OffsetInCluster
)) ? (BytesPerCluster
- OffsetInCluster
) : BytesToRead
;
1179 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1181 if (!FatReadPartialCluster(ClusterNumber
, OffsetInCluster
, LengthInCluster
, Buffer
))
1185 if (BytesRead
!= NULL
)
1187 *BytesRead
+= LengthInCluster
;
1189 BytesToRead
-= LengthInCluster
;
1190 FatFileInfo
->FilePointer
+= LengthInCluster
;
1191 Buffer
+= LengthInCluster
;
1195 // Do the math for our second read (if any data left)
1197 if (BytesToRead
> 0)
1200 // Determine how many full clusters we need to read
1202 NumberOfClusters
= (BytesToRead
/ BytesPerCluster
);
1204 if (NumberOfClusters
> 0)
1206 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1207 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1210 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1212 if (!FatReadClusterChain(ClusterNumber
, NumberOfClusters
, Buffer
))
1216 if (BytesRead
!= NULL
)
1218 *BytesRead
+= (NumberOfClusters
* BytesPerCluster
);
1220 BytesToRead
-= (NumberOfClusters
* BytesPerCluster
);
1221 FatFileInfo
->FilePointer
+= (NumberOfClusters
* BytesPerCluster
);
1222 Buffer
+= (NumberOfClusters
* BytesPerCluster
);
1227 // Do the math for our third read (if any data left)
1229 if (BytesToRead
> 0)
1231 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1232 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1235 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1237 if (!FatReadPartialCluster(ClusterNumber
, 0, BytesToRead
, Buffer
))
1241 if (BytesRead
!= NULL
)
1243 *BytesRead
+= BytesToRead
;
1245 BytesToRead
-= BytesToRead
;
1246 FatFileInfo
->FilePointer
+= BytesToRead
;
1247 Buffer
+= BytesToRead
;
1253 ULONG
FatGetFileSize(FILE *FileHandle
)
1255 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1257 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFileSize() FileSize = %d\n", FatFileHandle
->FileSize
));
1259 return FatFileHandle
->FileSize
;
1262 VOID
FatSetFilePointer(FILE *FileHandle
, ULONG NewFilePointer
)
1264 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1266 DbgPrint((DPRINT_FILESYSTEM
, "FatSetFilePointer() NewFilePointer = %d\n", NewFilePointer
));
1268 FatFileHandle
->FilePointer
= NewFilePointer
;
1271 ULONG
FatGetFilePointer(FILE *FileHandle
)
1273 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1275 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFilePointer() FilePointer = %d\n", FatFileHandle
->FilePointer
));
1277 return FatFileHandle
->FilePointer
;
1280 BOOL
FatReadVolumeSectors(ULONG DriveNumber
, ULONG SectorNumber
, ULONG SectorCount
, PVOID Buffer
)
1282 //return DiskReadMultipleLogicalSectors(DriveNumber, SectorNumber + FatVolumeBootSector->HiddenSectors, SectorCount, Buffer);
1283 return CacheReadDiskSectors(DriveNumber
, SectorNumber
+ FatVolumeBootSector
->HiddenSectors
, SectorCount
, Buffer
);