mirror of https://github.com/acidanthera/audk.git
ArmPkg/SemihostFs: Fix open file issues revealed by SCT
Fix return codes in case of errors. Fix translation from EFI open mode to semi-hosting open mode to avoid the truncate to zero length of an already existing file opened in read/write or read/write/create mode. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ronald Cron <ronald.cron@arm.com> Reviewed-By: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16241 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
0f0a6fe907
commit
fdd12bd569
|
@ -57,7 +57,7 @@ EFI_FILE gSemihostFsFile = {
|
|||
};
|
||||
|
||||
//
|
||||
// Device path for SemiHosting. It contains our autogened Caller ID GUID.
|
||||
// Device path for semi-hosting. It contains our autogened Caller ID GUID.
|
||||
//
|
||||
typedef struct {
|
||||
VENDOR_DEVICE_PATH Guid;
|
||||
|
@ -149,100 +149,151 @@ VolumeOpen (
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
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 *File,
|
||||
IN EFI_FILE *This,
|
||||
OUT EFI_FILE **NewHandle,
|
||||
IN CHAR16 *FileName,
|
||||
IN UINT64 OpenMode,
|
||||
IN UINT64 Attributes
|
||||
)
|
||||
{
|
||||
SEMIHOST_FCB *FileFcb = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
SEMIHOST_FCB *FileFcb;
|
||||
RETURN_STATUS Return;
|
||||
EFI_STATUS Status;
|
||||
UINTN SemihostHandle;
|
||||
CHAR8 *AsciiFileName;
|
||||
UINT32 SemihostMode;
|
||||
BOOLEAN IsRoot;
|
||||
UINTN Length;
|
||||
|
||||
if ((FileName == NULL) || (NewHandle == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Semihosting does not support directories
|
||||
if (Attributes & EFI_FILE_DIRECTORY) {
|
||||
return EFI_UNSUPPORTED;
|
||||
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;
|
||||
}
|
||||
|
||||
// Semihost interface requires ASCII filenames
|
||||
AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));
|
||||
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)) {
|
||||
// Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
|
||||
IsRoot = TRUE;
|
||||
|
||||
// Root directory node doesn't have a name.
|
||||
(AsciiStrCmp (AsciiFileName, ".") == 0) ) {
|
||||
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) {
|
||||
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 {
|
||||
return EFI_UNSUPPORTED;
|
||||
SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE;
|
||||
}
|
||||
Return = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);
|
||||
|
||||
// Add the creation flag if necessary
|
||||
if (RETURN_ERROR (Return)) {
|
||||
if (OpenMode & EFI_FILE_MODE_CREATE) {
|
||||
SemihostMode |= SEMIHOST_FILE_MODE_UPDATE;
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Call the semihosting interface to open the file.
|
||||
Status = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
} else {
|
||||
Status = EFI_NOT_FOUND;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
IsRoot = FALSE;
|
||||
}
|
||||
|
||||
// Allocate a control block and fill it
|
||||
FileFcb = AllocateFCB ();
|
||||
if (FileFcb == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
FileFcb->FileName = AsciiFileName;
|
||||
FileFcb->SemihostHandle = SemihostHandle;
|
||||
FileFcb->Position = 0;
|
||||
FileFcb->IsRoot = IsRoot;
|
||||
FileFcb->IsRoot = 0;
|
||||
FileFcb->OpenMode = OpenMode;
|
||||
|
||||
if (!IsRoot) {
|
||||
Status = SemihostFileLength (SemihostHandle, &Length);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
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 = Attributes;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,9 +22,35 @@ VolumeOpen (
|
|||
OUT EFI_FILE **Root
|
||||
);
|
||||
|
||||
/**
|
||||
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 *File,
|
||||
IN EFI_FILE *This,
|
||||
OUT EFI_FILE **NewHandle,
|
||||
IN CHAR16 *FileName,
|
||||
IN UINT64 OpenMode,
|
||||
|
|
Loading…
Reference in New Issue