--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005, Intel Corporation\r
+All rights reserved. This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ ReadWrite.c\r
+\r
+Abstract:\r
+\r
+ Functions that perform file read/write\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatGetPosition (\r
+ IN EFI_FILE *FHand,\r
+ OUT UINT64 *Position\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file's position of the file.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of file.\r
+ Position - The file's position of the file.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_UNSUPPORTED - The open file is not a file.\r
+\r
+--*/\r
+{\r
+ FAT_IFILE *IFile;\r
+ FAT_OFILE *OFile;\r
+\r
+ IFile = IFILE_FROM_FHAND (FHand);\r
+ OFile = IFile->OFile;\r
+\r
+ if (OFile->Error == EFI_NOT_FOUND) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (OFile->ODir != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ *Position = IFile->Position;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatSetPosition (\r
+ IN EFI_FILE *FHand,\r
+ IN UINT64 Position\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the file's position of the file.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of file.\r
+ Position - The file's position of the file.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_UNSUPPORTED - Set a directory with a not-zero position.\r
+\r
+--*/\r
+{\r
+ FAT_IFILE *IFile;\r
+ FAT_OFILE *OFile;\r
+\r
+ IFile = IFILE_FROM_FHAND (FHand);\r
+ OFile = IFile->OFile;\r
+\r
+ if (OFile->Error == EFI_NOT_FOUND) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // If this is a directory, we can only set back to position 0\r
+ //\r
+ if (OFile->ODir != NULL) {\r
+ if (Position != 0) {\r
+ //\r
+ // Reset current directory cursor;\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ FatResetODirCursor (OFile);\r
+ }\r
+ //\r
+ // Set the position\r
+ //\r
+ if (Position == -1) {\r
+ Position = OFile->FileSize;\r
+ }\r
+ //\r
+ // Set the position\r
+ //\r
+ IFile->Position = Position;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatIFileReadDir (\r
+ IN FAT_IFILE *IFile,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file info from the open file of the IFile into Buffer.\r
+\r
+Arguments:\r
+\r
+ IFile - The instance of the open file.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing read data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_OFILE *OFile;\r
+ FAT_ODIR *ODir;\r
+ FAT_DIRENT *DirEnt;\r
+ UINT32 CurrentPos;\r
+\r
+ OFile = IFile->OFile;\r
+ ODir = OFile->ODir;\r
+ CurrentPos = ((UINT32) IFile->Position) / sizeof (FAT_DIRECTORY_ENTRY);\r
+\r
+ //\r
+ // We need to relocate the directory\r
+ //\r
+ if (CurrentPos < ODir->CurrentPos) {\r
+ //\r
+ // The directory cursor has been modified by another IFile, we reset the cursor\r
+ //\r
+ FatResetODirCursor (OFile);\r
+ }\r
+ //\r
+ // We seek the next directory entry's position\r
+ //\r
+ do {\r
+ Status = FatGetNextDirEnt (OFile, &DirEnt);\r
+ if (EFI_ERROR (Status) || DirEnt == NULL) {\r
+ //\r
+ // Something error occurred or reach the end of directory,\r
+ // return 0 buffersize\r
+ //\r
+ *BufferSize = 0;\r
+ goto Done;\r
+ }\r
+ } while (ODir->CurrentPos <= CurrentPos);\r
+ Status = FatGetDirEntInfo (OFile->Volume, DirEnt, BufferSize, Buffer);\r
+\r
+Done:\r
+ //\r
+ // Update IFile's Position\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Update IFile->Position, if everything is all right\r
+ //\r
+ CurrentPos = ODir->CurrentPos;\r
+ IFile->Position = (UINT64) (CurrentPos * sizeof (FAT_DIRECTORY_ENTRY));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatIFileAccess (\r
+ IN EFI_FILE *FHand,\r
+ IN IO_MODE IoMode,\r
+ IN OUT UINTN *BufferSize,\r
+ IN OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file info from the open file of the IFile into Buffer.\r
+\r
+Arguments:\r
+\r
+ FHand - The file handle to access.\r
+ IoMode - Indicate whether the access mode is reading or writing.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing read data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.\r
+ EFI_WRITE_PROTECTED - The disk is write protect.\r
+ EFI_ACCESS_DENIED - The file is read-only.\r
+ other - An error occurred when operating on the disk.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_IFILE *IFile;\r
+ FAT_OFILE *OFile;\r
+ FAT_VOLUME *Volume;\r
+ UINT64 EndPosition;\r
+\r
+ IFile = IFILE_FROM_FHAND (FHand);\r
+ OFile = IFile->OFile;\r
+ Volume = OFile->Volume;\r
+\r
+ if (OFile->Error == EFI_NOT_FOUND) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (IoMode == READ_DATA) {\r
+ //\r
+ // If position is at EOF, then return device error\r
+ //\r
+ if (IFile->Position > OFile->FileSize) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ } else {\r
+ //\r
+ // Check if the we can write data\r
+ //\r
+ if (Volume->ReadOnly) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ if (IFile->ReadOnly) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ }\r
+\r
+ FatAcquireLock ();\r
+\r
+ Status = OFile->Error;\r
+ if (!EFI_ERROR (Status)) {\r
+ if (OFile->ODir != NULL) {\r
+ //\r
+ // Access a directory\r
+ //\r
+ Status = EFI_UNSUPPORTED;\r
+ if (IoMode == READ_DATA) {\r
+ //\r
+ // Read a directory is supported\r
+ //\r
+ Status = FatIFileReadDir (IFile, BufferSize, Buffer);\r
+ }\r
+\r
+ OFile = NULL;\r
+ } else {\r
+ //\r
+ // Access a file\r
+ //\r
+ EndPosition = IFile->Position + *BufferSize;\r
+ if (EndPosition > OFile->FileSize) {\r
+ //\r
+ // The position goes beyond the end of file\r
+ //\r
+ if (IoMode == READ_DATA) {\r
+ //\r
+ // Adjust the actual size read\r
+ //\r
+ *BufferSize -= (UINTN) EndPosition - OFile->FileSize;\r
+ } else {\r
+ //\r
+ // We expand the file size of OFile\r
+ //\r
+ Status = FatGrowEof (OFile, EndPosition);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Must update the file's info into the file's Directory Entry\r
+ // and then flush the dirty cache info into disk.\r
+ //\r
+ *BufferSize = 0;\r
+ FatOFileFlush (OFile);\r
+ OFile = NULL;\r
+ goto Done;\r
+ }\r
+\r
+ FatUpdateDirEntClusterSizeInfo (OFile);\r
+ }\r
+ }\r
+\r
+ Status = FatAccessOFile (OFile, IoMode, (UINTN) IFile->Position, BufferSize, Buffer);\r
+ IFile->Position += *BufferSize;\r
+ }\r
+ }\r
+\r
+Done:\r
+ if (EFI_ERROR (Status)) {\r
+ Status = FatCleanupVolume (Volume, OFile, Status);\r
+ }\r
+ //\r
+ // On EFI_SUCCESS case, not calling FatCleanupVolume():\r
+ // 1) The Cache flush operation is avoided to enhance\r
+ // performance. Caller is responsible to call Flush() when necessary.\r
+ // 2) The volume dirty bit is probably set already, and is expected to be\r
+ // cleaned in subsequent Flush() or other operations.\r
+ // 3) Write operation doesn't affect OFile/IFile structure, so\r
+ // Reference checking is not necessary.\r
+ //\r
+ FatReleaseLock ();\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatRead (\r
+ IN EFI_FILE *FHand,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file info.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of the file.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing read data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+ return FatIFileAccess (FHand, READ_DATA, BufferSize, Buffer);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatWrite (\r
+ IN EFI_FILE *FHand,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Write the content of buffer into files.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of the file.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing write data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the file info successfully.\r
+ EFI_WRITE_PROTECTED - The disk is write protect.\r
+ EFI_ACCESS_DENIED - The file is read-only.\r
+ EFI_DEVICE_ERROR - The OFile is not valid.\r
+ EFI_UNSUPPORTED - The open file is not a file.\r
+ - The writing file size is larger than 4GB.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+ return FatIFileAccess (FHand, WRITE_DATA, BufferSize, Buffer);\r
+}\r
+\r
+EFI_STATUS\r
+FatAccessOFile (\r
+ IN FAT_OFILE *OFile,\r
+ IN IO_MODE IoMode,\r
+ IN UINTN Position,\r
+ IN OUT UINTN *DataBufferSize,\r
+ IN OUT UINT8 *UserBuffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function reads data from a file or writes data to a file.\r
+ It uses OFile->PosRem to determine how much data can be accessed in one time.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file.\r
+ IoMode - Indicate whether the access mode is reading or writing.\r
+ Position - The position where data will be accessed.\r
+ DataBufferSize - Size of Buffer.\r
+ UserBuffer - Buffer containing data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Access the data successfully.\r
+ other - An error occurred when operating on the disk.\r
+\r
+--*/\r
+{\r
+ FAT_VOLUME *Volume;\r
+ UINTN Len;\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+\r
+ BufferSize = *DataBufferSize;\r
+ Volume = OFile->Volume;\r
+ ASSERT_VOLUME_LOCKED (Volume);\r
+\r
+ Status = EFI_SUCCESS;\r
+ while (BufferSize > 0) {\r
+ //\r
+ // Seek the OFile to the file position\r
+ //\r
+ Status = FatOFilePosition (OFile, Position, BufferSize);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ //\r
+ // Clip length to block run\r
+ //\r
+ Len = BufferSize > OFile->PosRem ? OFile->PosRem : BufferSize;\r
+\r
+ //\r
+ // Write the data\r
+ //\r
+ Status = FatDiskIo (Volume, IoMode, OFile->PosDisk, Len, UserBuffer);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ //\r
+ // Data was successfully accessed\r
+ //\r
+ Position += Len;\r
+ UserBuffer += Len;\r
+ BufferSize -= Len;\r
+ if (IoMode == WRITE_DATA) {\r
+ OFile->Dirty = TRUE;\r
+ OFile->Archive = TRUE;\r
+ }\r
+ //\r
+ // Make sure no outbound occurred\r
+ //\r
+ ASSERT (Position <= OFile->FileSize);\r
+ }\r
+ //\r
+ // Update the number of bytes accessed\r
+ //\r
+ *DataBufferSize -= BufferSize;\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatExpandOFile (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINT64 ExpandedSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Expand OFile by appending zero bytes at the end of OFile.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file.\r
+ ExpandedSize - The number of zero bytes appended at the end of the file.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The file is expanded successfully.\r
+ other - An error occurred when expanding file.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN WritePos;\r
+\r
+ WritePos = OFile->FileSize;\r
+ Status = FatGrowEof (OFile, ExpandedSize);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = FatWriteZeroPool (OFile, WritePos);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatWriteZeroPool (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINTN WritePos\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Write zero pool from the WritePos to the end of OFile.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file to write zero pool.\r
+ WritePos - The number of zero bytes written.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Write the zero pool successfully.\r
+ EFI_OUT_OF_RESOURCES - Not enough memory to perform the operation.\r
+ other - An error occurred when writing disk.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *ZeroBuffer;\r
+ UINTN AppendedSize;\r
+ UINTN BufferSize;\r
+ UINTN WriteSize;\r
+\r
+ AppendedSize = OFile->FileSize - WritePos;\r
+ BufferSize = AppendedSize;\r
+ if (AppendedSize > FAT_MAX_ALLOCATE_SIZE) {\r
+ //\r
+ // If the appended size is larger, maybe we can not allocate the whole\r
+ // memory once. So if the growed size is larger than 10M, we just\r
+ // allocate 10M memory (one healthy system should have 10M available\r
+ // memory), and then write the zerobuffer to the file several times.\r
+ //\r
+ BufferSize = FAT_MAX_ALLOCATE_SIZE;\r
+ }\r
+\r
+ ZeroBuffer = AllocateZeroPool (BufferSize);\r
+ if (ZeroBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ do {\r
+ WriteSize = AppendedSize > BufferSize ? BufferSize : (UINTN) AppendedSize;\r
+ AppendedSize -= WriteSize;\r
+ Status = FatAccessOFile (OFile, WRITE_DATA, WritePos, &WriteSize, ZeroBuffer);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ WritePos += WriteSize;\r
+ } while (AppendedSize > 0);\r
+\r
+ FreePool (ZeroBuffer);\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatTruncateOFile (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINTN TruncatedSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Truncate the OFile to smaller file size.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file.\r
+ TruncatedSize - The new file size.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The file is truncated successfully.\r
+ other - An error occurred when truncating file.\r
+\r
+--*/\r
+{\r
+ OFile->FileSize = TruncatedSize;\r
+ return FatShrinkEof (OFile);\r
+}\r