From 1de86ce7bfe5a0e01b1b4d0bfbeebe5a4e61693f Mon Sep 17 00:00:00 2001 From: vit9696 Date: Sat, 20 Apr 2019 23:53:46 +0300 Subject: [PATCH] OcFileLib: Implement incompatible trailing slash hack for older firmwares --- Include/Library/OcFileLib.h | 25 +++ .../OcAppleDiskImageBlockIo.c | 5 +- .../OcBootManagementLib/OcBootManagementLib.c | 139 --------------- Library/OcFileLib/OcFileLib.inf | 1 + Library/OcFileLib/OpenFileByDp.c | 163 ++++++++++++++++++ 5 files changed, 191 insertions(+), 142 deletions(-) create mode 100644 Library/OcFileLib/OpenFileByDp.c diff --git a/Include/Library/OcFileLib.h b/Include/Library/OcFileLib.h index 31953cb3..56113a37 100755 --- a/Include/Library/OcFileLib.h +++ b/Include/Library/OcFileLib.h @@ -196,4 +196,29 @@ FindWritableFileSystem ( IN OUT EFI_FILE_PROTOCOL **WritableFs ); +/** + Open a file or directory by device path. This is a modified + version of EfiOpenFileByDevicePath function, which handles paths + with trailing slashes, that cause Open failure on old firmwares. + EfiOpenFileByDevicePath is additionally not available in UDK. + + See more details at: + https://github.com/tianocore/edk2/commit/768b611136d0f2b99a99e446c089d1a30c3fa5d5 + + @param[in,out] FilePath Device path protocol. + @param[out] File Resulting file protocol. + @param[in] OpenMode File open mode. + @param[in] Attributes File attributes. + + @retval EFI_SUCCESS on succesful open. +**/ +EFI_STATUS +EFIAPI +OcOpenFileByDevicePath ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT EFI_FILE_PROTOCOL **File, + IN UINT64 OpenMode, + IN UINT64 Attributes + ); + #endif // OC_FILE_LIB_H diff --git a/Library/OcAppleDiskImageLib/OcAppleDiskImageBlockIo.c b/Library/OcAppleDiskImageLib/OcAppleDiskImageBlockIo.c index a0c18322..094337ff 100644 --- a/Library/OcAppleDiskImageLib/OcAppleDiskImageBlockIo.c +++ b/Library/OcAppleDiskImageLib/OcAppleDiskImageBlockIo.c @@ -212,10 +212,9 @@ InternalConstructDmgDevicePath ( DevPath->Size.Vendor.Header.SubType = MSG_VENDOR_DP; DevPath->Size.Length = FileSize; SetDevicePathNodeLength (&DevPath->Size, sizeof (DevPath->Size)); - CopyMem ( + CopyGuid ( &DevPath->Size.Vendor.Guid, - &gAppleDiskImageProtocolGuid, - sizeof (DevPath->Size.Vendor.Guid) + &gAppleDiskImageProtocolGuid ); SetDevicePathEndNode (&DevPath->End); diff --git a/Library/OcBootManagementLib/OcBootManagementLib.c b/Library/OcBootManagementLib/OcBootManagementLib.c index 87652eae..cd441c35 100644 --- a/Library/OcBootManagementLib/OcBootManagementLib.c +++ b/Library/OcBootManagementLib/OcBootManagementLib.c @@ -851,145 +851,6 @@ InternalFindDmgChunklist ( return NULL; } -/** - FIXME: Remove this once EfiOpenFileByDevicePath lands into UDK. - https://github.com/tianocore/edk2/commit/768b611136d0f2b99a99e446c089d1a30c3fa5d5 -**/ -EFI_STATUS -EFIAPI -OcOpenFileByDevicePath ( - IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, - OUT EFI_FILE_PROTOCOL **File, - IN UINT64 OpenMode, - IN UINT64 Attributes - ) -{ - EFI_STATUS Status; - EFI_HANDLE FileSystemHandle; - EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem; - EFI_FILE_PROTOCOL *LastFile; - FILEPATH_DEVICE_PATH *FilePathNode; - CHAR16 *AlignedPathName; - CHAR16 *PathName; - EFI_FILE_PROTOCOL *NextFile; - - if (File == NULL) { - return EFI_INVALID_PARAMETER; - } - *File = NULL; - - if (FilePath == NULL) { - return EFI_INVALID_PARAMETER; - } - - // - // Look up the filesystem. - // - Status = gBS->LocateDevicePath ( - &gEfiSimpleFileSystemProtocolGuid, - FilePath, - &FileSystemHandle - ); - if (EFI_ERROR (Status)) { - return Status; - } - Status = gBS->OpenProtocol ( - FileSystemHandle, - &gEfiSimpleFileSystemProtocolGuid, - (VOID **)&FileSystem, - gImageHandle, - NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Open the root directory of the filesystem. After this operation succeeds, - // we have to release LastFile on error. - // - Status = FileSystem->OpenVolume (FileSystem, &LastFile); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Traverse the device path nodes relative to the filesystem. - // - while (!IsDevicePathEnd (*FilePath)) { - if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH || - DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP) { - Status = EFI_INVALID_PARAMETER; - goto CloseLastFile; - } - FilePathNode = (FILEPATH_DEVICE_PATH *)*FilePath; - - // - // FilePathNode->PathName may be unaligned, and the UEFI specification - // requires pointers that are passed to protocol member functions to be - // aligned. Create an aligned copy of the pathname if necessary. - // - if ((UINTN)FilePathNode->PathName % sizeof *FilePathNode->PathName == 0) { - AlignedPathName = NULL; - PathName = FilePathNode->PathName; - } else { - AlignedPathName = AllocateCopyPool ( - (DevicePathNodeLength (FilePathNode) - - SIZE_OF_FILEPATH_DEVICE_PATH), - FilePathNode->PathName - ); - if (AlignedPathName == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto CloseLastFile; - } - PathName = AlignedPathName; - } - - // - // Open or create the file corresponding to the next pathname fragment. - // - Status = LastFile->Open ( - LastFile, - &NextFile, - PathName, - OpenMode, - Attributes - ); - - // - // Release any AlignedPathName on both error and success paths; PathName is - // no longer needed. - // - if (AlignedPathName != NULL) { - FreePool (AlignedPathName); - } - if (EFI_ERROR (Status)) { - goto CloseLastFile; - } - - // - // Advance to the next device path node. - // - LastFile->Close (LastFile); - LastFile = NextFile; - *FilePath = NextDevicePathNode (FilePathNode); - } - - *File = LastFile; - return EFI_SUCCESS; - -CloseLastFile: - LastFile->Close (LastFile); - - // - // We are on the error path; we must have set an error Status for returning - // to the caller. - // - ASSERT (EFI_ERROR (Status)); - return Status; -} - STATIC EFI_DEVICE_PATH_PROTOCOL * InternalLoadDmg ( diff --git a/Library/OcFileLib/OcFileLib.inf b/Library/OcFileLib/OcFileLib.inf index 6cbc6df9..c295d989 100755 --- a/Library/OcFileLib/OcFileLib.inf +++ b/Library/OcFileLib/OcFileLib.inf @@ -31,6 +31,7 @@ GetFileInfo.c GetVolumeLabel.c LocateFileSystem.c + OpenFileByDp.c ReadFile.c [Packages] diff --git a/Library/OcFileLib/OpenFileByDp.c b/Library/OcFileLib/OpenFileByDp.c new file mode 100644 index 00000000..a691e51a --- /dev/null +++ b/Library/OcFileLib/OpenFileByDp.c @@ -0,0 +1,163 @@ +/** @file + The UEFI Library provides functions and macros that simplify the development of + UEFI Drivers and UEFI Applications. These functions and macros help manage EFI + events, build simple locks utilizing EFI Task Priority Levels (TPLs), install + EFI Driver Model related protocols, manage Unicode string tables for UEFI Drivers, + and print messages on the console output and standard error devices. + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ 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 + +#include +#include +#include +#include +#include + +#include +#include + +EFI_STATUS +EFIAPI +OcOpenFileByDevicePath ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT EFI_FILE_PROTOCOL **File, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + EFI_HANDLE FileSystemHandle; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem; + EFI_FILE_PROTOCOL *LastFile; + FILEPATH_DEVICE_PATH *FilePathNode; + CHAR16 *AlignedPathName; + CHAR16 *PathName; + UINTN PathLength; + EFI_FILE_PROTOCOL *NextFile; + + if (File == NULL) { + return EFI_INVALID_PARAMETER; + } + *File = NULL; + + if (FilePath == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Look up the filesystem. + // + Status = gBS->LocateDevicePath ( + &gEfiSimpleFileSystemProtocolGuid, + FilePath, + &FileSystemHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + Status = gBS->OpenProtocol ( + FileSystemHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID **)&FileSystem, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Open the root directory of the filesystem. After this operation succeeds, + // we have to release LastFile on error. + // + Status = FileSystem->OpenVolume (FileSystem, &LastFile); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Traverse the device path nodes relative to the filesystem. + // + while (!IsDevicePathEnd (*FilePath)) { + if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH || + DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP) { + Status = EFI_INVALID_PARAMETER; + goto CloseLastFile; + } + FilePathNode = (FILEPATH_DEVICE_PATH *)*FilePath; + + // + // FilePathNode->PathName may be unaligned, and the UEFI specification + // requires pointers that are passed to protocol member functions to be + // aligned. Create an aligned copy of the pathname to match that + // and to apply the hack below. + // + AlignedPathName = AllocateCopyPool ( + (DevicePathNodeLength (FilePathNode) - + SIZE_OF_FILEPATH_DEVICE_PATH), + FilePathNode->PathName + ); + if (AlignedPathName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto CloseLastFile; + } + + // + // This is a compatibility hack for firmwares not supporting + // opening filepaths (directories) with a trailing slash in the end. + // More details in a852f85986c1fe23fc3a429605e3c560ea800c54 OpenCorePkg commit. + // + PathLength = StrLen (AlignedPathName); + if (PathLength > 0 && AlignedPathName[PathLength - 1] == '\\') { + AlignedPathName[PathLength - 1] = '\0'; + } + + PathName = AlignedPathName; + + // + // Open or create the file corresponding to the next pathname fragment. + // + Status = LastFile->Open ( + LastFile, + &NextFile, + PathName, + OpenMode, + Attributes + ); + + FreePool (AlignedPathName); + + if (EFI_ERROR (Status)) { + goto CloseLastFile; + } + + // + // Advance to the next device path node. + // + LastFile->Close (LastFile); + LastFile = NextFile; + *FilePath = NextDevicePathNode (FilePathNode); + } + + *File = LastFile; + return EFI_SUCCESS; + +CloseLastFile: + LastFile->Close (LastFile); + + // + // We are on the error path; we must have set an error Status for returning + // to the caller. + // + ASSERT (EFI_ERROR (Status)); + return Status; +}