From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/FatPkg/EnhancedFatDxe/ReadWrite.c | 620 ++++++++++++++++++++++++++++ 1 file changed, 620 insertions(+) create mode 100644 roms/edk2/FatPkg/EnhancedFatDxe/ReadWrite.c (limited to 'roms/edk2/FatPkg/EnhancedFatDxe/ReadWrite.c') diff --git a/roms/edk2/FatPkg/EnhancedFatDxe/ReadWrite.c b/roms/edk2/FatPkg/EnhancedFatDxe/ReadWrite.c new file mode 100644 index 000000000..07bed7003 --- /dev/null +++ b/roms/edk2/FatPkg/EnhancedFatDxe/ReadWrite.c @@ -0,0 +1,620 @@ +/** @file + Functions that perform file read/write. + +Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +#include "Fat.h" + +/** + + Get the file's position of the file. + + + @param FHand - The handle of file. + @param Position - The file's position of the file. + + @retval EFI_SUCCESS - Get the info successfully. + @retval EFI_DEVICE_ERROR - Can not find the OFile for the file. + @retval EFI_UNSUPPORTED - The open file is not a file. + +**/ +EFI_STATUS +EFIAPI +FatGetPosition ( + IN EFI_FILE_PROTOCOL *FHand, + OUT UINT64 *Position + ) +{ + FAT_IFILE *IFile; + FAT_OFILE *OFile; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + + if (OFile->Error == EFI_NOT_FOUND) { + return EFI_DEVICE_ERROR; + } + + if (OFile->ODir != NULL) { + return EFI_UNSUPPORTED; + } + + *Position = IFile->Position; + return EFI_SUCCESS; +} + +/** + + Set the file's position of the file. + + @param FHand - The handle of file. + @param Position - The file's position of the file. + + @retval EFI_SUCCESS - Set the info successfully. + @retval EFI_DEVICE_ERROR - Can not find the OFile for the file. + @retval EFI_UNSUPPORTED - Set a directory with a not-zero position. + +**/ +EFI_STATUS +EFIAPI +FatSetPosition ( + IN EFI_FILE_PROTOCOL *FHand, + IN UINT64 Position + ) +{ + FAT_IFILE *IFile; + FAT_OFILE *OFile; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + + if (OFile->Error == EFI_NOT_FOUND) { + return EFI_DEVICE_ERROR; + } + + FatWaitNonblockingTask (IFile); + + // + // If this is a directory, we can only set back to position 0 + // + if (OFile->ODir != NULL) { + if (Position != 0) { + // + // Reset current directory cursor; + // + return EFI_UNSUPPORTED; + } + + FatResetODirCursor (OFile); + } + // + // Set the position + // + if (Position == (UINT64)-1) { + Position = OFile->FileSize; + } + // + // Set the position + // + IFile->Position = Position; + return EFI_SUCCESS; +} + +/** + + Get the file info from the open file of the IFile into Buffer. + + @param IFile - The instance of the open file. + @param BufferSize - Size of Buffer. + @param Buffer - Buffer containing read data. + + @retval EFI_SUCCESS - Get the file info successfully. + @retval other - An error occurred when operation the disk. + +**/ +EFI_STATUS +FatIFileReadDir ( + IN FAT_IFILE *IFile, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + FAT_OFILE *OFile; + FAT_ODIR *ODir; + FAT_DIRENT *DirEnt; + UINT32 CurrentPos; + + OFile = IFile->OFile; + ODir = OFile->ODir; + CurrentPos = ((UINT32) IFile->Position) / sizeof (FAT_DIRECTORY_ENTRY); + + // + // We need to relocate the directory + // + if (CurrentPos < ODir->CurrentPos) { + // + // The directory cursor has been modified by another IFile, we reset the cursor + // + FatResetODirCursor (OFile); + } + // + // We seek the next directory entry's position + // + do { + Status = FatGetNextDirEnt (OFile, &DirEnt); + if (EFI_ERROR (Status) || DirEnt == NULL) { + // + // Something error occurred or reach the end of directory, + // return 0 buffersize + // + *BufferSize = 0; + goto Done; + } + } while (ODir->CurrentPos <= CurrentPos); + Status = FatGetDirEntInfo (OFile->Volume, DirEnt, BufferSize, Buffer); + +Done: + // + // Update IFile's Position + // + if (!EFI_ERROR (Status)) { + // + // Update IFile->Position, if everything is all right + // + CurrentPos = ODir->CurrentPos; + IFile->Position = CurrentPos * sizeof (FAT_DIRECTORY_ENTRY); + } + + return Status; +} + +/** + + Get the file info from the open file of the IFile into Buffer. + + @param FHand - The file handle to access. + @param IoMode - Indicate whether the access mode is reading or writing. + @param BufferSize - Size of Buffer. + @param Buffer - Buffer containing read data. + @param Token - A pointer to the token associated with the transaction. + + @retval EFI_SUCCESS - Get the file info successfully. + @retval EFI_DEVICE_ERROR - Can not find the OFile for the file. + @retval EFI_VOLUME_CORRUPTED - The file type of open file is error. + @retval EFI_WRITE_PROTECTED - The disk is write protect. + @retval EFI_ACCESS_DENIED - The file is read-only. + @return other - An error occurred when operating on the disk. + +**/ +EFI_STATUS +FatIFileAccess ( + IN EFI_FILE_PROTOCOL *FHand, + IN IO_MODE IoMode, + IN OUT UINTN *BufferSize, + IN OUT VOID *Buffer, + IN EFI_FILE_IO_TOKEN *Token + ) +{ + EFI_STATUS Status; + FAT_IFILE *IFile; + FAT_OFILE *OFile; + FAT_VOLUME *Volume; + UINT64 EndPosition; + FAT_TASK *Task; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + Volume = OFile->Volume; + Task = NULL; + + // + // Write to a directory is unsupported + // + if ((OFile->ODir != NULL) && (IoMode == WriteData)) { + return EFI_UNSUPPORTED; + } + + if (OFile->Error == EFI_NOT_FOUND) { + return EFI_DEVICE_ERROR; + } + + if (IoMode == ReadData) { + // + // If position is at EOF, then return device error + // + if (IFile->Position > OFile->FileSize) { + return EFI_DEVICE_ERROR; + } + } else { + // + // Check if the we can write data + // + if (Volume->ReadOnly) { + return EFI_WRITE_PROTECTED; + } + + if (IFile->ReadOnly) { + return EFI_ACCESS_DENIED; + } + } + + if (Token == NULL) { + FatWaitNonblockingTask (IFile); + } else { + // + // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2. + // But if it calls, the below check can avoid crash. + // + if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) { + return EFI_UNSUPPORTED; + } + Task = FatCreateTask (IFile, Token); + if (Task == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + FatAcquireLock (); + + Status = OFile->Error; + if (!EFI_ERROR (Status)) { + if (OFile->ODir != NULL) { + // + // Read a directory is supported + // + ASSERT (IoMode == ReadData); + Status = FatIFileReadDir (IFile, BufferSize, Buffer); + OFile = NULL; + } else { + // + // Access a file + // + EndPosition = IFile->Position + *BufferSize; + if (EndPosition > OFile->FileSize) { + // + // The position goes beyond the end of file + // + if (IoMode == ReadData) { + // + // Adjust the actual size read + // + *BufferSize -= (UINTN) EndPosition - OFile->FileSize; + } else { + // + // We expand the file size of OFile + // + Status = FatGrowEof (OFile, EndPosition); + if (EFI_ERROR (Status)) { + // + // Must update the file's info into the file's Directory Entry + // and then flush the dirty cache info into disk. + // + *BufferSize = 0; + FatOFileFlush (OFile); + OFile = NULL; + goto Done; + } + + FatUpdateDirEntClusterSizeInfo (OFile); + } + } + + Status = FatAccessOFile (OFile, IoMode, (UINTN) IFile->Position, BufferSize, Buffer, Task); + IFile->Position += *BufferSize; + } + } + + if (Token != NULL) { + if (!EFI_ERROR (Status)) { + Status = FatQueueTask (IFile, Task); + } else { + FatDestroyTask (Task); + } + } + +Done: + // + // On EFI_SUCCESS case, not calling FatCleanupVolume(): + // 1) The Cache flush operation is avoided to enhance + // performance. Caller is responsible to call Flush() when necessary. + // 2) The volume dirty bit is probably set already, and is expected to be + // cleaned in subsequent Flush() or other operations. + // 3) Write operation doesn't affect OFile/IFile structure, so + // Reference checking is not necessary. + // + if (EFI_ERROR (Status)) { + Status = FatCleanupVolume (Volume, OFile, Status, NULL); + } + + FatReleaseLock (); + return Status; +} + +/** + + Get the file info. + + @param FHand - The handle of the file. + @param BufferSize - Size of Buffer. + @param Buffer - Buffer containing read data. + + + @retval EFI_SUCCESS - Get the file info successfully. + @retval EFI_DEVICE_ERROR - Can not find the OFile for the file. + @retval EFI_VOLUME_CORRUPTED - The file type of open file is error. + @return other - An error occurred when operation the disk. + +**/ +EFI_STATUS +EFIAPI +FatRead ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + return FatIFileAccess (FHand, ReadData, BufferSize, Buffer, NULL); +} + +/** + + Get the file info. + + @param FHand - The handle of the file. + @param Token - A pointer to the token associated with the transaction. + + @retval EFI_SUCCESS - Get the file info successfully. + @retval EFI_DEVICE_ERROR - Can not find the OFile for the file. + @retval EFI_VOLUME_CORRUPTED - The file type of open file is error. + @return other - An error occurred when operation the disk. + +**/ +EFI_STATUS +EFIAPI +FatReadEx ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT EFI_FILE_IO_TOKEN *Token + ) +{ + return FatIFileAccess (FHand, ReadData, &Token->BufferSize, Token->Buffer, Token); +} + +/** + + Write the content of buffer into files. + + @param FHand - The handle of the file. + @param BufferSize - Size of Buffer. + @param Buffer - Buffer containing write data. + + @retval EFI_SUCCESS - Set the file info successfully. + @retval EFI_WRITE_PROTECTED - The disk is write protect. + @retval EFI_ACCESS_DENIED - The file is read-only. + @retval EFI_DEVICE_ERROR - The OFile is not valid. + @retval EFI_UNSUPPORTED - The open file is not a file. + - The writing file size is larger than 4GB. + @return other - An error occurred when operation the disk. + +**/ +EFI_STATUS +EFIAPI +FatWrite ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + return FatIFileAccess (FHand, WriteData, BufferSize, Buffer, NULL); +} + +/** + + Get the file info. + + @param FHand - The handle of the file. + @param Token - A pointer to the token associated with the transaction. + + @retval EFI_SUCCESS - Get the file info successfully. + @retval EFI_DEVICE_ERROR - Can not find the OFile for the file. + @retval EFI_VOLUME_CORRUPTED - The file type of open file is error. + @return other - An error occurred when operation the disk. + +**/ +EFI_STATUS +EFIAPI +FatWriteEx ( + IN EFI_FILE_PROTOCOL *FHand, + IN OUT EFI_FILE_IO_TOKEN *Token + ) +{ + return FatIFileAccess (FHand, WriteData, &Token->BufferSize, Token->Buffer, Token); +} + +/** + + This function reads data from a file or writes data to a file. + It uses OFile->PosRem to determine how much data can be accessed in one time. + + @param OFile - The open file. + @param IoMode - Indicate whether the access mode is reading or writing. + @param Position - The position where data will be accessed. + @param DataBufferSize - Size of Buffer. + @param UserBuffer - Buffer containing data. + @param Task point to task instance. + + @retval EFI_SUCCESS - Access the data successfully. + @return other - An error occurred when operating on the disk. + +**/ +EFI_STATUS +FatAccessOFile ( + IN FAT_OFILE *OFile, + IN IO_MODE IoMode, + IN UINTN Position, + IN OUT UINTN *DataBufferSize, + IN OUT UINT8 *UserBuffer, + IN FAT_TASK *Task + ) +{ + FAT_VOLUME *Volume; + UINTN Len; + EFI_STATUS Status; + UINTN BufferSize; + + BufferSize = *DataBufferSize; + Volume = OFile->Volume; + ASSERT_VOLUME_LOCKED (Volume); + + Status = EFI_SUCCESS; + while (BufferSize > 0) { + // + // Seek the OFile to the file position + // + Status = FatOFilePosition (OFile, Position, BufferSize); + if (EFI_ERROR (Status)) { + break; + } + // + // Clip length to block run + // + Len = BufferSize > OFile->PosRem ? OFile->PosRem : BufferSize; + + // + // Write the data + // + Status = FatDiskIo (Volume, IoMode, OFile->PosDisk, Len, UserBuffer, Task); + if (EFI_ERROR (Status)) { + break; + } + // + // Data was successfully accessed + // + Position += Len; + UserBuffer += Len; + BufferSize -= Len; + if (IoMode == WriteData) { + OFile->Dirty = TRUE; + OFile->Archive = TRUE; + } + // + // Make sure no outbound occurred + // + ASSERT (Position <= OFile->FileSize); + } + // + // Update the number of bytes accessed + // + *DataBufferSize -= BufferSize; + return Status; +} + +/** + + Expand OFile by appending zero bytes at the end of OFile. + + @param OFile - The open file. + @param ExpandedSize - The number of zero bytes appended at the end of the file. + + @retval EFI_SUCCESS - The file is expanded successfully. + @return other - An error occurred when expanding file. + +**/ +EFI_STATUS +FatExpandOFile ( + IN FAT_OFILE *OFile, + IN UINT64 ExpandedSize + ) +{ + EFI_STATUS Status; + UINTN WritePos; + + WritePos = OFile->FileSize; + Status = FatGrowEof (OFile, ExpandedSize); + if (!EFI_ERROR (Status)) { + Status = FatWriteZeroPool (OFile, WritePos); + } + + return Status; +} + +/** + + Write zero pool from the WritePos to the end of OFile. + + @param OFile - The open file to write zero pool. + @param WritePos - The number of zero bytes written. + + @retval EFI_SUCCESS - Write the zero pool successfully. + @retval EFI_OUT_OF_RESOURCES - Not enough memory to perform the operation. + @return other - An error occurred when writing disk. + +**/ +EFI_STATUS +FatWriteZeroPool ( + IN FAT_OFILE *OFile, + IN UINTN WritePos + ) +{ + EFI_STATUS Status; + VOID *ZeroBuffer; + UINTN AppendedSize; + UINTN BufferSize; + UINTN WriteSize; + + AppendedSize = OFile->FileSize - WritePos; + BufferSize = AppendedSize; + if (AppendedSize > FAT_MAX_ALLOCATE_SIZE) { + // + // If the appended size is larger, maybe we can not allocate the whole + // memory once. So if the growed size is larger than 10M, we just + // allocate 10M memory (one healthy system should have 10M available + // memory), and then write the zerobuffer to the file several times. + // + BufferSize = FAT_MAX_ALLOCATE_SIZE; + } + + ZeroBuffer = AllocateZeroPool (BufferSize); + if (ZeroBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + do { + WriteSize = AppendedSize > BufferSize ? BufferSize : (UINTN) AppendedSize; + AppendedSize -= WriteSize; + Status = FatAccessOFile (OFile, WriteData, WritePos, &WriteSize, ZeroBuffer, NULL); + if (EFI_ERROR (Status)) { + break; + } + + WritePos += WriteSize; + } while (AppendedSize > 0); + + FreePool (ZeroBuffer); + return Status; +} + +/** + + Truncate the OFile to smaller file size. + + @param OFile - The open file. + @param TruncatedSize - The new file size. + + @retval EFI_SUCCESS - The file is truncated successfully. + @return other - An error occurred when truncating file. + +**/ +EFI_STATUS +FatTruncateOFile ( + IN FAT_OFILE *OFile, + IN UINTN TruncatedSize + ) +{ + OFile->FileSize = TruncatedSize; + return FatShrinkEof (OFile); +} -- cgit 1.2.3-korg