3 * Copyright (C) 1999, 2000, 2001 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.
31 PFAT_BOOTSECTOR FatVolumeBootSector
= NULL
;
32 PFAT32_BOOTSECTOR Fat32VolumeBootSector
= NULL
;
34 ULONG RootDirSectorStart
; // Starting sector of the root directory (fat12/16)
35 ULONG DataSectorStart
; // Starting sector of the data area
36 ULONG SectorsPerFat
; // Sectors per FAT table
37 ULONG RootDirSectors
; // Number of sectors of the root directory (fat32)
39 ULONG FatType
= 0; // FAT12, FAT16, or FAT32
42 BOOL
FatOpenVolume(ULONG DriveNumber
, ULONG VolumeStartHead
, ULONG VolumeStartTrack
, ULONG VolumeStartSector
, ULONG FatFileSystemType
)
44 FatType
= FatFileSystemType
;
47 // Free any memory previously allocated
49 if (FatVolumeBootSector
!= NULL
)
51 FreeMemory(FatVolumeBootSector
);
53 FatVolumeBootSector
= NULL
;
54 Fat32VolumeBootSector
= NULL
;
58 // Now allocate the memory to hold the boot sector
60 FatVolumeBootSector
= (PFAT_BOOTSECTOR
) AllocateMemory(512);
61 Fat32VolumeBootSector
= (PFAT32_BOOTSECTOR
) FatVolumeBootSector
;
64 // Make sure we got the memory
66 if (FatVolumeBootSector
== NULL
)
68 FileSystemError("Out of memory.");
73 // Now try to read the boot sector
74 // If this fails then abort
76 if (!BiosInt13Read(DriveNumber
, VolumeStartHead
, VolumeStartTrack
, VolumeStartSector
, 1, FatVolumeBootSector
))
83 DbgPrint((DPRINT_FILESYSTEM
, "Dumping boot sector:\n"));
85 if (FatFileSystemType
== FAT32
)
87 DbgPrint((DPRINT_FILESYSTEM
, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR
)));
89 DbgPrint((DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector
->JumpBoot
[0], Fat32VolumeBootSector
->JumpBoot
[1], Fat32VolumeBootSector
->JumpBoot
[2]));
90 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]));
91 DbgPrint((DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", Fat32VolumeBootSector
->BytesPerSector
));
92 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", Fat32VolumeBootSector
->SectorsPerCluster
));
93 DbgPrint((DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", Fat32VolumeBootSector
->ReservedSectors
));
94 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", Fat32VolumeBootSector
->NumberOfFats
));
95 DbgPrint((DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", Fat32VolumeBootSector
->RootDirEntries
));
96 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectors: %d\n", Fat32VolumeBootSector
->TotalSectors
));
97 DbgPrint((DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", Fat32VolumeBootSector
->MediaDescriptor
));
98 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", Fat32VolumeBootSector
->SectorsPerFat
));
99 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", Fat32VolumeBootSector
->SectorsPerTrack
));
100 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", Fat32VolumeBootSector
->NumberOfHeads
));
101 DbgPrint((DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", Fat32VolumeBootSector
->HiddenSectors
));
102 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", Fat32VolumeBootSector
->TotalSectorsBig
));
103 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFatBig: %d\n", Fat32VolumeBootSector
->SectorsPerFatBig
));
104 DbgPrint((DPRINT_FILESYSTEM
, "ExtendedFlags: 0x%x\n", Fat32VolumeBootSector
->ExtendedFlags
));
105 DbgPrint((DPRINT_FILESYSTEM
, "FileSystemVersion: 0x%x\n", Fat32VolumeBootSector
->FileSystemVersion
));
106 DbgPrint((DPRINT_FILESYSTEM
, "RootDirStartCluster: %d\n", Fat32VolumeBootSector
->RootDirStartCluster
));
107 DbgPrint((DPRINT_FILESYSTEM
, "FsInfo: %d\n", Fat32VolumeBootSector
->FsInfo
));
108 DbgPrint((DPRINT_FILESYSTEM
, "BackupBootSector: %d\n", Fat32VolumeBootSector
->BackupBootSector
));
109 DbgPrint((DPRINT_FILESYSTEM
, "Reserved: 0x%x\n", Fat32VolumeBootSector
->Reserved
));
110 DbgPrint((DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", Fat32VolumeBootSector
->DriveNumber
));
111 DbgPrint((DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", Fat32VolumeBootSector
->Reserved1
));
112 DbgPrint((DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", Fat32VolumeBootSector
->BootSignature
));
113 DbgPrint((DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector
->VolumeSerialNumber
));
114 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]));
115 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]));
116 DbgPrint((DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", Fat32VolumeBootSector
->BootSectorMagic
));
120 DbgPrint((DPRINT_FILESYSTEM
, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR
)));
122 DbgPrint((DPRINT_FILESYSTEM
, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector
->JumpBoot
[0], FatVolumeBootSector
->JumpBoot
[1], FatVolumeBootSector
->JumpBoot
[2]));
123 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]));
124 DbgPrint((DPRINT_FILESYSTEM
, "BytesPerSector: %d\n", FatVolumeBootSector
->BytesPerSector
));
125 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerCluster: %d\n", FatVolumeBootSector
->SectorsPerCluster
));
126 DbgPrint((DPRINT_FILESYSTEM
, "ReservedSectors: %d\n", FatVolumeBootSector
->ReservedSectors
));
127 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfFats: %d\n", FatVolumeBootSector
->NumberOfFats
));
128 DbgPrint((DPRINT_FILESYSTEM
, "RootDirEntries: %d\n", FatVolumeBootSector
->RootDirEntries
));
129 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectors: %d\n", FatVolumeBootSector
->TotalSectors
));
130 DbgPrint((DPRINT_FILESYSTEM
, "MediaDescriptor: 0x%x\n", FatVolumeBootSector
->MediaDescriptor
));
131 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerFat: %d\n", FatVolumeBootSector
->SectorsPerFat
));
132 DbgPrint((DPRINT_FILESYSTEM
, "SectorsPerTrack: %d\n", FatVolumeBootSector
->SectorsPerTrack
));
133 DbgPrint((DPRINT_FILESYSTEM
, "NumberOfHeads: %d\n", FatVolumeBootSector
->NumberOfHeads
));
134 DbgPrint((DPRINT_FILESYSTEM
, "HiddenSectors: %d\n", FatVolumeBootSector
->HiddenSectors
));
135 DbgPrint((DPRINT_FILESYSTEM
, "TotalSectorsBig: %d\n", FatVolumeBootSector
->TotalSectorsBig
));
136 DbgPrint((DPRINT_FILESYSTEM
, "DriveNumber: 0x%x\n", FatVolumeBootSector
->DriveNumber
));
137 DbgPrint((DPRINT_FILESYSTEM
, "Reserved1: 0x%x\n", FatVolumeBootSector
->Reserved1
));
138 DbgPrint((DPRINT_FILESYSTEM
, "BootSignature: 0x%x\n", FatVolumeBootSector
->BootSignature
));
139 DbgPrint((DPRINT_FILESYSTEM
, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector
->VolumeSerialNumber
));
140 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]));
141 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]));
142 DbgPrint((DPRINT_FILESYSTEM
, "BootSectorMagic: 0x%x\n", FatVolumeBootSector
->BootSectorMagic
));
145 #endif // defined DEBUG
148 // Check the boot sector magic
150 if (FatVolumeBootSector
->BootSectorMagic
!= 0xaa55)
152 FileSystemError("Invalid boot sector magic (0xaa55)");
156 DiskSetDriveGeometry(get_cylinders(DriveNumber
), get_heads(DriveNumber
), get_sectors(DriveNumber
), FatVolumeBootSector
->BytesPerSector
);
157 DiskSetVolumeProperties(FatVolumeBootSector
->HiddenSectors
);
160 // Check the FAT cluster size
161 // We do not support clusters bigger than 64k
163 if ((FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
) > (64 * 1024))
165 FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
170 // Clear our variables
172 RootDirSectorStart
= 0;
178 // Get the sectors per FAT,
179 // root directory starting sector,
180 // and data sector start
182 if (FatType
!= FAT32
)
184 SectorsPerFat
= FatVolumeBootSector
->SectorsPerFat
;
186 RootDirSectorStart
= (FatVolumeBootSector
->NumberOfFats
* SectorsPerFat
) + FatVolumeBootSector
->ReservedSectors
;
187 RootDirSectors
= ((FatVolumeBootSector
->RootDirEntries
* 32) + (FatVolumeBootSector
->BytesPerSector
- 1)) / FatVolumeBootSector
->BytesPerSector
;
189 DataSectorStart
= FatVolumeBootSector
->ReservedSectors
+ (FatVolumeBootSector
->NumberOfFats
* FatVolumeBootSector
->SectorsPerFat
) + RootDirSectors
;
193 SectorsPerFat
= Fat32VolumeBootSector
->SectorsPerFatBig
;
195 DataSectorStart
= FatVolumeBootSector
->ReservedSectors
+ (FatVolumeBootSector
->NumberOfFats
* Fat32VolumeBootSector
->SectorsPerFatBig
) + RootDirSectors
;
200 // we only work with version 0
202 if (Fat32VolumeBootSector
->FileSystemVersion
!= 0)
204 FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
212 PVOID
FatBufferDirectory(UINT32 DirectoryStartCluster
, PUINT32 EntryCountPointer
, BOOL RootDirectory
)
214 UINT32 RootDirectoryStartSector
;
215 UINT32 RootDirectorySectorCount
;
216 PVOID DirectoryBuffer
;
217 UINT32 DirectorySize
;
219 DbgPrint((DPRINT_FILESYSTEM
, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster
, (RootDirectory
? "TRUE" : "FALSE")));
222 // Calculate the size of the directory
224 if ((RootDirectory
) && (FatType
!= FAT32
))
226 DirectorySize
= (FatVolumeBootSector
->RootDirEntries
/ 32) * 512;
232 DirectorySize
= (FatCountClustersInChain(Fat32VolumeBootSector
->RootDirStartCluster
) * Fat32VolumeBootSector
->SectorsPerCluster
) * Fat32VolumeBootSector
->BytesPerSector
;
236 DirectorySize
= (FatCountClustersInChain(DirectoryStartCluster
) * FatVolumeBootSector
->SectorsPerCluster
) * FatVolumeBootSector
->BytesPerSector
;
241 // Attempt to allocate memory for directory buffer
243 DirectoryBuffer
= AllocateMemory(DirectorySize
);
245 if (DirectoryBuffer
== NULL
)
251 // Now read directory contents into DirectoryBuffer
255 if (FatType
== FAT32
)
257 if (!FatReadClusterChain(Fat32VolumeBootSector
->RootDirStartCluster
, 0xFFFFFFFF, DirectoryBuffer
))
259 FreeMemory(DirectoryBuffer
);
266 // FAT type is not FAT32 so the root directory comes right after the fat table
268 RootDirectoryStartSector
= FatVolumeBootSector
->ReservedSectors
+ (FatVolumeBootSector
->NumberOfFats
* FatVolumeBootSector
->SectorsPerFat
);
269 RootDirectorySectorCount
= FatVolumeBootSector
->RootDirEntries
/ 32;
271 if (!DiskReadMultipleLogicalSectors(RootDirectoryStartSector
, RootDirectorySectorCount
, DirectoryBuffer
))
273 FreeMemory(DirectoryBuffer
);
280 if (!FatReadClusterChain(DirectoryStartCluster
, 0xFFFFFFFF, DirectoryBuffer
))
282 FreeMemory(DirectoryBuffer
);
287 *EntryCountPointer
= (DirectorySize
/ 32);
289 return DirectoryBuffer
;
292 BOOL
FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer
, UINT32 EntryCount
, PUCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
296 PLFN_DIRENTRY LfnDirEntry
;
297 UCHAR LfnNameBuffer
[261];
298 UCHAR ShortNameBuffer
[13];
301 DbgPrint((DPRINT_FILESYSTEM
, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer
, EntryCount
, FileName
));
303 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
304 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
306 for (CurrentEntry
=0; CurrentEntry
<EntryCount
; CurrentEntry
++)
308 DirEntry
= (PDIRENTRY
)(DirectoryBuffer
+ (CurrentEntry
* 32) );
309 LfnDirEntry
= (PLFN_DIRENTRY
)DirEntry
;
312 // Check if this is the last file in the directory
313 // If DirEntry[0] == 0x00 then that means all the
314 // entries after this one are unused. If this is the
315 // last entry then we didn't find the file in this directory.
317 if (DirEntry
->FileName
[0] == 0x00)
323 // Check if this is a deleted entry or not
325 if (DirEntry
->FileName
[0] == 0xE5)
327 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
328 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
333 // Check if this is a LFN entry
334 // If so it needs special handling
336 if (DirEntry
->Attr
== ATTR_LONG_NAME
)
339 // Check to see if this is a deleted LFN entry, if so continue
341 if (LfnDirEntry
->SequenceNumber
& 0x80)
347 // Mask off high two bits of sequence number
348 // and make the sequence number zero-based
350 LfnDirEntry
->SequenceNumber
&= 0x3F;
351 LfnDirEntry
->SequenceNumber
--;
354 // Get all 13 LFN entry characters
356 if (LfnDirEntry
->Name0_4
[0] != 0xFFFF)
358 LfnNameBuffer
[0 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[0];
360 if (LfnDirEntry
->Name0_4
[1] != 0xFFFF)
362 LfnNameBuffer
[1 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[1];
364 if (LfnDirEntry
->Name0_4
[2] != 0xFFFF)
366 LfnNameBuffer
[2 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[2];
368 if (LfnDirEntry
->Name0_4
[3] != 0xFFFF)
370 LfnNameBuffer
[3 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[3];
372 if (LfnDirEntry
->Name0_4
[4] != 0xFFFF)
374 LfnNameBuffer
[4 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name0_4
[4];
376 if (LfnDirEntry
->Name5_10
[0] != 0xFFFF)
378 LfnNameBuffer
[5 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[0];
380 if (LfnDirEntry
->Name5_10
[1] != 0xFFFF)
382 LfnNameBuffer
[6 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[1];
384 if (LfnDirEntry
->Name5_10
[2] != 0xFFFF)
386 LfnNameBuffer
[7 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[2];
388 if (LfnDirEntry
->Name5_10
[3] != 0xFFFF)
390 LfnNameBuffer
[8 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[3];
392 if (LfnDirEntry
->Name5_10
[4] != 0xFFFF)
394 LfnNameBuffer
[9 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[4];
396 if (LfnDirEntry
->Name5_10
[5] != 0xFFFF)
398 LfnNameBuffer
[10 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name5_10
[5];
400 if (LfnDirEntry
->Name11_12
[0] != 0xFFFF)
402 LfnNameBuffer
[11 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[0];
404 if (LfnDirEntry
->Name11_12
[1] != 0xFFFF)
406 LfnNameBuffer
[12 + (LfnDirEntry
->SequenceNumber
* 13)] = (UCHAR
)LfnDirEntry
->Name11_12
[1];
413 // Check for the volume label attribute
414 // and skip over this entry if found
416 if (DirEntry
->Attr
& ATTR_VOLUMENAME
)
418 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
419 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
424 // If we get here then we've found a short file name
425 // entry and LfnNameBuffer contains the long file
426 // name or zeroes. All we have to do now is see if the
427 // file name matches either the short or long file name
428 // and fill in the FAT_FILE_INFO structure if it does
429 // or zero our buffers and continue looking.
433 // Get short file name
435 FatParseShortFileName(ShortNameBuffer
, DirEntry
);
437 DbgPrint((DPRINT_FILESYSTEM
, "Entry: %d LFN = %s\n", CurrentEntry
, LfnNameBuffer
));
438 DbgPrint((DPRINT_FILESYSTEM
, "Entry: %d DOS name = %s\n", CurrentEntry
, ShortNameBuffer
));
441 // See if the file name matches either the short or long name
443 if (((strlen(FileName
) == strlen(LfnNameBuffer
)) && (stricmp(FileName
, LfnNameBuffer
) == 0)) ||
444 ((strlen(FileName
) == strlen(ShortNameBuffer
)) && (stricmp(FileName
, ShortNameBuffer
) == 0)))
447 // We found the entry, now fill in the FAT_FILE_INFO struct
449 FatFileInfoPointer
->FileSize
= DirEntry
->Size
;
450 FatFileInfoPointer
->FilePointer
= 0;
453 // Get the cluster chain
455 StartCluster
= ((UINT32
)DirEntry
->ClusterHigh
<< 16) + DirEntry
->ClusterLow
;
456 FatFileInfoPointer
->FileFatChain
= FatGetClusterChainArray(StartCluster
);
459 // See if memory allocation failed
461 if (FatFileInfoPointer
->FileFatChain
== NULL
)
470 // Nope, no match - zero buffers and continue looking
472 memset(ShortNameBuffer
, 0, 13 * sizeof(UCHAR
));
473 memset(LfnNameBuffer
, 0, 261 * sizeof(UCHAR
));
482 * This function searches the file system for the
483 * specified filename and fills in a FAT_STRUCT structure
484 * with info describing the file, etc. returns true
485 * if the file exists or false otherwise
487 BOOL
FatLookupFile(PUCHAR FileName
, PFAT_FILE_INFO FatFileInfoPointer
)
490 ULONG NumberOfPathParts
;
492 PVOID DirectoryBuffer
;
493 UINT32 DirectoryStartCluster
= 0;
494 ULONG DirectoryEntryCount
;
495 FAT_FILE_INFO FatFileInfo
;
497 DbgPrint((DPRINT_FILESYSTEM
, "FatLookupFile() FileName = %s\n", FileName
));
499 memset(FatFileInfoPointer
, 0, sizeof(FAT_FILE_INFO
));
502 // Check and see if the first character is '\' and remove it if so
504 while (*FileName
== '\\')
510 // Figure out how many sub-directories we are nested in
512 NumberOfPathParts
= FatGetNumPathParts(FileName
);
515 // Loop once for each part
517 for (i
=0; i
<NumberOfPathParts
; i
++)
520 // Get first path part
522 FatGetFirstNameFromPath(PathPart
, FileName
);
525 // Advance to the next part of the path
527 for (; (*FileName
!= '\\') && (*FileName
!= '\0'); FileName
++)
533 // Buffer the directory contents
535 DirectoryBuffer
= FatBufferDirectory(DirectoryStartCluster
, &DirectoryEntryCount
, (i
== 0) );
536 if (DirectoryBuffer
== NULL
)
542 // Search for file name in directory
544 if (!FatSearchDirectoryBufferForFile(DirectoryBuffer
, DirectoryEntryCount
, PathPart
, &FatFileInfo
))
546 FreeMemory(DirectoryBuffer
);
550 FreeMemory(DirectoryBuffer
);
553 // If we have another sub-directory to go then
554 // grab the start cluster and free the fat chain array
556 if ((i
+1) < NumberOfPathParts
)
558 DirectoryStartCluster
= FatFileInfo
.FileFatChain
[0];
559 FreeMemory(FatFileInfo
.FileFatChain
);
563 memcpy(FatFileInfoPointer
, &FatFileInfo
, sizeof(FAT_FILE_INFO
));
569 * FatGetNumPathParts()
570 * This function parses a path in the form of dir1\dir2\file1.ext
571 * and returns the number of parts it has (i.e. 3 - dir1,dir2,file1.ext)
573 ULONG
FatGetNumPathParts(PUCHAR Path
)
578 for (i
=0,num
=0; i
<(int)strlen(Path
); i
++)
587 DbgPrint((DPRINT_FILESYSTEM
, "FatGetNumPathParts() Path = %s NumPathParts = %d\n", Path
, num
));
593 * FatGetFirstNameFromPath()
594 * This function parses a path in the form of dir1\dir2\file1.ext
595 * and puts the first name of the path (e.g. "dir1") in buffer
596 * compatible with the MSDOS directory structure
598 VOID
FatGetFirstNameFromPath(PUCHAR Buffer
, PUCHAR Path
)
602 // Copy all the characters up to the end of the
603 // string or until we hit a '\' character
604 // and put them in Buffer
605 for (i
=0; i
<(int)strlen(Path
); i
++)
619 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFirstNameFromPath() Path = %s FirstName = %s\n", Path
, Buffer
));
624 * This function parses a directory entry name which
625 * is in the form of "FILE EXT" and puts it in Buffer
626 * in the form of "file.ext"
628 void FatParseShortFileName(PUCHAR Buffer
, PDIRENTRY DirEntry
)
635 // Fixup first character
637 if (DirEntry
->FileName
[0] == 0x05)
639 DirEntry
->FileName
[0] = 0xE5;
647 if (DirEntry
->FileName
[Idx
] == ' ')
652 Buffer
[Idx
] = DirEntry
->FileName
[Idx
];
659 if ((DirEntry
->FileName
[8] != ' '))
662 Buffer
[Idx
++] = (DirEntry
->FileName
[8] == ' ') ? '\0' : DirEntry
->FileName
[8];
663 Buffer
[Idx
++] = (DirEntry
->FileName
[9] == ' ') ? '\0' : DirEntry
->FileName
[9];
664 Buffer
[Idx
++] = (DirEntry
->FileName
[10] == ' ') ? '\0' : DirEntry
->FileName
[10];
668 // Null-Terminate string
670 Buffer
[Idx
+ 4] = '\0';
672 DbgPrint((DPRINT_FILESYSTEM
, "FatParseShortFileName() ShortName = %s\n", Buffer
));
677 * returns the Fat entry for a given cluster number
679 DWORD
FatGetFatEntry(DWORD nCluster
)
684 int ThisFatEntOffset
;
686 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", nCluster
));
692 FatOffset
= nCluster
+ (nCluster
/ 2);
693 ThisFatSecNum
= FatVolumeBootSector
->ReservedSectors
+ (FatOffset
/ FatVolumeBootSector
->BytesPerSector
);
694 ThisFatEntOffset
= (FatOffset
% FatVolumeBootSector
->BytesPerSector
);
696 DbgPrint((DPRINT_FILESYSTEM
, "FatOffset: %d\n", FatOffset
));
697 DbgPrint((DPRINT_FILESYSTEM
, "ThisFatSecNum: %d\n", ThisFatSecNum
));
698 DbgPrint((DPRINT_FILESYSTEM
, "ThisFatEntOffset: %d\n", ThisFatEntOffset
));
700 if (ThisFatEntOffset
== (FatVolumeBootSector
->BytesPerSector
- 1))
702 if (!DiskReadMultipleLogicalSectors(ThisFatSecNum
, 2, (PVOID
)DISKREADBUFFER
))
709 if (!DiskReadLogicalSector(ThisFatSecNum
, (PVOID
)DISKREADBUFFER
))
715 fat
= *((WORD
*) (DISKREADBUFFER
+ ThisFatEntOffset
));
716 if (nCluster
& 0x0001)
717 fat
= fat
>> 4; /* Cluster number is ODD */
719 fat
= fat
& 0x0FFF; /* Cluster number is EVEN */
725 FatOffset
= (nCluster
* 2);
726 ThisFatSecNum
= FatVolumeBootSector
->ReservedSectors
+ (FatOffset
/ FatVolumeBootSector
->BytesPerSector
);
727 ThisFatEntOffset
= (FatOffset
% FatVolumeBootSector
->BytesPerSector
);
729 if (!DiskReadLogicalSector(ThisFatSecNum
, (PVOID
)DISKREADBUFFER
))
734 fat
= *((WORD
*) (DISKREADBUFFER
+ ThisFatEntOffset
));
740 FatOffset
= (nCluster
* 4);
741 ThisFatSecNum
= FatVolumeBootSector
->ReservedSectors
+ (FatOffset
/ FatVolumeBootSector
->BytesPerSector
);
742 ThisFatEntOffset
= (FatOffset
% FatVolumeBootSector
->BytesPerSector
);
744 if (!DiskReadLogicalSector(ThisFatSecNum
, (PVOID
)DISKREADBUFFER
))
750 fat
= (*((DWORD
*) (DISKREADBUFFER
+ ThisFatEntOffset
))) & 0x0FFFFFFF;
756 DbgPrint((DPRINT_FILESYSTEM
, "FAT entry is 0x%x.\n", fat
));
763 * Tries to open the file 'name' and returns true or false
764 * for success and failure respectively
766 FILE* FatOpenFile(PUCHAR FileName
)
768 FAT_FILE_INFO TempFatFileInfo
;
769 PFAT_FILE_INFO FileHandle
;
771 DbgPrint((DPRINT_FILESYSTEM
, "FatOpenFile() FileName = %s\n", FileName
));
773 if (!FatLookupFile(FileName
, &TempFatFileInfo
))
778 FileHandle
= AllocateMemory(sizeof(FAT_FILE_INFO
));
780 if (FileHandle
== NULL
)
785 memcpy(FileHandle
, &TempFatFileInfo
, sizeof(FAT_FILE_INFO
));
787 return (FILE*)FileHandle
;
790 UINT32
FatCountClustersInChain(UINT32 StartCluster
)
792 UINT32 ClusterCount
= 0;
794 DbgPrint((DPRINT_FILESYSTEM
, "FatCountClustersInChain() StartCluster = %d\n", StartCluster
));
799 // If end of chain then break out of our cluster counting loop
801 if (((FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
802 ((FatType
== FAT16
) && (StartCluster
>= 0xfff8)) ||
803 ((FatType
== FAT32
) && (StartCluster
>= 0x0ffffff8)))
816 StartCluster
= FatGetFatEntry(StartCluster
);
819 DbgPrint((DPRINT_FILESYSTEM
, "FatCountClustersInChain() ClusterCount = %d\n", ClusterCount
));
824 PUINT32
FatGetClusterChainArray(UINT32 StartCluster
)
828 PUINT32 ArrayPointer
;
831 DbgPrint((DPRINT_FILESYSTEM
, "FatGetClusterChainArray() StartCluster = %d\n", StartCluster
));
833 ClusterCount
= FatCountClustersInChain(StartCluster
) + 1; // Lets get the 0x0ffffff8 on the end of the array
834 ArraySize
= ClusterCount
* sizeof(UINT32
);
837 // Allocate array memory
839 ArrayPointer
= AllocateMemory(ArraySize
);
841 if (ArrayPointer
== NULL
)
847 // Loop through and set array values
849 for (Idx
=0; Idx
<ClusterCount
; Idx
++)
852 // Set current cluster
854 ArrayPointer
[Idx
] = StartCluster
;
857 // Don't try to get next cluster for last cluster
859 if (((FatType
== FAT12
) && (StartCluster
>= 0xff8)) ||
860 ((FatType
== FAT16
) && (StartCluster
>= 0xfff8)) ||
861 ((FatType
== FAT32
) && (StartCluster
>= 0x0ffffff8)))
870 StartCluster
= FatGetFatEntry(StartCluster
);
878 * Reads the specified cluster into memory
879 * and returns the number of bytes read
881 BOOL
FatReadCluster(ULONG ClusterNumber
, PVOID Buffer
)
883 ULONG ClusterStartSector
;
885 ClusterStartSector
= ((ClusterNumber
- 2) * FatVolumeBootSector
->SectorsPerCluster
) + DataSectorStart
;
887 DbgPrint((DPRINT_FILESYSTEM
, "FatReadCluster() ClusterNumber = %d Buffer = 0x%x ClusterStartSector = %d\n", ClusterNumber
, Buffer
, ClusterStartSector
));
889 if (!DiskReadMultipleLogicalSectors(ClusterStartSector
, FatVolumeBootSector
->SectorsPerCluster
, (PVOID
)DISKREADBUFFER
))
894 memcpy(Buffer
, (PVOID
)DISKREADBUFFER
, FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
);
900 * FatReadClusterChain()
901 * Reads the specified clusters into memory
903 BOOL
FatReadClusterChain(ULONG StartClusterNumber
, ULONG NumberOfClusters
, PVOID Buffer
)
905 ULONG ClusterStartSector
;
907 DbgPrint((DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
));
909 while (NumberOfClusters
> 0)
912 DbgPrint((DPRINT_FILESYSTEM
, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber
, NumberOfClusters
, Buffer
));
914 // Calculate starting sector for cluster
916 ClusterStartSector
= ((StartClusterNumber
- 2) * FatVolumeBootSector
->SectorsPerCluster
) + DataSectorStart
;
919 // Read cluster into memory
921 if (!DiskReadMultipleLogicalSectors(ClusterStartSector
, FatVolumeBootSector
->SectorsPerCluster
, (PVOID
)DISKREADBUFFER
))
926 memcpy(Buffer
, (PVOID
)DISKREADBUFFER
, FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
);
929 // Decrement count of clusters left to read
934 // Increment buffer address by cluster size
936 Buffer
+= (FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
);
941 StartClusterNumber
= FatGetFatEntry(StartClusterNumber
);
944 // If end of chain then break out of our cluster reading loop
946 if (((FatType
== FAT12
) && (StartClusterNumber
>= 0xff8)) ||
947 ((FatType
== FAT16
) && (StartClusterNumber
>= 0xfff8)) ||
948 ((FatType
== FAT32
) && (StartClusterNumber
>= 0x0ffffff8)))
958 * FatReadPartialCluster()
959 * Reads part of a cluster into memory
961 BOOL
FatReadPartialCluster(ULONG ClusterNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
)
963 ULONG ClusterStartSector
;
965 DbgPrint((DPRINT_FILESYSTEM
, "FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber
, StartingOffset
, Length
, Buffer
));
967 ClusterStartSector
= ((ClusterNumber
- 2) * FatVolumeBootSector
->SectorsPerCluster
) + DataSectorStart
;
969 if (!DiskReadMultipleLogicalSectors(ClusterStartSector
, FatVolumeBootSector
->SectorsPerCluster
, (PVOID
)DISKREADBUFFER
))
974 memcpy(Buffer
, (PVOID
)(DISKREADBUFFER
+ StartingOffset
), Length
);
981 * Reads BytesToRead from open file and
982 * returns the number of bytes read in BytesRead
984 BOOL
FatReadFile(FILE *FileHandle
, ULONG BytesToRead
, PULONG BytesRead
, PVOID Buffer
)
986 PFAT_FILE_INFO FatFileInfo
= (PFAT_FILE_INFO
)FileHandle
;
987 UINT32 ClusterNumber
;
988 UINT32 OffsetInCluster
;
989 UINT32 LengthInCluster
;
990 UINT32 NumberOfClusters
;
991 UINT32 BytesPerCluster
;
993 DbgPrint((DPRINT_FILESYSTEM
, "FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead
, Buffer
));
995 if (BytesRead
!= NULL
)
1001 // If they are trying to read past the
1002 // end of the file then return success
1003 // with BytesRead == 0
1005 if (FatFileInfo
->FilePointer
>= FatFileInfo
->FileSize
)
1011 // If they are trying to read more than there is to read
1012 // then adjust the amount to read
1014 if ((FatFileInfo
->FilePointer
+ BytesToRead
) > FatFileInfo
->FileSize
)
1016 BytesToRead
= (FatFileInfo
->FileSize
- FatFileInfo
->FilePointer
);
1020 // Ok, now we have to perform at most 3 calculations
1021 // I'll draw you a picture (using nifty ASCII art):
1023 // CurrentFilePointer -+
1025 // +----------------+
1027 // +-----------+-----------+-----------+-----------+
1028 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 |
1029 // +-----------+-----------+-----------+-----------+
1031 // +---------------+--------------------+
1033 // BytesToRead -------+
1035 // 1 - The first calculation (and read) will align
1036 // the file pointer with the next cluster.
1037 // boundary (if we are supposed to read that much)
1038 // 2 - The next calculation (and read) will read
1039 // in all the full clusters that the requested
1040 // amount of data would cover (in this case
1042 // 3 - The last calculation (and read) would read
1043 // in the remainder of the data requested out of
1044 // the last cluster.
1047 BytesPerCluster
= (FatVolumeBootSector
->SectorsPerCluster
* FatVolumeBootSector
->BytesPerSector
);
1050 // Only do the first read if we
1051 // aren't aligned on a cluster boundary
1053 if (FatFileInfo
->FilePointer
% BytesPerCluster
)
1056 // Do the math for our first read
1058 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1059 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1060 OffsetInCluster
= (FatFileInfo
->FilePointer
% BytesPerCluster
);
1061 LengthInCluster
= (BytesToRead
> (BytesPerCluster
- OffsetInCluster
)) ? (BytesPerCluster
- OffsetInCluster
) : BytesToRead
;
1064 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1066 if (!FatReadPartialCluster(ClusterNumber
, OffsetInCluster
, LengthInCluster
, Buffer
))
1070 if (BytesRead
!= NULL
)
1072 *BytesRead
+= LengthInCluster
;
1074 BytesToRead
-= LengthInCluster
;
1075 FatFileInfo
->FilePointer
+= LengthInCluster
;
1076 Buffer
+= LengthInCluster
;
1080 // Do the math for our second read (if any data left)
1082 if (BytesToRead
> 0)
1085 // Determine how many full clusters we need to read
1087 NumberOfClusters
= (BytesToRead
/ BytesPerCluster
);
1089 if (NumberOfClusters
> 0)
1091 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1092 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1095 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1097 if (!FatReadClusterChain(ClusterNumber
, NumberOfClusters
, Buffer
))
1101 if (BytesRead
!= NULL
)
1103 *BytesRead
+= (NumberOfClusters
* BytesPerCluster
);
1105 BytesToRead
-= (NumberOfClusters
* BytesPerCluster
);
1106 FatFileInfo
->FilePointer
+= (NumberOfClusters
* BytesPerCluster
);
1107 Buffer
+= (NumberOfClusters
* BytesPerCluster
);
1112 // Do the math for our third read (if any data left)
1114 if (BytesToRead
> 0)
1116 ClusterNumber
= (FatFileInfo
->FilePointer
/ BytesPerCluster
);
1117 ClusterNumber
= FatFileInfo
->FileFatChain
[ClusterNumber
];
1120 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
1122 if (!FatReadPartialCluster(ClusterNumber
, 0, BytesToRead
, Buffer
))
1126 if (BytesRead
!= NULL
)
1128 *BytesRead
+= BytesToRead
;
1130 BytesToRead
-= BytesToRead
;
1131 FatFileInfo
->FilePointer
+= BytesToRead
;
1132 Buffer
+= BytesToRead
;
1138 ULONG
FatGetFileSize(FILE *FileHandle
)
1140 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1142 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFileSize() FileSize = %d\n", FatFileHandle
->FileSize
));
1144 return FatFileHandle
->FileSize
;
1147 VOID
FatSetFilePointer(FILE *FileHandle
, ULONG NewFilePointer
)
1149 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1151 DbgPrint((DPRINT_FILESYSTEM
, "FatSetFilePointer() NewFilePointer = %d\n", NewFilePointer
));
1153 FatFileHandle
->FilePointer
= NewFilePointer
;
1156 ULONG
FatGetFilePointer(FILE *FileHandle
)
1158 PFAT_FILE_INFO FatFileHandle
= (PFAT_FILE_INFO
)FileHandle
;
1160 DbgPrint((DPRINT_FILESYSTEM
, "FatGetFilePointer() FilePointer = %d\n", FatFileHandle
->FilePointer
));
1162 return FatFileHandle
->FilePointer
;