]> git.proxmox.com Git - mirror_edk2.git/blobdiff - FatPkg/EnhancedFatDxe/ReadWrite.c
Add EDK II Prime FatPkg New Feature: Support both Unicode Collation and Unicode Colla...
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / ReadWrite.c
diff --git a/FatPkg/EnhancedFatDxe/ReadWrite.c b/FatPkg/EnhancedFatDxe/ReadWrite.c
new file mode 100644 (file)
index 0000000..7ccf517
--- /dev/null
@@ -0,0 +1,612 @@
+/*++\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