]> code.delx.au - refind/blobdiff - refind/lib.c
NTFS driver support, minor filesystem code tweaks, and changes to
[refind] / refind / lib.c
index 0053c2b51385037d61e5000096470fc26bf51bd5..1a7bb811466be342cb4641c0034ff388755714ba 100644 (file)
@@ -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
 //
@@ -675,6 +713,9 @@ VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume)
           case DISK_KIND_OPTICAL:
              Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL);
              break;
+          case DISK_KIND_NET:
+             Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET);
+             break;
       } // switch()
    }
 } // VOID SetVolumeBadgeIcon()
@@ -712,36 +753,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 +805,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 +815,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 +823,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 +872,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 +914,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 +947,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 +956,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 +1041,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 +1056,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 +1103,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 +1153,6 @@ VOID ScanVolumes(VOID)
             MyFreePool(SectorBuffer1);
             MyFreePool(SectorBuffer2);
         }
-
     } // for
 } /* VOID ScanVolumes() */
 
@@ -1570,6 +1625,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 +1905,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 +2067,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 +2117,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()
+