]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c
ArmPkg/SemihostFs: Fix open file issues revealed by SCT
[mirror_edk2.git] / ArmPkg / Filesystem / SemihostFs / Arm / SemihostFs.c
index b865143c74be6294d4af57263d4f8adca6a12565..34e2f62402b755a80da7fc786dcd565752a3eb33 100644 (file)
@@ -57,7 +57,7 @@ EFI_FILE gSemihostFsFile = {
 };\r
 \r
 //\r
-// Device path for SemiHosting. It contains our autogened Caller ID GUID.\r
+// Device path for semi-hosting. It contains our autogened Caller ID GUID.\r
 //\r
 typedef struct {\r
   VENDOR_DEVICE_PATH        Guid;\r
@@ -149,100 +149,151 @@ VolumeOpen (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Open a file on the host system by means of the semihosting interface.\r
+\r
+  @param[in]   This        A pointer to the EFI_FILE_PROTOCOL instance that is\r
+                           the file handle to source location.\r
+  @param[out]  NewHandle   A pointer to the location to return the opened\r
+                           handle for the new file.\r
+  @param[in]   FileName    The Null-terminated string of the name of the file\r
+                           to be opened.\r
+  @param[in]   OpenMode    The mode to open the file : Read or Read/Write or\r
+                           Read/Write/Create\r
+  @param[in]   Attributes  Only valid for EFI_FILE_MODE_CREATE, in which case these\r
+                           are the attribute bits for the newly created file. The\r
+                           mnemonics of the attribute bits are : EFI_FILE_READ_ONLY,\r
+                           EFI_FILE_HIDDEN, EFI_FILE_SYSTEM, EFI_FILE_RESERVED,\r
+                           EFI_FILE_DIRECTORY and EFI_FILE_ARCHIVE.\r
+\r
+  @retval  EFI_SUCCESS            The file was open.\r
+  @retval  EFI_NOT_FOUND          The specified file could not be found.\r
+  @retval  EFI_DEVICE_ERROR       The last issued semi-hosting operation failed.\r
+  @retval  EFI_WRITE_PROTECTED    Attempt to create a directory. This is not possible\r
+                                  with the semi-hosting interface.\r
+  @retval  EFI_OUT_OF_RESOURCES   Not enough resources were available to open the file.\r
+  @retval  EFI_INVALID_PARAMETER  At least one of the parameters is invalid.\r
+\r
+**/\r
 EFI_STATUS\r
 FileOpen (\r
-  IN  EFI_FILE    *File,\r
-  OUT EFI_FILE    **NewHandle,\r
-  IN  CHAR16      *FileName,\r
-  IN  UINT64      OpenMode,\r
-  IN  UINT64      Attributes\r
+  IN  EFI_FILE  *This,\r
+  OUT EFI_FILE  **NewHandle,\r
+  IN  CHAR16    *FileName,\r
+  IN  UINT64    OpenMode,\r
+  IN  UINT64    Attributes\r
   )\r
 {\r
-  SEMIHOST_FCB  *FileFcb = NULL;\r
-  EFI_STATUS    Status   = EFI_SUCCESS;\r
-  UINTN         SemihostHandle;\r
-  CHAR8         *AsciiFileName;\r
-  UINT32        SemihostMode;\r
-  BOOLEAN       IsRoot;\r
-  UINTN         Length;\r
+  SEMIHOST_FCB   *FileFcb;\r
+  RETURN_STATUS  Return;\r
+  EFI_STATUS     Status;\r
+  UINTN          SemihostHandle;\r
+  CHAR8          *AsciiFileName;\r
+  UINT32         SemihostMode;\r
+  UINTN          Length;\r
 \r
   if ((FileName == NULL) || (NewHandle == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  // Semihosting does not support directories\r
-  if (Attributes & EFI_FILE_DIRECTORY) {\r
-    return EFI_UNSUPPORTED;\r
+  if ( (OpenMode != EFI_FILE_MODE_READ) &&\r
+       (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE)) &&\r
+       (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE)) ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((OpenMode & EFI_FILE_MODE_CREATE) &&\r
+      (Attributes & EFI_FILE_DIRECTORY)    ) {\r
+    return EFI_WRITE_PROTECTED;\r
   }\r
 \r
-  // Semihost interface requires ASCII filenames\r
-  AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));\r
+  AsciiFileName = AllocatePool (StrLen (FileName) + 1);\r
   if (AsciiFileName == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
   UnicodeStrToAsciiStr (FileName, AsciiFileName);\r
 \r
+  // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory\r
   if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||\r
       (AsciiStrCmp (AsciiFileName, "/")  == 0) ||\r
       (AsciiStrCmp (AsciiFileName, "")   == 0) ||\r
-      (AsciiStrCmp (AsciiFileName, ".")  == 0)) {\r
-    // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory\r
-    IsRoot = TRUE;\r
-\r
-    // Root directory node doesn't have a name.\r
+      (AsciiStrCmp (AsciiFileName, ".")  == 0)    ) {\r
     FreePool (AsciiFileName);\r
-    AsciiFileName = NULL;\r
+    return (VolumeOpen (&gSemihostFs, NewHandle));\r
+  }\r
+\r
+  //\r
+  // No control is done here concerning the file path. It is passed\r
+  // as it is to the host operating system through the semi-hosting\r
+  // interface. We first try to open the file in the read or update\r
+  // mode even if the file creation has been asked for. That way, if\r
+  // the file already exists, it is not truncated to zero length. In\r
+  // write mode (bit SEMIHOST_FILE_MODE_WRITE up), if the file already\r
+  // exists, it is reset to an empty file.\r
+  //\r
+  if (OpenMode == EFI_FILE_MODE_READ) {\r
+    SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY;\r
   } else {\r
-    // Translate EFI_FILE_MODE into Semihosting mode\r
-    if (OpenMode & EFI_FILE_MODE_WRITE) {\r
-      SemihostMode = SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY;\r
-    } else if (OpenMode & EFI_FILE_MODE_READ) {\r
-      SemihostMode = SEMIHOST_FILE_MODE_READ  | SEMIHOST_FILE_MODE_BINARY;\r
-    } else {\r
-      return EFI_UNSUPPORTED;\r
-    }\r
+    SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE;\r
+  }\r
+  Return = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);\r
 \r
-    // Add the creation flag if necessary\r
+  if (RETURN_ERROR (Return)) {\r
     if (OpenMode & EFI_FILE_MODE_CREATE) {\r
-      SemihostMode |= SEMIHOST_FILE_MODE_UPDATE;\r
-    }\r
-\r
-    // Call the semihosting interface to open the file.\r
-    Status = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);\r
-    if (EFI_ERROR(Status)) {\r
-      return Status;\r
+      //\r
+      // In the create if does not exist case, if the opening in update\r
+      // mode failed, create it and open it in update mode. The update\r
+      // mode allows for both read and write from and to the file.\r
+      //\r
+      Return = SemihostFileOpen (\r
+                 AsciiFileName,\r
+                 SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE,\r
+                 &SemihostHandle\r
+                 );\r
+      if (RETURN_ERROR (Return)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Error;\r
+      }\r
+    } else {\r
+      Status = EFI_NOT_FOUND;\r
+      goto Error;\r
     }\r
-\r
-    IsRoot = FALSE;\r
   }\r
 \r
   // Allocate a control block and fill it\r
   FileFcb = AllocateFCB ();\r
   if (FileFcb == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
   }\r
 \r
   FileFcb->FileName       = AsciiFileName;\r
   FileFcb->SemihostHandle = SemihostHandle;\r
   FileFcb->Position       = 0;\r
-  FileFcb->IsRoot         = IsRoot;\r
+  FileFcb->IsRoot         = 0;\r
   FileFcb->OpenMode       = OpenMode;\r
 \r
-  if (!IsRoot) {\r
-    Status = SemihostFileLength (SemihostHandle, &Length);\r
-    if (EFI_ERROR(Status)) {\r
-      return Status;\r
-    }\r
-\r
-    FileFcb->Info.FileSize     = Length;\r
-    FileFcb->Info.PhysicalSize = Length;\r
-    FileFcb->Info.Attribute    = Attributes;\r
+  Return = SemihostFileLength (SemihostHandle, &Length);\r
+  if (RETURN_ERROR (Return)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    FreeFCB (FileFcb);\r
+    goto Error;\r
   }\r
 \r
+  FileFcb->Info.FileSize     = Length;\r
+  FileFcb->Info.PhysicalSize = Length;\r
+  FileFcb->Info.Attribute    = (OpenMode & EFI_FILE_MODE_CREATE) ? Attributes : 0;\r
+\r
   InsertTailList (&gFileList, &FileFcb->Link);\r
 \r
   *NewHandle = &FileFcb->File;\r
 \r
+  return EFI_SUCCESS;\r
+\r
+Error:\r
+\r
+  FreePool (AsciiFileName);\r
+\r
   return Status;\r
 }\r
 \r