Partially fix APFS recovery detection

This commit is contained in:
vit9696 2019-01-24 22:41:38 +03:00
parent 5e3dc3c6df
commit b13c2a493e
4 changed files with 186 additions and 9 deletions

View File

@ -47,4 +47,30 @@ OcDescribeBootEntry (
IN OUT CHAR16 **BootPathName OPTIONAL
);
/**
Discovered boot entry.
Note, DevicePath must be freed.
**/
typedef struct OC_BOOT_ENTRY_ {
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
BOOLEAN PrefersDmgBoot;
} OC_BOOT_ENTRY;
/**
@param[in] BootPolicy Apple Boot Policy Protocol.
@param[in] Mode Lookup mode.
@param[out] BootEntries List of boot entries (allocated from pool).
@param[out] Count Number of boot entries.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval EFI_ALREADY_STARTED The protocol has already been installed.
**/
EFI_STATUS
OcScanForBootEntries (
IN APPLE_BOOT_POLICY_PROTOCOL *BootPolicy,
IN UINT32 Mode,
OUT OC_BOOT_ENTRY **BootEntries,
OUT UINTN *Count
);
#endif // OC_APPLE_BOOT_POLICY_LIB_H

View File

@ -556,9 +556,10 @@ HasValidGuidStringPrefix (
}
for (Index = 0; Index < GuidLength; ++Index) {
if ((Index == 8 || Index == 12 || Index == 16 || Index == 20)
&& String[Index] != '-') {
return FALSE;
if (Index == 8 || Index == 13 || Index == 18 || Index == 23) {
if (String[Index] != '-') {
return FALSE;
}
} else if (!(String[Index] >= L'0' && String[Index] <= L'9')
&& !(String[Index] >= L'A' && String[Index] <= L'F')
&& !(String[Index] >= L'a' && String[Index] <= L'f')) {
@ -1035,12 +1036,12 @@ BootPolicyGetPathNameOnApfsRecovery (
}
NewHandle->Close (NewHandle);
(*Root)->Close (*Root);
if (!EFI_ERROR (Result)) {
break;
}
(*Root)->Close (*Root);
FreePool (FullPathBuffer);
}

View File

@ -44,6 +44,7 @@
gAppleApfsVolumeInfoGuid ## SOMETIMES_CONSUMES
gAppleBlessedSystemFileInfoGuid ## SOMETIMES_CONSUMES
gAppleBlessedSystemFolderInfoGuid ## SOMETIMES_CONSUMES
gAppleBlessedAlternateOsInfoGuid ## SOMETIMES_CONSUMES
gEfiFileInfoGuid ## SOMETIMES_CONSUMES
[Protocols]

View File

@ -36,7 +36,8 @@ STATIC
CHAR16 *
GetAppleDiskLabel (
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem,
IN CONST CHAR16 *BootDirectoryName
IN CONST CHAR16 *BootDirectoryName,
IN CONST CHAR16 *LabelFilename
)
{
CHAR16 *DiskLabelPath;
@ -45,14 +46,14 @@ GetAppleDiskLabel (
CHAR16 *UnicodeDiskLabel;
UINTN DiskLabelLength;
DiskLabelPathSize = StrSize (BootDirectoryName) + L_STR_SIZE_NT (L".disk_label.contentDetails");
DiskLabelPathSize = StrSize (BootDirectoryName) + StrLen (LabelFilename);
DiskLabelPath = AllocatePool (DiskLabelPathSize);
if (DiskLabelPath == NULL) {
return NULL;
}
UnicodeSPrint (DiskLabelPath, DiskLabelPathSize, L"%s.disk_label.contentDetails", BootDirectoryName);
UnicodeSPrint (DiskLabelPath, DiskLabelPathSize, L"%s%s", BootDirectoryName, LabelFilename);
AsciiDiskLabel = (CHAR8 *) ReadFile (FileSystem, DiskLabelPath, &DiskLabelLength);
FreePool (DiskLabelPath);
@ -158,6 +159,54 @@ GetAppleRecoveryName (
return UnicodeDiskLabel;
}
STATIC
EFI_STATUS
GetAlternateOsBooter (
IN EFI_HANDLE Device,
OUT EFI_DEVICE_PATH_PROTOCOL **FilePath
)
{
EFI_STATUS Status;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
EFI_FILE_PROTOCOL *Root;
UINTN FilePathSize;
Status = gBS->HandleProtocol (
Device,
&gEfiSimpleFileSystemProtocolGuid,
(VOID **) &FileSystem
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = FileSystem->OpenVolume (FileSystem, &Root);
if (EFI_ERROR (Status)) {
return Status;
}
*FilePath = (EFI_DEVICE_PATH_PROTOCOL *) GetFileInfo (
Root,
&gAppleBlessedAlternateOsInfoGuid,
sizeof (EFI_DEVICE_PATH_PROTOCOL),
&FilePathSize
);
if (*FilePath != NULL) {
if (!IsDevicePathValid(*FilePath, FilePathSize)) {
FreePool (*FilePath);
*FilePath = NULL;
Status = EFI_NOT_FOUND;
}
} else {
Status = EFI_NOT_FOUND;
}
Root->Close (Root);
return Status;
}
EFI_STATUS
OcDescribeBootEntry (
IN APPLE_BOOT_POLICY_PROTOCOL *BootPolicy,
@ -198,7 +247,13 @@ OcDescribeBootEntry (
}
if (BootEntryName != NULL) {
*BootEntryName = GetAppleDiskLabel (FileSystem, BootDirectoryName);
//
// Try to use APFS-style label or legacy HFS one.
//
*BootEntryName = GetAppleDiskLabel (FileSystem, BootDirectoryName, L".contentDetails");
if (*BootEntryName == NULL) {
*BootEntryName = GetAppleDiskLabel (FileSystem, BootDirectoryName, L".disk_label.contentDetails");
}
if (*BootEntryName == NULL) {
*BootEntryName = GetVolumeLabel (FileSystem);
if (*BootEntryName != NULL && !StrCmp (*BootEntryName, L"Recovery HD")) {
@ -223,4 +278,98 @@ OcDescribeBootEntry (
}
return EFI_SUCCESS;
}
}
EFI_STATUS
OcScanForBootEntries (
IN APPLE_BOOT_POLICY_PROTOCOL *BootPolicy,
IN UINT32 Mode,
OUT OC_BOOT_ENTRY **BootEntries,
OUT UINTN *Count
)
{
EFI_STATUS Status;
UINTN NoHandles;
EFI_HANDLE *Handles;
UINTN Index;
OC_BOOT_ENTRY *Entries;
UINTN EntryIndex;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
CHAR16 *RecoveryPath;
VOID *Reserved;
EFI_FILE_PROTOCOL *RecoveryRoot;
EFI_HANDLE RecoveryDeviceHandle;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiSimpleFileSystemProtocolGuid,
NULL,
&NoHandles,
&Handles
);
if (EFI_ERROR (Status)) {
return Status;
}
if (NoHandles == 0) {
FreePool (Handles);
return EFI_NOT_FOUND;
}
Entries = AllocateZeroPool (NoHandles * 2 * sizeof (OC_BOOT_ENTRY));
if (Entries == NULL) {
FreePool (Handles);
return EFI_OUT_OF_RESOURCES;
}
EntryIndex = 0;
for (Index = 0; Index < NoHandles; ++Index) {
Status = BootPolicy->GetBootFileEx (
Handles[Index],
APPLE_BOOT_POLICY_MODE_1,
&DevicePath
);
if (EFI_ERROR (Status)) {
continue;
}
Entries[EntryIndex].DevicePath = DevicePath;
++EntryIndex;
Status = BootPolicy->GetPathNameOnApfsRecovery (
DevicePath,
L"",
&RecoveryPath,
&Reserved,
&RecoveryRoot,
&RecoveryDeviceHandle
);
if (!EFI_ERROR (Status)) {
DevicePath = FileDevicePath (RecoveryDeviceHandle, RecoveryPath);
FreePool (RecoveryPath);
RecoveryRoot->Close (RecoveryRoot);
} else {
Status = GetAlternateOsBooter (Handles[Index], &DevicePath);
if (EFI_ERROR (Status)) {
continue;
}
}
Entries[EntryIndex].DevicePath = DevicePath;
Entries[EntryIndex].PrefersDmgBoot = TRUE;
++EntryIndex;
}
FreePool (Handles);
*BootEntries = Entries;
*Count = EntryIndex;
return EFI_SUCCESS;
}