+/** @file\r
+ Provides interface to EFI_FILE_HANDLE functionality.\r
+\r
+Copyright (c) 2006 - 2009, Intel Corporation\r
+All rights reserved. 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 <Library/ShellLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include <Protocol/SimpleFileSystem.h>\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\92s information. It is the \r
+ caller\92s 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_GUID FileInfoGuid;\r
+ EFI_FILE_INFO *pFileInfo;\r
+ UINTN FileInfoSize;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // ASSERT if FileHandle is NULL\r
+ //\r
+ ASSERT (FileHandle != NULL);\r
+\r
+ //\r
+ // Get the required size to allocate\r
+ //\r
+ FileInfoGuid = gEfiFileInfoGuid;\r
+ FileInfoSize = 0;\r
+ pFileInfo = NULL;\r
+ Status = FileHandle->GetInfo(FileHandle, \r
+ &FileInfoGuid, \r
+ &FileInfoSize, \r
+ pFileInfo);\r
+ //\r
+ // error is expected. getting size to allocate\r
+ //\r
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+ pFileInfo = AllocateZeroPool(FileInfoSize);\r
+ ASSERT (pFileInfo != NULL);\r
+ //\r
+ // now get the information\r
+ //\r
+ Status = FileHandle->GetInfo(FileHandle, \r
+ &FileInfoGuid, \r
+ &FileInfoSize, \r
+ pFileInfo);\r
+ //\r
+ // if we got an error free the memory and return NULL\r
+ //\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool(pFileInfo);\r
+ return NULL;\r
+ }\r
+ return (pFileInfo);\r
+}\r
+\r
+/**\r
+ This function will set the information about the file for the opened handle \r
+ specified.\r
+\r
+ @param FileHandle The file handle of the file for which information \r
+ is being set\r
+\r
+ @param FileInfo The infotmation to set.\r
+\r
+ @retval EFI_SUCCESS The information was set.\r
+ @retval EFI_UNSUPPORTED The InformationType is not known.\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
+ EFI_GUID FileInfoGuid;\r
+ \r
+ //\r
+ // ASSERT if the FileHandle or FileInfo is NULL\r
+ //\r
+ ASSERT (FileHandle != NULL);\r
+ ASSERT (FileInfo != NULL);\r
+\r
+ FileInfoGuid = gEfiFileInfoGuid;\r
+ //\r
+ // Set the info\r
+ //\r
+ return (FileHandle->SetInfo(FileHandle, \r
+ &FileInfoGuid,\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\92s 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\92s 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\92s 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
+ //\r
+ // ASSERT if FileHandle is NULL\r
+ //\r
+ ASSERT (FileHandle != NULL);\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 \93volume space full\94). \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
+ //\r
+ // ASSERT if FileHandle is NULL\r
+ //\r
+ ASSERT (FileHandle != NULL);\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 \93dirty\94 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
+ // ASSERT if FileHandle is NULL\r
+ //\r
+ ASSERT (FileHandle != NULL);\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
+ // ASSERT if FileHandle is NULL\r
+ //\r
+ ASSERT (FileHandle != NULL);\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
+ //\r
+ // ASSERT if FileHandle is NULL\r
+ //\r
+ ASSERT (FileHandle != NULL);\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
+ //\r
+ // ASSERT if FileHandle is NULL\r
+ //\r
+ ASSERT (FileHandle != NULL);\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
+ //\r
+ // ASSERT if FileHandle is NULL\r
+ //\r
+ ASSERT (FileHandle != NULL);\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 ASSERT()\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
+ //\r
+ // ASSERT if DirHandle is NULL\r
+ //\r
+ ASSERT(DirHandle != NULL);\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
+/**\r
+ Retrieves the first file from a directory\r
+\r
+ This function opens a directory and gets the first file\92s info in the \r
+ directory. Caller can use FileHandleFindNextFile() to get other files. When \r
+ complete the caller is responsible for calling FreePool() on Buffer.\r
+\r
+ @param DirHandle The file handle of the directory to search\r
+ @param Buffer 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
+ //\r
+ // ASSERTs\r
+ //\r
+ ASSERT (DirHandle != NULL);\r
+ ASSERT (Buffer != NULL);\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
+ // reset to the begining of the directory \r
+ //\r
+ Status = FileHandleSetPosition(DirHandle, 0);\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
+ ASSERT (*Buffer != NULL);\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)) {\r
+ FreePool(*Buffer);\r
+ *Buffer = NULL;\r
+ return (Status);\r
+ }\r
+ return (EFI_SUCCESS);\r
+}\r
+/**\r
+ Retrieves the next file in a directory.\r
+\r
+ To use this function, caller must call the FileHandleFindFirstFile() to get the \r
+ first file, and then use this function get other files. This function can be \r
+ called for several times to get each file's information in the directory. If \r
+ the call of FileHandleFindNextFile() got the last file in the directory, the next \r
+ call of this function has no file to get. *NoFile will be set to TRUE and the \r
+ Buffer memory will be automatically freed. \r
+\r
+ @param DirHandle the file handle of the directory\r
+ @param Buffer pointer to buffer for file's information\r
+ @param NoFile 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
+ //\r
+ // ASSERTs for DirHandle or Buffer or NoFile poitners being NULL\r
+ //\r
+ ASSERT (DirHandle != NULL);\r
+ ASSERT (Buffer != NULL);\r
+ ASSERT (NoFile != NULL);\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
+ // 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
+ Retrieve the size of a file.\r
+\r
+ if FileHandle is NULL then ASSERT()\r
+ if Size is NULL then ASSERT()\r
+\r
+ This function extracts the file size info from the FileHandle\92s 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
+ //\r
+ // ASSERT for FileHandle or Size being NULL\r
+ //\r
+ ASSERT (FileHandle != NULL);\r
+ ASSERT (Size != NULL);\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
+}
\ No newline at end of file