+
+// 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).
+BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List) {
+ UINTN i = 0;
+ BOOLEAN Found = FALSE;
+ CHAR16 *OneElement;
+
+ if (SmallString && List) {
+ while (!Found && (OneElement = FindCommaDelimited(List, i++))) {
+ if (StriCmp(OneElement, SmallString) == 0)
+ Found = TRUE;
+ } // while
+ } // if
+ 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) {
+ if (Pointer != NULL)
+ FreePool(Pointer);
+}
+
+static EFI_GUID AppleRemovableMediaGuid = APPLE_REMOVABLE_MEDIA_PROTOCOL_GUID;
+
+// Eject all removable media.
+// Returns TRUE if any media were ejected, FALSE otherwise.
+BOOLEAN EjectMedia(VOID) {
+ EFI_STATUS Status;
+ UINTN HandleIndex, HandleCount = 0, Ejected = 0;
+ EFI_HANDLE *Handles, Handle;
+ APPLE_REMOVABLE_MEDIA_PROTOCOL *Ejectable;
+
+ Status = LibLocateHandle(ByProtocol, &AppleRemovableMediaGuid, NULL, &HandleCount, &Handles);
+ if (EFI_ERROR(Status) || HandleCount == 0)
+ return (FALSE); // probably not an Apple system
+
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ Handle = Handles[HandleIndex];
+ Status = refit_call3_wrapper(BS->HandleProtocol, Handle, &AppleRemovableMediaGuid, (VOID **) &Ejectable);
+ if (EFI_ERROR(Status))
+ continue;
+ Status = refit_call1_wrapper(Ejectable->Eject, Ejectable);
+ if (!EFI_ERROR(Status))
+ Ejected++;
+ }
+ MyFreePool(Handles);
+ return (Ejected > 0);
+} // VOID EjectMedia()
+
+
+// Return the GUID as a string, suitable for display to the user. Note that the calling
+// function is responsible for freeing the allocated memory.
+CHAR16 * GuidAsString(EFI_GUID *GuidData) {
+ CHAR16 *TheString;
+
+ TheString = AllocateZeroPool(42 * sizeof(CHAR16));
+ if (TheString != 0) {
+ SPrint (TheString, 82, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ (UINTN)GuidData->Data1, (UINTN)GuidData->Data2, (UINTN)GuidData->Data3,
+ (UINTN)GuidData->Data4[0], (UINTN)GuidData->Data4[1], (UINTN)GuidData->Data4[2],
+ (UINTN)GuidData->Data4[3], (UINTN)GuidData->Data4[4], (UINTN)GuidData->Data4[5],
+ (UINTN)GuidData->Data4[6], (UINTN)GuidData->Data4[7]);
+ }
+ return TheString;
+} // GuidAsString(EFI_GUID *GuidData)