X-Git-Url: https://code.delx.au/refind/blobdiff_plain/e3d2b4a15b8e4a6e7d6e3a6421270fccfb06c4f0..83e1f5a6803d47d7d6ef9bbd23e8467e5e4346e1:/refind/lib.c diff --git a/refind/lib.c b/refind/lib.c index 0053c2b..893f62c 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -48,7 +48,7 @@ #include "screen.h" #include "../include/refit_call_wrapper.h" #include "../include/RemovableMedia.h" -//#include "../include/UsbMass.h" +#include "gpt.h" #ifdef __MAKEWITH_GNUEFI #define EfiReallocatePool ReallocatePool @@ -86,6 +86,7 @@ CHAR16 *SelfDirPath; REFIT_VOLUME *SelfVolume = NULL; REFIT_VOLUME **Volumes = NULL; UINTN VolumesCount = 0; +extern GPT_DATA *gPartitions; // Maximum size for disk sectors #define SECTOR_SIZE 4096 @@ -264,6 +265,43 @@ static EFI_STATUS FinishInitRefitLib(VOID) return EFI_SUCCESS; } +// +// EFI variable read and write functions +// + +// From gummiboot: Retrieve a raw EFI variable. +// Returns EFI status +EFI_STATUS EfivarGetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) { + CHAR8 *buf; + UINTN l; + EFI_STATUS err; + + l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE; + buf = AllocatePool(l); + if (!buf) + return EFI_OUT_OF_RESOURCES; + + err = refit_call5_wrapper(RT->GetVariable, name, vendor, NULL, &l, buf); + if (EFI_ERROR(err) == EFI_SUCCESS) { + *buffer = buf; + if (size) + *size = l; + } else + MyFreePool(buf); + return err; +} // EFI_STATUS EfivarGetRaw() + +// From gummiboot: Set an EFI variable +EFI_STATUS EfivarSetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) { + UINT32 flags; + + flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS; + if (persistent) + flags |= EFI_VARIABLE_NON_VOLATILE; + + return refit_call5_wrapper(RT->SetVariable, name, vendor, flags, size, buf); +} // EFI_STATUS EfivarSetRaw() + // // list functions // @@ -712,36 +750,46 @@ static CHAR16 *SizeInIEEEUnits(UINT64 SizeInBytes) { // this information can be extracted. // The calling function is responsible for freeing the memory allocated // for the name string. -static CHAR16 *GetVolumeName(IN REFIT_VOLUME *Volume) { - EFI_FILE_SYSTEM_INFO *FileSystemInfoPtr; +static CHAR16 *GetVolumeName(REFIT_VOLUME *Volume) { + EFI_FILE_SYSTEM_INFO *FileSystemInfoPtr = NULL; CHAR16 *FoundName = NULL; CHAR16 *SISize, *TypeName; - FileSystemInfoPtr = LibFileSystemInfo(Volume->RootDir); - if (FileSystemInfoPtr != NULL) { // we have filesystem information (size, label).... - if ((FileSystemInfoPtr->VolumeLabel != NULL) && (StrLen(FileSystemInfoPtr->VolumeLabel) > 0)) { - FoundName = StrDuplicate(FileSystemInfoPtr->VolumeLabel); - } - - // Special case: rEFInd HFS+ driver always returns label of "HFS+ volume", so wipe - // this so that we can build a new name that includes the size.... - if ((FoundName != NULL) && (StrCmp(FoundName, L"HFS+ volume") == 0) && (Volume->FSType == FS_TYPE_HFSPLUS)) { - MyFreePool(FoundName); - FoundName = NULL; - } // if rEFInd HFS+ driver suspected - - if (FoundName == NULL) { // filesystem has no name, so use fs type and size - FoundName = AllocateZeroPool(sizeof(CHAR16) * 256); - if (FoundName != NULL) { - SISize = SizeInIEEEUnits(FileSystemInfoPtr->VolumeSize); - SPrint(FoundName, 255, L"%s%s volume", SISize, FSTypeName(Volume->FSType)); - MyFreePool(SISize); - } // if allocated memory OK - } // if (FoundName == NULL) - - FreePool(FileSystemInfoPtr); - - } else { // fs driver not returning info; fall back on our own information.... + if (Volume->RootDir != NULL) { + FileSystemInfoPtr = LibFileSystemInfo(Volume->RootDir); + } + + if ((FileSystemInfoPtr != NULL) && (FileSystemInfoPtr->VolumeLabel != NULL) && + (StrLen(FileSystemInfoPtr->VolumeLabel) > 0)) { + FoundName = StrDuplicate(FileSystemInfoPtr->VolumeLabel); + } + + // Special case: Old versions of the rEFInd HFS+ driver always returns label of "HFS+ volume", so wipe + // this so that we can build a new name that includes the size.... + if ((FoundName != NULL) && (StrCmp(FoundName, L"HFS+ volume") == 0) && (Volume->FSType == FS_TYPE_HFSPLUS)) { + MyFreePool(FoundName); + FoundName = NULL; + } // if rEFInd HFS+ driver suspected + + // If no filesystem name, try to use the partition name.... + if ((FoundName == NULL) && (Volume->PartName != NULL) && (StrLen(Volume->PartName) > 0) && + !IsIn(Volume->PartName, IGNORE_PARTITION_NAMES)) { + FoundName = StrDuplicate(Volume->PartName); + } // if use partition name + + // No filesystem or acceptable partition name, so use fs type and size + if ((FoundName == NULL) && (FileSystemInfoPtr != NULL)) { + FoundName = AllocateZeroPool(sizeof(CHAR16) * 256); + if (FoundName != NULL) { + SISize = SizeInIEEEUnits(FileSystemInfoPtr->VolumeSize); + SPrint(FoundName, 255, L"%s%s volume", SISize, FSTypeName(Volume->FSType)); + MyFreePool(SISize); + } // if allocated memory OK + } // if (FoundName == NULL) + + MyFreePool(FileSystemInfoPtr); + + if (FoundName == NULL) { FoundName = AllocateZeroPool(sizeof(CHAR16) * 256); if (FoundName != NULL) { TypeName = FSTypeName(Volume->FSType); // NOTE: Don't free TypeName; function returns constant @@ -754,7 +802,6 @@ static CHAR16 *GetVolumeName(IN REFIT_VOLUME *Volume) { // TODO: Above could be improved/extended, in case filesystem name is not found, // such as: - // - use partition label // - use or add disk/partition number (e.g., "(hd0,2)") // Desperate fallback name.... @@ -765,7 +812,7 @@ static CHAR16 *GetVolumeName(IN REFIT_VOLUME *Volume) { } // static CHAR16 *GetVolumeName() // Determine the unique GUID of the volume and store it. -static VOID SetPartGuid(REFIT_VOLUME *Volume, EFI_DEVICE_PATH_PROTOCOL *DevicePath) { +static VOID SetPartGuidAndName(REFIT_VOLUME *Volume, EFI_DEVICE_PATH_PROTOCOL *DevicePath) { HARDDRIVE_DEVICE_PATH *HdDevicePath; if (Volume == NULL) @@ -773,8 +820,11 @@ static VOID SetPartGuid(REFIT_VOLUME *Volume, EFI_DEVICE_PATH_PROTOCOL *DevicePa if ((DevicePath->Type == MEDIA_DEVICE_PATH) && (DevicePath->SubType == MEDIA_HARDDRIVE_DP)) { HdDevicePath = (HARDDRIVE_DEVICE_PATH*) DevicePath; - Volume->PartGuid = *((EFI_GUID*) HdDevicePath->Signature); - } + if (HdDevicePath->SignatureType == SIGNATURE_TYPE_GUID) { + Volume->PartGuid = *((EFI_GUID*) HdDevicePath->Signature); + Volume->PartName = PartNameFromGuid(&(Volume->PartGuid)); + } // if + } // if } // VOID SetPartGuid() VOID ScanVolume(REFIT_VOLUME *Volume) @@ -819,7 +869,7 @@ VOID ScanVolume(REFIT_VOLUME *Volume) NextDevicePath = NextDevicePathNode(DevicePath); if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH) { - SetPartGuid(Volume, DevicePath); + SetPartGuidAndName(Volume, DevicePath); } if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH && (DevicePathSubType(DevicePath) == MSG_USB_DP || @@ -861,7 +911,8 @@ VOID ScanVolume(REFIT_VOLUME *Volume) } // look at the BlockIO protocol - Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol, (VOID **) &Volume->WholeDiskBlockIO); + Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol, + (VOID **) &Volume->WholeDiskBlockIO); if (!EFI_ERROR(Status)) { // check the media block size @@ -893,6 +944,8 @@ VOID ScanVolume(REFIT_VOLUME *Volume) // Set volume icon based on .VolumeBadge icon or disk kind SetVolumeBadgeIcon(Volume); + Volume->VolName = GetVolumeName(Volume); + if (Volume->RootDir == NULL) { Volume->IsReadable = FALSE; return; @@ -900,8 +953,6 @@ VOID ScanVolume(REFIT_VOLUME *Volume) Volume->IsReadable = TRUE; } - Volume->VolName = GetVolumeName(Volume); - // get custom volume icons if present if (!Volume->VolIconImage) Volume->VolIconImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeIcon", GlobalConfig.IconSizes[ICON_SIZE_BIG]); @@ -987,11 +1038,11 @@ VOID ScanVolumes(VOID) MyFreePool(Volumes); Volumes = NULL; VolumesCount = 0; + ForgetPartitionTables(); // get all filesystem handles Status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &Handles); UuidList = AllocateZeroPool(sizeof(EFI_GUID) * HandleCount); - // was: &FileSystemProtocol if (Status == EFI_NOT_FOUND) { return; // no filesystems. strange, but true... } @@ -1002,6 +1053,7 @@ VOID ScanVolumes(VOID) for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { Volume = AllocateZeroPool(sizeof(REFIT_VOLUME)); Volume->DeviceHandle = Handles[HandleIndex]; + AddPartitionTable(Volume); ScanVolume(Volume); if (UuidList) { UuidList[HandleIndex] = Volume->VolUuid; @@ -1048,8 +1100,9 @@ VOID ScanVolumes(VOID) Volume->BlockIO != Volume->WholeDiskBlockIO) { for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) { if (Volumes[VolumeIndex2]->BlockIO == Volume->WholeDiskBlockIO && - Volumes[VolumeIndex2]->BlockIOOffset == 0) + Volumes[VolumeIndex2]->BlockIOOffset == 0) { WholeDiskVolume = Volumes[VolumeIndex2]; + } } } @@ -1097,7 +1150,6 @@ VOID ScanVolumes(VOID) MyFreePool(SectorBuffer1); MyFreePool(SectorBuffer2); } - } // for } /* VOID ScanVolumes() */ @@ -1570,6 +1622,89 @@ CHAR16 *FindPath(IN CHAR16* FullPath) { return (PathOnly); } +/*++ + * + * Routine Description: + * + * Find a substring. + * + * Arguments: + * + * String - Null-terminated string to search. + * StrCharSet - Null-terminated string to search for. + * + * Returns: + * The address of the first occurrence of the matching substring if successful, or NULL otherwise. + * --*/ +CHAR16* MyStrStr (CHAR16 *String, CHAR16 *StrCharSet) +{ + CHAR16 *Src; + CHAR16 *Sub; + + if ((String == NULL) || (StrCharSet == NULL)) + return NULL; + + Src = String; + Sub = StrCharSet; + + while ((*String != L'\0') && (*StrCharSet != L'\0')) { + if (*String++ != *StrCharSet) { + String = ++Src; + StrCharSet = Sub; + } else { + StrCharSet++; + } + } + if (*StrCharSet == L'\0') { + return Src; + } else { + return NULL; + } +} // CHAR16 *MyStrStr() + +// Restrict TheString to at most Limit characters. +// Does this in two ways: +// - Locates stretches of two or more spaces and compresses +// them down to one space. +// - Truncates TheString +// Returns TRUE if changes were made, FALSE otherwise +BOOLEAN LimitStringLength(CHAR16 *TheString, UINTN Limit) { + CHAR16 *SubString, *TempString; + UINTN i; + BOOLEAN HasChanged = FALSE; + + // SubString will be NULL or point WITHIN TheString + SubString = MyStrStr(TheString, L" "); + while (SubString != NULL) { + i = 0; + while (SubString[i] == L' ') + i++; + if (i >= StrLen(SubString)) { + SubString[0] = '\0'; + HasChanged = TRUE; + } else { + TempString = StrDuplicate(&SubString[i]); + if (TempString != NULL) { + StrCpy(&SubString[1], TempString); + MyFreePool(TempString); + HasChanged = TRUE; + } else { + // memory allocation problem; abort to avoid potentially infinite loop! + break; + } // if/else + } // if/else + SubString = MyStrStr(TheString, L" "); + } // while + + // If the string is still too long, truncate it.... + if (StrLen(TheString) > Limit) { + TheString[Limit] = '\0'; + HasChanged = TRUE; + } // if + + return HasChanged; +} // BOOLEAN LimitStringLength() + // Takes an input loadpath, splits it into disk and filename components, finds a matching // DeviceVolume, and returns that and the filename (*loader). VOID FindVolumeAndFilename(IN EFI_DEVICE_PATH *loadpath, OUT REFIT_VOLUME **DeviceVolume, OUT CHAR16 **loader) { @@ -1767,9 +1902,26 @@ BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List) { Found = TRUE; } // while } // if - return Found; + return Found; } // BOOLEAN IsIn() +// Returns TRUE if any element of List can be found as a substring of +// BigString, FALSE otherwise. Performs comparisons case-insensitively. +BOOLEAN IsInSubstring(IN CHAR16 *BigString, IN CHAR16 *List) { + UINTN i = 0, ElementLength; + BOOLEAN Found = FALSE; + CHAR16 *OneElement; + + if (BigString && List) { + while (!Found && (OneElement = FindCommaDelimited(List, i++))) { + ElementLength = StrLen(OneElement); + if ((ElementLength <= StrLen(BigString)) && (StriSubCmp(OneElement, BigString))) + Found = TRUE; + } // while + } // if + return Found; +} // BOOLEAN IsSubstringIn() + // Returns TRUE if specified Volume, Directory, and Filename correspond to an // element in the comma-delimited List, FALSE otherwise. Note that Directory and // Filename must *NOT* include a volume or path specification (that's part of @@ -1912,11 +2064,12 @@ BOOLEAN IsGuid(CHAR16 *UnknownString) { for (i = 0; i < Length; i++) { a = UnknownString[i]; - if (((i == 8) || (i == 13) || (i == 18) || (i == 23)) && (a != '-')) { - retval = FALSE; + if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) { + if (a != '-') + retval = FALSE; } else if (((a < 'a') || (a > 'f')) && ((a < 'A') || (a > 'F')) && ((a < '0') && (a > '9'))) { retval = FALSE; - } // if/else + } // if/else if } // for return retval; } // BOOLEAN IsGuid() @@ -1961,9 +2114,6 @@ EFI_GUID StringAsGuid(CHAR16 * InString) { // Returns TRUE if the two GUIDs are equal, FALSE otherwise BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2) { - return ((Guid1->Data1 == Guid2->Data1) && (Guid1->Data2 == Guid2->Data2) && (Guid1->Data3 == Guid2->Data3) && - (Guid1->Data4[0] == Guid2->Data4[0]) && (Guid1->Data4[1] == Guid2->Data4[1]) && - (Guid1->Data4[2] == Guid2->Data4[2]) && (Guid1->Data4[3] == Guid2->Data4[3]) && - (Guid1->Data4[4] == Guid2->Data4[4]) && (Guid1->Data4[5] == Guid2->Data4[5]) && - (Guid1->Data4[6] == Guid2->Data4[6]) && (Guid1->Data4[7] == Guid2->Data4[7])); -} // BOOLEAN CompareGuids() \ No newline at end of file + return (CompareMem(Guid1, Guid2, 16) == 0); +} // BOOLEAN CompareGuids() +