Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfat.c
Go to the documentation of this file.
00001 /* 00002 * FreeLoader 00003 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com> 00004 * Copyright (C) 2009 Hervé Poussineau 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License along 00017 * with this program; if not, write to the Free Software Foundation, Inc., 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00019 */ 00020 00021 #include <freeldr.h> 00022 00023 #define NDEBUG 00024 #include <debug.h> 00025 00026 DBG_DEFAULT_CHANNEL(FILESYSTEM); 00027 00028 ULONG FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector, ULONGLONG PartitionSectorCount); 00029 PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, ULONG* EntryCountPointer, BOOLEAN RootDirectory); 00030 BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG EntryCount, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer); 00031 LONG FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, ULONG DeviceId, PFAT_FILE_INFO FatFileInfoPointer); 00032 void FatParseShortFileName(PCHAR Buffer, PDIRENTRY DirEntry); 00033 BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPointer); 00034 ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, ULONG StartCluster); 00035 ULONG* FatGetClusterChainArray(PFAT_VOLUME_INFO Volume, ULONG StartCluster); 00036 BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, ULONG StartClusterNumber, ULONG NumberOfClusters, PVOID Buffer); 00037 BOOLEAN FatReadPartialCluster(PFAT_VOLUME_INFO Volume, ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer); 00038 BOOLEAN FatReadVolumeSectors(PFAT_VOLUME_INFO Volume, ULONG SectorNumber, ULONG SectorCount, PVOID Buffer); 00039 00040 typedef struct _FAT_VOLUME_INFO 00041 { 00042 ULONG BytesPerSector; /* Number of bytes per sector */ 00043 ULONG SectorsPerCluster; /* Number of sectors per cluster */ 00044 ULONG FatSectorStart; /* Starting sector of 1st FAT table */ 00045 ULONG ActiveFatSectorStart; /* Starting sector of active FAT table */ 00046 ULONG NumberOfFats; /* Number of FAT tables */ 00047 ULONG SectorsPerFat; /* Sectors per FAT table */ 00048 ULONG RootDirSectorStart; /* Starting sector of the root directory (non-fat32) */ 00049 ULONG RootDirSectors; /* Number of sectors of the root directory (non-fat32) */ 00050 ULONG RootDirStartCluster; /* Starting cluster number of the root directory (fat32 only) */ 00051 ULONG DataSectorStart; /* Starting sector of the data area */ 00052 ULONG FatType; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */ 00053 ULONG DeviceId; 00054 } FAT_VOLUME_INFO; 00055 00056 PFAT_VOLUME_INFO FatVolumes[MAX_FDS]; 00057 00058 VOID FatSwapFatBootSector(PFAT_BOOTSECTOR Obj) 00059 { 00060 SW(Obj, BytesPerSector); 00061 SW(Obj, ReservedSectors); 00062 SW(Obj, RootDirEntries); 00063 SW(Obj, TotalSectors); 00064 SW(Obj, SectorsPerFat); 00065 SW(Obj, SectorsPerTrack); 00066 SW(Obj, NumberOfHeads); 00067 SD(Obj, HiddenSectors); 00068 SD(Obj, TotalSectorsBig); 00069 SD(Obj, VolumeSerialNumber); 00070 SW(Obj, BootSectorMagic); 00071 } 00072 00073 VOID FatSwapFat32BootSector(PFAT32_BOOTSECTOR Obj) 00074 { 00075 SW(Obj, BytesPerSector); 00076 SW(Obj, ReservedSectors); 00077 SW(Obj, RootDirEntries); 00078 SW(Obj, TotalSectors); 00079 SW(Obj, SectorsPerFat); 00080 SW(Obj, NumberOfHeads); 00081 SD(Obj, HiddenSectors); 00082 SD(Obj, TotalSectorsBig); 00083 SD(Obj, SectorsPerFatBig); 00084 SW(Obj, ExtendedFlags); 00085 SW(Obj, FileSystemVersion); 00086 SD(Obj, RootDirStartCluster); 00087 SW(Obj, FsInfo); 00088 SW(Obj, BackupBootSector); 00089 SD(Obj, VolumeSerialNumber); 00090 SW(Obj, BootSectorMagic); 00091 } 00092 00093 VOID FatSwapFatXBootSector(PFATX_BOOTSECTOR Obj) 00094 { 00095 SD(Obj, VolumeSerialNumber); 00096 SD(Obj, SectorsPerCluster); 00097 SW(Obj, NumberOfFats); 00098 } 00099 00100 VOID FatSwapDirEntry(PDIRENTRY Obj) 00101 { 00102 SW(Obj, CreateTime); 00103 SW(Obj, CreateDate); 00104 SW(Obj, LastAccessDate); 00105 SW(Obj, ClusterHigh); 00106 SW(Obj, Time); 00107 SW(Obj, Date); 00108 SW(Obj, ClusterLow); 00109 SD(Obj, Size); 00110 } 00111 00112 VOID FatSwapLFNDirEntry(PLFN_DIRENTRY Obj) 00113 { 00114 int i; 00115 SW(Obj, StartCluster); 00116 for(i = 0; i < 5; i++) 00117 Obj->Name0_4[i] = SWAPW(Obj->Name0_4[i]); 00118 for(i = 0; i < 6; i++) 00119 Obj->Name5_10[i] = SWAPW(Obj->Name5_10[i]); 00120 for(i = 0; i < 2; i++) 00121 Obj->Name11_12[i] = SWAPW(Obj->Name11_12[i]); 00122 } 00123 00124 VOID FatSwapFatXDirEntry(PFATX_DIRENTRY Obj) 00125 { 00126 SD(Obj, StartCluster); 00127 SD(Obj, Size); 00128 SW(Obj, Time); 00129 SW(Obj, Date); 00130 SW(Obj, CreateTime); 00131 SW(Obj, CreateDate); 00132 SW(Obj, LastAccessTime); 00133 SW(Obj, LastAccessDate); 00134 } 00135 00136 BOOLEAN FatOpenVolume(PFAT_VOLUME_INFO Volume, PFAT_BOOTSECTOR BootSector, ULONGLONG PartitionSectorCount) 00137 { 00138 char ErrMsg[80]; 00139 ULONG FatSize; 00140 PFAT_BOOTSECTOR FatVolumeBootSector; 00141 PFAT32_BOOTSECTOR Fat32VolumeBootSector; 00142 PFATX_BOOTSECTOR FatXVolumeBootSector; 00143 00144 TRACE("FatOpenVolume() DeviceId = %d\n", Volume->DeviceId); 00145 00146 // 00147 // Allocate the memory to hold the boot sector 00148 // 00149 FatVolumeBootSector = (PFAT_BOOTSECTOR)BootSector; 00150 Fat32VolumeBootSector = (PFAT32_BOOTSECTOR)BootSector; 00151 FatXVolumeBootSector = (PFATX_BOOTSECTOR)BootSector; 00152 00153 // Get the FAT type 00154 Volume->FatType = FatDetermineFatType(FatVolumeBootSector, PartitionSectorCount); 00155 00156 // Dump boot sector (and swap it for big endian systems) 00157 TRACE("Dumping boot sector:\n"); 00158 if (ISFATX(Volume->FatType)) 00159 { 00160 FatSwapFatXBootSector(FatXVolumeBootSector); 00161 TRACE("sizeof(FATX_BOOTSECTOR) = 0x%x.\n", sizeof(FATX_BOOTSECTOR)); 00162 00163 TRACE("FileSystemType: %c%c%c%c.\n", FatXVolumeBootSector->FileSystemType[0], FatXVolumeBootSector->FileSystemType[1], FatXVolumeBootSector->FileSystemType[2], FatXVolumeBootSector->FileSystemType[3]); 00164 TRACE("VolumeSerialNumber: 0x%x\n", FatXVolumeBootSector->VolumeSerialNumber); 00165 TRACE("SectorsPerCluster: %d\n", FatXVolumeBootSector->SectorsPerCluster); 00166 TRACE("NumberOfFats: %d\n", FatXVolumeBootSector->NumberOfFats); 00167 TRACE("Unknown: 0x%x\n", FatXVolumeBootSector->Unknown); 00168 00169 TRACE("FatType %s\n", Volume->FatType == FATX16 ? "FATX16" : "FATX32"); 00170 00171 } 00172 else if (Volume->FatType == FAT32) 00173 { 00174 FatSwapFat32BootSector(Fat32VolumeBootSector); 00175 TRACE("sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR)); 00176 00177 TRACE("JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector->JumpBoot[0], Fat32VolumeBootSector->JumpBoot[1], Fat32VolumeBootSector->JumpBoot[2]); 00178 TRACE("OemName: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->OemName[0], Fat32VolumeBootSector->OemName[1], Fat32VolumeBootSector->OemName[2], Fat32VolumeBootSector->OemName[3], Fat32VolumeBootSector->OemName[4], Fat32VolumeBootSector->OemName[5], Fat32VolumeBootSector->OemName[6], Fat32VolumeBootSector->OemName[7]); 00179 TRACE("BytesPerSector: %d\n", Fat32VolumeBootSector->BytesPerSector); 00180 TRACE("SectorsPerCluster: %d\n", Fat32VolumeBootSector->SectorsPerCluster); 00181 TRACE("ReservedSectors: %d\n", Fat32VolumeBootSector->ReservedSectors); 00182 TRACE("NumberOfFats: %d\n", Fat32VolumeBootSector->NumberOfFats); 00183 TRACE("RootDirEntries: %d\n", Fat32VolumeBootSector->RootDirEntries); 00184 TRACE("TotalSectors: %d\n", Fat32VolumeBootSector->TotalSectors); 00185 TRACE("MediaDescriptor: 0x%x\n", Fat32VolumeBootSector->MediaDescriptor); 00186 TRACE("SectorsPerFat: %d\n", Fat32VolumeBootSector->SectorsPerFat); 00187 TRACE("SectorsPerTrack: %d\n", Fat32VolumeBootSector->SectorsPerTrack); 00188 TRACE("NumberOfHeads: %d\n", Fat32VolumeBootSector->NumberOfHeads); 00189 TRACE("HiddenSectors: %d\n", Fat32VolumeBootSector->HiddenSectors); 00190 TRACE("TotalSectorsBig: %d\n", Fat32VolumeBootSector->TotalSectorsBig); 00191 TRACE("SectorsPerFatBig: %d\n", Fat32VolumeBootSector->SectorsPerFatBig); 00192 TRACE("ExtendedFlags: 0x%x\n", Fat32VolumeBootSector->ExtendedFlags); 00193 TRACE("FileSystemVersion: 0x%x\n", Fat32VolumeBootSector->FileSystemVersion); 00194 TRACE("RootDirStartCluster: %d\n", Fat32VolumeBootSector->RootDirStartCluster); 00195 TRACE("FsInfo: %d\n", Fat32VolumeBootSector->FsInfo); 00196 TRACE("BackupBootSector: %d\n", Fat32VolumeBootSector->BackupBootSector); 00197 TRACE("Reserved: 0x%x\n", Fat32VolumeBootSector->Reserved); 00198 TRACE("DriveNumber: 0x%x\n", Fat32VolumeBootSector->DriveNumber); 00199 TRACE("Reserved1: 0x%x\n", Fat32VolumeBootSector->Reserved1); 00200 TRACE("BootSignature: 0x%x\n", Fat32VolumeBootSector->BootSignature); 00201 TRACE("VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector->VolumeSerialNumber); 00202 TRACE("VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->VolumeLabel[0], Fat32VolumeBootSector->VolumeLabel[1], Fat32VolumeBootSector->VolumeLabel[2], Fat32VolumeBootSector->VolumeLabel[3], Fat32VolumeBootSector->VolumeLabel[4], Fat32VolumeBootSector->VolumeLabel[5], Fat32VolumeBootSector->VolumeLabel[6], Fat32VolumeBootSector->VolumeLabel[7], Fat32VolumeBootSector->VolumeLabel[8], Fat32VolumeBootSector->VolumeLabel[9], Fat32VolumeBootSector->VolumeLabel[10]); 00203 TRACE("FileSystemType: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->FileSystemType[0], Fat32VolumeBootSector->FileSystemType[1], Fat32VolumeBootSector->FileSystemType[2], Fat32VolumeBootSector->FileSystemType[3], Fat32VolumeBootSector->FileSystemType[4], Fat32VolumeBootSector->FileSystemType[5], Fat32VolumeBootSector->FileSystemType[6], Fat32VolumeBootSector->FileSystemType[7]); 00204 TRACE("BootSectorMagic: 0x%x\n", Fat32VolumeBootSector->BootSectorMagic); 00205 } 00206 else 00207 { 00208 FatSwapFatBootSector(FatVolumeBootSector); 00209 TRACE("sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR)); 00210 00211 TRACE("JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector->JumpBoot[0], FatVolumeBootSector->JumpBoot[1], FatVolumeBootSector->JumpBoot[2]); 00212 TRACE("OemName: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector->OemName[0], FatVolumeBootSector->OemName[1], FatVolumeBootSector->OemName[2], FatVolumeBootSector->OemName[3], FatVolumeBootSector->OemName[4], FatVolumeBootSector->OemName[5], FatVolumeBootSector->OemName[6], FatVolumeBootSector->OemName[7]); 00213 TRACE("BytesPerSector: %d\n", FatVolumeBootSector->BytesPerSector); 00214 TRACE("SectorsPerCluster: %d\n", FatVolumeBootSector->SectorsPerCluster); 00215 TRACE("ReservedSectors: %d\n", FatVolumeBootSector->ReservedSectors); 00216 TRACE("NumberOfFats: %d\n", FatVolumeBootSector->NumberOfFats); 00217 TRACE("RootDirEntries: %d\n", FatVolumeBootSector->RootDirEntries); 00218 TRACE("TotalSectors: %d\n", FatVolumeBootSector->TotalSectors); 00219 TRACE("MediaDescriptor: 0x%x\n", FatVolumeBootSector->MediaDescriptor); 00220 TRACE("SectorsPerFat: %d\n", FatVolumeBootSector->SectorsPerFat); 00221 TRACE("SectorsPerTrack: %d\n", FatVolumeBootSector->SectorsPerTrack); 00222 TRACE("NumberOfHeads: %d\n", FatVolumeBootSector->NumberOfHeads); 00223 TRACE("HiddenSectors: %d\n", FatVolumeBootSector->HiddenSectors); 00224 TRACE("TotalSectorsBig: %d\n", FatVolumeBootSector->TotalSectorsBig); 00225 TRACE("DriveNumber: 0x%x\n", FatVolumeBootSector->DriveNumber); 00226 TRACE("Reserved1: 0x%x\n", FatVolumeBootSector->Reserved1); 00227 TRACE("BootSignature: 0x%x\n", FatVolumeBootSector->BootSignature); 00228 TRACE("VolumeSerialNumber: 0x%x\n", FatVolumeBootSector->VolumeSerialNumber); 00229 TRACE("VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", FatVolumeBootSector->VolumeLabel[0], FatVolumeBootSector->VolumeLabel[1], FatVolumeBootSector->VolumeLabel[2], FatVolumeBootSector->VolumeLabel[3], FatVolumeBootSector->VolumeLabel[4], FatVolumeBootSector->VolumeLabel[5], FatVolumeBootSector->VolumeLabel[6], FatVolumeBootSector->VolumeLabel[7], FatVolumeBootSector->VolumeLabel[8], FatVolumeBootSector->VolumeLabel[9], FatVolumeBootSector->VolumeLabel[10]); 00230 TRACE("FileSystemType: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector->FileSystemType[0], FatVolumeBootSector->FileSystemType[1], FatVolumeBootSector->FileSystemType[2], FatVolumeBootSector->FileSystemType[3], FatVolumeBootSector->FileSystemType[4], FatVolumeBootSector->FileSystemType[5], FatVolumeBootSector->FileSystemType[6], FatVolumeBootSector->FileSystemType[7]); 00231 TRACE("BootSectorMagic: 0x%x\n", FatVolumeBootSector->BootSectorMagic); 00232 } 00233 00234 // 00235 // Check the boot sector magic 00236 // 00237 if (! ISFATX(Volume->FatType) && FatVolumeBootSector->BootSectorMagic != 0xaa55) 00238 { 00239 sprintf(ErrMsg, "Invalid boot sector magic (expected 0xaa55 found 0x%x)", 00240 FatVolumeBootSector->BootSectorMagic); 00241 FileSystemError(ErrMsg); 00242 return FALSE; 00243 } 00244 00245 // 00246 // Check the FAT cluster size 00247 // We do not support clusters bigger than 64k 00248 // 00249 if ((ISFATX(Volume->FatType) && 64 * 1024 < FatXVolumeBootSector->SectorsPerCluster * 512) || 00250 (! ISFATX(Volume->FatType) && 64 * 1024 < FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector)) 00251 { 00252 FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this."); 00253 return FALSE; 00254 } 00255 00256 // 00257 // Get the sectors per FAT, 00258 // root directory starting sector, 00259 // and data sector start 00260 // 00261 if (ISFATX(Volume->FatType)) 00262 { 00263 Volume->BytesPerSector = 512; 00264 Volume->SectorsPerCluster = SWAPD(FatXVolumeBootSector->SectorsPerCluster); 00265 Volume->FatSectorStart = (4096 / Volume->BytesPerSector); 00266 Volume->ActiveFatSectorStart = Volume->FatSectorStart; 00267 Volume->NumberOfFats = 1; 00268 FatSize = (ULONG)(PartitionSectorCount / Volume->SectorsPerCluster * 00269 (Volume->FatType == FATX16 ? 2 : 4)); 00270 Volume->SectorsPerFat = (((FatSize + 4095) / 4096) * 4096) / Volume->BytesPerSector; 00271 00272 Volume->RootDirSectorStart = Volume->FatSectorStart + Volume->NumberOfFats * Volume->SectorsPerFat; 00273 Volume->RootDirSectors = FatXVolumeBootSector->SectorsPerCluster; 00274 00275 Volume->DataSectorStart = Volume->RootDirSectorStart + Volume->RootDirSectors; 00276 } 00277 else if (Volume->FatType != FAT32) 00278 { 00279 Volume->BytesPerSector = FatVolumeBootSector->BytesPerSector; 00280 Volume->SectorsPerCluster = FatVolumeBootSector->SectorsPerCluster; 00281 Volume->FatSectorStart = FatVolumeBootSector->ReservedSectors; 00282 Volume->ActiveFatSectorStart = Volume->FatSectorStart; 00283 Volume->NumberOfFats = FatVolumeBootSector->NumberOfFats; 00284 Volume->SectorsPerFat = FatVolumeBootSector->SectorsPerFat; 00285 00286 Volume->RootDirSectorStart = Volume->FatSectorStart + Volume->NumberOfFats * Volume->SectorsPerFat; 00287 Volume->RootDirSectors = ((FatVolumeBootSector->RootDirEntries * 32) + (Volume->BytesPerSector - 1)) / Volume->BytesPerSector; 00288 00289 Volume->DataSectorStart = Volume->RootDirSectorStart + Volume->RootDirSectors; 00290 } 00291 else 00292 { 00293 Volume->BytesPerSector = Fat32VolumeBootSector->BytesPerSector; 00294 Volume->SectorsPerCluster = Fat32VolumeBootSector->SectorsPerCluster; 00295 Volume->FatSectorStart = Fat32VolumeBootSector->ReservedSectors; 00296 Volume->ActiveFatSectorStart = Volume->FatSectorStart + 00297 ((Fat32VolumeBootSector->ExtendedFlags & 0x80) ? ((Fat32VolumeBootSector->ExtendedFlags & 0x0f) * Fat32VolumeBootSector->SectorsPerFatBig) : 0); 00298 Volume->NumberOfFats = Fat32VolumeBootSector->NumberOfFats; 00299 Volume->SectorsPerFat = Fat32VolumeBootSector->SectorsPerFatBig; 00300 00301 Volume->RootDirStartCluster = Fat32VolumeBootSector->RootDirStartCluster; 00302 Volume->DataSectorStart = Volume->FatSectorStart + Volume->NumberOfFats * Volume->SectorsPerFat; 00303 00304 // 00305 // Check version 00306 // we only work with version 0 00307 // 00308 if (Fat32VolumeBootSector->FileSystemVersion != 0) 00309 { 00310 FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader."); 00311 return FALSE; 00312 } 00313 } 00314 00315 return TRUE; 00316 } 00317 00318 ULONG FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector, ULONGLONG PartitionSectorCount) 00319 { 00320 ULONG RootDirSectors; 00321 ULONG DataSectorCount; 00322 ULONG SectorsPerFat; 00323 ULONG TotalSectors; 00324 ULONG CountOfClusters; 00325 PFAT32_BOOTSECTOR Fat32BootSector = (PFAT32_BOOTSECTOR)FatBootSector; 00326 PFATX_BOOTSECTOR FatXBootSector = (PFATX_BOOTSECTOR)FatBootSector; 00327 00328 if (0 == strncmp(FatXBootSector->FileSystemType, "FATX", 4)) 00329 { 00330 CountOfClusters = (ULONG)(PartitionSectorCount / FatXBootSector->SectorsPerCluster); 00331 if (CountOfClusters < 65525) 00332 { 00333 /* Volume is FATX16 */ 00334 return FATX16; 00335 } 00336 else 00337 { 00338 /* Volume is FAT32 */ 00339 return FATX32; 00340 } 00341 } 00342 else 00343 { 00344 RootDirSectors = ((SWAPW(FatBootSector->RootDirEntries) * 32) + (SWAPW(FatBootSector->BytesPerSector) - 1)) / SWAPW(FatBootSector->BytesPerSector); 00345 SectorsPerFat = SWAPW(FatBootSector->SectorsPerFat) ? SWAPW(FatBootSector->SectorsPerFat) : SWAPD(Fat32BootSector->SectorsPerFatBig); 00346 TotalSectors = SWAPW(FatBootSector->TotalSectors) ? SWAPW(FatBootSector->TotalSectors) : SWAPD(FatBootSector->TotalSectorsBig); 00347 DataSectorCount = TotalSectors - (SWAPW(FatBootSector->ReservedSectors) + (FatBootSector->NumberOfFats * SectorsPerFat) + RootDirSectors); 00348 00349 //mjl 00350 if (FatBootSector->SectorsPerCluster == 0) 00351 CountOfClusters = 0; 00352 else 00353 CountOfClusters = DataSectorCount / FatBootSector->SectorsPerCluster; 00354 00355 if (CountOfClusters < 4085) 00356 { 00357 /* Volume is FAT12 */ 00358 return FAT12; 00359 } 00360 else if (CountOfClusters < 65525) 00361 { 00362 /* Volume is FAT16 */ 00363 return FAT16; 00364 } 00365 else 00366 { 00367 /* Volume is FAT32 */ 00368 return FAT32; 00369 } 00370 } 00371 } 00372 00373 typedef struct _DIRECTORY_BUFFER 00374 { 00375 LIST_ENTRY Link; 00376 PVOID Volume; 00377 ULONG DirectoryStartCluster; 00378 ULONG DirectorySize; 00379 UCHAR Data[]; 00380 } DIRECTORY_BUFFER, *PDIRECTORY_BUFFER; 00381 00382 LIST_ENTRY DirectoryBufferListHead = {&DirectoryBufferListHead, &DirectoryBufferListHead}; 00383 00384 PVOID FatBufferDirectory(PFAT_VOLUME_INFO Volume, ULONG DirectoryStartCluster, ULONG *DirectorySize, BOOLEAN RootDirectory) 00385 { 00386 PDIRECTORY_BUFFER DirectoryBuffer; 00387 PLIST_ENTRY Entry; 00388 00389 TRACE("FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster, (RootDirectory ? "TRUE" : "FALSE")); 00390 00391 /* 00392 * For FAT32, the root directory is nothing special. We can treat it the same 00393 * as a subdirectory. 00394 */ 00395 if (RootDirectory && Volume->FatType == FAT32) 00396 { 00397 DirectoryStartCluster = Volume->RootDirStartCluster; 00398 RootDirectory = FALSE; 00399 } 00400 00401 /* Search the list for a match */ 00402 for (Entry = DirectoryBufferListHead.Flink; 00403 Entry != &DirectoryBufferListHead; 00404 Entry = Entry->Flink) 00405 { 00406 DirectoryBuffer = CONTAINING_RECORD(Entry, DIRECTORY_BUFFER, Link); 00407 00408 /* Check if it matches */ 00409 if ((DirectoryBuffer->Volume == Volume) && 00410 (DirectoryBuffer->DirectoryStartCluster == DirectoryStartCluster)) 00411 { 00412 TRACE("Found cached buffer\n"); 00413 *DirectorySize = DirectoryBuffer->DirectorySize; 00414 return DirectoryBuffer->Data; 00415 } 00416 } 00417 00418 // 00419 // Calculate the size of the directory 00420 // 00421 if (RootDirectory) 00422 { 00423 *DirectorySize = Volume->RootDirSectors * Volume->BytesPerSector; 00424 } 00425 else 00426 { 00427 *DirectorySize = FatCountClustersInChain(Volume, DirectoryStartCluster) * Volume->SectorsPerCluster * Volume->BytesPerSector; 00428 } 00429 00430 // 00431 // Attempt to allocate memory for directory buffer 00432 // 00433 TRACE("Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize); 00434 DirectoryBuffer = MmHeapAlloc(*DirectorySize + sizeof(DIRECTORY_BUFFER)); 00435 00436 if (DirectoryBuffer == NULL) 00437 { 00438 return NULL; 00439 } 00440 00441 // 00442 // Now read directory contents into DirectoryBuffer 00443 // 00444 if (RootDirectory) 00445 { 00446 if (!FatReadVolumeSectors(Volume, Volume->RootDirSectorStart, Volume->RootDirSectors, DirectoryBuffer->Data)) 00447 { 00448 MmHeapFree(DirectoryBuffer); 00449 return NULL; 00450 } 00451 } 00452 else 00453 { 00454 if (!FatReadClusterChain(Volume, DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer->Data)) 00455 { 00456 MmHeapFree(DirectoryBuffer); 00457 return NULL; 00458 } 00459 } 00460 00461 /* Enqueue it in the list */ 00462 DirectoryBuffer->Volume = Volume; 00463 DirectoryBuffer->DirectoryStartCluster = DirectoryStartCluster; 00464 DirectoryBuffer->DirectorySize = *DirectorySize; 00465 InsertTailList(&DirectoryBufferListHead, &DirectoryBuffer->Link); 00466 00467 return DirectoryBuffer->Data; 00468 } 00469 00470 BOOLEAN FatSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer) 00471 { 00472 ULONG EntryCount; 00473 ULONG CurrentEntry; 00474 CHAR LfnNameBuffer[265]; 00475 CHAR ShortNameBuffer[20]; 00476 ULONG StartCluster; 00477 DIRENTRY OurDirEntry; 00478 LFN_DIRENTRY OurLfnDirEntry; 00479 PDIRENTRY DirEntry = &OurDirEntry; 00480 PLFN_DIRENTRY LfnDirEntry = &OurLfnDirEntry; 00481 00482 EntryCount = DirectorySize / sizeof(DIRENTRY); 00483 00484 TRACE("FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer, EntryCount, FileName); 00485 00486 memset(ShortNameBuffer, 0, 13 * sizeof(CHAR)); 00487 memset(LfnNameBuffer, 0, 261 * sizeof(CHAR)); 00488 00489 for (CurrentEntry=0; CurrentEntry<EntryCount; CurrentEntry++, DirectoryBuffer = ((PDIRENTRY)DirectoryBuffer)+1) 00490 { 00491 OurLfnDirEntry = *((PLFN_DIRENTRY) DirectoryBuffer); 00492 FatSwapLFNDirEntry(LfnDirEntry); 00493 OurDirEntry = *((PDIRENTRY) DirectoryBuffer); 00494 FatSwapDirEntry(DirEntry); 00495 00496 //TRACE("Dumping directory entry %d:\n", CurrentEntry); 00497 //DbgDumpBuffer(DPRINT_FILESYSTEM, DirEntry, sizeof(DIRENTRY)); 00498 00499 // 00500 // Check if this is the last file in the directory 00501 // If DirEntry[0] == 0x00 then that means all the 00502 // entries after this one are unused. If this is the 00503 // last entry then we didn't find the file in this directory. 00504 // 00505 if (DirEntry->FileName[0] == '\0') 00506 { 00507 return FALSE; 00508 } 00509 00510 // 00511 // Check if this is a deleted entry or not 00512 // 00513 if (DirEntry->FileName[0] == '\xE5') 00514 { 00515 memset(ShortNameBuffer, 0, 13 * sizeof(CHAR)); 00516 memset(LfnNameBuffer, 0, 261 * sizeof(CHAR)); 00517 continue; 00518 } 00519 00520 // 00521 // Check if this is a LFN entry 00522 // If so it needs special handling 00523 // 00524 if (DirEntry->Attr == ATTR_LONG_NAME) 00525 { 00526 // 00527 // Check to see if this is a deleted LFN entry, if so continue 00528 // 00529 if (LfnDirEntry->SequenceNumber & 0x80) 00530 { 00531 continue; 00532 } 00533 00534 // 00535 // Mask off high two bits of sequence number 00536 // and make the sequence number zero-based 00537 // 00538 LfnDirEntry->SequenceNumber &= 0x3F; 00539 LfnDirEntry->SequenceNumber--; 00540 00541 // 00542 // Get all 13 LFN entry characters 00543 // 00544 if (LfnDirEntry->Name0_4[0] != 0xFFFF) 00545 { 00546 LfnNameBuffer[0 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[0]; 00547 } 00548 if (LfnDirEntry->Name0_4[1] != 0xFFFF) 00549 { 00550 LfnNameBuffer[1 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[1]; 00551 } 00552 if (LfnDirEntry->Name0_4[2] != 0xFFFF) 00553 { 00554 LfnNameBuffer[2 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[2]; 00555 } 00556 if (LfnDirEntry->Name0_4[3] != 0xFFFF) 00557 { 00558 LfnNameBuffer[3 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[3]; 00559 } 00560 if (LfnDirEntry->Name0_4[4] != 0xFFFF) 00561 { 00562 LfnNameBuffer[4 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[4]; 00563 } 00564 if (LfnDirEntry->Name5_10[0] != 0xFFFF) 00565 { 00566 LfnNameBuffer[5 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[0]; 00567 } 00568 if (LfnDirEntry->Name5_10[1] != 0xFFFF) 00569 { 00570 LfnNameBuffer[6 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[1]; 00571 } 00572 if (LfnDirEntry->Name5_10[2] != 0xFFFF) 00573 { 00574 LfnNameBuffer[7 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[2]; 00575 } 00576 if (LfnDirEntry->Name5_10[3] != 0xFFFF) 00577 { 00578 LfnNameBuffer[8 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[3]; 00579 } 00580 if (LfnDirEntry->Name5_10[4] != 0xFFFF) 00581 { 00582 LfnNameBuffer[9 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[4]; 00583 } 00584 if (LfnDirEntry->Name5_10[5] != 0xFFFF) 00585 { 00586 LfnNameBuffer[10 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[5]; 00587 } 00588 if (LfnDirEntry->Name11_12[0] != 0xFFFF) 00589 { 00590 LfnNameBuffer[11 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[0]; 00591 } 00592 if (LfnDirEntry->Name11_12[1] != 0xFFFF) 00593 { 00594 LfnNameBuffer[12 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[1]; 00595 } 00596 00597 //TRACE("Dumping long name buffer:\n"); 00598 //DbgDumpBuffer(DPRINT_FILESYSTEM, LfnNameBuffer, 260); 00599 00600 continue; 00601 } 00602 00603 // 00604 // Check for the volume label attribute 00605 // and skip over this entry if found 00606 // 00607 if (DirEntry->Attr & ATTR_VOLUMENAME) 00608 { 00609 memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR)); 00610 memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR)); 00611 continue; 00612 } 00613 00614 // 00615 // If we get here then we've found a short file name 00616 // entry and LfnNameBuffer contains the long file 00617 // name or zeroes. All we have to do now is see if the 00618 // file name matches either the short or long file name 00619 // and fill in the FAT_FILE_INFO structure if it does 00620 // or zero our buffers and continue looking. 00621 // 00622 00623 // 00624 // Get short file name 00625 // 00626 FatParseShortFileName(ShortNameBuffer, DirEntry); 00627 00628 //TRACE("Entry: %d LFN = %s\n", CurrentEntry, LfnNameBuffer); 00629 //TRACE("Entry: %d DOS name = %s\n", CurrentEntry, ShortNameBuffer); 00630 00631 // 00632 // See if the file name matches either the short or long name 00633 // 00634 if (((strlen(FileName) == strlen(LfnNameBuffer)) && (_stricmp(FileName, LfnNameBuffer) == 0)) || 00635 ((strlen(FileName) == strlen(ShortNameBuffer)) && (_stricmp(FileName, ShortNameBuffer) == 0))) { 00636 // 00637 // We found the entry, now fill in the FAT_FILE_INFO struct 00638 // 00639 FatFileInfoPointer->Attributes = DirEntry->Attr; 00640 FatFileInfoPointer->FileSize = DirEntry->Size; 00641 FatFileInfoPointer->FilePointer = 0; 00642 00643 TRACE("MSDOS Directory Entry:\n"); 00644 TRACE("FileName[11] = %c%c%c%c%c%c%c%c%c%c%c\n", DirEntry->FileName[0], DirEntry->FileName[1], DirEntry->FileName[2], DirEntry->FileName[3], DirEntry->FileName[4], DirEntry->FileName[5], DirEntry->FileName[6], DirEntry->FileName[7], DirEntry->FileName[8], DirEntry->FileName[9], DirEntry->FileName[10]); 00645 TRACE("Attr = 0x%x\n", DirEntry->Attr); 00646 TRACE("ReservedNT = 0x%x\n", DirEntry->ReservedNT); 00647 TRACE("TimeInTenths = %d\n", DirEntry->TimeInTenths); 00648 TRACE("CreateTime = %d\n", DirEntry->CreateTime); 00649 TRACE("CreateDate = %d\n", DirEntry->CreateDate); 00650 TRACE("LastAccessDate = %d\n", DirEntry->LastAccessDate); 00651 TRACE("ClusterHigh = 0x%x\n", DirEntry->ClusterHigh); 00652 TRACE("Time = %d\n", DirEntry->Time); 00653 TRACE("Date = %d\n", DirEntry->Date); 00654 TRACE("ClusterLow = 0x%x\n", DirEntry->ClusterLow); 00655 TRACE("Size = %d\n", DirEntry->Size); 00656 00657 // 00658 // Get the cluster chain 00659 // 00660 StartCluster = ((ULONG)DirEntry->ClusterHigh << 16) + DirEntry->ClusterLow; 00661 TRACE("StartCluster = 0x%x\n", StartCluster); 00662 FatFileInfoPointer->FileFatChain = FatGetClusterChainArray(Volume, StartCluster); 00663 00664 // 00665 // See if memory allocation failed 00666 // 00667 if (FatFileInfoPointer->FileFatChain == NULL) 00668 { 00669 return FALSE; 00670 } 00671 00672 return TRUE; 00673 } 00674 00675 // 00676 // Nope, no match - zero buffers and continue looking 00677 // 00678 memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR)); 00679 memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR)); 00680 continue; 00681 } 00682 00683 return FALSE; 00684 } 00685 00686 static BOOLEAN FatXSearchDirectoryBufferForFile(PFAT_VOLUME_INFO Volume, PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer) 00687 { 00688 ULONG EntryCount; 00689 ULONG CurrentEntry; 00690 SIZE_T FileNameLen; 00691 FATX_DIRENTRY OurDirEntry; 00692 PFATX_DIRENTRY DirEntry = &OurDirEntry; 00693 00694 EntryCount = DirectorySize / sizeof(FATX_DIRENTRY); 00695 00696 TRACE("FatXSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer, EntryCount, FileName); 00697 00698 FileNameLen = strlen(FileName); 00699 00700 for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++, DirectoryBuffer = ((PFATX_DIRENTRY)DirectoryBuffer)+1) 00701 { 00702 OurDirEntry = *(PFATX_DIRENTRY) DirectoryBuffer; 00703 FatSwapFatXDirEntry(&OurDirEntry); 00704 if (0xff == DirEntry->FileNameSize) 00705 { 00706 break; 00707 } 00708 if (0xe5 == DirEntry->FileNameSize) 00709 { 00710 continue; 00711 } 00712 if (FileNameLen == DirEntry->FileNameSize && 00713 0 == _strnicmp(FileName, DirEntry->FileName, FileNameLen)) 00714 { 00715 /* 00716 * We found the entry, now fill in the FAT_FILE_INFO struct 00717 */ 00718 FatFileInfoPointer->FileSize = DirEntry->Size; 00719 FatFileInfoPointer->FilePointer = 0; 00720 00721 TRACE("FATX Directory Entry:\n"); 00722 TRACE("FileNameSize = %d\n", DirEntry->FileNameSize); 00723 TRACE("Attr = 0x%x\n", DirEntry->Attr); 00724 TRACE("StartCluster = 0x%x\n", DirEntry->StartCluster); 00725 TRACE("Size = %d\n", DirEntry->Size); 00726 TRACE("Time = %d\n", DirEntry->Time); 00727 TRACE("Date = %d\n", DirEntry->Date); 00728 TRACE("CreateTime = %d\n", DirEntry->CreateTime); 00729 TRACE("CreateDate = %d\n", DirEntry->CreateDate); 00730 TRACE("LastAccessTime = %d\n", DirEntry->LastAccessTime); 00731 TRACE("LastAccessDate = %d\n", DirEntry->LastAccessDate); 00732 00733 /* 00734 * Get the cluster chain 00735 */ 00736 FatFileInfoPointer->FileFatChain = FatGetClusterChainArray(Volume, DirEntry->StartCluster); 00737 00738 /* 00739 * See if memory allocation failed 00740 */ 00741 if (NULL == FatFileInfoPointer->FileFatChain) 00742 { 00743 return FALSE; 00744 } 00745 00746 return TRUE; 00747 } 00748 } 00749 00750 return FALSE; 00751 } 00752 00753 /* 00754 * FatLookupFile() 00755 * This function searches the file system for the 00756 * specified filename and fills in an FAT_FILE_INFO structure 00757 * with info describing the file, etc. returns ARC error code 00758 */ 00759 LONG FatLookupFile(PFAT_VOLUME_INFO Volume, PCSTR FileName, ULONG DeviceId, PFAT_FILE_INFO FatFileInfoPointer) 00760 { 00761 UINT32 i; 00762 ULONG NumberOfPathParts; 00763 CHAR PathPart[261]; 00764 PVOID DirectoryBuffer; 00765 ULONG DirectoryStartCluster = 0; 00766 ULONG DirectorySize; 00767 FAT_FILE_INFO FatFileInfo; 00768 00769 TRACE("FatLookupFile() FileName = %s\n", FileName); 00770 00771 memset(FatFileInfoPointer, 0, sizeof(FAT_FILE_INFO)); 00772 00773 // 00774 // Figure out how many sub-directories we are nested in 00775 // 00776 NumberOfPathParts = FsGetNumPathParts(FileName); 00777 00778 // 00779 // Loop once for each part 00780 // 00781 for (i=0; i<NumberOfPathParts; i++) 00782 { 00783 // 00784 // Get first path part 00785 // 00786 FsGetFirstNameFromPath(PathPart, FileName); 00787 00788 // 00789 // Advance to the next part of the path 00790 // 00791 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++) 00792 { 00793 } 00794 FileName++; 00795 00796 // 00797 // Buffer the directory contents 00798 // 00799 DirectoryBuffer = FatBufferDirectory(Volume, DirectoryStartCluster, &DirectorySize, (i == 0) ); 00800 if (DirectoryBuffer == NULL) 00801 { 00802 return ENOMEM; 00803 } 00804 00805 // 00806 // Search for file name in directory 00807 // 00808 if (ISFATX(Volume->FatType)) 00809 { 00810 if (!FatXSearchDirectoryBufferForFile(Volume, DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo)) 00811 { 00812 return ENOENT; 00813 } 00814 } 00815 else 00816 { 00817 if (!FatSearchDirectoryBufferForFile(Volume, DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo)) 00818 { 00819 return ENOENT; 00820 } 00821 } 00822 00823 // 00824 // If we have another sub-directory to go then 00825 // grab the start cluster and free the fat chain array 00826 // 00827 if ((i+1) < NumberOfPathParts) 00828 { 00829 // 00830 // Check if current entry is a directory 00831 // 00832 if (!(FatFileInfo.Attributes & ATTR_DIRECTORY)) 00833 { 00834 MmHeapFree(FatFileInfo.FileFatChain); 00835 return ENOTDIR; 00836 } 00837 DirectoryStartCluster = FatFileInfo.FileFatChain[0]; 00838 MmHeapFree(FatFileInfo.FileFatChain); 00839 FatFileInfo.FileFatChain = NULL; 00840 } 00841 } 00842 00843 memcpy(FatFileInfoPointer, &FatFileInfo, sizeof(FAT_FILE_INFO)); 00844 00845 return ESUCCESS; 00846 } 00847 00848 /* 00849 * FatParseFileName() 00850 * This function parses a directory entry name which 00851 * is in the form of "FILE EXT" and puts it in Buffer 00852 * in the form of "file.ext" 00853 */ 00854 void FatParseShortFileName(PCHAR Buffer, PDIRENTRY DirEntry) 00855 { 00856 ULONG Idx; 00857 00858 Idx = 0; 00859 RtlZeroMemory(Buffer, 13); 00860 00861 // 00862 // Fixup first character 00863 // 00864 if (DirEntry->FileName[0] == 0x05) 00865 { 00866 DirEntry->FileName[0] = 0xE5; 00867 } 00868 00869 // 00870 // Get the file name 00871 // 00872 while (Idx < 8) 00873 { 00874 if (DirEntry->FileName[Idx] == ' ') 00875 { 00876 break; 00877 } 00878 00879 Buffer[Idx] = DirEntry->FileName[Idx]; 00880 Idx++; 00881 } 00882 00883 // 00884 // Get extension 00885 // 00886 if ((DirEntry->FileName[8] != ' ')) 00887 { 00888 Buffer[Idx++] = '.'; 00889 Buffer[Idx++] = (DirEntry->FileName[8] == ' ') ? '\0' : DirEntry->FileName[8]; 00890 Buffer[Idx++] = (DirEntry->FileName[9] == ' ') ? '\0' : DirEntry->FileName[9]; 00891 Buffer[Idx++] = (DirEntry->FileName[10] == ' ') ? '\0' : DirEntry->FileName[10]; 00892 } 00893 00894 //TRACE("FatParseShortFileName() ShortName = %s\n", Buffer); 00895 } 00896 00897 /* 00898 * FatGetFatEntry() 00899 * returns the Fat entry for a given cluster number 00900 */ 00901 BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPointer) 00902 { 00903 ULONG fat = 0; 00904 UINT32 FatOffset; 00905 UINT32 ThisFatSecNum; 00906 UINT32 ThisFatEntOffset; 00907 00908 //TRACE("FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster); 00909 00910 switch(Volume->FatType) 00911 { 00912 case FAT12: 00913 00914 FatOffset = Cluster + (Cluster / 2); 00915 ThisFatSecNum = Volume->ActiveFatSectorStart + (FatOffset / Volume->BytesPerSector); 00916 ThisFatEntOffset = (FatOffset % Volume->BytesPerSector); 00917 00918 TRACE("FatOffset: %d\n", FatOffset); 00919 TRACE("ThisFatSecNum: %d\n", ThisFatSecNum); 00920 TRACE("ThisFatEntOffset: %d\n", ThisFatEntOffset); 00921 00922 if (ThisFatEntOffset == (Volume->BytesPerSector - 1)) 00923 { 00924 if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 2, (PVOID)FILESYSBUFFER)) 00925 { 00926 return FALSE; 00927 } 00928 } 00929 else 00930 { 00931 if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER)) 00932 { 00933 return FALSE; 00934 } 00935 } 00936 00937 fat = *((USHORT *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset)); 00938 fat = SWAPW(fat); 00939 if (Cluster & 0x0001) 00940 fat = fat >> 4; /* Cluster number is ODD */ 00941 else 00942 fat = fat & 0x0FFF; /* Cluster number is EVEN */ 00943 00944 break; 00945 00946 case FAT16: 00947 case FATX16: 00948 00949 FatOffset = (Cluster * 2); 00950 ThisFatSecNum = Volume->ActiveFatSectorStart + (FatOffset / Volume->BytesPerSector); 00951 ThisFatEntOffset = (FatOffset % Volume->BytesPerSector); 00952 00953 if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER)) 00954 { 00955 return FALSE; 00956 } 00957 00958 fat = *((USHORT *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset)); 00959 fat = SWAPW(fat); 00960 00961 break; 00962 00963 case FAT32: 00964 case FATX32: 00965 00966 FatOffset = (Cluster * 4); 00967 ThisFatSecNum = Volume->ActiveFatSectorStart + (FatOffset / Volume->BytesPerSector); 00968 ThisFatEntOffset = (FatOffset % Volume->BytesPerSector); 00969 00970 if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, (PVOID)FILESYSBUFFER)) 00971 { 00972 return FALSE; 00973 } 00974 00975 // Get the fat entry 00976 fat = (*((ULONG *) ((ULONG_PTR)FILESYSBUFFER + ThisFatEntOffset))) & 0x0FFFFFFF; 00977 fat = SWAPD(fat); 00978 00979 break; 00980 00981 default: 00982 TRACE("Unknown FAT type %d\n", Volume->FatType); 00983 return FALSE; 00984 00985 } 00986 00987 //TRACE("FAT entry is 0x%x.\n", fat); 00988 00989 *ClusterPointer = fat; 00990 00991 return TRUE; 00992 } 00993 00994 ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, ULONG StartCluster) 00995 { 00996 ULONG ClusterCount = 0; 00997 00998 TRACE("FatCountClustersInChain() StartCluster = %d\n", StartCluster); 00999 01000 while (1) 01001 { 01002 // 01003 // If end of chain then break out of our cluster counting loop 01004 // 01005 if (((Volume->FatType == FAT12) && (StartCluster >= 0xff8)) || 01006 ((Volume->FatType == FAT16 || Volume->FatType == FATX16) && (StartCluster >= 0xfff8)) || 01007 ((Volume->FatType == FAT32 || Volume->FatType == FATX32) && (StartCluster >= 0x0ffffff8))) 01008 { 01009 break; 01010 } 01011 01012 // 01013 // Increment count 01014 // 01015 ClusterCount++; 01016 01017 // 01018 // Get next cluster 01019 // 01020 if (!FatGetFatEntry(Volume, StartCluster, &StartCluster)) 01021 { 01022 return 0; 01023 } 01024 } 01025 01026 TRACE("FatCountClustersInChain() ClusterCount = %d\n", ClusterCount); 01027 01028 return ClusterCount; 01029 } 01030 01031 ULONG* FatGetClusterChainArray(PFAT_VOLUME_INFO Volume, ULONG StartCluster) 01032 { 01033 ULONG ClusterCount; 01034 ULONG ArraySize; 01035 ULONG* ArrayPointer; 01036 ULONG Idx; 01037 01038 TRACE("FatGetClusterChainArray() StartCluster = %d\n", StartCluster); 01039 01040 ClusterCount = FatCountClustersInChain(Volume, StartCluster) + 1; // Lets get the 0x0ffffff8 on the end of the array 01041 ArraySize = ClusterCount * sizeof(ULONG); 01042 01043 // 01044 // Allocate array memory 01045 // 01046 ArrayPointer = MmHeapAlloc(ArraySize); 01047 01048 if (ArrayPointer == NULL) 01049 { 01050 return NULL; 01051 } 01052 01053 // 01054 // Loop through and set array values 01055 // 01056 for (Idx=0; Idx<ClusterCount; Idx++) 01057 { 01058 // 01059 // Set current cluster 01060 // 01061 ArrayPointer[Idx] = StartCluster; 01062 01063 // 01064 // Don't try to get next cluster for last cluster 01065 // 01066 if (((Volume->FatType == FAT12) && (StartCluster >= 0xff8)) || 01067 ((Volume->FatType == FAT16 || Volume->FatType == FATX16) && (StartCluster >= 0xfff8)) || 01068 ((Volume->FatType == FAT32 || Volume->FatType == FATX32) && (StartCluster >= 0x0ffffff8))) 01069 { 01070 Idx++; 01071 break; 01072 } 01073 01074 // 01075 // Get next cluster 01076 // 01077 if (!FatGetFatEntry(Volume, StartCluster, &StartCluster)) 01078 { 01079 MmHeapFree(ArrayPointer); 01080 return NULL; 01081 } 01082 } 01083 01084 return ArrayPointer; 01085 } 01086 01087 /* 01088 * FatReadClusterChain() 01089 * Reads the specified clusters into memory 01090 */ 01091 BOOLEAN FatReadClusterChain(PFAT_VOLUME_INFO Volume, ULONG StartClusterNumber, ULONG NumberOfClusters, PVOID Buffer) 01092 { 01093 ULONG ClusterStartSector; 01094 01095 TRACE("FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer); 01096 01097 while (NumberOfClusters > 0) 01098 { 01099 01100 //TRACE("FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer); 01101 // 01102 // Calculate starting sector for cluster 01103 // 01104 ClusterStartSector = ((StartClusterNumber - 2) * Volume->SectorsPerCluster) + Volume->DataSectorStart; 01105 01106 // 01107 // Read cluster into memory 01108 // 01109 if (!FatReadVolumeSectors(Volume, ClusterStartSector, Volume->SectorsPerCluster, (PVOID)FILESYSBUFFER)) 01110 { 01111 return FALSE; 01112 } 01113 01114 memcpy(Buffer, (PVOID)FILESYSBUFFER, Volume->SectorsPerCluster * Volume->BytesPerSector); 01115 01116 // 01117 // Decrement count of clusters left to read 01118 // 01119 NumberOfClusters--; 01120 01121 // 01122 // Increment buffer address by cluster size 01123 // 01124 Buffer = (PVOID)((ULONG_PTR)Buffer + (Volume->SectorsPerCluster * Volume->BytesPerSector)); 01125 01126 // 01127 // Get next cluster 01128 // 01129 if (!FatGetFatEntry(Volume, StartClusterNumber, &StartClusterNumber)) 01130 { 01131 return FALSE; 01132 } 01133 01134 // 01135 // If end of chain then break out of our cluster reading loop 01136 // 01137 if (((Volume->FatType == FAT12) && (StartClusterNumber >= 0xff8)) || 01138 ((Volume->FatType == FAT16 || Volume->FatType == FATX16) && (StartClusterNumber >= 0xfff8)) || 01139 ((Volume->FatType == FAT32 || Volume->FatType == FATX32) && (StartClusterNumber >= 0x0ffffff8))) 01140 { 01141 break; 01142 } 01143 } 01144 01145 return TRUE; 01146 } 01147 01148 /* 01149 * FatReadPartialCluster() 01150 * Reads part of a cluster into memory 01151 */ 01152 BOOLEAN FatReadPartialCluster(PFAT_VOLUME_INFO Volume, ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer) 01153 { 01154 ULONG ClusterStartSector; 01155 01156 //TRACE("FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber, StartingOffset, Length, Buffer); 01157 01158 ClusterStartSector = ((ClusterNumber - 2) * Volume->SectorsPerCluster) + Volume->DataSectorStart; 01159 01160 if (!FatReadVolumeSectors(Volume, ClusterStartSector, Volume->SectorsPerCluster, (PVOID)FILESYSBUFFER)) 01161 { 01162 return FALSE; 01163 } 01164 01165 memcpy(Buffer, (PVOID)((ULONG_PTR)FILESYSBUFFER + StartingOffset), Length); 01166 01167 return TRUE; 01168 } 01169 01170 /* 01171 * FatReadFile() 01172 * Reads BytesToRead from open file and 01173 * returns the number of bytes read in BytesRead 01174 */ 01175 BOOLEAN FatReadFile(PFAT_FILE_INFO FatFileInfo, ULONG BytesToRead, ULONG* BytesRead, PVOID Buffer) 01176 { 01177 PFAT_VOLUME_INFO Volume = FatFileInfo->Volume; 01178 ULONG ClusterNumber; 01179 ULONG OffsetInCluster; 01180 ULONG LengthInCluster; 01181 ULONG NumberOfClusters; 01182 ULONG BytesPerCluster; 01183 01184 TRACE("FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead, Buffer); 01185 01186 if (BytesRead != NULL) 01187 { 01188 *BytesRead = 0; 01189 } 01190 01191 // 01192 // If they are trying to read past the 01193 // end of the file then return success 01194 // with BytesRead == 0 01195 // 01196 if (FatFileInfo->FilePointer >= FatFileInfo->FileSize) 01197 { 01198 return TRUE; 01199 } 01200 01201 // 01202 // If they are trying to read more than there is to read 01203 // then adjust the amount to read 01204 // 01205 if ((FatFileInfo->FilePointer + BytesToRead) > FatFileInfo->FileSize) 01206 { 01207 BytesToRead = (FatFileInfo->FileSize - FatFileInfo->FilePointer); 01208 } 01209 01210 // 01211 // Ok, now we have to perform at most 3 calculations 01212 // I'll draw you a picture (using nifty ASCII art): 01213 // 01214 // CurrentFilePointer -+ 01215 // | 01216 // +----------------+ 01217 // | 01218 // +-----------+-----------+-----------+-----------+ 01219 // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 | 01220 // +-----------+-----------+-----------+-----------+ 01221 // | | 01222 // +---------------+--------------------+ 01223 // | 01224 // BytesToRead -------+ 01225 // 01226 // 1 - The first calculation (and read) will align 01227 // the file pointer with the next cluster. 01228 // boundary (if we are supposed to read that much) 01229 // 2 - The next calculation (and read) will read 01230 // in all the full clusters that the requested 01231 // amount of data would cover (in this case 01232 // clusters 2 & 3). 01233 // 3 - The last calculation (and read) would read 01234 // in the remainder of the data requested out of 01235 // the last cluster. 01236 // 01237 01238 BytesPerCluster = Volume->SectorsPerCluster * Volume->BytesPerSector; 01239 01240 // 01241 // Only do the first read if we 01242 // aren't aligned on a cluster boundary 01243 // 01244 if (FatFileInfo->FilePointer % BytesPerCluster) 01245 { 01246 // 01247 // Do the math for our first read 01248 // 01249 ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster); 01250 ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber]; 01251 OffsetInCluster = (FatFileInfo->FilePointer % BytesPerCluster); 01252 LengthInCluster = (BytesToRead > (BytesPerCluster - OffsetInCluster)) ? (BytesPerCluster - OffsetInCluster) : BytesToRead; 01253 01254 // 01255 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer 01256 // 01257 if (!FatReadPartialCluster(Volume, ClusterNumber, OffsetInCluster, LengthInCluster, Buffer)) 01258 { 01259 return FALSE; 01260 } 01261 if (BytesRead != NULL) 01262 { 01263 *BytesRead += LengthInCluster; 01264 } 01265 BytesToRead -= LengthInCluster; 01266 FatFileInfo->FilePointer += LengthInCluster; 01267 Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInCluster); 01268 } 01269 01270 // 01271 // Do the math for our second read (if any data left) 01272 // 01273 if (BytesToRead > 0) 01274 { 01275 // 01276 // Determine how many full clusters we need to read 01277 // 01278 NumberOfClusters = (BytesToRead / BytesPerCluster); 01279 01280 if (NumberOfClusters > 0) 01281 { 01282 ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster); 01283 ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber]; 01284 01285 // 01286 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer 01287 // 01288 if (!FatReadClusterChain(Volume, ClusterNumber, NumberOfClusters, Buffer)) 01289 { 01290 return FALSE; 01291 } 01292 if (BytesRead != NULL) 01293 { 01294 *BytesRead += (NumberOfClusters * BytesPerCluster); 01295 } 01296 BytesToRead -= (NumberOfClusters * BytesPerCluster); 01297 FatFileInfo->FilePointer += (NumberOfClusters * BytesPerCluster); 01298 Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfClusters * BytesPerCluster)); 01299 } 01300 } 01301 01302 // 01303 // Do the math for our third read (if any data left) 01304 // 01305 if (BytesToRead > 0) 01306 { 01307 ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster); 01308 ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber]; 01309 01310 // 01311 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer 01312 // 01313 if (!FatReadPartialCluster(Volume, ClusterNumber, 0, BytesToRead, Buffer)) 01314 { 01315 return FALSE; 01316 } 01317 if (BytesRead != NULL) 01318 { 01319 *BytesRead += BytesToRead; 01320 } 01321 FatFileInfo->FilePointer += BytesToRead; 01322 BytesToRead -= BytesToRead; 01323 Buffer = (PVOID)((ULONG_PTR)Buffer + BytesToRead); 01324 } 01325 01326 return TRUE; 01327 } 01328 01329 BOOLEAN FatReadVolumeSectors(PFAT_VOLUME_INFO Volume, ULONG SectorNumber, ULONG SectorCount, PVOID Buffer) 01330 { 01331 LARGE_INTEGER Position; 01332 ULONG Count; 01333 LONG ret; 01334 01335 //TRACE("FatReadVolumeSectors(): SectorNumber %d, SectorCount %d, Buffer %p\n", 01336 // SectorNumber, SectorCount, Buffer); 01337 01338 // 01339 // Seek to right position 01340 // 01341 Position.QuadPart = SectorNumber * 512; 01342 ret = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute); 01343 if (ret != ESUCCESS) 01344 { 01345 TRACE("FatReadVolumeSectors() Failed to seek\n"); 01346 return FALSE; 01347 } 01348 01349 // 01350 // Read data 01351 // 01352 ret = ArcRead(Volume->DeviceId, Buffer, SectorCount * 512, &Count); 01353 if (ret != ESUCCESS || Count != SectorCount * 512) 01354 { 01355 TRACE("FatReadVolumeSectors() Failed to read\n"); 01356 return FALSE; 01357 } 01358 01359 // Return success 01360 return TRUE; 01361 } 01362 01363 LONG FatClose(ULONG FileId) 01364 { 01365 PFAT_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 01366 01367 if (FileHandle->FileFatChain) MmHeapFree(FileHandle->FileFatChain); 01368 MmHeapFree(FileHandle); 01369 01370 return ESUCCESS; 01371 } 01372 01373 LONG FatGetFileInformation(ULONG FileId, FILEINFORMATION* Information) 01374 { 01375 PFAT_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 01376 01377 RtlZeroMemory(Information, sizeof(FILEINFORMATION)); 01378 Information->EndingAddress.LowPart = FileHandle->FileSize; 01379 Information->CurrentAddress.LowPart = FileHandle->FilePointer; 01380 01381 TRACE("FatGetFileInformation() FileSize = %d\n", 01382 Information->EndingAddress.LowPart); 01383 TRACE("FatGetFileInformation() FilePointer = %d\n", 01384 Information->CurrentAddress.LowPart); 01385 01386 return ESUCCESS; 01387 } 01388 01389 LONG FatOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId) 01390 { 01391 PFAT_VOLUME_INFO FatVolume; 01392 FAT_FILE_INFO TempFileInfo; 01393 PFAT_FILE_INFO FileHandle; 01394 ULONG DeviceId; 01395 BOOLEAN IsDirectory; 01396 LONG ret; 01397 01398 if (OpenMode != OpenReadOnly && OpenMode != OpenDirectory) 01399 return EACCES; 01400 01401 DeviceId = FsGetDeviceId(*FileId); 01402 FatVolume = FatVolumes[DeviceId]; 01403 01404 TRACE("FatOpen() FileName = %s\n", Path); 01405 01406 RtlZeroMemory(&TempFileInfo, sizeof(TempFileInfo)); 01407 ret = FatLookupFile(FatVolume, Path, DeviceId, &TempFileInfo); 01408 if (ret != ESUCCESS) 01409 return ENOENT; 01410 01411 // 01412 // Check if caller opened what he expected (dir vs file) 01413 // 01414 IsDirectory = (TempFileInfo.Attributes & ATTR_DIRECTORY) != 0; 01415 if (IsDirectory && OpenMode != OpenDirectory) 01416 return EISDIR; 01417 else if (!IsDirectory && OpenMode != OpenReadOnly) 01418 return ENOTDIR; 01419 01420 FileHandle = MmHeapAlloc(sizeof(FAT_FILE_INFO)); 01421 if (!FileHandle) 01422 return ENOMEM; 01423 01424 RtlCopyMemory(FileHandle, &TempFileInfo, sizeof(FAT_FILE_INFO)); 01425 FileHandle->Volume = FatVolume; 01426 01427 FsSetDeviceSpecific(*FileId, FileHandle); 01428 return ESUCCESS; 01429 } 01430 01431 LONG FatRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count) 01432 { 01433 PFAT_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 01434 BOOLEAN ret; 01435 01436 // 01437 // Call old read method 01438 // 01439 ret = FatReadFile(FileHandle, N, Count, Buffer); 01440 01441 // 01442 // Check for success 01443 // 01444 if (ret) 01445 return ESUCCESS; 01446 else 01447 return EIO; 01448 } 01449 01450 LONG FatSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode) 01451 { 01452 PFAT_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); 01453 01454 TRACE("FatSeek() NewFilePointer = %lu\n", Position->LowPart); 01455 01456 if (SeekMode != SeekAbsolute) 01457 return EINVAL; 01458 if (Position->HighPart != 0) 01459 return EINVAL; 01460 if (Position->LowPart >= FileHandle->FileSize) 01461 return EINVAL; 01462 01463 FileHandle->FilePointer = Position->LowPart; 01464 return ESUCCESS; 01465 } 01466 01467 const DEVVTBL FatFuncTable = 01468 { 01469 FatClose, 01470 FatGetFileInformation, 01471 FatOpen, 01472 FatRead, 01473 FatSeek, 01474 L"fastfat", 01475 }; 01476 01477 const DEVVTBL* FatMount(ULONG DeviceId) 01478 { 01479 PFAT_VOLUME_INFO Volume; 01480 UCHAR Buffer[512]; 01481 PFAT_BOOTSECTOR BootSector = (PFAT_BOOTSECTOR)Buffer; 01482 PFAT32_BOOTSECTOR BootSector32 = (PFAT32_BOOTSECTOR)Buffer; 01483 PFATX_BOOTSECTOR BootSectorX = (PFATX_BOOTSECTOR)Buffer; 01484 FILEINFORMATION FileInformation; 01485 LARGE_INTEGER Position; 01486 ULONG Count; 01487 ULARGE_INTEGER SectorCount; 01488 LONG ret; 01489 01490 // 01491 // Allocate data for volume information 01492 // 01493 Volume = MmHeapAlloc(sizeof(FAT_VOLUME_INFO)); 01494 if (!Volume) 01495 return NULL; 01496 RtlZeroMemory(Volume, sizeof(FAT_VOLUME_INFO)); 01497 01498 // 01499 // Read the BootSector 01500 // 01501 Position.HighPart = 0; 01502 Position.LowPart = 0; 01503 ret = ArcSeek(DeviceId, &Position, SeekAbsolute); 01504 if (ret != ESUCCESS) 01505 { 01506 MmHeapFree(Volume); 01507 return NULL; 01508 } 01509 ret = ArcRead(DeviceId, Buffer, sizeof(Buffer), &Count); 01510 if (ret != ESUCCESS || Count != sizeof(Buffer)) 01511 { 01512 MmHeapFree(Volume); 01513 return NULL; 01514 } 01515 01516 // 01517 // Check if BootSector is valid. If no, return early 01518 // 01519 if (!RtlEqualMemory(BootSector->FileSystemType, "FAT12 ", 8) && 01520 !RtlEqualMemory(BootSector->FileSystemType, "FAT16 ", 8) && 01521 !RtlEqualMemory(BootSector32->FileSystemType, "FAT32 ", 8) && 01522 !RtlEqualMemory(BootSectorX->FileSystemType, "FATX", 4)) 01523 { 01524 MmHeapFree(Volume); 01525 return NULL; 01526 } 01527 01528 // 01529 // Determine sector count 01530 // 01531 ret = ArcGetFileInformation(DeviceId, &FileInformation); 01532 if (ret != ESUCCESS) 01533 { 01534 MmHeapFree(Volume); 01535 return NULL; 01536 } 01537 SectorCount.HighPart = FileInformation.EndingAddress.HighPart; 01538 SectorCount.LowPart = FileInformation.EndingAddress.LowPart; 01539 SectorCount.QuadPart /= SECTOR_SIZE; 01540 01541 // 01542 // Keep device id 01543 // 01544 Volume->DeviceId = DeviceId; 01545 01546 // 01547 // Really open the volume 01548 // 01549 if (!FatOpenVolume(Volume, BootSector, SectorCount.QuadPart)) 01550 { 01551 MmHeapFree(Volume); 01552 return NULL; 01553 } 01554 01555 // 01556 // Remember FAT volume information 01557 // 01558 FatVolumes[DeviceId] = Volume; 01559 01560 // 01561 // Return success 01562 // 01563 return &FatFuncTable; 01564 } Generated on Sat May 26 2012 04:17:57 for ReactOS by
1.7.6.1
|