/** @file | |
Provides interface to EFI_FILE_HANDLE functionality. | |
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved. <BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#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); | |
// | |
// 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) && (FileInfo != NULL)) { | |
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 sucessfully. | |
**/ | |
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 sucessfully | |
@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 begining of file | |
@retval EFI_SUCCESS Operation completed sucessfully. | |
@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 begining of file. | |
@retval EFI_SUCCESS the operation completed sucessfully. | |
@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 begining 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 sucessfully. | |
@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 { | |
// | |
// We got info... do we have a name? if yes preceed the current path with it... | |
// | |
if (StrLen (FileInfo->FileName) == 0) { | |
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); | |
} | |
} | |
// | |
// Move to the parent directory | |
// | |
Status = CurrentHandle->Open (CurrentHandle, &NextHigherHandle, L"..", EFI_FILE_MODE_READ, 0); | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
FileHandleClose(CurrentHandle); | |
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; | |
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){ | |
*Size = (CountSoFar+1-CrCount)*sizeof(CHAR16); | |
if (!Truncate) { | |
if (Buffer != NULL && *Size != 0) { | |
ZeroMem(Buffer, *Size); | |
} | |
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 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; | |
} | |
UnicodeStrToAsciiStr (Buffer, AsciiBuffer); | |
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 sucessful | |
@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); | |
} |