#include "lib.h"
#include "icns.h"
#include "screen.h"
-#include "refit_call_wrapper.h"
-#include "RemovableMedia.h"
+#include "../include/refit_call_wrapper.h"
+#include "../include/RemovableMedia.h"
+
+#ifdef __MAKEWITH_GNUEFI
+#define EfiReallocatePool ReallocatePool
+#else
+#define LibLocateHandle gBS->LocateHandleBuffer
+#define DevicePathProtocol gEfiDevicePathProtocolGuid
+#define BlockIoProtocol gEfiBlockIoProtocolGuid
+#define LibFileSystemInfo EfiLibFileSystemInfo
+#define LibOpenRoot EfiLibOpenRoot
+EFI_DEVICE_PATH EndDevicePath[] = {
+ {END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}}
+};
+
+//#define EndDevicePath DevicePath
+#endif
// variables
//
// Converts forward slashes to backslashes, removes duplicate slashes, and
-// removes slashes from both the start and end of the pathname.
+// removes slashes from the end of the pathname.
// Necessary because some (buggy?) EFI implementations produce "\/" strings
// in pathnames, because some user inputs can produce duplicate directory
// separators, and because we want consistent start and end slashes for
UINTN i, FinalChar = 0;
BOOLEAN LastWasSlash = FALSE;
- NewName = AllocateZeroPool(sizeof(CHAR16) * (StrLen(PathName) + 2));
+ NewName = AllocateZeroPool(sizeof(CHAR16) * (StrLen(PathName) + 4));
if (NewName != NULL) {
for (i = 0; i < StrLen(PathName); i++) {
if ((PathName[i] == L'/') || (PathName[i] == L'\\')) {
- if ((!LastWasSlash) && (FinalChar != 0))
+ if ((!LastWasSlash) /* && (FinalChar != 0) */)
NewName[FinalChar++] = L'\\';
LastWasSlash = TRUE;
} else {
+ if (FinalChar == 0) {
+ NewName[FinalChar++] = L'\\';
+ }
NewName[FinalChar++] = PathName[i];
LastWasSlash = FALSE;
} // if/else
} // for
NewName[FinalChar] = 0;
- if ((FinalChar > 0) && (NewName[FinalChar - 1] == L'\\'))
+ if ((FinalChar > 1) && (NewName[FinalChar - 1] == L'\\'))
NewName[--FinalChar] = 0;
if (FinalChar == 0) {
NewName[0] = L'\\';
} // if allocation OK
} // CleanUpPathNameSlashes()
+// Splits an EFI device path into device and filename components. For instance, if InString is
+// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000)/\bzImage-3.5.1.efi,
+// this function will truncate that input to
+// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000)
+// and return bzImage-3.5.1.efi as its return value.
+// It does this by searching for the last ")" character in InString, copying everything
+// after that string (after some cleanup) as the return value, and truncating the original
+// input value.
+// If InString contains no ")" character, this function leaves the original input string
+// unmodified and also returns that string.
+static CHAR16* SplitDeviceString(IN OUT CHAR16 *InString) {
+ INTN i;
+ CHAR16 *FileName = NULL;
+ BOOLEAN Found = FALSE;
+
+ i = StrLen(InString) - 1;
+ while ((i >= 0) && (!Found)) {
+ if (InString[i] == L')') {
+ Found = TRUE;
+ FileName = StrDuplicate(&InString[i + 1]);
+ CleanUpPathNameSlashes(FileName);
+ InString[i + 1] = '\0';
+ } // if
+ i--;
+ } // while
+ if (FileName == NULL)
+ FileName = StrDuplicate(InString);
+ return FileName;
+} // static CHAR16* SplitDeviceString()
+
EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle)
{
EFI_STATUS Status;
- CHAR16 *DevicePathAsString;
+ CHAR16 *DevicePathAsString, *Temp;
SelfImageHandle = ImageHandle;
Status = refit_call3_wrapper(BS->HandleProtocol, SelfImageHandle, &LoadedImageProtocol, (VOID **) &SelfLoadedImage);
// find the current directory
DevicePathAsString = DevicePathToStr(SelfLoadedImage->FilePath);
CleanUpPathNameSlashes(DevicePathAsString);
- if (SelfDirPath != NULL)
- FreePool(SelfDirPath);
- SelfDirPath = FindPath(DevicePathAsString);
- FreePool(DevicePathAsString);
+ MyFreePool(SelfDirPath);
+ Temp = FindPath(DevicePathAsString);
+ SelfDirPath = SplitDeviceString(Temp);
+ MyFreePool(DevicePathAsString);
+ MyFreePool(Temp);
return FinishInitRefitLib();
}
if (*ElementCount == 0)
*ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount);
else
- *ListPtr = ReallocatePool(*ListPtr, sizeof(VOID *) * (*ElementCount), sizeof(VOID *) * AllocateCount);
+ *ListPtr = EfiReallocatePool(*ListPtr, sizeof(VOID *) * (*ElementCount), sizeof(VOID *) * AllocateCount);
}
(*ListPtr)[*ElementCount] = NewElement;
(*ElementCount)++;
{
UINTN i;
- if (*ElementCount > 0) {
+ if ((*ElementCount > 0) && (**ListPtr != NULL)) {
for (i = 0; i < *ElementCount; i++) {
// TODO: call a user-provided routine for each element here
- FreePool((*ListPtr)[i]);
+ MyFreePool((*ListPtr)[i]);
}
- FreePool(*ListPtr);
+ MyFreePool(*ListPtr);
}
-}
+} // VOID FreeList()
//
// firmware device path discovery
MaxPaths--; // leave space for the terminating NULL pointer
// get all LoadedImage handles
- Status = LibLocateHandle(ByProtocol, &LoadedImageProtocol, NULL,
- &HandleCount, &Handles);
+ Status = LibLocateHandle(ByProtocol, &LoadedImageProtocol, NULL, &HandleCount, &Handles);
if (CheckError(Status, L"while listing LoadedImage handles")) {
if (HardcodedPathList) {
for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++)
PathList[PathCount++] = AppendDevicePath(DevicePath, LegacyLoaderMediaPath);
}
- FreePool(Handles);
+ MyFreePool(Handles);
if (HardcodedPathList) {
for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++)
} // switch()
}
-static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume)
+VOID ScanVolume(IN OUT REFIT_VOLUME *Volume)
{
EFI_STATUS Status;
EFI_DEVICE_PATH *DevicePath, *NextDevicePath;
// get the handle for that path
RemainingDevicePath = DiskDevicePath;
- //Print(L" * looking at %s\n", DevicePathToStr(RemainingDevicePath));
Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle);
- //Print(L" * remaining: %s\n", DevicePathToStr(RemainingDevicePath));
FreePool(DiskDevicePath);
if (!EFI_ERROR(Status)) {
if (FileExists(Volume->RootDir, VOLUME_ICON_NAME)) {
Volume->VolIconImage = LoadIcns(Volume->RootDir, VOLUME_ICON_NAME, 128);
}
-}
+} // ScanVolume()
static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry)
{
Volume->DiskKind = WholeDiskVolume->DiskKind;
Volume->IsMbrPartition = TRUE;
Volume->MbrPartitionIndex = LogicalPartitionIndex++;
- Volume->VolName = PoolPrint(L"Partition %d", Volume->MbrPartitionIndex + 1);
+ Volume->VolName = AllocateZeroPool(256 * sizeof(UINT16));
+ SPrint(Volume->VolName, 255, L"Partition %d", Volume->MbrPartitionIndex + 1);
Volume->BlockIO = WholeDiskVolume->BlockIO;
Volume->BlockIOOffset = ExtCurrent + EMbrTable[i].StartLBA;
Volume->WholeDiskBlockIO = WholeDiskVolume->BlockIO;
UINT8 *SectorBuffer1, *SectorBuffer2;
UINTN SectorSum, i;
- FreePool(Volumes);
+ MyFreePool(Volumes);
Volumes = NULL;
VolumesCount = 0;
// get all filesystem handles
Status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &Handles);
// was: &FileSystemProtocol
- if (Status == EFI_NOT_FOUND)
+ if (Status == EFI_NOT_FOUND) {
return; // no filesystems. strange, but true...
+ }
if (CheckError(Status, L"while listing all file systems"))
return;
if (Volume->DeviceHandle == SelfLoadedImage->DeviceHandle)
SelfVolume = Volume;
}
- FreePool(Handles);
+ MyFreePool(Handles);
if (SelfVolume == NULL)
Print(L"WARNING: SelfVolume not found");
// now we're reasonably sure the association is correct...
Volume->IsMbrPartition = TRUE;
Volume->MbrPartitionIndex = PartitionIndex;
- if (Volume->VolName == NULL)
- Volume->VolName = PoolPrint(L"Partition %d", PartitionIndex + 1);
+ if (Volume->VolName == NULL) {
+ Volume->VolName = AllocateZeroPool(sizeof(CHAR16) * 256);
+ SPrint(Volume->VolName, 255, L"Partition %d", PartitionIndex + 1);
+ }
break;
}
- FreePool(SectorBuffer1);
- FreePool(SectorBuffer2);
+ MyFreePool(SectorBuffer1);
+ MyFreePool(SectorBuffer2);
}
}
// free pointer from last call
if (*DirEntry != NULL) {
- FreePool(*DirEntry);
- *DirEntry = NULL;
+ FreePool(*DirEntry);
+ *DirEntry = NULL;
}
// read next directory entry
Print(L"Reallocating buffer from %d to %d\n", LastBufferSize, BufferSize);
#endif
}
- Buffer = ReallocatePool(Buffer, LastBufferSize, BufferSize);
+ Buffer = EfiReallocatePool(Buffer, LastBufferSize, BufferSize);
LastBufferSize = BufferSize;
}
if (EFI_ERROR(Status)) {
DirIter->LastFileInfo = NULL;
}
+#ifndef __MAKEWITH_GNUEFI
+EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
+
+static EFI_STATUS
+InitializeUnicodeCollationProtocol (VOID)
+{
+ EFI_STATUS Status;
+
+ if (mUnicodeCollation != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
+ // instances first and then select one which support English language.
+ // Current implementation just pick the first instance.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiUnicodeCollation2ProtocolGuid,
+ NULL,
+ (VOID **) &mUnicodeCollation
+ );
+ if (EFI_ERROR(Status)) {
+ Status = gBS->LocateProtocol (
+ &gEfiUnicodeCollationProtocolGuid,
+ NULL,
+ (VOID **) &mUnicodeCollation
+ );
+
+ }
+ return Status;
+}
+
+static BOOLEAN
+MetaiMatch (IN CHAR16 *String, IN CHAR16 *Pattern)
+{
+ if (!mUnicodeCollation) {
+ InitializeUnicodeCollationProtocol();
+ }
+ if (mUnicodeCollation)
+ return mUnicodeCollation->MetaiMatch (mUnicodeCollation, String, Pattern);
+ return FALSE; // Shouldn't happen
+}
+
+static VOID StrLwr (IN OUT CHAR16 *Str) {
+ if (!mUnicodeCollation) {
+ InitializeUnicodeCollationProtocol();
+ }
+ if (mUnicodeCollation)
+ mUnicodeCollation->StrLwr (mUnicodeCollation, Str);
+}
+
+#endif
+
BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL,
OUT EFI_FILE_INFO **DirEntry)
{
CHAR16 *OnePattern;
if (DirIter->LastFileInfo != NULL) {
- FreePool(DirIter->LastFileInfo);
- DirIter->LastFileInfo = NULL;
+ FreePool(DirIter->LastFileInfo);
+ DirIter->LastFileInfo = NULL;
}
if (EFI_ERROR(DirIter->LastStatus))
EFI_STATUS DirIterClose(IN OUT REFIT_DIR_ITER *DirIter)
{
- if (DirIter->LastFileInfo != NULL) {
- FreePool(DirIter->LastFileInfo);
- DirIter->LastFileInfo = NULL;
- }
- if (DirIter->CloseDirHandle)
- refit_call1_wrapper(DirIter->DirHandle->Close, DirIter->DirHandle);
- return DirIter->LastStatus;
+ if (DirIter->LastFileInfo != NULL) {
+ FreePool(DirIter->LastFileInfo);
+ DirIter->LastFileInfo = NULL;
+ }
+ if (DirIter->CloseDirHandle)
+ refit_call1_wrapper(DirIter->DirHandle->Close, DirIter->DirHandle);
+ return DirIter->LastStatus;
}
//
while ((!Found) && (StartPoint < NumCompares)) {
Found = (StrnCmp(SmallCopy, &BigCopy[StartPoint++], SmallLen) == 0);
} // while
- FreePool(SmallCopy);
- FreePool(BigCopy);
+ MyFreePool(SmallCopy);
+ MyFreePool(BigCopy);
} // if
return (Found);
} // if (*First != NULL)
if (Second != NULL)
StrCat(NewString, Second);
- FreePool(*First);
+ MyFreePool(*First);
*First = NewString;
} else {
Print(L"Error! Unable to allocate memory in MergeStrings()!\n");
// Returns the directory portion of a pathname. For instance,
// if FullPath is 'EFI\foo\bar.efi', this function returns the
-// string 'EFI\foo'.
+// string 'EFI\foo'. The calling function is responsible for
+// freeing the returned string's memory.
CHAR16 *FindPath(IN CHAR16* FullPath) {
UINTN i, LastBackslash = 0;
CHAR16 *PathOnly;
return (PathOnly);
}
+// 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) {
+ CHAR16 *DeviceString, *VolumeDeviceString, *Temp;
+ UINTN i = 0;
+ BOOLEAN Found = FALSE;
+
+ MyFreePool(*loader);
+ MyFreePool(*DeviceVolume);
+ *DeviceVolume = NULL;
+ DeviceString = DevicePathToStr(loadpath);
+ *loader = SplitDeviceString(DeviceString);
+
+ while ((i < VolumesCount) && (!Found)) {
+ VolumeDeviceString = DevicePathToStr(Volumes[i]->DevicePath);
+ Temp = SplitDeviceString(VolumeDeviceString);
+ if (StriCmp(DeviceString, VolumeDeviceString) == 0) {
+ Found = TRUE;
+ *DeviceVolume = Volumes[i];
+ }
+ MyFreePool(Temp);
+ MyFreePool(VolumeDeviceString);
+ i++;
+ } // while
+
+ MyFreePool(DeviceString);
+} // VOID FindVolumeAndFilename()
+
// Returns all the digits in the input string, including intervening
// non-digit characters. For instance, if InString is "foo-3.3.4-7.img",
// this function returns "3.3.4-7". If InString contains no digits,
return (FoundString);
} // CHAR16 *FindCommaDelimited()
+// 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()
+
+// 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 OUT VOID *Pointer) {
+ if (Pointer != NULL)
+ FreePool(Pointer);
+}
static EFI_GUID AppleRemovableMediaGuid = APPLE_REMOVABLE_MEDIA_PROTOCOL_GUID;
if (!EFI_ERROR(Status))
Ejected++;
}
- FreePool(Handles);
+ 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)