/** @file FAT file system access routines for file access PEIM ;****************************************************************************** ;* Copyright (c) 2014, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ /*++ This file contains 'Framework Code' and is licensed as such under the terms of your license agreement with Intel or your vendor. This file may not be modified, except as allowed by additional terms of your license agreement. --*/ /*++ Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved This software and associated documentation (if any) is furnished under a license and may only be used or copied in accordance with the terms of the license. Except as permitted by such license, no part of this software or documentation may be reproduced, stored in a retrieval system, or transmitted in any form or by any means without the express written consent of Intel Corporation. Module Name: FatAccess.c Abstract: FAT file system access routines for file access PEIM --*/ #include "FatPeim.h" /** Check if there is a valid FAT in the corresponding Block device of the volume and if yes, fill in the relevant fields for the volume structure. Note there should be a valid Block device number already set. @param PrivateData Global memory map for accessing global variables. @param Volume On input, the BlockDeviceNumber field of the Volume should be a valid value. On successful output, all fields except the VolumeNumber field is initialized. @retval EFI_SUCCESS A FAT is found and the volume structure is initialized. @retval EFI_NOT_FOUND There is no FAT on the corresponding device. @retval EFI_DEVICE_ERROR There is something error while accessing device. **/ EFI_STATUS FatGetBpbInfo ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN OUT PEI_FAT_VOLUME *Volume ) { EFI_STATUS Status; PEI_FAT_BOOT_SECTOR Bpb; PEI_FAT_BOOT_SECTOR_EX BpbEx; UINT32 Sectors; UINT32 SectorsPerFat; UINT32 RootDirSectors; UINT64 FatLba; UINT64 RootLba; UINT64 FirstClusterLba; // // Read in the BPB // Status = FatReadDisk ( PrivateData, Volume->BlockDeviceNo, 0, sizeof (PEI_FAT_BOOT_SECTOR_EX), &BpbEx ); if (EFI_ERROR (Status)) { return Status; } CopyMem ( (UINT8 *) (&Bpb), (UINT8 *) (&BpbEx), sizeof (PEI_FAT_BOOT_SECTOR) ); Volume->FatType = FatUnknown; Sectors = Bpb.Sectors; if (Sectors == 0) { Sectors = Bpb.LargeSectors; } SectorsPerFat = Bpb.SectorsPerFat; if (SectorsPerFat == 0) { SectorsPerFat = BpbEx.LargeSectorsPerFat; Volume->FatType = Fat32; } // // Filter out those not a FAT // if (Bpb.Ia32Jump[0] != 0xe9 && Bpb.Ia32Jump[0] != 0xeb && Bpb.Ia32Jump[0] != 0x49) { return EFI_NOT_FOUND; } if (Bpb.ReservedSectors == 0 || Bpb.NoFats == 0 || Sectors == 0) { return EFI_NOT_FOUND; } if (Bpb.SectorsPerCluster != 1 && Bpb.SectorsPerCluster != 2 && Bpb.SectorsPerCluster != 4 && Bpb.SectorsPerCluster != 8 && Bpb.SectorsPerCluster != 16 && Bpb.SectorsPerCluster != 32 && Bpb.SectorsPerCluster != 64 && Bpb.SectorsPerCluster != 128 ) { return EFI_NOT_FOUND; } if (Volume->FatType == Fat32 && (SectorsPerFat == 0 || BpbEx.FsVersion != 0)) { return EFI_NOT_FOUND; } if (Bpb.Media != 0xf0 && Bpb.Media != 0xf8 && Bpb.Media != 0xf9 && Bpb.Media != 0xfb && Bpb.Media != 0xfc && Bpb.Media != 0xfd && Bpb.Media != 0xfe && Bpb.Media != 0xff && // // FujitsuFMR // Bpb.Media != 0x00 && Bpb.Media != 0x01 && Bpb.Media != 0xfa ) { return EFI_NOT_FOUND; } if (Volume->FatType != Fat32 && Bpb.RootEntries == 0) { return EFI_NOT_FOUND; } // // If this is fat32, refuse to mount mirror-disabled volumes // if (Volume->FatType == Fat32 && ((BpbEx.ExtendedFlags & 0x80) != 0)) { return EFI_NOT_FOUND; } // // Fill in the volume structure fields // (Sectors & SectorsPerFat is computed earlier already) // Volume->ClusterSize = Bpb.SectorSize * Bpb.SectorsPerCluster; Volume->RootEntries = Bpb.RootEntries; Volume->SectorSize = Bpb.SectorSize; RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (Volume->SectorSize - 1)) / Volume->SectorSize; FatLba = Bpb.ReservedSectors; RootLba = Bpb.NoFats * SectorsPerFat + FatLba; FirstClusterLba = RootLba + RootDirSectors; Volume->VolumeSize = MultU64x32 (Sectors, Volume->SectorSize); Volume->FatPos = MultU64x32 (FatLba, Volume->SectorSize); Volume->RootDirPos = MultU64x32 (RootLba, Volume->SectorSize); Volume->FirstClusterPos = MultU64x32 (FirstClusterLba, Volume->SectorSize); Volume->MaxCluster = (UINT32) (Sectors - FirstClusterLba) / Bpb.SectorsPerCluster; Volume->RootDirCluster = BpbEx.RootDirFirstCluster; // // If this is not a fat32, determine if it's a fat16 or fat12 // if (Volume->FatType != Fat32) { Volume->FatType = Volume->MaxCluster < 4085 ? Fat12 : Fat16; } return EFI_SUCCESS; } /** Get the physical starting address of the cluster. @param[in] PrivateData Pointer to the PEI_FAT_PRIVATE_DATA structure @param[in] Volume Pointer to the PEI_FAT_VOLUME structure @param[in] ClusterNo The cluster number @param[out] Position Pointer to the physical starting address of the cluster @retval EFI_SUCCESS The physical address of the cluster is successfully retrieved @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume. **/ EFI_STATUS FatGetClusterPos ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_VOLUME *Volume, IN UINT32 ClusterNo, OUT UINT64 *Position ) { if (ClusterNo > Volume->MaxCluster + 1) { return EFI_INVALID_PARAMETER; } *Position = Volume->FirstClusterPos + MultU64x32 (Volume->ClusterSize, ClusterNo - 2); return EFI_SUCCESS; } /** Get the next cluster in the cluster chain @param PrivateData Global memory map for accessing global variables @param Volume The volume @param Cluster The cluster @param NextCluster The cluster number of the next cluster @retval EFI_SUCCESS The address is got @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume. @retval EFI_DEVICE_ERROR Read disk error **/ EFI_STATUS FatGetNextCluster ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_VOLUME *Volume, IN UINT32 Cluster, OUT UINT32 *NextCluster ) { EFI_STATUS Status; UINT64 FatEntryPos; Status = EFI_SUCCESS; if ((Cluster > Volume->MaxCluster + 1) || (Cluster < 2)) { return EFI_INVALID_PARAMETER; } *NextCluster = 0; if (Volume->FatType == Fat32) { FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster); Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster); *NextCluster &= 0x0fffffff; // // Pad high bits for our FAT_CLUSTER_... macro definitions to work // if ((*NextCluster) >= 0x0ffffff7) { *NextCluster |= (-1 &~0xf); } } else if (Volume->FatType == Fat16) { FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster); Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster); // // Pad high bits for our FAT_CLUSTER_... macro definitions to work // if ((*NextCluster) >= 0xfff7) { *NextCluster |= (-1 &~0xf); } } else { FatEntryPos = Volume->FatPos + DivU64x32 (MultU64x32 (3, Cluster), 2); Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster); if ((Cluster & 0x01) != 0) { *NextCluster = (*NextCluster) >> 4; } else { *NextCluster = (*NextCluster) & 0x0fff; } // // Pad high bits for our FAT_CLUSTER_... macro definitions to work // if ((*NextCluster) >= 0x0ff7) { *NextCluster |= (-1 &~0xf); } } if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** Read the cluster data @param[in] PrivateData Global memory map for accessing global variables @param[in] Volume The volume @param[in] Cluster The cluster number @param[in] BufferSize Size of the data buffer @param[out] Buffer The data buffer to store the cluster data @retval EFI_SUCCESS The cluster is successfully read @retval EFI_INVALID_PARAMETER The cluster number exceeds the max cluster number allowed in this volume @retval EFI_DEVICE_ERROR Something error while accessing media. **/ EFI_STATUS FatReadCluster ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_VOLUME *Volume, IN UINT32 Cluster, IN UINTN BufferSize, OUT VOID *Buffer ) { EFI_STATUS Status; UINT32 ClusterSize; UINT64 ClusterPos; Status = EFI_SUCCESS; if (Cluster > Volume->MaxCluster + 1) { return EFI_INVALID_PARAMETER; } Status = FatGetClusterPos (PrivateData, Volume, Cluster, &ClusterPos); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } ClusterSize = Volume->ClusterSize; if (BufferSize < ClusterSize) { return EFI_BUFFER_TOO_SMALL; } Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, ClusterPos, ClusterSize, Buffer); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } else { return EFI_SUCCESS; } } /** Compute the amount of data that could be read continguously from the file's current position @param[in] PrivateData Pointer to the PEI_FAT_PRIVATE_DATA structure @param[in] File Pointer to the PEI_FAT_FILE structure @retval EFI_SUCCESS Function executed successfully @retval EFI_DEVICE_ERROR Something error while accessing media. **/ EFI_STATUS FatComputeStraightRead ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_FILE *File ) { EFI_STATUS Status; UINT32 Cluster; UINT32 PrevCluster; UINTN Offset; if (File->IsFixedRootDir) { File->StraightReadAmount = (UINT32) (MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos); } else { File->StraightReadAmount = 0; Cluster = File->CurrentCluster; while (!FAT_CLUSTER_FUNCTIONAL (Cluster)) { File->StraightReadAmount += File->Volume->ClusterSize; PrevCluster = Cluster; Status = FatGetNextCluster (PrivateData, File->Volume, Cluster, &Cluster); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } if (Cluster != PrevCluster + 1) { break; } } DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset); File->StraightReadAmount -= (UINT32) Offset; } return EFI_SUCCESS; } /** Set a file's CurrentPos and CurrentCluster. @param[in] PrivateData Pointer to the PEI_FAT_PRIVATE_DATA structure @param[in] File Pointer to the PEI_FAT_FILE structure @param[in] Pos The file position @param[in] Absolute if TRUE, the Position is counted from starting of file if FALSE, tht Position is counted from File->CurrentPos @retval EFI_SUCCESS Function executed successfully @retval EFI_INVALID_PARAMETER Pos is beyond file's size. @retval EFI_DEVICE_ERROR Something error while accessing media. **/ EFI_STATUS FatSetFilePos ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_FILE *File, IN UINT32 Pos, IN BOOLEAN Absolute ) { EFI_STATUS Status; UINT32 ClusterSize; UINT32 AlignedPos; UINTN Offset; if (Absolute) { File->CurrentPos = 0; File->CurrentCluster = File->StartingCluster; } if (File->IsFixedRootDir) { if (Pos >= MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos) { return EFI_INVALID_PARAMETER; } File->CurrentPos += Pos; } else { ClusterSize = File->Volume->ClusterSize; DivU64x32Remainder (File->CurrentPos, ClusterSize, &Offset); AlignedPos = (UINT32) File->CurrentPos - (UINT32) Offset; while (!FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster) && AlignedPos + ClusterSize <= File->CurrentPos + Pos) { AlignedPos += ClusterSize; Status = FatGetNextCluster ( PrivateData, File->Volume, File->CurrentCluster, &File->CurrentCluster ); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } } if (FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster)) { return EFI_INVALID_PARAMETER; } File->CurrentPos += Pos; } return FatComputeStraightRead (PrivateData, File); } /** Read file data. Updates the file's CurrentPos. @param PrivateData Global memory map for accessing global variables @param File The file. @param Size Pointer to the amount of data to read. @param Buffer The buffer storing the data. @retval EFI_SUCCESS The data is read. @retval EFI_INVALID_PARAMETER File is invalid. @retval EFI_DEVICE_ERROR Something error while accessing media. **/ EFI_STATUS FatReadFile ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_FILE *File, IN UINTN *Size, OUT VOID *Buffer ) { EFI_STATUS Status; CHAR8 *BufferPtr; UINTN Offset; UINT64 PhysicalAddr; UINTN ClusterSize; UINTN Amount; UINTN TotalAmount; Status = EFI_SUCCESS; TotalAmount = 0; ClusterSize = File->Volume->ClusterSize; BufferPtr = Buffer; if (File->IsFixedRootDir) { // // This is the fixed root dir in FAT12 and FAT16 // *Size = *Size < (File->Volume->RootEntries * 32 - File->CurrentPos) ? *Size : (UINTN) (File->Volume->RootEntries * 32 - File->CurrentPos); Status = FatReadDisk ( PrivateData, File->Volume->BlockDeviceNo, File->Volume->RootDirPos + File->CurrentPos, *Size, Buffer ); File->CurrentPos += (UINT32) *Size; return Status; } else { // // Fat32 // if (!(File->Attributes & FAT_ATTR_DIRECTORY)) { *Size = *Size < (File->FileSize - File->CurrentPos) ? *Size : (UINTN) (File->FileSize - File->CurrentPos); } // // This is a normal cluster based file // while (*Size) { DivU64x32Remainder (File->CurrentPos, ClusterSize, &Offset); Status = FatGetClusterPos (PrivateData, File->Volume, File->CurrentCluster, &PhysicalAddr); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } Amount = File->StraightReadAmount; Amount = *Size > Amount ? Amount : *Size; Status = FatReadDisk ( PrivateData, File->Volume->BlockDeviceNo, PhysicalAddr + Offset, Amount, BufferPtr ); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } // // Advance the file's current pos and current cluster // FatSetFilePos (PrivateData, File, (UINT32) Amount, FALSE); BufferPtr += Amount; *Size -= Amount; TotalAmount += Amount; // // if this is the end of cluster chain? // if (FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster)) { *Size = TotalAmount; return EFI_SUCCESS; } } *Size = TotalAmount; return Status; } } /** Write file data. Updates the file's CurrentPos. @param PrivateData Global memory map for accessing global variables @param File The file. @param Size Pointer to the amount of data to write. @param Buffer The buffer storing the data. @retval EFI_SUCCESS The data is write. @retval EFI_INVALID_PARAMETER File is invalid. @retval EFI_DEVICE_ERROR Something error while accessing media. if write directory used FatWriteDisk(), because File is locate at start of one Cluster, directory not. **/ EFI_STATUS FatWriteFile ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_FILE *File, IN UINTN *Size, IN VOID *Buffer ) { EFI_STATUS Status; CHAR8 *BufferPtr; UINTN Offset; UINT64 PhysicalAddr; //Physical bytes address UINTN ClusterSize; UINTN Amount; UINTN TotalAmount; Status = EFI_SUCCESS; TotalAmount = 0; ClusterSize = File->Volume->ClusterSize; BufferPtr = Buffer; if (File->IsFixedRootDir) { // // This is the fixed root dir in FAT12 and FAT16 // *Size = *Size < (File->Volume->RootEntries * 32 - File->CurrentPos) ? *Size : (UINTN) (File->Volume->RootEntries * 32 - File->CurrentPos); Status = FatWriteDisk ( PrivateData, File->Volume->BlockDeviceNo, File->Volume->RootDirPos + File->CurrentPos, *Size, Buffer ); File->CurrentPos += (UINT32) *Size; return Status; } else { // // This part is FAT32 // if (!(File->Attributes & FAT_ATTR_DIRECTORY)) { *Size = *Size < (File->FileSize - File->CurrentPos) ? *Size : (UINTN) (File->FileSize - File->CurrentPos); } // // This is a normal cluster based file // while (*Size) { DivU64x32Remainder (File->CurrentPos, ClusterSize, &Offset); Status = FatGetClusterPos (PrivateData, File->Volume, File->CurrentCluster, &PhysicalAddr); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } Amount = File->StraightReadAmount; Amount = *Size > Amount ? Amount : *Size; Status = FatWriteDisk ( PrivateData, File->Volume->BlockDeviceNo, PhysicalAddr + Offset, Amount, BufferPtr ); if (EFI_ERROR (Status)) { return Status; } // // Advance the file's current pos and current cluster // FatSetFilePos (PrivateData, File, (UINT32) Amount, FALSE); BufferPtr += Amount; *Size -= Amount; TotalAmount += Amount; // // if this is the end of cluster chain? // if (FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster)) { *Size = TotalAmount; return EFI_SUCCESS; } } *Size = TotalAmount; return Status; } } /** This function reads the next item in the parent directory and initializes the output parameter SubFile (CurrentPos is initialized to 0). The function updates the CurrentPos of the parent dir to after the item read. If no more items were found, the function returns EFI_NOT_FOUND. @param[in] PrivateData Global memory map for accessing global variables @param[in] ParentDir The parent directory @param[out] SubFile The retrieved file @retval EFI_SUCCESS The next sub file is successfully retrieved. @retval EFI_INVALID_PARAMETER The ParentDir is not a directory. @retval EFI_NOT_FOUND No more sub file found @retval EFI_DEVICE_ERROR Something error while accessing media. **/ EFI_STATUS FatReadNextSubFile ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_FILE *ParentDir, OUT PEI_FAT_FILE *SubFile ) { EFI_STATUS Status; UINTN Dummy; UINTN DataSize; FAT_DIRECTORY_ENTRY DirEntryBuffer; FAT_DIRECTORY_ENTRY *DirEntry; FAT_DIRECTORY_LFN *LfnEntry; UINT8 LfnOrdinal; UINT8 LfnChecksum; CHAR16 *Pos; BOOLEAN IsInvalidEntry; UINT64 CurrentPos; CHAR16 BaseName[9]; CHAR16 Ext[4]; Status = EFI_SUCCESS; DirEntry = (FAT_DIRECTORY_ENTRY *) &DirEntryBuffer; LfnEntry = (FAT_DIRECTORY_LFN *) &DirEntryBuffer; (*PrivateData->PeiServices)->SetMem ((UINT8 *) SubFile, sizeof (PEI_FAT_FILE), 0); ParentDir->FileLastCluster = ParentDir->CurrentCluster; // // Check the parameter // if (!(ParentDir->Attributes & FAT_ATTR_DIRECTORY)) { return EFI_INVALID_PARAMETER; } CurrentPos = ParentDir->CurrentPos; DivU64x32Remainder (CurrentPos, FILE_DESCRIPTION_BLOCK_SIZE, &Dummy); if (Dummy) { return EFI_INVALID_PARAMETER; } // // Pick a valid directory entry // while (1) { IsInvalidEntry = FALSE; // // Read one entry // DataSize = FILE_DESCRIPTION_BLOCK_SIZE; Status = FatReadFile (PrivateData, ParentDir, &DataSize, &DirEntryBuffer); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } if (ParentDir->FileLastCluster != ParentDir->CurrentCluster && ParentDir->CurrentCluster != FAT_CLUSTER_LAST) { ParentDir->FileLastCluster = ParentDir->CurrentCluster; } DirEntry = (FAT_DIRECTORY_ENTRY *) &DirEntryBuffer; LfnEntry = (FAT_DIRECTORY_LFN *) &DirEntryBuffer; if (DataSize < FILE_DESCRIPTION_BLOCK_SIZE) { return EFI_NOT_FOUND; } // // Just read the 8Dot3 name here, if it's the beginning of a lfn, // we will overwrite it soon // EngFatToStr (FAT_MAIN_NAME_LEN, DirEntry->FileName, BaseName); EngFatToStr (FAT_EXTEND_NAME_LEN, DirEntry->FileName + FAT_MAIN_NAME_LEN, Ext); Pos = (UINT16 *) SubFile->FileName; SetMem ((UINT8 *) Pos, FAT_MAX_FILE_NAME_LENGTH, 0); CopyMem ((UINT8 *) Pos, (UINT8 *) BaseName, StrSize (BaseName)); if (Ext[0] != 0) { Pos += StrLen (BaseName); *Pos = '.'; Pos++; CopyMem ((UINT8 *) Pos, (UINT8 *) Ext, StrSize (Ext)); } // // If the entry is the start of a long file name, start processing it // if (DirEntry->Attributes == FAT_ATTR_LFN && LfnEntry->MustBeZero == 0 && (LfnEntry->Ordinal & FAT_LFN_LAST) && (LfnEntry->Ordinal &~FAT_LFN_LAST) > 0 && (LfnEntry->Ordinal &~FAT_LFN_LAST) < FAT_MAX_LFN_ENTRIES ) { LfnOrdinal = (UINT8) (LfnEntry->Ordinal &~FAT_LFN_LAST); LfnChecksum = LfnEntry->Checksum; // // Loop and read each portion of the name // for (;;) { // // Copy this portion of the name to the file string // if ((LfnOrdinal - 1) * 13 < FAT_MAX_FILE_NAME_LENGTH) { Pos = SubFile->FileName + (LfnOrdinal - 1) * 13; } else { // // If the file name is more than FAT_MAX_FILE_NAME_LENGTH, // set the positiion to the last. // Pos = SubFile->FileName + FAT_MAX_FILE_NAME_LENGTH - 1; } if (Pos + 12 < (SubFile->FileName + FAT_MAX_FILE_NAME_LENGTH)) { CopyMem ((UINT8 *) (Pos + 0), (UINT8 *) LfnEntry->Name1, sizeof (CHAR16) * 5); CopyMem ((UINT8 *) (Pos + 5), (UINT8 *) LfnEntry->Name2, sizeof (CHAR16) * 6); CopyMem ((UINT8 *) (Pos + 11), (UINT8 *) LfnEntry->Name3, sizeof (CHAR16) * 2); } // // If this is the last LFN dir entry, stop // LfnOrdinal -= 1; if (LfnOrdinal == 0) { break; } // // Read next name fragment // DataSize = FILE_DESCRIPTION_BLOCK_SIZE; Status = FatReadFile (PrivateData, ParentDir, &DataSize, &DirEntryBuffer); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } DirEntry = (FAT_DIRECTORY_ENTRY *) &DirEntryBuffer; LfnEntry = (FAT_DIRECTORY_LFN *) &DirEntryBuffer; if (DataSize < FILE_DESCRIPTION_BLOCK_SIZE) { return EFI_NOT_FOUND; } // // If something is wrong with the entry, just return it as unknown // if (DirEntry->Attributes != FAT_ATTR_LFN || LfnEntry->MustBeZero != 0 || LfnEntry->Ordinal != LfnOrdinal || LfnEntry->Checksum != LfnChecksum ) { IsInvalidEntry = TRUE; break; } } // // end of Lfn entries reading // // Read the 8.3 file entry for this lfn // DataSize = FILE_DESCRIPTION_BLOCK_SIZE; Status = FatReadFile (PrivateData, ParentDir, &DataSize, &DirEntryBuffer); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } DirEntry = (FAT_DIRECTORY_ENTRY *) &DirEntryBuffer; LfnEntry = (FAT_DIRECTORY_LFN *) &DirEntryBuffer; if (DataSize < FILE_DESCRIPTION_BLOCK_SIZE) { return EFI_NOT_FOUND; } // // Verify the LFN is for this entry // if (FatDirEntryChecksum (DirEntry) != LfnChecksum) { IsInvalidEntry = TRUE; } } // // end of Lfn processing // // if this is a terminator dir entry, just return EFI_NOT_FOUND // if (DirEntry->FileName[0] == 0) { return EFI_NOT_FOUND; } // // If this not an invalid entry neither an empty entry, this is what we want. // otherwise we will start a new loop to continue to find something meaningful // if (!IsInvalidEntry && DirEntry->FileName[0] != (CHAR8)(UINT8)DELETE_ENTRY_MARK) { break; } } // // fill in the output parameter // CurrentPos = ParentDir->CurrentPos - FILE_DESCRIPTION_BLOCK_SIZE; DivU64x32Remainder (CurrentPos, ParentDir->Volume->ClusterSize, &Dummy); SubFile->Attributes = DirEntry->Attributes; SubFile->CurrentCluster = DirEntry->FileClusterHigh << 16 | DirEntry->FileCluster; SubFile->CurrentPos = 0; SubFile->DirEntryOffset = Dummy; SubFile->FileSize = DirEntry->FileSize; SubFile->DirEntryCluster = ParentDir->CurrentCluster; SubFile->StartingCluster = SubFile->CurrentCluster; SubFile->FileLastCluster = 0; SubFile->Volume = ParentDir->Volume; SubFile->IsRootDir = FALSE; CopyMem ((UINT8 *)&SubFile->FileDir, (UINT8 *) &DirEntryBuffer, sizeof (FAT_DIRECTORY_ENTRY)); if (SubFile->StartingCluster) { Status = FatSetFilePos (PrivateData, SubFile, 0, TRUE); } // // in Pei phase, time parameters do not need to be filled for minimum use. // return Status; } /** Construct root dir file instance for a volume @param[in] PrivateData Pointer to the PEF_FAT_PRIVATE_DATA structure @param[in] Volume Pointer to the PEI_FAT_VOLUME structure @param[out] RootDir The retrieved root directory @retval EFI_SUCCESS The root directory is successfully retrieved. @retval EFI_INVALID_PARAMETER The volume instance is invalid. @retval EFI_DEVICE_ERROR Something error while accessing media. **/ EFI_STATUS FatGetRootDir ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_VOLUME *Volume, OUT PEI_FAT_FILE *RootDir ) { RootDir->IsRootDir = TRUE; RootDir->IsFixedRootDir = (BOOLEAN) ((Volume->FatType == Fat32) ? FALSE : TRUE); RootDir->Attributes = FAT_ATTR_DIRECTORY; RootDir->CurrentPos = 0; RootDir->CurrentCluster = RootDir->IsFixedRootDir ? 0 : Volume->RootDirCluster; RootDir->StartingCluster = RootDir->CurrentCluster; RootDir->Volume = Volume; RootDir->FileLastCluster = 0; return FatSetFilePos (PrivateData, RootDir, 0, TRUE); } /** Search the Root directory entry for the possible volume label. @param[in] PrivateData Pointer to the PEF_FAT_PRIVATE_DATA structure @param[in] ParentDir The parent directory. @param[out] DirEnt The returned directory entry of volume label. @retval EFI_SUCCESS The search process is completed successfully. @return others An error occurred while searching volume label. **/ EFI_STATUS FatFindVolumeLabel ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_FILE *ParentDir, OUT FAT_DIRECTORY_ENTRY *DirEnt ) { EFI_STATUS Status; UINT16 EntryPos; FAT_DIRECTORY_ENTRY *Entry; UINTN BufferSize; EntryPos = 0; Entry = DirEnt; BufferSize = sizeof (FAT_DIRECTORY_ENTRY); do { Status = FatReadFile (PrivateData, ParentDir, &BufferSize, Entry); if (EFI_ERROR (Status)) { return Status; } if ((Entry->FileName[0] != FAT_DELETE_ENTRY_MARK) && (((Entry->Attributes) & (~FAT_ATTR_ARCHIVE)) == FAT_ATTR_VOLUME_ID)) { break; } EntryPos++; } while (Entry->FileName[0] != FAT_EMPTY_ENTRY_MARK); return EFI_SUCCESS; } /** Write zero value start from file's CurrentPos to the end of File. @param[in] PrivateData Pointer to the PEF_FAT_PRIVATE_DATA structure @param[in] File The fat file struct. @retval EFI_SUCCESS Write the zero value successfully. @retval EFI_OUT_OF_RESOURCES Not enough memory to perform the operation. @return others An error occurred when writing disk. **/ EFI_STATUS FatWriteZeroPool ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_FILE *File ) { EFI_STATUS Status; VOID *ZeroBuffer; UINTN AppendedSize; UINTN WriteSize; AppendedSize = File->FileSize - File->CurrentPos; ZeroBuffer = PrivateData->ZeroPool; do { WriteSize = AppendedSize > PEI_FAT_MAX_BLOCK_SIZE ? PEI_FAT_MAX_BLOCK_SIZE : (UINTN) AppendedSize; AppendedSize -= WriteSize; Status = FatWriteFile (PrivateData, File, &WriteSize, ZeroBuffer); if (EFI_ERROR (Status)) { break; } } while (AppendedSize > 0); return Status; }