/** Close a specified file handle. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to close. @retval EFI_SUCCESS The file was closed. @retval EFI_INVALID_PARAMETER The parameter "This" is NULL. **/ EFI_STATUS FileClose ( IN EFI_FILE *This ) { SEMIHOST_FCB *Fcb; if (This == NULL) { return EFI_INVALID_PARAMETER; } Fcb = SEMIHOST_FCB_FROM_THIS(This); if (!Fcb->IsRoot) { SemihostFileClose (Fcb->SemihostHandle); // // The file size might have been reduced from its actual // size on the host file system with FileSetInfo(). In // that case, the file has to be truncated. // if (Fcb->Info.FileSize < Fcb->Info.PhysicalSize) { TruncateFile (Fcb->FileName, Fcb->Info.FileSize); } FreePool (Fcb->FileName); } FreeFCB (Fcb); return EFI_SUCCESS; }
EFI_STATUS FileSetPosition ( IN EFI_FILE *File, IN UINT64 Position ) { SEMIHOST_FCB *Fcb = NULL; UINTN Length; EFI_STATUS Status; Fcb = SEMIHOST_FCB_FROM_THIS(File); if (!Fcb->IsRoot) { Status = SemihostFileLength (Fcb->SemihostHandle, &Length); if (!EFI_ERROR(Status) && (Length < Position)) { Position = Length; } Status = SemihostFileSeek (Fcb->SemihostHandle, (UINT32)Position); if (!EFI_ERROR(Status)) { Fcb->Position = Position; } } else { Fcb->Position = Position; Status = EFI_SUCCESS; } return Status; }
EFI_STATUS FileDelete ( IN EFI_FILE *File ) { SEMIHOST_FCB *Fcb = NULL; EFI_STATUS Status; CHAR8 *FileName; UINTN NameSize; Fcb = SEMIHOST_FCB_FROM_THIS(File); if (!Fcb->IsRoot) { // Get the filename from the Fcb NameSize = AsciiStrLen (Fcb->FileName); FileName = AllocatePool (NameSize + 1); AsciiStrCpy (FileName, Fcb->FileName); // Close the file if it's open. Disregard return status, // since it might give an error if the file isn't open. File->Close (File); // Call the semihost interface to delete the file. Status = SemihostFileRemove (FileName); } else { Status = EFI_UNSUPPORTED; } return Status; }
/** Write data to an open file. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to write data to. @param[in out] BufferSize On input, the size of the Buffer. On output, the size of the data actually written. In both cases, the size is measured in bytes. @param[in] Buffer The buffer of data to write. @retval EFI_SUCCESS The data was written. @retval EFI_ACCESS_DENIED Attempt to write into a read only file or in a file opened in read only mode. @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed. @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL. **/ EFI_STATUS FileWrite ( IN EFI_FILE *This, IN OUT UINTN *BufferSize, IN VOID *Buffer ) { SEMIHOST_FCB *Fcb; EFI_STATUS Status; UINTN WriteSize; RETURN_STATUS Return; UINTN Length; if ((This == NULL) || (BufferSize == NULL) || (Buffer == NULL)) { return EFI_INVALID_PARAMETER; } Fcb = SEMIHOST_FCB_FROM_THIS (This); // We cannot write a read-only file if ((Fcb->Info.Attribute & EFI_FILE_READ_ONLY) || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE)) { return EFI_ACCESS_DENIED; } // // If the position has been set past the end of the file, first grow the // file from its current size "Fcb->Info.FileSize" to "Fcb->Position" // size, filling the gap with zeros. // if (Fcb->Position > Fcb->Info.FileSize) { Status = ExtendFile (Fcb, Fcb->Position - Fcb->Info.FileSize); if (EFI_ERROR (Status)) { return Status; } Fcb->Info.FileSize = Fcb->Position; } WriteSize = *BufferSize; Return = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer); if (RETURN_ERROR (Return)) { return EFI_DEVICE_ERROR; } Fcb->Position += *BufferSize; if (Fcb->Position > Fcb->Info.FileSize) { Fcb->Info.FileSize = Fcb->Position; } Return = SemihostFileLength (Fcb->SemihostHandle, &Length); if (RETURN_ERROR (Return)) { return EFI_DEVICE_ERROR; } Fcb->Info.PhysicalSize = Length; return EFI_SUCCESS; }
/** Set information about a file or a file system. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle the information is for. @param[in] InformationType The type identifier for the information being set : EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or EFI_FILE_SYSTEM_VOLUME_LABEL_ID @param[in] BufferSize The size, in bytes, of Buffer. @param[in] Buffer A pointer to the data buffer to write. The type of the data inside the buffer is indicated by InformationType. @retval EFI_SUCCESS The information was set. @retval EFI_UNSUPPORTED The InformationType is not known. @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed. @retval EFI_ACCESS_DENIED An attempt is being made to change the EFI_FILE_DIRECTORY Attribute. @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and 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_ACCESS_DENIED An attempt is made to change the name of a file to a file that is already present. @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only attribute. @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by the data inside the buffer. @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed. @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid. **/ EFI_STATUS FileSetInfo ( IN EFI_FILE *This, IN EFI_GUID *InformationType, IN UINTN BufferSize, IN VOID *Buffer ) { SEMIHOST_FCB *Fcb; EFI_FILE_INFO *Info; EFI_FILE_SYSTEM_INFO *SystemInfo; CHAR16 *VolumeLabel; if ((This == NULL) || (InformationType == NULL) || (Buffer == NULL)) { return EFI_INVALID_PARAMETER; } Fcb = SEMIHOST_FCB_FROM_THIS (This); if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { Info = Buffer; if (Info->Size < (SIZE_OF_EFI_FILE_INFO + StrSize (Info->FileName))) { return EFI_INVALID_PARAMETER; } if (BufferSize < Info->Size) { return EFI_BAD_BUFFER_SIZE; } return SetFileInfo (Fcb, Info); } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { SystemInfo = Buffer; if (SystemInfo->Size < (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (SystemInfo->VolumeLabel))) { return EFI_INVALID_PARAMETER; } if (BufferSize < SystemInfo->Size) { return EFI_BAD_BUFFER_SIZE; } Buffer = SystemInfo->VolumeLabel; if (StrSize (Buffer) > 0) { VolumeLabel = AllocateCopyPool (StrSize (Buffer), Buffer); if (VolumeLabel != NULL) { FreePool (mSemihostFsLabel); mSemihostFsLabel = VolumeLabel; return EFI_SUCCESS; } else { return EFI_OUT_OF_RESOURCES; } } else { return EFI_INVALID_PARAMETER; } } else if (!CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { return EFI_UNSUPPORTED; } else { return EFI_UNSUPPORTED; } }
EFI_STATUS FileGetPosition ( IN EFI_FILE *File, OUT UINT64 *Position ) { SEMIHOST_FCB *Fcb = NULL; if (Position == NULL) { return EFI_INVALID_PARAMETER; } Fcb = SEMIHOST_FCB_FROM_THIS(File); *Position = Fcb->Position; return EFI_SUCCESS; }
/** Return a file's current position. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to get the current position on. @param[out] Position The address to return the file's current position value. @retval EFI_SUCCESS The position was returned. @retval EFI_INVALID_PARAMETER The parameter "This" or "Position" is NULL. **/ EFI_STATUS FileGetPosition ( IN EFI_FILE *This, OUT UINT64 *Position ) { SEMIHOST_FCB *Fcb; if ((This == NULL) || (Position == NULL)) { return EFI_INVALID_PARAMETER; } Fcb = SEMIHOST_FCB_FROM_THIS(This); *Position = Fcb->Position; return EFI_SUCCESS; }
/** Return information about a file or a file system. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle the requested information is for. @param[in] InformationType The type identifier for the information being requested : EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or EFI_FILE_SYSTEM_VOLUME_LABEL_ID @param[in out] BufferSize The size, in bytes, of Buffer. @param[out] Buffer A pointer to the data buffer to return. The type of the data inside the buffer is indicated by InformationType. @retval EFI_SUCCESS The information was returned. @retval EFI_UNSUPPORTED The InformationType is not known. @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information. BufferSize has been updated with the size needed to complete the request. @retval EFI_INVALID_PARAMETER The parameter "This" or "InformationType" or "BufferSize" is NULL or "Buffer" is NULL and "*Buffersize" is greater than 0. **/ EFI_STATUS FileGetInfo ( IN EFI_FILE *This, IN EFI_GUID *InformationType, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { SEMIHOST_FCB *Fcb; EFI_STATUS Status; UINTN ResultSize; if ((This == NULL) || (InformationType == NULL) || (BufferSize == NULL) || ((Buffer == NULL) && (*BufferSize > 0)) ) { return EFI_INVALID_PARAMETER; } Fcb = SEMIHOST_FCB_FROM_THIS(This); if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { Status = GetFilesystemInfo (Fcb, BufferSize, Buffer); } else if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { Status = GetFileInfo (Fcb, BufferSize, Buffer); } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { ResultSize = StrSize (mSemihostFsLabel); if (*BufferSize >= ResultSize) { StrCpy (Buffer, mSemihostFsLabel); Status = EFI_SUCCESS; } else { Status = EFI_BUFFER_TOO_SMALL; } *BufferSize = ResultSize; } else { Status = EFI_UNSUPPORTED; } return Status; }
EFI_STATUS FileFlush ( IN EFI_FILE *File ) { SEMIHOST_FCB *Fcb; Fcb = SEMIHOST_FCB_FROM_THIS(File); if (Fcb->IsRoot) { return EFI_SUCCESS; } else { if ((Fcb->Info.Attribute & EFI_FILE_READ_ONLY) || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE)) { return EFI_ACCESS_DENIED; } else { return EFI_SUCCESS; } } }
EFI_STATUS FileGetInfo ( IN EFI_FILE *File, IN EFI_GUID *InformationType, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { SEMIHOST_FCB *Fcb = NULL; EFI_STATUS Status = EFI_UNSUPPORTED; Fcb = SEMIHOST_FCB_FROM_THIS(File); if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid) != 0) { Status = GetFilesystemInfo(Fcb, BufferSize, Buffer); } else if (CompareGuid(InformationType, &gEfiFileInfoGuid) != 0) { Status = GetFileInfo(Fcb, BufferSize, Buffer); } return Status; }
/** Set a file's current position. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to set the requested position on. @param[in] Position The byte position from the start of the file to set. @retval EFI_SUCCESS The position was set. @retval EFI_DEVICE_ERROR The semi-hosting positionning operation failed. @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open directories. @retval EFI_INVALID_PARAMETER The parameter "This" is NULL. **/ EFI_STATUS FileSetPosition ( IN EFI_FILE *This, IN UINT64 Position ) { SEMIHOST_FCB *Fcb; RETURN_STATUS Return; if (This == NULL) { return EFI_INVALID_PARAMETER; } Fcb = SEMIHOST_FCB_FROM_THIS (This); if (Fcb->IsRoot) { if (Position != 0) { return EFI_UNSUPPORTED; } } else { // // UEFI Spec section 12.5: // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to // be set to the end of the file." // if (Position == 0xFFFFFFFFFFFFFFFF) { Position = Fcb->Info.FileSize; } Return = SemihostFileSeek (Fcb->SemihostHandle, MIN (Position, Fcb->Info.FileSize)); if (RETURN_ERROR (Return)) { return EFI_DEVICE_ERROR; } } Fcb->Position = Position; return EFI_SUCCESS; }
/** Read data from an open file. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to read data from. @param[in out] BufferSize On input, the size of the Buffer. On output, the amount of data returned in Buffer. In both cases, the size is measured in bytes. @param[out] Buffer The buffer into which the data is read. @retval EFI_SUCCESS The data was read. @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file, or the semi-hosting interface reported an error while performing the read operation. @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL. **/ EFI_STATUS FileRead ( IN EFI_FILE *This, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { SEMIHOST_FCB *Fcb; EFI_STATUS Status; RETURN_STATUS Return; if ((This == NULL) || (BufferSize == NULL) || (Buffer == NULL)) { return EFI_INVALID_PARAMETER; } Fcb = SEMIHOST_FCB_FROM_THIS (This); if (Fcb->IsRoot) { // The semi-hosting interface does not allow to list files on the host machine. Status = EFI_UNSUPPORTED; } else { Status = EFI_SUCCESS; if (Fcb->Position >= Fcb->Info.FileSize) { *BufferSize = 0; if (Fcb->Position > Fcb->Info.FileSize) { Status = EFI_DEVICE_ERROR; } } else { Return = SemihostFileRead (Fcb->SemihostHandle, BufferSize, Buffer); if (RETURN_ERROR (Return)) { Status = EFI_DEVICE_ERROR; } else { Fcb->Position += *BufferSize; } } } return Status; }
EFI_STATUS FileWrite ( IN EFI_FILE *File, IN OUT UINTN *BufferSize, IN VOID *Buffer ) { SEMIHOST_FCB *Fcb = NULL; EFI_STATUS Status; UINTN WriteSize = *BufferSize; Fcb = SEMIHOST_FCB_FROM_THIS(File); Status = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer); if (!EFI_ERROR(Status)) { // Semihost write return the number of bytes *NOT* written. *BufferSize -= WriteSize; Fcb->Position += *BufferSize; } return Status; }
EFI_STATUS FileClose ( IN EFI_FILE *File ) { SEMIHOST_FCB *Fcb = NULL; EFI_STATUS Status = EFI_SUCCESS; Fcb = SEMIHOST_FCB_FROM_THIS(File); if (Fcb->IsRoot == TRUE) { FreeFCB (Fcb); Status = EFI_SUCCESS; } else { Status = SemihostFileClose (Fcb->SemihostHandle); if (!EFI_ERROR(Status)) { FreePool (Fcb->FileName); FreeFCB (Fcb); } } return Status; }
/** Close and delete a file. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to delete. @retval EFI_SUCCESS The file was closed and deleted. @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted. @retval EFI_INVALID_PARAMETER The parameter "This" is NULL. **/ EFI_STATUS FileDelete ( IN EFI_FILE *This ) { SEMIHOST_FCB *Fcb; RETURN_STATUS Return; CHAR8 *FileName; UINTN NameSize; if (This == NULL) { return EFI_INVALID_PARAMETER; } Fcb = SEMIHOST_FCB_FROM_THIS (This); if (!Fcb->IsRoot) { // Get the filename from the Fcb NameSize = AsciiStrLen (Fcb->FileName); FileName = AllocatePool (NameSize + 1); AsciiStrCpy (FileName, Fcb->FileName); // Close the file if it's open. Disregard return status, // since it might give an error if the file isn't open. This->Close (This); // Call the semihost interface to delete the file. Return = SemihostFileRemove (FileName); if (RETURN_ERROR (Return)) { return EFI_WARN_DELETE_FAILURE; } return EFI_SUCCESS; } else { return EFI_WARN_DELETE_FAILURE; } }
EFI_STATUS FileRead ( IN EFI_FILE *File, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { SEMIHOST_FCB *Fcb = NULL; EFI_STATUS Status; Fcb = SEMIHOST_FCB_FROM_THIS(File); if (Fcb->IsRoot == TRUE) { // By design, the Semihosting feature does not allow to list files on the host machine. Status = EFI_UNSUPPORTED; } else { Status = SemihostFileRead (Fcb->SemihostHandle, BufferSize, Buffer); if (!EFI_ERROR (Status)) { Fcb->Position += *BufferSize; } } return Status; }