aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/FatPkg/EnhancedFatDxe/ReadWrite.c
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/FatPkg/EnhancedFatDxe/ReadWrite.c
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/FatPkg/EnhancedFatDxe/ReadWrite.c')
-rw-r--r--roms/edk2/FatPkg/EnhancedFatDxe/ReadWrite.c620
1 files changed, 620 insertions, 0 deletions
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.<BR>
+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);
+}