/** @file | |
Provides interface to EFI_FILE_HANDLE functionality. | |
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <Uefi.h> | |
#include <Protocol/SimpleFileSystem.h> | |
#include <Protocol/UnicodeCollation.h> | |
#include <Guid/FileInfo.h> | |
#include <Library/DebugLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Library/BaseLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/FileHandleLib.h> | |
#include <Library/PcdLib.h> | |
#include <Library/PrintLib.h> | |
CONST UINT16 gUnicodeFileTag = EFI_UNICODE_BYTE_ORDER_MARK; | |
#define MAX_FILE_NAME_LEN 522// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes) | |
#define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN) | |
/** | |
This function will retrieve the information about the file for the handle | |
specified and store it in allocated pool memory. | |
This function allocates a buffer to store the file's information. It is the | |
caller's responsibility to free the buffer | |
@param FileHandle The file handle of the file for which information is | |
being requested. | |
@retval NULL information could not be retrieved. | |
@return the information about the file | |
**/ | |
EFI_FILE_INFO * | |
EFIAPI | |
FileHandleGetInfo ( | |
IN EFI_FILE_HANDLE FileHandle | |
) | |
{ | |
EFI_FILE_INFO *FileInfo; | |
UINTN FileInfoSize; | |
EFI_STATUS Status; | |
if (FileHandle == NULL) { | |
return (NULL); | |
} | |
// | |
// Get the required size to allocate | |
// | |
FileInfoSize = 0; | |
FileInfo = NULL; | |
Status = FileHandle->GetInfo ( | |
FileHandle, | |
&gEfiFileInfoGuid, | |
&FileInfoSize, | |
NULL | |
); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
// | |
// error is expected. getting size to allocate | |
// | |
FileInfo = AllocateZeroPool (FileInfoSize); | |
if (FileInfo != NULL) { | |
// | |
// now get the information | |
// | |
Status = FileHandle->GetInfo ( | |
FileHandle, | |
&gEfiFileInfoGuid, | |
&FileInfoSize, | |
FileInfo | |
); | |
// | |
// if we got an error free the memory and return NULL | |
// | |
if (EFI_ERROR (Status)) { | |
FreePool (FileInfo); | |
FileInfo = NULL; | |
} | |
} | |
} | |
return (FileInfo); | |
} | |
/** | |
This function sets the information about the file for the opened handle | |
specified. | |
@param[in] FileHandle The file handle of the file for which information | |
is being set. | |
@param[in] FileInfo The information to set. | |
@retval EFI_SUCCESS The information was set. | |
@retval EFI_INVALID_PARAMETER A parameter was out of range or invalid. | |
@retval EFI_UNSUPPORTED The FileHandle does not support FileInfo. | |
@retval EFI_NO_MEDIA The device has no medium. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_WRITE_PROTECTED The file or medium is write protected. | |
@retval EFI_ACCESS_DENIED The file was opened read only. | |
@retval EFI_VOLUME_FULL The volume is full. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleSetInfo ( | |
IN EFI_FILE_HANDLE FileHandle, | |
IN CONST EFI_FILE_INFO *FileInfo | |
) | |
{ | |
if ((FileHandle == NULL) || (FileInfo == NULL)) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// Set the info | |
// | |
return (FileHandle->SetInfo ( | |
FileHandle, | |
&gEfiFileInfoGuid, | |
(UINTN)FileInfo->Size, | |
(EFI_FILE_INFO *)FileInfo | |
)); | |
} | |
/** | |
This function reads information from an opened file. | |
If FileHandle is not a directory, the function reads the requested number of | |
bytes from the file at the file's current position and returns them in Buffer. | |
If the read goes beyond the end of the file, the read length is truncated to the | |
end of the file. The file's current position is increased by the number of bytes | |
returned. If FileHandle is a directory, the function reads the directory entry | |
at the file's current position and returns the entry in Buffer. If the Buffer | |
is not large enough to hold the current directory entry, then | |
EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated. | |
BufferSize is set to be the size of the buffer needed to read the entry. On | |
success, the current position is updated to the next directory entry. If there | |
are no more directory entries, the read returns a zero-length buffer. | |
EFI_FILE_INFO is the structure returned as the directory entry. | |
@param FileHandle the opened file handle | |
@param BufferSize on input the size of buffer in bytes. on return | |
the number of bytes written. | |
@param Buffer the buffer to put read data into. | |
@retval EFI_SUCCESS Data was read. | |
@retval EFI_NO_MEDIA The device has no media. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required | |
size. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleRead ( | |
IN EFI_FILE_HANDLE FileHandle, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
if (FileHandle == NULL) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// Perform the read based on EFI_FILE_PROTOCOL | |
// | |
return (FileHandle->Read (FileHandle, BufferSize, Buffer)); | |
} | |
/** | |
Write data to a file. | |
This function writes the specified number of bytes to the file at the current | |
file position. The current file position is advanced the actual number of bytes | |
written, which is returned in BufferSize. Partial writes only occur when there | |
has been a data error during the write attempt (such as "volume space full"). | |
The file is automatically grown to hold the data if required. Direct writes to | |
opened directories are not supported. | |
@param FileHandle The opened file for writing | |
@param BufferSize on input the number of bytes in Buffer. On output | |
the number of bytes written. | |
@param Buffer the buffer containing data to write is stored. | |
@retval EFI_SUCCESS Data was written. | |
@retval EFI_UNSUPPORTED Writes to an open directory are not supported. | |
@retval EFI_NO_MEDIA The device has no media. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_WRITE_PROTECTED The device is write-protected. | |
@retval EFI_ACCESS_DENIED The file was open for read only. | |
@retval EFI_VOLUME_FULL The volume is full. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleWrite ( | |
IN EFI_FILE_HANDLE FileHandle, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
if (FileHandle == NULL) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// Perform the write based on EFI_FILE_PROTOCOL | |
// | |
return (FileHandle->Write (FileHandle, BufferSize, Buffer)); | |
} | |
/** | |
Close an open file handle. | |
This function closes a specified file handle. All "dirty" cached file data is | |
flushed to the device, and the file is closed. In all cases the handle is | |
closed. | |
@param FileHandle the file handle to close. | |
@retval EFI_SUCCESS the file handle was closed successfully. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleClose ( | |
IN EFI_FILE_HANDLE FileHandle | |
) | |
{ | |
EFI_STATUS Status; | |
if (FileHandle == NULL) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// Perform the Close based on EFI_FILE_PROTOCOL | |
// | |
Status = FileHandle->Close (FileHandle); | |
return Status; | |
} | |
/** | |
Delete a file and close the handle | |
This function closes and deletes a file. In all cases the file handle is closed. | |
If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is | |
returned, but the handle is still closed. | |
@param FileHandle the file handle to delete | |
@retval EFI_SUCCESS the file was closed successfully | |
@retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not | |
deleted | |
@retval INVALID_PARAMETER One of the parameters has an invalid value. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleDelete ( | |
IN EFI_FILE_HANDLE FileHandle | |
) | |
{ | |
EFI_STATUS Status; | |
if (FileHandle == NULL) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// Perform the Delete based on EFI_FILE_PROTOCOL | |
// | |
Status = FileHandle->Delete (FileHandle); | |
return Status; | |
} | |
/** | |
Set the current position in a file. | |
This function sets the current file position for the handle to the position | |
supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only | |
absolute positioning is supported, and seeking past the end of the file is | |
allowed (a subsequent write would grow the file). Seeking to position | |
0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file. | |
If FileHandle is a directory, the only position that may be set is zero. This | |
has the effect of starting the read process of the directory entries over. | |
@param FileHandle The file handle on which the position is being set | |
@param Position Byte position from beginning of file | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_UNSUPPORTED the seek request for non-zero is not valid on | |
directories. | |
@retval INVALID_PARAMETER One of the parameters has an invalid value. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleSetPosition ( | |
IN EFI_FILE_HANDLE FileHandle, | |
IN UINT64 Position | |
) | |
{ | |
if (FileHandle == NULL) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// Perform the SetPosition based on EFI_FILE_PROTOCOL | |
// | |
return (FileHandle->SetPosition (FileHandle, Position)); | |
} | |
/** | |
Gets a file's current position | |
This function retrieves the current file position for the file handle. For | |
directories, the current file position has no meaning outside of the file | |
system driver and as such the operation is not supported. An error is returned | |
if FileHandle is a directory. | |
@param FileHandle The open file handle on which to get the position. | |
@param Position Byte position from beginning of file. | |
@retval EFI_SUCCESS the operation completed successfully. | |
@retval INVALID_PARAMETER One of the parameters has an invalid value. | |
@retval EFI_UNSUPPORTED the request is not valid on directories. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleGetPosition ( | |
IN EFI_FILE_HANDLE FileHandle, | |
OUT UINT64 *Position | |
) | |
{ | |
if ((Position == NULL) || (FileHandle == NULL)) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// Perform the GetPosition based on EFI_FILE_PROTOCOL | |
// | |
return (FileHandle->GetPosition (FileHandle, Position)); | |
} | |
/** | |
Flushes data on a file | |
This function flushes all modified data associated with a file to a device. | |
@param FileHandle The file handle on which to flush data | |
@retval EFI_SUCCESS The data was flushed. | |
@retval EFI_NO_MEDIA The device has no media. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_WRITE_PROTECTED The file or medium is write protected. | |
@retval EFI_ACCESS_DENIED The file was opened for read only. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleFlush ( | |
IN EFI_FILE_HANDLE FileHandle | |
) | |
{ | |
if (FileHandle == NULL) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// Perform the Flush based on EFI_FILE_PROTOCOL | |
// | |
return (FileHandle->Flush (FileHandle)); | |
} | |
/** | |
Function to determine if a given handle is a directory handle. | |
Open the file information on the DirHandle and verify that the Attribute | |
includes EFI_FILE_DIRECTORY bit set. | |
@param[in] DirHandle Handle to open file. | |
@retval EFI_SUCCESS DirHandle is a directory. | |
@retval EFI_INVALID_PARAMETER DirHandle is NULL. | |
The file information returns from FileHandleGetInfo is NULL. | |
@retval EFI_NOT_FOUND DirHandle is not a directory. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleIsDirectory ( | |
IN EFI_FILE_HANDLE DirHandle | |
) | |
{ | |
EFI_FILE_INFO *DirInfo; | |
if (DirHandle == NULL) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// get the file information for DirHandle | |
// | |
DirInfo = FileHandleGetInfo (DirHandle); | |
// | |
// Parse DirInfo | |
// | |
if (DirInfo == NULL) { | |
// | |
// We got nothing... | |
// | |
return (EFI_INVALID_PARAMETER); | |
} | |
if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) { | |
// | |
// Attributes say this is not a directory | |
// | |
FreePool (DirInfo); | |
return (EFI_NOT_FOUND); | |
} | |
// | |
// all good... | |
// | |
FreePool (DirInfo); | |
return (EFI_SUCCESS); | |
} | |
/** Retrieve first entry from a directory. | |
This function takes an open directory handle and gets information from the | |
first entry in the directory. A buffer is allocated to contain | |
the information and a pointer to the buffer is returned in *Buffer. The | |
caller can use FileHandleFindNextFile() to get subsequent directory entries. | |
The buffer will be freed by FileHandleFindNextFile() when the last directory | |
entry is read. Otherwise, the caller must free the buffer, using FreePool, | |
when finished with it. | |
@param[in] DirHandle The file handle of the directory to search. | |
@param[out] Buffer The pointer to pointer to buffer for file's information. | |
@retval EFI_SUCCESS Found the first file. | |
@retval EFI_NOT_FOUND Cannot find the directory. | |
@retval EFI_NO_MEDIA The device has no media. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@return Others status of FileHandleGetInfo, FileHandleSetPosition, | |
or FileHandleRead | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleFindFirstFile ( | |
IN EFI_FILE_HANDLE DirHandle, | |
OUT EFI_FILE_INFO **Buffer | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN BufferSize; | |
if ((Buffer == NULL) || (DirHandle == NULL)) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// verify that DirHandle is a directory | |
// | |
Status = FileHandleIsDirectory (DirHandle); | |
if (EFI_ERROR (Status)) { | |
return (Status); | |
} | |
// | |
// Allocate a buffer sized to struct size + enough for the string at the end | |
// | |
BufferSize = FIND_XXXXX_FILE_BUFFER_SIZE; | |
*Buffer = AllocateZeroPool (BufferSize); | |
if (*Buffer == NULL) { | |
return (EFI_OUT_OF_RESOURCES); | |
} | |
// | |
// reset to the beginning of the directory | |
// | |
Status = FileHandleSetPosition (DirHandle, 0); | |
if (EFI_ERROR (Status)) { | |
FreePool (*Buffer); | |
*Buffer = NULL; | |
return (Status); | |
} | |
// | |
// read in the info about the first file | |
// | |
Status = FileHandleRead (DirHandle, &BufferSize, *Buffer); | |
ASSERT (Status != EFI_BUFFER_TOO_SMALL); | |
if (EFI_ERROR (Status) || (BufferSize == 0)) { | |
FreePool (*Buffer); | |
*Buffer = NULL; | |
if (BufferSize == 0) { | |
return (EFI_NOT_FOUND); | |
} | |
return (Status); | |
} | |
return (EFI_SUCCESS); | |
} | |
/** Retrieve next entries from a directory. | |
To use this function, the caller must first call the FileHandleFindFirstFile() | |
function to get the first directory entry. Subsequent directory entries are | |
retrieved by using the FileHandleFindNextFile() function. This function can | |
be called several times to get each entry from the directory. If the call of | |
FileHandleFindNextFile() retrieved the last directory entry, the next call of | |
this function will set *NoFile to TRUE and free the buffer. | |
@param[in] DirHandle The file handle of the directory. | |
@param[out] Buffer The pointer to buffer for file's information. | |
@param[out] NoFile The pointer to boolean when last file is found. | |
@retval EFI_SUCCESS Found the next file, or reached last file | |
@retval EFI_NO_MEDIA The device has no media. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleFindNextFile ( | |
IN EFI_FILE_HANDLE DirHandle, | |
OUT EFI_FILE_INFO *Buffer, | |
OUT BOOLEAN *NoFile | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN BufferSize; | |
if ((DirHandle == NULL) || (Buffer == NULL) || (NoFile == NULL)) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// This BufferSize MUST stay equal to the originally allocated one in GetFirstFile | |
// | |
BufferSize = FIND_XXXXX_FILE_BUFFER_SIZE; | |
// | |
// read in the info about the next file | |
// | |
Status = FileHandleRead (DirHandle, &BufferSize, Buffer); | |
ASSERT (Status != EFI_BUFFER_TOO_SMALL); | |
if (EFI_ERROR (Status)) { | |
return (Status); | |
} | |
// | |
// If we read 0 bytes (but did not have erros) we already read in the last file. | |
// | |
if (BufferSize == 0) { | |
FreePool (Buffer); | |
*NoFile = TRUE; | |
} | |
return (EFI_SUCCESS); | |
} | |
/** | |
Retrieve the size of a file. | |
This function extracts the file size info from the FileHandle's EFI_FILE_INFO | |
data. | |
@param[in] FileHandle The file handle from which size is retrieved. | |
@param[out] Size The pointer to size. | |
@retval EFI_SUCCESS Operation was completed successfully. | |
@retval EFI_DEVICE_ERROR Cannot access the file. | |
@retval EFI_INVALID_PARAMETER FileHandle is NULL. | |
Size is NULL. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleGetSize ( | |
IN EFI_FILE_HANDLE FileHandle, | |
OUT UINT64 *Size | |
) | |
{ | |
EFI_FILE_INFO *FileInfo; | |
if ((FileHandle == NULL) || (Size == NULL)) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// get the FileInfo structure | |
// | |
FileInfo = FileHandleGetInfo (FileHandle); | |
if (FileInfo == NULL) { | |
return (EFI_DEVICE_ERROR); | |
} | |
// | |
// Assign the Size pointer to the correct value | |
// | |
*Size = FileInfo->FileSize; | |
// | |
// free the FileInfo memory | |
// | |
FreePool (FileInfo); | |
return (EFI_SUCCESS); | |
} | |
/** | |
Set the size of a file. | |
This function changes the file size info from the FileHandle's EFI_FILE_INFO | |
data. | |
@param[in] FileHandle The file handle whose size is to be changed. | |
@param[in] Size The new size. | |
@retval EFI_SUCCESS The operation completed successfully. | |
@retval EFI_DEVICE_ERROR Cannot access the file. | |
@retval EFI_INVALID_PARAMETER FileHandle is NULL. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleSetSize ( | |
IN EFI_FILE_HANDLE FileHandle, | |
IN UINT64 Size | |
) | |
{ | |
EFI_FILE_INFO *FileInfo; | |
EFI_STATUS Status; | |
if (FileHandle == NULL) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// get the FileInfo structure | |
// | |
FileInfo = FileHandleGetInfo (FileHandle); | |
if (FileInfo == NULL) { | |
return (EFI_DEVICE_ERROR); | |
} | |
// | |
// Assign the FileSize pointer to the new value | |
// | |
FileInfo->FileSize = Size; | |
Status = FileHandleSetInfo (FileHandle, FileInfo); | |
// | |
// free the FileInfo memory | |
// | |
FreePool (FileInfo); | |
return (Status); | |
} | |
/** | |
Safely append (on the left) with automatic string resizing given length of Destination and | |
desired length of copy from Source. | |
append the first D characters of Source to the end of Destination, where D is | |
the lesser of Count and the StrLen() of Source. If appending those D characters | |
will fit within Destination (whose Size is given as CurrentSize) and | |
still leave room for a NULL terminator, then those characters are appended, | |
starting at the original terminating NULL of Destination, and a new terminating | |
NULL is appended. | |
If appending D characters onto Destination will result in a overflow of the size | |
given in CurrentSize the string will be grown such that the copy can be performed | |
and CurrentSize will be updated to the new size. | |
If Source is NULL, there is nothing to append, just return the current buffer in | |
Destination. | |
if Destination is NULL, then return error | |
if Destination's current length (including NULL terminator) is already more then | |
CurrentSize, then ASSERT() | |
@param[in, out] Destination The String to append onto | |
@param[in, out] CurrentSize on call the number of bytes in Destination. On | |
return possibly the new size (still in bytes). if NULL | |
then allocate whatever is needed. | |
@param[in] Source The String to append from | |
@param[in] Count Maximum number of characters to append. if 0 then | |
all are appended. | |
@return Destination return the resultant string. | |
**/ | |
CHAR16 * | |
EFIAPI | |
StrnCatGrowLeft ( | |
IN OUT CHAR16 **Destination, | |
IN OUT UINTN *CurrentSize, | |
IN CONST CHAR16 *Source, | |
IN UINTN Count | |
) | |
{ | |
UINTN DestinationStartSize; | |
UINTN NewSize; | |
UINTN CopySize; | |
if (Destination == NULL) { | |
return (NULL); | |
} | |
// | |
// If there's nothing to do then just return Destination | |
// | |
if (Source == NULL) { | |
return (*Destination); | |
} | |
// | |
// allow for NULL pointers address as Destination | |
// | |
if (*Destination != NULL) { | |
ASSERT (CurrentSize != 0); | |
DestinationStartSize = StrSize (*Destination); | |
ASSERT (DestinationStartSize <= *CurrentSize); | |
} else { | |
DestinationStartSize = 0; | |
// ASSERT(*CurrentSize == 0); | |
} | |
// | |
// Append all of Source? | |
// | |
if (Count == 0) { | |
Count = StrSize (Source); | |
} | |
// | |
// Test and grow if required | |
// | |
if (CurrentSize != NULL) { | |
NewSize = *CurrentSize; | |
while (NewSize < (DestinationStartSize + Count)) { | |
NewSize += 2 * Count; | |
} | |
*Destination = ReallocatePool (*CurrentSize, NewSize, *Destination); | |
*CurrentSize = NewSize; | |
} else { | |
*Destination = AllocateZeroPool (Count+sizeof (CHAR16)); | |
} | |
if (*Destination == NULL) { | |
return NULL; | |
} | |
CopySize = StrSize (*Destination); | |
CopyMem ((*Destination)+((Count-2)/sizeof (CHAR16)), *Destination, CopySize); | |
CopyMem (*Destination, Source, Count-2); | |
return (*Destination); | |
} | |
/** | |
Function to get a full filename given a EFI_FILE_HANDLE somewhere lower on the | |
directory 'stack'. If the file is a directory, then append the '\' char at the | |
end of name string. If it's not a directory, then the last '\' should not be | |
added. | |
if Handle is NULL, return EFI_INVALID_PARAMETER | |
@param[in] Handle Handle to the Directory or File to create path to. | |
@param[out] FullFileName pointer to pointer to generated full file name. It | |
is the responsibility of the caller to free this memory | |
with a call to FreePool(). | |
@retval EFI_SUCCESS the operation was sucessful and the FullFileName is valid. | |
@retval EFI_INVALID_PARAMETER Handle was NULL. | |
@retval EFI_INVALID_PARAMETER FullFileName was NULL. | |
@retval EFI_OUT_OF_RESOURCES a memory allocation failed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleGetFileName ( | |
IN CONST EFI_FILE_HANDLE Handle, | |
OUT CHAR16 **FullFileName | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN Size; | |
EFI_FILE_HANDLE CurrentHandle; | |
EFI_FILE_HANDLE NextHigherHandle; | |
EFI_FILE_INFO *FileInfo; | |
Size = 0; | |
// | |
// Check our parameters | |
// | |
if ((FullFileName == NULL) || (Handle == NULL)) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
*FullFileName = NULL; | |
CurrentHandle = NULL; | |
Status = Handle->Open (Handle, &CurrentHandle, L".", EFI_FILE_MODE_READ, 0); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Reverse out the current directory on the device | |
// | |
for ( ; ;) { | |
FileInfo = FileHandleGetInfo (CurrentHandle); | |
if (FileInfo == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
break; | |
} else { | |
// | |
// Prepare to move to the parent directory. | |
// Also determine whether CurrentHandle refers to the Root directory. | |
// | |
Status = CurrentHandle->Open (CurrentHandle, &NextHigherHandle, L"..", EFI_FILE_MODE_READ, 0); | |
// | |
// We got info... do we have a name? if yes precede the current path with it... | |
// | |
if ((StrLen (FileInfo->FileName) == 0) || EFI_ERROR (Status)) { | |
// | |
// Both FileInfo->FileName being '\0' and EFI_ERROR() suggest that | |
// CurrentHandle refers to the Root directory. As this loop ensures | |
// FullFileName is starting with '\\' at all times, signal success | |
// and exit the loop. | |
// While FileInfo->FileName could theoretically be a value other than | |
// '\0' or '\\', '\\' is guaranteed to be supported by the | |
// specification and hence its value can safely be ignored. | |
// | |
Status = EFI_SUCCESS; | |
if (*FullFileName == NULL) { | |
ASSERT ((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL)); | |
*FullFileName = StrnCatGrowLeft (FullFileName, &Size, L"\\", 0); | |
} | |
FreePool (FileInfo); | |
break; | |
} else { | |
if (*FullFileName == NULL) { | |
ASSERT ((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL)); | |
*FullFileName = StrnCatGrowLeft (FullFileName, &Size, L"\\", 0); | |
} | |
ASSERT ((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL)); | |
*FullFileName = StrnCatGrowLeft (FullFileName, &Size, FileInfo->FileName, 0); | |
*FullFileName = StrnCatGrowLeft (FullFileName, &Size, L"\\", 0); | |
FreePool (FileInfo); | |
} | |
} | |
FileHandleClose (CurrentHandle); | |
// | |
// Move to the parent directory | |
// | |
CurrentHandle = NextHigherHandle; | |
} | |
} else if (Status == EFI_NOT_FOUND) { | |
Status = EFI_SUCCESS; | |
ASSERT ((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL)); | |
*FullFileName = StrnCatGrowLeft (FullFileName, &Size, L"\\", 0); | |
} | |
if ((*FullFileName != NULL) && | |
((*FullFileName)[StrLen (*FullFileName) - 1] == L'\\') && | |
(StrLen (*FullFileName) > 1) && | |
(FileHandleIsDirectory (Handle) == EFI_NOT_FOUND) | |
) | |
{ | |
(*FullFileName)[StrLen (*FullFileName) - 1] = CHAR_NULL; | |
} | |
if (CurrentHandle != NULL) { | |
CurrentHandle->Close (CurrentHandle); | |
} | |
if (EFI_ERROR (Status) && (*FullFileName != NULL)) { | |
FreePool (*FullFileName); | |
} | |
return (Status); | |
} | |
/** | |
Function to read a single line from a file. The \n is not included in the returned | |
buffer. The returned buffer must be callee freed. | |
If the position upon start is 0, then the Ascii Boolean will be set. This should be | |
maintained and not changed for all operations with the same file. | |
@param[in] Handle FileHandle to read from. | |
@param[in, out] Ascii Boolean value for indicating whether the file is Ascii (TRUE) or UCS2 (FALSE); | |
@return The line of text from the file. | |
@sa FileHandleReadLine | |
**/ | |
CHAR16 * | |
EFIAPI | |
FileHandleReturnLine ( | |
IN EFI_FILE_HANDLE Handle, | |
IN OUT BOOLEAN *Ascii | |
) | |
{ | |
CHAR16 *RetVal; | |
UINTN Size; | |
EFI_STATUS Status; | |
Size = 0; | |
RetVal = NULL; | |
Status = FileHandleReadLine (Handle, RetVal, &Size, FALSE, Ascii); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
RetVal = AllocateZeroPool (Size); | |
Status = FileHandleReadLine (Handle, RetVal, &Size, FALSE, Ascii); | |
} | |
ASSERT_EFI_ERROR (Status); | |
if (EFI_ERROR (Status) && (RetVal != NULL)) { | |
FreePool (RetVal); | |
RetVal = NULL; | |
} | |
return (RetVal); | |
} | |
/** | |
Function to read a single line (up to but not including the \n) from a file. | |
If the position upon start is 0, then the Ascii Boolean will be set. This should be | |
maintained and not changed for all operations with the same file. | |
The function will not return the \r and \n character in buffer. When an empty line is | |
read a CHAR_NULL character will be returned in buffer. | |
@param[in] Handle FileHandle to read from. | |
@param[in, out] Buffer The pointer to buffer to read into. | |
@param[in, out] Size The pointer to number of bytes in Buffer. | |
@param[in] Truncate If the buffer is large enough, this has no effect. | |
If the buffer is is too small and Truncate is TRUE, | |
the line will be truncated. | |
If the buffer is is too small and Truncate is FALSE, | |
then no read will occur. | |
@param[in, out] Ascii Boolean value for indicating whether the file is | |
Ascii (TRUE) or UCS2 (FALSE). | |
@retval EFI_SUCCESS The operation was successful. The line is stored in | |
Buffer. | |
@retval EFI_INVALID_PARAMETER Handle was NULL. | |
@retval EFI_INVALID_PARAMETER Size was NULL. | |
@retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line. | |
Size was updated to the minimum space required. | |
@sa FileHandleRead | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleReadLine ( | |
IN EFI_FILE_HANDLE Handle, | |
IN OUT CHAR16 *Buffer, | |
IN OUT UINTN *Size, | |
IN BOOLEAN Truncate, | |
IN OUT BOOLEAN *Ascii | |
) | |
{ | |
EFI_STATUS Status; | |
CHAR16 CharBuffer; | |
UINT64 FileSize; | |
UINTN CharSize; | |
UINTN CountSoFar; | |
UINTN CrCount; | |
UINTN OldSize; | |
UINT64 OriginalFilePosition; | |
if ( (Handle == NULL) | |
|| (Size == NULL) | |
|| ((Buffer == NULL) && (*Size != 0)) | |
) | |
{ | |
return (EFI_INVALID_PARAMETER); | |
} | |
if ((Buffer != NULL) && (*Size != 0)) { | |
*Buffer = CHAR_NULL; | |
} | |
Status = FileHandleGetSize (Handle, &FileSize); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} else if (FileSize == 0) { | |
*Ascii = TRUE; | |
return EFI_SUCCESS; | |
} | |
FileHandleGetPosition (Handle, &OriginalFilePosition); | |
if (OriginalFilePosition == 0) { | |
CharSize = sizeof (CHAR16); | |
Status = FileHandleRead (Handle, &CharSize, &CharBuffer); | |
ASSERT_EFI_ERROR (Status); | |
if (CharBuffer == gUnicodeFileTag) { | |
*Ascii = FALSE; | |
} else { | |
*Ascii = TRUE; | |
FileHandleSetPosition (Handle, OriginalFilePosition); | |
} | |
} | |
CrCount = 0; | |
for (CountSoFar = 0; ; CountSoFar++) { | |
CharBuffer = 0; | |
if (*Ascii) { | |
CharSize = sizeof (CHAR8); | |
} else { | |
CharSize = sizeof (CHAR16); | |
} | |
Status = FileHandleRead (Handle, &CharSize, &CharBuffer); | |
if ( EFI_ERROR (Status) | |
|| (CharSize == 0) | |
|| ((CharBuffer == L'\n') && !(*Ascii)) | |
|| ((CharBuffer == '\n') && *Ascii) | |
) | |
{ | |
break; | |
} else if ( | |
((CharBuffer == L'\r') && !(*Ascii)) || | |
((CharBuffer == '\r') && *Ascii) | |
) | |
{ | |
CrCount++; | |
continue; | |
} | |
// | |
// if we have space save it... | |
// | |
if ((CountSoFar+1-CrCount)*sizeof (CHAR16) < *Size) { | |
ASSERT (Buffer != NULL); | |
((CHAR16 *)Buffer)[CountSoFar-CrCount] = CharBuffer; | |
((CHAR16 *)Buffer)[CountSoFar+1-CrCount] = CHAR_NULL; | |
} | |
} | |
// | |
// if we ran out of space tell when... | |
// | |
if ((CountSoFar+1-CrCount)*sizeof (CHAR16) > *Size) { | |
OldSize = *Size; | |
*Size = (CountSoFar+1-CrCount)*sizeof (CHAR16); | |
if (!Truncate) { | |
if ((Buffer != NULL) && (OldSize != 0)) { | |
ZeroMem (Buffer, OldSize); | |
} | |
FileHandleSetPosition (Handle, OriginalFilePosition); | |
return (EFI_BUFFER_TOO_SMALL); | |
} else { | |
DEBUG ((DEBUG_WARN, "The line was truncated in FileHandleReadLine")); | |
return (EFI_SUCCESS); | |
} | |
} | |
return (Status); | |
} | |
/** | |
Function to write a line of text to a file. | |
If the file is a Unicode file (with UNICODE file tag) then write the unicode | |
text. | |
If the file is an ASCII file then write the ASCII text. | |
If the size of file is zero (without file tag at the beginning) then write | |
ASCII text as default. | |
@param[in] Handle FileHandle to write to. | |
@param[in] Buffer Buffer to write, if NULL the function will | |
take no action and return EFI_SUCCESS. | |
@retval EFI_SUCCESS The data was written. | |
Buffer is NULL. | |
@retval EFI_INVALID_PARAMETER Handle is NULL. | |
@retval EFI_OUT_OF_RESOURCES Unable to allocate temporary space for ASCII | |
string due to out of resources. | |
@sa FileHandleWrite | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandleWriteLine ( | |
IN EFI_FILE_HANDLE Handle, | |
IN CHAR16 *Buffer | |
) | |
{ | |
EFI_STATUS Status; | |
CHAR16 CharBuffer; | |
UINTN Size; | |
UINTN Index; | |
UINTN CharSize; | |
UINT64 FileSize; | |
UINT64 OriginalFilePosition; | |
BOOLEAN Ascii; | |
CHAR8 *AsciiBuffer; | |
if (Buffer == NULL) { | |
return (EFI_SUCCESS); | |
} | |
if (Handle == NULL) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
Ascii = FALSE; | |
AsciiBuffer = NULL; | |
Status = FileHandleGetPosition (Handle, &OriginalFilePosition); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = FileHandleSetPosition (Handle, 0); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = FileHandleGetSize (Handle, &FileSize); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if (FileSize == 0) { | |
Ascii = TRUE; | |
} else { | |
CharSize = sizeof (CHAR16); | |
Status = FileHandleRead (Handle, &CharSize, &CharBuffer); | |
ASSERT_EFI_ERROR (Status); | |
if (CharBuffer == gUnicodeFileTag) { | |
Ascii = FALSE; | |
} else { | |
Ascii = TRUE; | |
} | |
} | |
Status = FileHandleSetPosition (Handle, OriginalFilePosition); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if (Ascii) { | |
Size = (StrSize (Buffer) / sizeof (CHAR16)) * sizeof (CHAR8); | |
AsciiBuffer = (CHAR8 *)AllocateZeroPool (Size); | |
if (AsciiBuffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
UnicodeStrToAsciiStrS (Buffer, AsciiBuffer, Size); | |
for (Index = 0; Index < Size; Index++) { | |
if ((AsciiBuffer[Index] & BIT7) != 0) { | |
FreePool (AsciiBuffer); | |
return EFI_INVALID_PARAMETER; | |
} | |
} | |
Size = AsciiStrSize (AsciiBuffer) - sizeof (CHAR8); | |
Status = FileHandleWrite (Handle, &Size, AsciiBuffer); | |
if (EFI_ERROR (Status)) { | |
FreePool (AsciiBuffer); | |
return (Status); | |
} | |
Size = AsciiStrSize ("\r\n") - sizeof (CHAR8); | |
Status = FileHandleWrite (Handle, &Size, "\r\n"); | |
} else { | |
if (OriginalFilePosition == 0) { | |
Status = FileHandleSetPosition (Handle, sizeof (CHAR16)); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
} | |
Size = StrSize (Buffer) - sizeof (CHAR16); | |
Status = FileHandleWrite (Handle, &Size, Buffer); | |
if (EFI_ERROR (Status)) { | |
return (Status); | |
} | |
Size = StrSize (L"\r\n") - sizeof (CHAR16); | |
Status = FileHandleWrite (Handle, &Size, L"\r\n"); | |
} | |
if (AsciiBuffer != NULL) { | |
FreePool (AsciiBuffer); | |
} | |
return Status; | |
} | |
/** | |
function to take a formatted argument and print it to a file. | |
@param[in] Handle the file handle for the file to write to | |
@param[in] Format the format argument (see printlib for format specifier) | |
@param[in] ... the variable arguments for the format | |
@retval EFI_SUCCESS the operation was successful | |
@return other a return value from FileHandleWriteLine | |
@sa FileHandleWriteLine | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileHandlePrintLine ( | |
IN EFI_FILE_HANDLE Handle, | |
IN CONST CHAR16 *Format, | |
... | |
) | |
{ | |
VA_LIST Marker; | |
CHAR16 *Buffer; | |
EFI_STATUS Status; | |
// | |
// Get a buffer to print into | |
// | |
Buffer = AllocateZeroPool (PcdGet16 (PcdUefiFileHandleLibPrintBufferSize)); | |
if (Buffer == NULL) { | |
return (EFI_OUT_OF_RESOURCES); | |
} | |
// | |
// Print into our buffer | |
// | |
VA_START (Marker, Format); | |
UnicodeVSPrint (Buffer, PcdGet16 (PcdUefiFileHandleLibPrintBufferSize), Format, Marker); | |
VA_END (Marker); | |
// | |
// Print buffer into file | |
// | |
Status = FileHandleWriteLine (Handle, Buffer); | |
// | |
// Cleanup and return | |
// | |
FreePool (Buffer); | |
return (Status); | |
} | |
/** | |
Function to determine if a FILE_HANDLE is at the end of the file. | |
This will NOT work on directories. | |
If Handle is NULL, then return False. | |
@param[in] Handle the file handle | |
@retval TRUE the position is at the end of the file | |
@retval FALSE the position is not at the end of the file | |
**/ | |
BOOLEAN | |
EFIAPI | |
FileHandleEof ( | |
IN EFI_FILE_HANDLE Handle | |
) | |
{ | |
EFI_FILE_INFO *Info; | |
UINT64 Pos; | |
BOOLEAN RetVal; | |
if (Handle == NULL) { | |
return (FALSE); | |
} | |
FileHandleGetPosition (Handle, &Pos); | |
Info = FileHandleGetInfo (Handle); | |
if (Info == NULL) { | |
return (FALSE); | |
} | |
FileHandleSetPosition (Handle, Pos); | |
if (Pos == Info->FileSize) { | |
RetVal = TRUE; | |
} else { | |
RetVal = FALSE; | |
} | |
FreePool (Info); | |
return (RetVal); | |
} |