Beispiel #1
0
EFI_STATUS
FileOpen (
  IN  EFI_FILE    *File,
  OUT EFI_FILE    **NewHandle,
  IN  CHAR16      *FileName,
  IN  UINT64      OpenMode,
  IN  UINT64      Attributes
  )
{
  SEMIHOST_FCB  *FileFcb = NULL;
  EFI_STATUS    Status   = EFI_SUCCESS;
  UINTN         SemihostHandle;
  CHAR8         *AsciiFileName;
  UINT32        SemihostMode;
  BOOLEAN       IsRoot;

  if ((FileName == NULL) || (NewHandle == NULL)) {
    return EFI_INVALID_PARAMETER;
  }

  // Semihost interface requires ASCII filenames
  AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));
  if (AsciiFileName == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  UnicodeStrToAsciiStr (FileName, AsciiFileName);

  if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||
      (AsciiStrCmp (AsciiFileName, "/")  == 0) ||
      (AsciiStrCmp (AsciiFileName, "")   == 0) ||
      (AsciiStrCmp (AsciiFileName, ".")  == 0)) {
    // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
    IsRoot = TRUE;

    // Root directory node doesn't have a name.
    FreePool (AsciiFileName);
    AsciiFileName = NULL;
  } else {
    // Translate EFI_FILE_MODE into Semihosting mode
    if (OpenMode & EFI_FILE_MODE_WRITE) {
      SemihostMode = SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY;
    } else if (OpenMode & EFI_FILE_MODE_READ) {
      SemihostMode = SEMIHOST_FILE_MODE_READ  | SEMIHOST_FILE_MODE_BINARY;
    } else {
      return EFI_UNSUPPORTED;
    }

    // Add the creation flag if necessary
    if (OpenMode & EFI_FILE_MODE_CREATE) {
      SemihostMode |= SEMIHOST_FILE_MODE_CREATE;
    }

    // Call the semihosting interface to open the file.
    Status = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);
    if (EFI_ERROR(Status)) {
      return Status;
    }
    
    IsRoot = FALSE;
  }

  // Allocate a control block and fill it
  FileFcb = AllocateFCB ();
  if (FileFcb == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  FileFcb->FileName       = AsciiFileName;
  FileFcb->SemihostHandle = SemihostHandle;
  FileFcb->Position       = 0;
  FileFcb->IsRoot         = IsRoot;

  InsertTailList (&gFileList, &FileFcb->Link);

  *NewHandle = &FileFcb->File;

  return Status;
}
Beispiel #2
0
/**
  Worker function that truncate a file specified by its name to a given size.

  @param[in]  FileName  The Null-terminated string of the name of the file to be opened.
  @param[in]  Size      The target size for the file.

  @retval  EFI_SUCCESS       The file was truncated.
  @retval  EFI_DEVICE_ERROR  The last issued semi-hosting operation failed.

**/
STATIC
EFI_STATUS
TruncateFile (
  IN CHAR8  *FileName,
  IN UINTN   Size
  )
{
  EFI_STATUS     Status;
  RETURN_STATUS  Return;
  UINTN          FileHandle;
  UINT8          *Buffer;
  UINTN          Remaining;
  UINTN          Read;
  UINTN          ToRead;

  Status     = EFI_DEVICE_ERROR;
  FileHandle = 0;
  Buffer     = NULL;

  Return = SemihostFileOpen (
             FileName,
             SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY,
             &FileHandle
             );
  if (RETURN_ERROR (Return)) {
    goto Error;
  }

  Buffer = AllocatePool (Size);
  if (Buffer == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Error;
  }

  Read = 0;
  Remaining = Size;
  while (Remaining > 0) {
    ToRead = Remaining;
    Return = SemihostFileRead (FileHandle, &ToRead, Buffer + Read);
    if (RETURN_ERROR (Return)) {
      goto Error;
    }
    Remaining -= ToRead;
    Read      += ToRead;
  }

  Return = SemihostFileClose (FileHandle);
  FileHandle = 0;
  if (RETURN_ERROR (Return)) {
    goto Error;
  }

  Return = SemihostFileOpen (
             FileName,
             SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY,
             &FileHandle
             );
  if (RETURN_ERROR (Return)) {
    goto Error;
  }

  if (Size > 0) {
    Return = SemihostFileWrite (FileHandle, &Size, Buffer);
    if (RETURN_ERROR (Return)) {
      goto Error;
    }
  }

  Status = EFI_SUCCESS;

Error:

  if (FileHandle != 0) {
    SemihostFileClose (FileHandle);
  }
  if (Buffer != NULL) {
    FreePool (Buffer);
  }

  return (Status);

}
Beispiel #3
0
/**
  Set information about a file.

  @param[in]  Fcb   A pointer to the description of the open file.
  @param[in]  Info  A pointer to the file information to write.

  @retval  EFI_SUCCESS           The information was set.
  @retval  EFI_ACCESS_DENIED     An attempt is made to change the name of a file
                                 to a file that is already present.
  @retval  EFI_ACCESS_DENIED     An attempt is being made to change the
                                 EFI_FILE_DIRECTORY Attribute.
  @retval  EFI_ACCESS_DENIED     The file is a read-only file or has been
                                 opened in read-only mode and an attempt is
                                 being made to modify a field other than
                                 Attribute.
  @retval  EFI_WRITE_PROTECTED   An attempt is being made to modify a
                                 read-only attribute.
  @retval  EFI_DEVICE_ERROR      The last issued semi-hosting operation failed.
  @retval  EFI_OUT_OF_RESOURCES  A allocation needed to process the request failed.

**/
STATIC
EFI_STATUS
SetFileInfo (
  IN  SEMIHOST_FCB   *Fcb,
  IN  EFI_FILE_INFO  *Info
  )
{
  EFI_STATUS     Status;
  RETURN_STATUS  Return;
  BOOLEAN        FileSizeIsDifferent;
  BOOLEAN        FileNameIsDifferent;
  BOOLEAN        ReadOnlyIsDifferent;
  CHAR8          *AsciiFileName;
  UINTN          FileSize;
  UINTN          Length;
  UINTN          SemihostHandle;

  //
  // A directory can not be changed to a file and a file can
  // not be changed to a directory.
  //
  if (((Info->Attribute & EFI_FILE_DIRECTORY) != 0) != Fcb->IsRoot) {
    return EFI_ACCESS_DENIED;
  }

  AsciiFileName = AllocatePool (StrLen (Info->FileName) + 1);
  if (AsciiFileName == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  UnicodeStrToAsciiStr (Info->FileName, AsciiFileName);

  FileSizeIsDifferent = (Info->FileSize != Fcb->Info.FileSize);
  FileNameIsDifferent = (AsciiStrCmp (AsciiFileName, Fcb->FileName) != 0);
  ReadOnlyIsDifferent = CompareMem (
                          &Info->CreateTime,
                          &Fcb->Info.CreateTime,
                          3 * sizeof (EFI_TIME)
                          ) != 0;

  //
  // For a read-only file or a file opened in read-only mode, only
  // the Attribute field can be modified. As the root directory is
  // read-only (i.e. VolumeOpen()), this protects the root directory
  // description.
  //
  if ((Fcb->OpenMode == EFI_FILE_MODE_READ)     ||
      (Fcb->Info.Attribute & EFI_FILE_READ_ONLY)  ) {
    if (FileSizeIsDifferent || FileNameIsDifferent || ReadOnlyIsDifferent) {
      Status = EFI_ACCESS_DENIED;
      goto Error;
    }
  }

  if (ReadOnlyIsDifferent) {
    Status = EFI_WRITE_PROTECTED;
    goto Error;
  }

  Status = EFI_DEVICE_ERROR;

  if (FileSizeIsDifferent) {
    FileSize = Info->FileSize;
    if (Fcb->Info.FileSize < FileSize) {
      Status = ExtendFile (Fcb, FileSize - Fcb->Info.FileSize);
      if (EFI_ERROR (Status)) {
        goto Error;
      }
      //
      // The read/write position from the host file system point of view
      // is at the end of the file. If the position from this module
      // point of view is smaller than the new file size, then
      // ask the host file system to move to that position.
      //
      if (Fcb->Position < FileSize) {
        FileSetPosition (&Fcb->File, Fcb->Position);
      }
    }
    Fcb->Info.FileSize = FileSize;

    Return = SemihostFileLength (Fcb->SemihostHandle, &Length);
    if (RETURN_ERROR (Return)) {
      goto Error;
    }
    Fcb->Info.PhysicalSize = Length;
  }

  //
  // Note down in RAM the Attribute field but we can not ask
  // for its modification to the host file system as the
  // semi-host interface does not provide this feature.
  //
  Fcb->Info.Attribute = Info->Attribute;

  if (FileNameIsDifferent) {
    Return = SemihostFileOpen (
               AsciiFileName,
               SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY,
               &SemihostHandle
               );
    if (!RETURN_ERROR (Return)) {
      SemihostFileClose (SemihostHandle);
      Status = EFI_ACCESS_DENIED;
      goto Error;
    }

    Return = SemihostFileRename (Fcb->FileName, AsciiFileName);
    if (RETURN_ERROR (Return)) {
      goto Error;
    }
    FreePool (Fcb->FileName);
    Fcb->FileName = AsciiFileName;
    AsciiFileName = NULL;
  }

  Status = EFI_SUCCESS;

Error:
  if (AsciiFileName != NULL) {
    FreePool (AsciiFileName);
  }

  return Status;
}
Beispiel #4
0
/**
  Open a file on the host system by means of the semihosting interface.

  @param[in]   This        A pointer to the EFI_FILE_PROTOCOL instance that is
                           the file handle to source location.
  @param[out]  NewHandle   A pointer to the location to return the opened
                           handle for the new file.
  @param[in]   FileName    The Null-terminated string of the name of the file
                           to be opened.
  @param[in]   OpenMode    The mode to open the file : Read or Read/Write or
                           Read/Write/Create
  @param[in]   Attributes  Only valid for EFI_FILE_MODE_CREATE, in which case these
                           are the attribute bits for the newly created file. The
                           mnemonics of the attribute bits are : EFI_FILE_READ_ONLY,
                           EFI_FILE_HIDDEN, EFI_FILE_SYSTEM, EFI_FILE_RESERVED,
                           EFI_FILE_DIRECTORY and EFI_FILE_ARCHIVE.

  @retval  EFI_SUCCESS            The file was open.
  @retval  EFI_NOT_FOUND          The specified file could not be found.
  @retval  EFI_DEVICE_ERROR       The last issued semi-hosting operation failed.
  @retval  EFI_WRITE_PROTECTED    Attempt to create a directory. This is not possible
                                  with the semi-hosting interface.
  @retval  EFI_OUT_OF_RESOURCES   Not enough resources were available to open the file.
  @retval  EFI_INVALID_PARAMETER  At least one of the parameters is invalid.

**/
EFI_STATUS
FileOpen (
  IN  EFI_FILE  *This,
  OUT EFI_FILE  **NewHandle,
  IN  CHAR16    *FileName,
  IN  UINT64    OpenMode,
  IN  UINT64    Attributes
  )
{
  SEMIHOST_FCB   *FileFcb;
  RETURN_STATUS  Return;
  EFI_STATUS     Status;
  UINTN          SemihostHandle;
  CHAR8          *AsciiFileName;
  UINT32         SemihostMode;
  UINTN          Length;

  if ((FileName == NULL) || (NewHandle == NULL)) {
    return EFI_INVALID_PARAMETER;
  }

  if ( (OpenMode != EFI_FILE_MODE_READ) &&
       (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE)) &&
       (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE)) ) {
    return EFI_INVALID_PARAMETER;
  }

  if ((OpenMode & EFI_FILE_MODE_CREATE) &&
      (Attributes & EFI_FILE_DIRECTORY)    ) {
    return EFI_WRITE_PROTECTED;
  }

  AsciiFileName = AllocatePool (StrLen (FileName) + 1);
  if (AsciiFileName == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  UnicodeStrToAsciiStr (FileName, AsciiFileName);

  // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
  if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||
      (AsciiStrCmp (AsciiFileName, "/")  == 0) ||
      (AsciiStrCmp (AsciiFileName, "")   == 0) ||
      (AsciiStrCmp (AsciiFileName, ".")  == 0)    ) {
    FreePool (AsciiFileName);
    return (VolumeOpen (&gSemihostFs, NewHandle));
  }

  //
  // No control is done here concerning the file path. It is passed
  // as it is to the host operating system through the semi-hosting
  // interface. We first try to open the file in the read or update
  // mode even if the file creation has been asked for. That way, if
  // the file already exists, it is not truncated to zero length. In
  // write mode (bit SEMIHOST_FILE_MODE_WRITE up), if the file already
  // exists, it is reset to an empty file.
  //
  if (OpenMode == EFI_FILE_MODE_READ) {
    SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY;
  } else {
    SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE;
  }
  Return = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);

  if (RETURN_ERROR (Return)) {
    if (OpenMode & EFI_FILE_MODE_CREATE) {
      //
      // In the create if does not exist case, if the opening in update
      // mode failed, create it and open it in update mode. The update
      // mode allows for both read and write from and to the file.
      //
      Return = SemihostFileOpen (
                 AsciiFileName,
                 SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE,
                 &SemihostHandle
                 );
      if (RETURN_ERROR (Return)) {
        Status = EFI_DEVICE_ERROR;
        goto Error;
      }
    } else {
      Status = EFI_NOT_FOUND;
      goto Error;
    }
  }

  // Allocate a control block and fill it
  FileFcb = AllocateFCB ();
  if (FileFcb == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Error;
  }

  FileFcb->FileName       = AsciiFileName;
  FileFcb->SemihostHandle = SemihostHandle;
  FileFcb->Position       = 0;
  FileFcb->IsRoot         = 0;
  FileFcb->OpenMode       = OpenMode;

  Return = SemihostFileLength (SemihostHandle, &Length);
  if (RETURN_ERROR (Return)) {
    Status = EFI_DEVICE_ERROR;
    FreeFCB (FileFcb);
    goto Error;
  }

  FileFcb->Info.FileSize     = Length;
  FileFcb->Info.PhysicalSize = Length;
  FileFcb->Info.Attribute    = (OpenMode & EFI_FILE_MODE_CREATE) ? Attributes : 0;

  InsertTailList (&gFileList, &FileFcb->Link);

  *NewHandle = &FileFcb->File;

  return EFI_SUCCESS;

Error:

  FreePool (AsciiFileName);

  return Status;
}