]> code.delx.au - refind/blobdiff - refind/lib.c
Refinements, mostly to shim/MOK support.
[refind] / refind / lib.c
index 2112721a10041d138ce08485d9ee596ac2a2d9c6..77e6842404b4cfe7a7ffb56f4c74d3e9bb1d39d2 100644 (file)
@@ -94,7 +94,7 @@ static VOID UninitVolumes(VOID);
 //
 
 // 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
@@ -106,20 +106,23 @@ VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) {
    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'\\';
@@ -131,10 +134,40 @@ VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) {
    } // 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);
@@ -144,10 +177,11 @@ EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle)
     // 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();
 }
@@ -249,14 +283,14 @@ VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *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
@@ -325,7 +359,7 @@ VOID ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DE
 
         PathList[PathCount++] = AppendDevicePath(DevicePath, LegacyLoaderMediaPath);
     }
-    FreePool(Handles);
+    MyFreePool(Handles);
 
     if (HardcodedPathList) {
         for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++)
@@ -579,9 +613,7 @@ VOID ScanVolume(IN OUT REFIT_VOLUME *Volume)
 
             // 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)) {
@@ -730,7 +762,7 @@ VOID ScanVolumes(VOID)
     UINT8                   *SectorBuffer1, *SectorBuffer2;
     UINTN                   SectorSum, i;
 
-    FreePool(Volumes);
+    MyFreePool(Volumes);
     Volumes = NULL;
     VolumesCount = 0;
 
@@ -754,7 +786,7 @@ VOID ScanVolumes(VOID)
         if (Volume->DeviceHandle == SelfLoadedImage->DeviceHandle)
             SelfVolume = Volume;
     }
-    FreePool(Handles);
+    MyFreePool(Handles);
 
     if (SelfVolume == NULL)
         Print(L"WARNING: SelfVolume not found");
@@ -826,8 +858,8 @@ VOID ScanVolumes(VOID)
                 break;
             }
 
-            FreePool(SectorBuffer1);
-            FreePool(SectorBuffer2);
+            MyFreePool(SectorBuffer1);
+            MyFreePool(SectorBuffer2);
         }
 
     }
@@ -924,8 +956,8 @@ EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry,
 
         // free pointer from last call
         if (*DirEntry != NULL) {
-            FreePool(*DirEntry);
-            *DirEntry = NULL;
+           FreePool(*DirEntry);
+           *DirEntry = NULL;
         }
 
         // read next directory entry
@@ -1049,8 +1081,8 @@ BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR
     CHAR16  *OnePattern;
 
     if (DirIter->LastFileInfo != NULL) {
-        FreePool(DirIter->LastFileInfo);
-        DirIter->LastFileInfo = NULL;
+       FreePool(DirIter->LastFileInfo);
+       DirIter->LastFileInfo = NULL;
     }
 
     if (EFI_ERROR(DirIter->LastStatus))
@@ -1081,13 +1113,13 @@ BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR
 
 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;
 }
 
 //
@@ -1166,8 +1198,8 @@ BOOLEAN StriSubCmp(IN CHAR16 *SmallStr, IN CHAR16 *BigStr) {
       while ((!Found) && (StartPoint < NumCompares)) {
          Found = (StrnCmp(SmallCopy, &BigCopy[StartPoint++], SmallLen) == 0);
       } // while
-      FreePool(SmallCopy);
-      FreePool(BigCopy);
+      MyFreePool(SmallCopy);
+      MyFreePool(BigCopy);
    } // if
 
    return (Found);
@@ -1202,7 +1234,7 @@ VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar) {
       } // 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");
@@ -1287,6 +1319,34 @@ CHAR16 *FindPath(IN CHAR16* FullPath) {
    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,
@@ -1368,6 +1428,13 @@ BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List) {
    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;
 
 // Eject all removable media.
@@ -1391,7 +1458,23 @@ BOOLEAN EjectMedia(VOID) {
       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)