diff options
Diffstat (limited to 'Core/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c')
-rw-r--r-- | Core/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c | 1272 |
1 files changed, 1272 insertions, 0 deletions
diff --git a/Core/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c b/Core/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c new file mode 100644 index 0000000000..57aad77bc1 --- /dev/null +++ b/Core/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c @@ -0,0 +1,1272 @@ +/** @file
+ Provides interface to EFI_FILE_HANDLE functionality.
+
+ Copyright (c) 2006 - 2017, 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 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 {
+ //
+ // We got info... do we have a name? if yes precede 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 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);
+}
|