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