/** @file | |
Internal file explorer helper functions for RamDiskDxe driver. | |
Copyright (c) 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 "RamDiskImpl.h" | |
/** | |
Helper function called as part of the code needed to allocate the proper | |
sized buffer for various EFI interfaces. | |
@param[in, out] Status Current status. | |
@param[in, out] Buffer Current allocated buffer, or NULL. | |
@param[in] BufferSize Current buffer size needed. | |
@retval TRUE If the buffer was reallocated and the caller should | |
try the API again. | |
@retval FALSE The caller should not call this function again. | |
**/ | |
BOOLEAN | |
GrowBuffer ( | |
IN OUT EFI_STATUS *Status, | |
IN OUT VOID **Buffer, | |
IN UINTN BufferSize | |
) | |
{ | |
BOOLEAN TryAgain; | |
// | |
// If this is an initial request, buffer will be null with a new buffer size | |
// | |
if ((*Buffer == NULL) && (BufferSize != 0)) { | |
*Status = EFI_BUFFER_TOO_SMALL; | |
} | |
// | |
// If the status code is "buffer too small", resize the buffer | |
// | |
TryAgain = FALSE; | |
if (*Status == EFI_BUFFER_TOO_SMALL) { | |
if (*Buffer != NULL) { | |
FreePool (*Buffer); | |
} | |
*Buffer = AllocateZeroPool (BufferSize); | |
if (*Buffer != NULL) { | |
TryAgain = TRUE; | |
} else { | |
*Status = EFI_OUT_OF_RESOURCES; | |
} | |
} | |
// | |
// If there's an error, free the buffer | |
// | |
if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) { | |
FreePool (*Buffer); | |
*Buffer = NULL; | |
} | |
return TryAgain; | |
} | |
/** | |
This function gets the file information from an open file descriptor, | |
and stores it in a buffer allocated from pool. | |
@param[in] FHand File Handle. | |
@return A pointer to a buffer with file information or NULL is returned. | |
**/ | |
EFI_FILE_INFO * | |
FileInfo ( | |
IN EFI_FILE_HANDLE FHand | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_FILE_INFO *Buffer; | |
UINTN BufferSize; | |
// | |
// Initialize for GrowBuffer loop | |
// | |
Buffer = NULL; | |
BufferSize = SIZE_OF_EFI_FILE_INFO + 200; | |
// | |
// Call the real function | |
// | |
while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) { | |
Status = FHand->GetInfo ( | |
FHand, | |
&gEfiFileInfoGuid, | |
&BufferSize, | |
Buffer | |
); | |
} | |
return Buffer; | |
} | |
/** | |
This function will open a file or directory referenced by DevicePath. | |
This function opens a file with the open mode according to the file path. The | |
Attributes is valid only for EFI_FILE_MODE_CREATE. | |
@param[in, out] FilePath On input, the device path to the file. | |
On output, the remaining device path. | |
@param[out] FileHandle Pointer to the file handle. | |
@param[in] OpenMode The mode to open the file with. | |
@param[in] Attributes The file's file attributes. | |
@retval EFI_SUCCESS The information was set. | |
@retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. | |
@retval EFI_UNSUPPORTED Could not open the file path. | |
@retval EFI_NOT_FOUND The specified file could not be found on the | |
device or the file system could not be found | |
on the device. | |
@retval EFI_NO_MEDIA The device has no medium. | |
@retval EFI_MEDIA_CHANGED The device has a different medium in it or | |
the medium is no longer supported. | |
@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_OUT_OF_RESOURCES Not enough resources were available to open | |
the file. | |
@retval EFI_VOLUME_FULL The volume is full. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
OpenFileByDevicePath( | |
IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, | |
OUT EFI_FILE_HANDLE *FileHandle, | |
IN UINT64 OpenMode, | |
IN UINT64 Attributes | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol; | |
EFI_FILE_PROTOCOL *Handle1; | |
EFI_FILE_PROTOCOL *Handle2; | |
EFI_HANDLE DeviceHandle; | |
if ((FilePath == NULL || FileHandle == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Status = gBS->LocateDevicePath ( | |
&gEfiSimpleFileSystemProtocolGuid, | |
FilePath, | |
&DeviceHandle | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = gBS->OpenProtocol( | |
DeviceHandle, | |
&gEfiSimpleFileSystemProtocolGuid, | |
(VOID**)&EfiSimpleFileSystemProtocol, | |
gImageHandle, | |
NULL, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1); | |
if (EFI_ERROR (Status)) { | |
FileHandle = NULL; | |
return Status; | |
} | |
// | |
// go down directories one node at a time. | |
// | |
while (!IsDevicePathEnd (*FilePath)) { | |
// | |
// For file system access each node should be a file path component | |
// | |
if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH || | |
DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP | |
) { | |
FileHandle = NULL; | |
return (EFI_INVALID_PARAMETER); | |
} | |
// | |
// Open this file path node | |
// | |
Handle2 = Handle1; | |
Handle1 = NULL; | |
// | |
// Try to test opening an existing file | |
// | |
Status = Handle2->Open ( | |
Handle2, | |
&Handle1, | |
((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, | |
OpenMode &~EFI_FILE_MODE_CREATE, | |
0 | |
); | |
// | |
// see if the error was that it needs to be created | |
// | |
if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) { | |
Status = Handle2->Open ( | |
Handle2, | |
&Handle1, | |
((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, | |
OpenMode, | |
Attributes | |
); | |
} | |
// | |
// Close the last node | |
// | |
Handle2->Close (Handle2); | |
if (EFI_ERROR(Status)) { | |
return (Status); | |
} | |
// | |
// Get the next node | |
// | |
*FilePath = NextDevicePathNode (*FilePath); | |
} | |
// | |
// This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also! | |
// | |
*FileHandle = (VOID*)Handle1; | |
return EFI_SUCCESS; | |
} |