X-Git-Url: https://code.delx.au/refind/blobdiff_plain/87bc9afcef9d2fc27b8bcff46fa9c88e8962fcae..39f21d099c9fb310bae28b54dc68d266ed610ed7:/refind/lib.c diff --git a/refind/lib.c b/refind/lib.c index 91a409b..3c9e4c4 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -69,7 +69,7 @@ EFI_DEVICE_PATH EndDevicePath[] = { #define EXT2_SUPER_MAGIC 0xEF53 #define HFSPLUS_MAGIC1 0x2B48 #define HFSPLUS_MAGIC2 0x5848 -#define REISERFS_SUPER_MAGIC 0x52654973 +#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" #define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs" @@ -88,6 +88,10 @@ UINTN VolumesCount = 0; // Maximum size for disk sectors #define SECTOR_SIZE 4096 +// Number of bytes to read from a partition to determine its filesystem type +// and identify its boot loader, and hence probable BIOS-mode OS installation +#define SAMPLE_SIZE 69632 /* 68 KiB -- ReiserFS superblock begins at 64 KiB */ + // Default names for volume badges (mini-icon to define disk type) and icons #define VOLUME_BADGE_NAME L".VolumeBadge.icns" #define VOLUME_ICON_NAME L".VolumeIcon.icns" @@ -420,9 +424,16 @@ static UINT32 IdentifyFilesystemType(IN UINT8 *Buffer, IN UINTN BufferSize) { UINT32 FoundType = FS_TYPE_UNKNOWN; UINT32 *Ext2Incompat, *Ext2Compat; UINT16 *Magic16; + char *MagicString; if (Buffer != NULL) { + if (BufferSize >= 512) { + Magic16 = (UINT16*) (Buffer + 510); + if (*Magic16 == FAT_MAGIC) + return FS_TYPE_FAT; + } // search for FAT magic + if (BufferSize >= (1024 + 100)) { Magic16 = (UINT16*) (Buffer + 1024 + 56); if (*Magic16 == EXT2_SUPER_MAGIC) { // ext2/3/4 @@ -438,11 +449,14 @@ static UINT32 IdentifyFilesystemType(IN UINT8 *Buffer, IN UINTN BufferSize) { } } // search for ext2/3/4 magic - if (BufferSize >= 512) { - Magic16 = (UINT16*) (Buffer + 510); - if (*Magic16 == FAT_MAGIC) - return FS_TYPE_FAT; - } // search for FAT magic + if (BufferSize >= (65536 + 62)) { + MagicString = (char*) (Buffer + 65536 + 52); + if ((CompareMem(MagicString, REISERFS_SUPER_MAGIC_STRING, 8) == 0) || + (CompareMem(MagicString, REISER2FS_SUPER_MAGIC_STRING, 9) == 0) || + (CompareMem(MagicString, REISER2FS_JR_SUPER_MAGIC_STRING, 9) == 0)) { + return FS_TYPE_REISERFS; + } // if + } // search for ReiserFS magic if (BufferSize >= (1024 + 2)) { Magic16 = (UINT16*) (Buffer + 1024); @@ -455,10 +469,10 @@ static UINT32 IdentifyFilesystemType(IN UINT8 *Buffer, IN UINTN BufferSize) { return FoundType; } -static VOID ScanVolumeBootcode(IN OUT REFIT_VOLUME *Volume, OUT BOOLEAN *Bootable) +static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable) { EFI_STATUS Status; - UINT8 SectorBuffer[SECTOR_SIZE]; + UINT8 Buffer[SAMPLE_SIZE]; UINTN i; MBR_PARTITION_INFO *MbrTable; BOOLEAN MbrTableFound; @@ -470,98 +484,98 @@ static VOID ScanVolumeBootcode(IN OUT REFIT_VOLUME *Volume, OUT BOOLEAN *Bootabl if (Volume->BlockIO == NULL) return; - if (Volume->BlockIO->Media->BlockSize > SECTOR_SIZE) + if (Volume->BlockIO->Media->BlockSize > SAMPLE_SIZE) return; // our buffer is too small... // look at the boot sector (this is used for both hard disks and El Torito images!) Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, - Volume->BlockIOOffset, SECTOR_SIZE, SectorBuffer); + Volume->BlockIOOffset, SAMPLE_SIZE, Buffer); if (!EFI_ERROR(Status)) { - Volume->FSType = IdentifyFilesystemType(SectorBuffer, SECTOR_SIZE); - if (*((UINT16 *)(SectorBuffer + 510)) == 0xaa55 && SectorBuffer[0] != 0) { + Volume->FSType = IdentifyFilesystemType(Buffer, SAMPLE_SIZE); + if (*((UINT16 *)(Buffer + 510)) == 0xaa55 && Buffer[0] != 0) { *Bootable = TRUE; Volume->HasBootCode = TRUE; } // detect specific boot codes - if (CompareMem(SectorBuffer + 2, "LILO", 4) == 0 || - CompareMem(SectorBuffer + 6, "LILO", 4) == 0 || - CompareMem(SectorBuffer + 3, "SYSLINUX", 8) == 0 || - FindMem(SectorBuffer, SECTOR_SIZE, "ISOLINUX", 8) >= 0) { + if (CompareMem(Buffer + 2, "LILO", 4) == 0 || + CompareMem(Buffer + 6, "LILO", 4) == 0 || + CompareMem(Buffer + 3, "SYSLINUX", 8) == 0 || + FindMem(Buffer, SECTOR_SIZE, "ISOLINUX", 8) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"linux"; Volume->OSName = L"Linux"; - } else if (FindMem(SectorBuffer, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) { // GRUB + } else if (FindMem(Buffer, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) { // GRUB Volume->HasBootCode = TRUE; Volume->OSIconName = L"grub,linux"; Volume->OSName = L"Linux"; // // Below doesn't produce a bootable entry, so commented out for the moment.... // // GRUB in BIOS boot partition: -// } else if (FindMem(SectorBuffer, 512, "Geom\0Read\0 Error", 16) >= 0) { +// } else if (FindMem(Buffer, 512, "Geom\0Read\0 Error", 16) >= 0) { // Volume->HasBootCode = TRUE; // Volume->OSIconName = L"grub,linux"; // Volume->OSName = L"Linux"; // Volume->VolName = L"BIOS Boot Partition"; // *Bootable = TRUE; - } else if ((*((UINT32 *)(SectorBuffer + 502)) == 0 && - *((UINT32 *)(SectorBuffer + 506)) == 50000 && - *((UINT16 *)(SectorBuffer + 510)) == 0xaa55) || - FindMem(SectorBuffer, SECTOR_SIZE, "Starting the BTX loader", 23) >= 0) { + } else if ((*((UINT32 *)(Buffer + 502)) == 0 && + *((UINT32 *)(Buffer + 506)) == 50000 && + *((UINT16 *)(Buffer + 510)) == 0xaa55) || + FindMem(Buffer, SECTOR_SIZE, "Starting the BTX loader", 23) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"freebsd"; Volume->OSName = L"FreeBSD"; - } else if (FindMem(SectorBuffer, 512, "!Loading", 8) >= 0 || - FindMem(SectorBuffer, SECTOR_SIZE, "/cdboot\0/CDBOOT\0", 16) >= 0) { + } else if (FindMem(Buffer, 512, "!Loading", 8) >= 0 || + FindMem(Buffer, SECTOR_SIZE, "/cdboot\0/CDBOOT\0", 16) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"openbsd"; Volume->OSName = L"OpenBSD"; - } else if (FindMem(SectorBuffer, 512, "Not a bootxx image", 18) >= 0 || - *((UINT32 *)(SectorBuffer + 1028)) == 0x7886b6d1) { + } else if (FindMem(Buffer, 512, "Not a bootxx image", 18) >= 0 || + *((UINT32 *)(Buffer + 1028)) == 0x7886b6d1) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"netbsd"; Volume->OSName = L"NetBSD"; - } else if (FindMem(SectorBuffer, SECTOR_SIZE, "NTLDR", 5) >= 0) { + } else if (FindMem(Buffer, SECTOR_SIZE, "NTLDR", 5) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"win"; Volume->OSName = L"Windows"; - } else if (FindMem(SectorBuffer, SECTOR_SIZE, "BOOTMGR", 7) >= 0) { + } else if (FindMem(Buffer, SECTOR_SIZE, "BOOTMGR", 7) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"winvista,win"; Volume->OSName = L"Windows"; - } else if (FindMem(SectorBuffer, 512, "CPUBOOT SYS", 11) >= 0 || - FindMem(SectorBuffer, 512, "KERNEL SYS", 11) >= 0) { + } else if (FindMem(Buffer, 512, "CPUBOOT SYS", 11) >= 0 || + FindMem(Buffer, 512, "KERNEL SYS", 11) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"freedos"; Volume->OSName = L"FreeDOS"; - } else if (FindMem(SectorBuffer, 512, "OS2LDR", 6) >= 0 || - FindMem(SectorBuffer, 512, "OS2BOOT", 7) >= 0) { + } else if (FindMem(Buffer, 512, "OS2LDR", 6) >= 0 || + FindMem(Buffer, 512, "OS2BOOT", 7) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"ecomstation"; Volume->OSName = L"eComStation"; - } else if (FindMem(SectorBuffer, 512, "Be Boot Loader", 14) >= 0) { + } else if (FindMem(Buffer, 512, "Be Boot Loader", 14) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"beos"; Volume->OSName = L"BeOS"; - } else if (FindMem(SectorBuffer, 512, "yT Boot Loader", 14) >= 0) { + } else if (FindMem(Buffer, 512, "yT Boot Loader", 14) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"zeta,beos"; Volume->OSName = L"ZETA"; - } else if (FindMem(SectorBuffer, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0 || - FindMem(SectorBuffer, 512, "\x06" "system\x0c" "haiku_loader", 20) >= 0) { + } else if (FindMem(Buffer, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0 || + FindMem(Buffer, 512, "\x06" "system\x0c" "haiku_loader", 20) >= 0) { Volume->HasBootCode = TRUE; Volume->OSIconName = L"haiku,beos"; Volume->OSName = L"Haiku"; @@ -578,21 +592,21 @@ static VOID ScanVolumeBootcode(IN OUT REFIT_VOLUME *Volume, OUT BOOLEAN *Bootabl #endif // dummy FAT boot sector (created by OS X's newfs_msdos) - if (FindMem(SectorBuffer, 512, "Non-system disk", 15) >= 0) + if (FindMem(Buffer, 512, "Non-system disk", 15) >= 0) Volume->HasBootCode = FALSE; // dummy FAT boot sector (created by Linux's mkdosfs) - if (FindMem(SectorBuffer, 512, "This is not a bootable disk", 27) >= 0) + if (FindMem(Buffer, 512, "This is not a bootable disk", 27) >= 0) Volume->HasBootCode = FALSE; // dummy FAT boot sector (created by Windows) - if (FindMem(SectorBuffer, 512, "Press any key to restart", 24) >= 0) + if (FindMem(Buffer, 512, "Press any key to restart", 24) >= 0) Volume->HasBootCode = FALSE; // check for MBR partition table - if (*((UINT16 *)(SectorBuffer + 510)) == 0xaa55) { + if (*((UINT16 *)(Buffer + 510)) == 0xaa55) { MbrTableFound = FALSE; - MbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); + MbrTable = (MBR_PARTITION_INFO *)(Buffer + 446); for (i = 0; i < 4; i++) if (MbrTable[i].StartLBA && MbrTable[i].Size) MbrTableFound = TRUE; @@ -610,7 +624,7 @@ static VOID ScanVolumeBootcode(IN OUT REFIT_VOLUME *Volume, OUT BOOLEAN *Bootabl CheckError(Status, L"while reading boot sector"); #endif } -} +} /* VOID ScanVolumeBootcode() */ // default volume badge icon based on disk kind static VOID ScanVolumeDefaultIcon(IN OUT REFIT_VOLUME *Volume) @@ -631,17 +645,18 @@ static VOID ScanVolumeDefaultIcon(IN OUT REFIT_VOLUME *Volume) // Return a string representing the input size in IEEE-1541 units. // The calling function is responsible for freeing the allocated memory. static CHAR16 *SizeInIEEEUnits(UINT64 SizeInBytes) { - float SizeInIeee; - UINTN Index = 0; + UINT64 SizeInIeee; + UINTN Index = 0, NumPrefixes; CHAR16 *Units, *Prefixes = L" KMGTPEZ"; CHAR16 *TheValue; - TheValue = AllocateZeroPool(sizeof(CHAR16) * 80); + TheValue = AllocateZeroPool(sizeof(CHAR16) * 256); if (TheValue != NULL) { - SizeInIeee = (float) SizeInBytes; - while ((SizeInIeee > 1024.0) && (Index < (StrLen(Prefixes) - 1))) { + NumPrefixes = StrLen(Prefixes); + SizeInIeee = SizeInBytes; + while ((SizeInIeee > 1024) && (Index < (NumPrefixes - 1))) { Index++; - SizeInIeee /= 1024.0; + SizeInIeee /= 1024; } // while if (Prefixes[Index] == ' ') { Units = StrDuplicate(L"-byte"); @@ -649,7 +664,7 @@ static CHAR16 *SizeInIEEEUnits(UINT64 SizeInBytes) { Units = StrDuplicate(L" iB"); Units[1] = Prefixes[Index]; } // if/else - SPrint(TheValue, 79, L"%d%s", (UINTN) SizeInIeee, Units); + SPrint(TheValue, 255, L"%ld%s", SizeInIeee, Units); } // if return TheValue; } // CHAR16 *SizeInSIUnits() @@ -666,7 +681,7 @@ static CHAR16 *GetVolumeName(IN REFIT_VOLUME *Volume) { CHAR16 *SISize, *TypeName; FileSystemInfoPtr = LibFileSystemInfo(Volume->RootDir); - if (FileSystemInfoPtr != NULL) { + if (FileSystemInfoPtr != NULL) { // we have filesystem information (size, label).... if ((FileSystemInfoPtr->VolumeLabel != NULL) && (StrLen(FileSystemInfoPtr->VolumeLabel) > 0)) { FoundName = StrDuplicate(FileSystemInfoPtr->VolumeLabel); } @@ -678,7 +693,7 @@ static CHAR16 *GetVolumeName(IN REFIT_VOLUME *Volume) { FoundName = NULL; } // if rEFInd HFS+ driver suspected - if (FoundName == NULL) { // filesystem has no name.... + 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); @@ -689,10 +704,10 @@ static CHAR16 *GetVolumeName(IN REFIT_VOLUME *Volume) { FreePool(FileSystemInfoPtr); - } else { + } else { // fs driver not returning info; fall back on our own information.... FoundName = AllocateZeroPool(sizeof(CHAR16) * 256); if (FoundName != NULL) { - TypeName = FSTypeName(Volume->FSType); // NOTE: Don't free TypeName; fn returns constant + TypeName = FSTypeName(Volume->FSType); // NOTE: Don't free TypeName; function returns constant if (StrLen(TypeName) > 0) SPrint(FoundName, 255, L"%s volume", FSTypeName(Volume->FSType)); else @@ -712,7 +727,7 @@ static CHAR16 *GetVolumeName(IN REFIT_VOLUME *Volume) { return FoundName; } // static CHAR16 *GetVolumeName() -VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) +VOID ScanVolume(REFIT_VOLUME *Volume) { EFI_STATUS Status; EFI_DEVICE_PATH *DevicePath, *NextDevicePath; @@ -901,7 +916,7 @@ static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_I } } } -} +} /* VOID ScanExtendedPartition() */ VOID ScanVolumes(VOID) { @@ -914,7 +929,7 @@ VOID ScanVolumes(VOID) MBR_PARTITION_INFO *MbrTable; UINTN PartitionIndex; UINT8 *SectorBuffer1, *SectorBuffer2; - UINTN SectorSum, i; + UINTN SectorSum, i, VolNumber = 0; MyFreePool(Volumes); Volumes = NULL; @@ -934,6 +949,8 @@ VOID ScanVolumes(VOID) Volume = AllocateZeroPool(sizeof(REFIT_VOLUME)); Volume->DeviceHandle = Handles[HandleIndex]; ScanVolume(Volume); + if (Volume->IsReadable) + Volume->VolNumber = VolNumber++; AddListElement((VOID ***) &Volumes, &VolumesCount, Volume); @@ -1016,7 +1033,7 @@ VOID ScanVolumes(VOID) MyFreePool(SectorBuffer2); } - } + } // for } /* VOID ScanVolumes() */ static VOID UninitVolumes(VOID) @@ -1361,8 +1378,8 @@ BOOLEAN StriSubCmp(IN CHAR16 *SmallStr, IN CHAR16 *BigStr) { // Merges two strings, creating a new one and returning a pointer to it. // If AddChar != 0, the specified character is placed between the two original -// strings (unless the first string is NULL). The original input string -// *First is de-allocated and replaced by the new merged string. +// strings (unless the first string is NULL or empty). The original input +// string *First is de-allocated and replaced by the new merged string. // This is similar to StrCat, but safer and more flexible because // MergeStrings allocates memory that's the correct size for the // new merged string, so it can take a NULL *First and it cleans @@ -1378,6 +1395,10 @@ VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar) { Length2 = StrLen(Second); NewString = AllocatePool(sizeof(CHAR16) * (Length1 + Length2 + 2)); if (NewString != NULL) { + if ((*First != NULL) && (StrLen(*First) == 0)) { + MyFreePool(*First); + *First = NULL; + } NewString[0] = L'\0'; if (*First != NULL) { StrCat(NewString, *First); @@ -1501,6 +1522,39 @@ VOID FindVolumeAndFilename(IN EFI_DEVICE_PATH *loadpath, OUT REFIT_VOLUME **Devi MyFreePool(DeviceString); } // VOID FindVolumeAndFilename() +// Splits a volume/filename string (e.g., "fs0:\EFI\BOOT") into separate +// volume and filename components (e.g., "fs0" and "\EFI\BOOT"), returning +// the filename component in the original *Path variable and the split-off +// volume component in the *VolName variable. +// Returns TRUE if both components are found, FALSE otherwise. +BOOLEAN SplitVolumeAndFilename(IN OUT CHAR16 **Path, OUT CHAR16 **VolName) { + UINTN i = 0, Length; + CHAR16 *Filename; + + if (*Path == NULL) + return FALSE; + + if (*VolName != NULL) { + MyFreePool(*VolName); + *VolName = NULL; + } + + Length = StrLen(*Path); + while ((i < Length) && ((*Path)[i] != L':')) { + i++; + } // while + + if (i < Length) { + Filename = StrDuplicate((*Path) + i + 1); + (*Path)[i] = 0; + *VolName = *Path; + *Path = Filename; + return TRUE; + } else { + return FALSE; + } +} // BOOLEAN SplitVolumeAndFilename() + // 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, @@ -1617,18 +1671,18 @@ BOOLEAN EjectMedia(VOID) { } // 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) +// 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)