| /** @file | |
| Provides interface to EFI_FILE_HANDLE functionality. | |
| Copyright (c) 2006 - 2016, 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] >= 0) && (AsciiBuffer[Index] < 128))){ | |
| 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); | |
| } |