]> code.delx.au - refind/blobdiff - refind/lib.c
Further tweaks to new NTFS Windows boot partition filtering.
[refind] / refind / lib.c
index 057026589c502b104180d336c3a8cb2771b85b81..48da11d0291ddd0e88f9ce9dc0dac62cdbff14fd 100644 (file)
@@ -34,7 +34,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 /*
- * Modifications copyright (c) 2012-2014 Roderick W. Smith
+ * Modifications copyright (c) 2012-2015 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
@@ -49,6 +49,7 @@
 #include "../include/refit_call_wrapper.h"
 #include "../include/RemovableMedia.h"
 #include "gpt.h"
+#include "config.h"
 
 #ifdef __MAKEWITH_GNUEFI
 #define EfiReallocatePool ReallocatePool
@@ -74,6 +75,7 @@ EFI_DEVICE_PATH EndDevicePath[] = {
 #define REISER2FS_SUPER_MAGIC_STRING     "ReIsEr2Fs"
 #define REISER2FS_JR_SUPER_MAGIC_STRING  "ReIsEr3Fs"
 #define BTRFS_SIGNATURE                  "_BHRfS_M"
+#define NTFS_SIGNATURE                   "NTFS    "
 
 // variables
 
@@ -458,6 +460,9 @@ static CHAR16 *FSTypeName(IN UINT32 TypeCode) {
       case FS_TYPE_ISO9660:
          retval = L" ISO-9660";
          break;
+      case FS_TYPE_NTFS:
+         retval = L" NTFS";
+         break;
       default:
          retval = L"";
          break;
@@ -466,15 +471,16 @@ static CHAR16 *FSTypeName(IN UINT32 TypeCode) {
 } // CHAR16 *FSTypeName()
 
 // Identify the filesystem type and record the filesystem's UUID/serial number,
-// if possible. Expects a Buffer containing the first few (normally 4096) bytes
-// of the filesystem. Sets the filesystem type code in Volume->FSType and the
-// UUID/serial number in Volume->VolUuid. Note that the UUID value is recognized
-// differently for each filesystem, and is currently supported only for
-// ext2/3/4fs and ReiserFS. If the UUID can't be determined, it's set to 0. Also, the UUID
-// is just read directly into memory; it is *NOT* valid when displayed by
-// GuidAsString() or used in other GUID/UUID-manipulating functions. (As I
-// write, it's being used merely to detect partitions that are part of a
-// RAID 1 array.)
+// if possible. Expects a Buffer containing the first few (normally at least
+// 4096) bytes of the filesystem. Sets the filesystem type code in Volume->FSType
+// and the UUID/serial number in Volume->VolUuid. Note that the UUID value is
+// recognized differently for each filesystem, and is currently supported only
+// for NTFS, ext2/3/4fs, and ReiserFS (and for NTFS it's really a 64-bit serial
+// number not a UUID or GUID). If the UUID can't be determined, it's set to 0.
+// Also, the UUID is just read directly into memory; it is *NOT* valid when
+// displayed by GuidAsString() or used in other GUID/UUID-manipulating
+// functions. (As I write, it's being used merely to detect partitions that are
+// part of a RAID 1 array.)
 static VOID SetFilesystemData(IN UINT8 *Buffer, IN UINTN BufferSize, IN OUT REFIT_VOLUME *Volume) {
    UINT32       *Ext2Incompat, *Ext2Compat;
    UINT16       *Magic16;
@@ -487,10 +493,21 @@ static VOID SetFilesystemData(IN UINT8 *Buffer, IN UINTN BufferSize, IN OUT REFI
       if (BufferSize >= 512) {
          Magic16 = (UINT16*) (Buffer + 510);
          if (*Magic16 == FAT_MAGIC) {
-            Volume->FSType = FS_TYPE_FAT;
+            MagicString = (char*) (Buffer + 3);
+            if (CompareMem(MagicString, NTFS_SIGNATURE, 8) == 0) {
+               Volume->FSType = FS_TYPE_NTFS;
+               CopyMem(&(Volume->VolUuid), Buffer + 0x48, sizeof(UINT64));
+            } else {
+               // NOTE: This misidentifies a whole disk as a FAT partition
+               // because FAT and MBR share the same 0xaa55 "magic" and
+               // no other distinguishing data. Later code, in ScanVolume(),
+               // resets to FS_TYPE_UNKNOWN if the "filesystem" can't be
+               // read.
+               Volume->FSType = FS_TYPE_FAT;
+            }
             return;
          } // if
-      } // search for FAT magic
+      } // search for FAT and NTFS magic
 
       if (BufferSize >= (1024 + 100)) {
          Magic16 = (UINT16*) (Buffer + 1024 + 56);
@@ -535,6 +552,7 @@ static VOID SetFilesystemData(IN UINT8 *Buffer, IN UINTN BufferSize, IN OUT REFI
             return;
          }
       } // search for HFS+ magic
+
    } // if (Buffer != NULL)
 
 } // UINT32 SetFilesystemData()
@@ -612,14 +630,16 @@ static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable)
             Volume->OSIconName = L"netbsd";
             Volume->OSName = L"NetBSD";
 
+        // Windows NT/200x/XP
         } else if (FindMem(Buffer, SECTOR_SIZE, "NTLDR", 5) >= 0) {
             Volume->HasBootCode = TRUE;
             Volume->OSIconName = L"win";
             Volume->OSName = L"Windows";
 
+        // Windows Vista/7/8
         } else if (FindMem(Buffer, SECTOR_SIZE, "BOOTMGR", 7) >= 0) {
             Volume->HasBootCode = TRUE;
-            Volume->OSIconName = L"winvista,win";
+            Volume->OSIconName = L"win8,win";
             Volume->OSName = L"Windows";
 
         } else if (FindMem(Buffer, 512, "CPUBOOT SYS", 11) >= 0 ||
@@ -653,7 +673,7 @@ static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable)
         }
 
         // NOTE: If you add an operating system with a name that starts with 'W' or 'L', you
-        //  need to fix AddLegacyEntry in main.c.
+        //  need to fix AddLegacyEntry in refind/legacy.c.
 
 #if REFIT_DEBUG > 0
         Print(L"  Result of bootcode detection: %s %s (%s)\n",
@@ -698,6 +718,9 @@ static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable)
 // Set default volume badge icon based on /.VolumeBadge.{icns|png} file or disk kind
 VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume)
 {
+   if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_BADGES)
+      return;
+
    if (Volume->VolBadgeImage == NULL) {
       Volume->VolBadgeImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeBadge", GlobalConfig.IconSizes[ICON_SIZE_BADGE]);
    }
@@ -713,6 +736,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()
@@ -751,42 +777,45 @@ static CHAR16 *SizeInIEEEUnits(UINT64 SizeInBytes) {
 // The calling function is responsible for freeing the memory allocated
 // for the name string.
 static CHAR16 *GetVolumeName(REFIT_VOLUME *Volume) {
-   EFI_FILE_SYSTEM_INFO    *FileSystemInfoPtr;
+   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: 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) {
-          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
@@ -799,7 +828,6 @@ static CHAR16 *GetVolumeName(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....
@@ -809,7 +837,7 @@ static CHAR16 *GetVolumeName(REFIT_VOLUME *Volume) {
    return FoundName;
 } // static CHAR16 *GetVolumeName()
 
-// Determine the unique GUID of the volume and store it.
+// Determine the unique GUID and name of the volume and store them.
 static VOID SetPartGuidAndName(REFIT_VOLUME *Volume, EFI_DEVICE_PATH_PROTOCOL *DevicePath) {
    HARDDRIVE_DEVICE_PATH    *HdDevicePath;
 
@@ -825,6 +853,21 @@ static VOID SetPartGuidAndName(REFIT_VOLUME *Volume, EFI_DEVICE_PATH_PROTOCOL *D
    } // if
 } // VOID SetPartGuid()
 
+// Return TRUE if NTFS boot files are found or if Volume is unreadable,
+// FALSE otherwise. The idea is to weed out non-boot NTFS volumes from
+// BIOS/legacy boot list on Macs. We can't assume NTFS will be readable,
+// so return TRUE if it's unreadable; but if it IS readable, return
+// TRUE only if Windows boot files are found.
+static BOOLEAN HasWindowsBiosBootFiles(REFIT_VOLUME *Volume) {
+   BOOLEAN FilesFound = TRUE;
+
+   if (Volume->RootDir != NULL) {
+      FilesFound = FileExists(Volume->RootDir, L"NTLDR") ||  // Windows NT/200x/XP boot file
+                   FileExists(Volume->RootDir, L"bootmgr");  // Windows Vista/7/8 boot file
+   } // if
+   return FilesFound;
+} // static VOID HasWindowsBiosBootFiles()
+
 VOID ScanVolume(REFIT_VOLUME *Volume)
 {
     EFI_STATUS              Status;
@@ -928,32 +971,36 @@ VOID ScanVolume(REFIT_VOLUME *Volume)
         DevicePath = NextDevicePath;
     } // while
 
-    if (!Bootable) {
+   if (!Bootable) {
 #if REFIT_DEBUG > 0
-        if (Volume->HasBootCode)
-            Print(L"  Volume considered non-bootable, but boot code is present\n");
+      if (Volume->HasBootCode)
+         Print(L"  Volume considered non-bootable, but boot code is present\n");
 #endif
-        Volume->HasBootCode = FALSE;
-    }
+      Volume->HasBootCode = FALSE;
+   }
 
-    // open the root directory of the volume
-    Volume->RootDir = LibOpenRoot(Volume->DeviceHandle);
+   // open the root directory of the volume
+   Volume->RootDir = LibOpenRoot(Volume->DeviceHandle);
 
-    // Set volume icon based on .VolumeBadge icon or disk kind
-    SetVolumeBadgeIcon(Volume);
+   // Set volume icon based on .VolumeBadge icon or disk kind
+   SetVolumeBadgeIcon(Volume);
 
-    if (Volume->RootDir == NULL) {
-        Volume->IsReadable = FALSE;
-        return;
-    } else {
-        Volume->IsReadable = TRUE;
-    }
+   Volume->VolName = GetVolumeName(Volume);
 
-    Volume->VolName = GetVolumeName(Volume);
+   if (Volume->RootDir == NULL) {
+      Volume->IsReadable = FALSE;
+      if (Volume->FSType != FS_TYPE_NTFS)
+          Volume->FSType = FS_TYPE_UNKNOWN;
+      return;
+   } else {
+      Volume->IsReadable = TRUE;
+      if ((GlobalConfig.LegacyType == LEGACY_TYPE_MAC) && (Volume->FSType == FS_TYPE_NTFS) && Volume->HasBootCode)
+         Volume->HasBootCode = HasWindowsBiosBootFiles(Volume);
+   } // if/else
 
-    // get custom volume icons if present
-    if (!Volume->VolIconImage)
-       Volume->VolIconImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeIcon", GlobalConfig.IconSizes[ICON_SIZE_BIG]);
+   // get custom volume icons if present
+   if (!Volume->VolIconImage)
+     Volume->VolIconImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeIcon", GlobalConfig.IconSizes[ICON_SIZE_BIG]);
 } // ScanVolume()
 
 static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry)