X-Git-Url: https://code.delx.au/refind/blobdiff_plain/9c6e61c4bcc4cc647abe94ae542e5f288b22963a..e3d2b4a15b8e4a6e7d6e3a6421270fccfb06c4f0:/refind/lib.c diff --git a/refind/lib.c b/refind/lib.c index 49c0b99..0053c2b 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -34,8 +34,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* - * Modifications copyright (c) 2012-2013 Roderick W. Smith - * + * Modifications copyright (c) 2012-2014 Roderick W. Smith + * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), a copy of which must be distributed * with this source code or binaries made from it. @@ -471,7 +471,7 @@ static VOID SetFilesystemData(IN UINT8 *Buffer, IN UINTN BufferSize, IN OUT REFI } } // search for ext2/3/4 magic - if (BufferSize >= (65536 + 62)) { + if (BufferSize >= (65536 + 100)) { MagicString = (char*) (Buffer + 65536 + 52); if ((CompareMem(MagicString, REISERFS_SUPER_MAGIC_STRING, 8) == 0) || (CompareMem(MagicString, REISER2FS_SUPER_MAGIC_STRING, 9) == 0) || @@ -507,7 +507,7 @@ static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable) UINT8 Buffer[SAMPLE_SIZE]; UINTN i; MBR_PARTITION_INFO *MbrTable; - BOOLEAN MbrTableFound; + BOOLEAN MbrTableFound = FALSE; Volume->HasBootCode = FALSE; Volume->OSIconName = NULL; @@ -637,7 +637,6 @@ static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable) // check for MBR partition table if (*((UINT16 *)(Buffer + 510)) == 0xaa55) { - MbrTableFound = FALSE; MbrTable = (MBR_PARTITION_INFO *)(Buffer + 446); for (i = 0; i < 4; i++) if (MbrTable[i].StartLBA && MbrTable[i].Size) @@ -662,7 +661,7 @@ static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable) VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume) { if (Volume->VolBadgeImage == NULL) { - Volume->VolBadgeImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeBadge", 128); + Volume->VolBadgeImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeBadge", GlobalConfig.IconSizes[ICON_SIZE_BADGE]); } if (Volume->VolBadgeImage == NULL) { @@ -705,7 +704,7 @@ static CHAR16 *SizeInIEEEUnits(UINT64 SizeInBytes) { SPrint(TheValue, 255, L"%ld%s", SizeInIeee, Units); } // if return TheValue; -} // CHAR16 *SizeInSIUnits() +} // CHAR16 *SizeInIEEEUnits() // Return a name for the volume. Ideally this should be the label for the // filesystem it contains, but this function falls back to describing the @@ -747,7 +746,7 @@ static CHAR16 *GetVolumeName(IN REFIT_VOLUME *Volume) { if (FoundName != NULL) { TypeName = FSTypeName(Volume->FSType); // NOTE: Don't free TypeName; function returns constant if (StrLen(TypeName) > 0) - SPrint(FoundName, 255, L"%s volume", FSTypeName(Volume->FSType)); + SPrint(FoundName, 255, L"%s volume", TypeName); else SPrint(FoundName, 255, L"unknown volume"); } // if allocated memory OK @@ -765,6 +764,19 @@ static CHAR16 *GetVolumeName(IN REFIT_VOLUME *Volume) { return FoundName; } // static CHAR16 *GetVolumeName() +// Determine the unique GUID of the volume and store it. +static VOID SetPartGuid(REFIT_VOLUME *Volume, EFI_DEVICE_PATH_PROTOCOL *DevicePath) { + HARDDRIVE_DEVICE_PATH *HdDevicePath; + + if (Volume == NULL) + return; + + if ((DevicePath->Type == MEDIA_DEVICE_PATH) && (DevicePath->SubType == MEDIA_HARDDRIVE_DP)) { + HdDevicePath = (HARDDRIVE_DEVICE_PATH*) DevicePath; + Volume->PartGuid = *((EFI_GUID*) HdDevicePath->Signature); + } +} // VOID SetPartGuid() + VOID ScanVolume(REFIT_VOLUME *Volume) { EFI_STATUS Status; @@ -806,6 +818,9 @@ VOID ScanVolume(REFIT_VOLUME *Volume) while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) { NextDevicePath = NextDevicePathNode(DevicePath); + if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH) { + SetPartGuid(Volume, DevicePath); + } if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH && (DevicePathSubType(DevicePath) == MSG_USB_DP || DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP || @@ -889,7 +904,7 @@ VOID ScanVolume(REFIT_VOLUME *Volume) // get custom volume icons if present if (!Volume->VolIconImage) - Volume->VolIconImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeIcon", 128); + Volume->VolIconImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeIcon", GlobalConfig.IconSizes[ICON_SIZE_BIG]); } // ScanVolume() static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry) @@ -967,7 +982,7 @@ VOID ScanVolumes(VOID) UINTN SectorSum, i, VolNumber = 0; UINT8 *SectorBuffer1, *SectorBuffer2; EFI_GUID *UuidList; - EFI_GUID NullUuid = { 00000000, 0000, 0000, {0000, 0000, 0000, 0000} }; + EFI_GUID NullUuid = NULL_GUID_VALUE; MyFreePool(Volumes); Volumes = NULL; @@ -1138,7 +1153,8 @@ VOID ReinitVolumes(VOID) if (!EFI_ERROR(Status)) { // get 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)) { Volume->WholeDiskBlockIO = NULL; CheckError(Status, L"from HandleProtocol"); @@ -1548,7 +1564,8 @@ CHAR16 *FindPath(IN CHAR16* FullPath) { LastBackslash = i; } // for PathOnly = StrDuplicate(FullPath); - PathOnly[LastBackslash] = 0; + if (PathOnly != NULL) + PathOnly[LastBackslash] = 0; } // if return (PathOnly); } @@ -1681,6 +1698,61 @@ CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index) { return (FoundString); } // CHAR16 *FindCommaDelimited() +// Return the position of SmallString within BigString, or -1 if +// not found. +INTN FindSubString(IN CHAR16 *SmallString, IN CHAR16 *BigString) { + INTN Position = -1; + UINTN i = 0, SmallSize, BigSize; + BOOLEAN Found = FALSE; + + if ((SmallString == NULL) || (BigString == NULL)) + return -1; + + SmallSize = StrLen(SmallString); + BigSize = StrLen(BigString); + if ((SmallSize > BigSize) || (SmallSize == 0) || (BigSize == 0)) + return -1; + + while ((i <= (BigSize - SmallSize) && !Found)) { + if (CompareMem(BigString + i, SmallString, SmallSize) == 0) { + Found = TRUE; + Position = i; + } // if + i++; + } // while() + return Position; +} // INTN FindSubString() + +// Take an input path name, which may include a volume specification and/or +// a path, and return separate volume, path, and file names. For instance, +// "BIGVOL:\EFI\ubuntu\grubx64.efi" will return a VolName of "BIGVOL", a Path +// of "EFI\ubuntu", and a Filename of "grubx64.efi". If an element is missing, +// the returned pointer is NULL. The calling function is responsible for +// freeing the allocated memory. +VOID SplitPathName(CHAR16 *InPath, CHAR16 **VolName, CHAR16 **Path, CHAR16 **Filename) { + CHAR16 *Temp = NULL; + + MyFreePool(*VolName); + MyFreePool(*Path); + MyFreePool(*Filename); + *VolName = *Path = *Filename = NULL; + Temp = StrDuplicate(InPath); + SplitVolumeAndFilename(&Temp, VolName); // VolName is NULL or has volume; Temp has rest of path + CleanUpPathNameSlashes(Temp); + *Path = FindPath(Temp); // *Path has path (may be 0-length); Temp unchanged. + *Filename = StrDuplicate(Temp + StrLen(*Path)); + CleanUpPathNameSlashes(*Filename); + if (StrLen(*Path) == 0) { + MyFreePool(*Path); + *Path = NULL; + } + if (StrLen(*Filename) == 0) { + MyFreePool(*Filename); + *Filename = NULL; + } + MyFreePool(Temp); +} // VOID SplitPathName + // Returns TRUE if SmallString is an element in the comma-delimited List, // FALSE otherwise. Performs comparison case-insensitively (except on // buggy EFIs with case-sensitive StriCmp() functions). @@ -1695,9 +1767,63 @@ BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List) { Found = TRUE; } // while } // if - return Found; + return Found; } // BOOLEAN IsIn() +// 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 +// the Volume variable), but the List elements may. Performs comparison +// case-insensitively (except on buggy EFIs with case-sensitive StriCmp() +// functions). +BOOLEAN FilenameIn(REFIT_VOLUME *Volume, CHAR16 *Directory, CHAR16 *Filename, CHAR16 *List) { + UINTN i = 0; + BOOLEAN Found = FALSE; + CHAR16 *OneElement; + CHAR16 *TargetVolName = NULL, *TargetPath = NULL, *TargetFilename = NULL; + + if (Filename && List) { + while (!Found && (OneElement = FindCommaDelimited(List, i++))) { + Found = TRUE; + SplitPathName(OneElement, &TargetVolName, &TargetPath, &TargetFilename); + VolumeNumberToName(Volume, &TargetVolName); + if (((TargetVolName != NULL) && ((Volume == NULL) || (StriCmp(TargetVolName, Volume->VolName) != 0))) || + ((TargetPath != NULL) && (StriCmp(TargetPath, Directory) != 0)) || + ((TargetFilename != NULL) && (StriCmp(TargetFilename, Filename) != 0))) { + Found = FALSE; + } // if + MyFreePool(OneElement); + } // while + } // if + + MyFreePool(TargetVolName); + MyFreePool(TargetPath); + MyFreePool(TargetFilename); + return Found; +} // BOOLEAN FilenameIn() + +// If *VolName is of the form "fs#", where "#" is a number, and if Volume points +// to this volume number, returns with *VolName changed to the volume name, as +// stored in the Volume data structure. +// Returns TRUE if this substitution was made, FALSE otherwise. +BOOLEAN VolumeNumberToName(REFIT_VOLUME *Volume, CHAR16 **VolName) { + BOOLEAN MadeSubstitution = FALSE; + UINTN VolNum; + + if ((VolName == NULL) || (*VolName == NULL)) + return FALSE; + + if ((StrLen(*VolName) > 2) && (*VolName[0] == L'f') && (*VolName[1] == L's') && (*VolName[2] >= L'0') && (*VolName[2] <= L'9')) { + VolNum = Atoi(*VolName + 2); + if (VolNum == Volume->VolNumber) { + MyFreePool(*VolName); + *VolName = StrDuplicate(Volume->VolName); + MadeSubstitution = TRUE; + } // if + } // if + return MadeSubstitution; +} // BOOLEAN VolumeMatchesNumber() + // Implement FreePool the way it should have been done to begin with, so that // it doesn't throw an ASSERT message if fed a NULL pointer.... VOID MyFreePool(IN VOID *Pointer) { @@ -1732,6 +1858,68 @@ BOOLEAN EjectMedia(VOID) { return (Ejected > 0); } // VOID EjectMedia() +// Converts consecutive characters in the input string into a +// number, interpreting the string as a hexadecimal number, starting +// at the specified position and continuing for the specified number +// of characters or until the end of the string, whichever is first. +// NumChars must be between 1 and 16. Ignores invalid characters. +UINT64 StrToHex(CHAR16 *Input, UINTN Pos, UINTN NumChars) { + UINT64 retval = 0x00; + UINTN NumDone = 0; + CHAR16 a; + + if ((Input == NULL) || (StrLen(Input) < Pos) || (NumChars == 0) || (NumChars > 16)) { + return 0; + } + + while ((StrLen(Input) >= Pos) && (NumDone < NumChars)) { + a = Input[Pos]; + if ((a >= '0') && (a <= '9')) { + retval *= 0x10; + retval += (a - '0'); + NumDone++; + } + if ((a >= 'a') && (a <= 'f')) { + retval *= 0x10; + retval += (a - 'a' + 0x0a); + NumDone++; + } + if ((a >= 'A') && (a <= 'F')) { + retval *= 0x10; + retval += (a - 'A' + 0x0a); + NumDone++; + } + Pos++; + } // while() + return retval; +} // StrToHex() + +// Returns TRUE if UnknownString can be interpreted as a GUID, FALSE otherwise. +// Note that the input string must have no extraneous spaces and must be +// conventionally formatted as a 36-character GUID, complete with dashes in +// appropriate places. +BOOLEAN IsGuid(CHAR16 *UnknownString) { + UINTN Length, i; + BOOLEAN retval = TRUE; + CHAR16 a; + + if (UnknownString == NULL) + return FALSE; + + Length = StrLen(UnknownString); + if (Length != 36) + return FALSE; + + for (i = 0; i < Length; i++) { + a = UnknownString[i]; + if (((i == 8) || (i == 13) || (i == 18) || (i == 23)) && (a != '-')) { + retval = FALSE; + } else if (((a < 'a') || (a > 'f')) && ((a < 'A') || (a > 'F')) && ((a < '0') && (a > '9'))) { + retval = FALSE; + } // if/else + } // for + return retval; +} // BOOLEAN IsGuid() // Return the GUID as a string, suitable for display to the user. Note that the calling // function is responsible for freeing the allocated memory. @@ -1748,3 +1936,34 @@ CHAR16 * GuidAsString(EFI_GUID *GuidData) { } return TheString; } // GuidAsString(EFI_GUID *GuidData) + +EFI_GUID StringAsGuid(CHAR16 * InString) { + EFI_GUID Guid = NULL_GUID_VALUE; + + if (!IsGuid(InString)) { + return Guid; + } + + Guid.Data1 = (UINT32) StrToHex(InString, 0, 8); + Guid.Data2 = (UINT16) StrToHex(InString, 9, 4); + Guid.Data3 = (UINT16) StrToHex(InString, 14, 4); + Guid.Data4[0] = (UINT8) StrToHex(InString, 19, 2); + Guid.Data4[1] = (UINT8) StrToHex(InString, 21, 2); + Guid.Data4[2] = (UINT8) StrToHex(InString, 23, 2); + Guid.Data4[3] = (UINT8) StrToHex(InString, 26, 2); + Guid.Data4[4] = (UINT8) StrToHex(InString, 28, 2); + Guid.Data4[5] = (UINT8) StrToHex(InString, 30, 2); + Guid.Data4[6] = (UINT8) StrToHex(InString, 32, 2); + Guid.Data4[7] = (UINT8) StrToHex(InString, 34, 2); + + return Guid; +} // EFI_GUID StringAsGuid() + +// 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