X-Git-Url: https://code.delx.au/refind/blobdiff_plain/39f21d099c9fb310bae28b54dc68d266ed610ed7..26d86fa4b6c17ae9d5afce77e18909d10ba19d90:/refind/lib.c diff --git a/refind/lib.c b/refind/lib.c index 3c9e4c4..c6a9257 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -1,5 +1,5 @@ /* - * refit/lib.c + * refind/lib.c * General library functions * * Copyright (c) 2006-2009 Christoph Pfisterer @@ -34,12 +34,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* - * Modifications copyright (c) 2012 Roderick W. Smith + * Modifications copyright (c) 2012-2013 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 * with this source code or binaries made from it. - * + * */ #include "global.h" @@ -48,6 +48,7 @@ #include "screen.h" #include "../include/refit_call_wrapper.h" #include "../include/RemovableMedia.h" +//#include "../include/UsbMass.h" #ifdef __MAKEWITH_GNUEFI #define EfiReallocatePool ReallocatePool @@ -72,6 +73,7 @@ EFI_DEVICE_PATH EndDevicePath[] = { #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" #define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs" +#define BTRFS_SIGNATURE "_BHRfS_M" // variables @@ -92,9 +94,6 @@ UINTN VolumesCount = 0; // 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" // functions @@ -116,10 +115,11 @@ static VOID UninitVolumes(VOID); // isn't present. VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) { CHAR16 *NewName; - UINTN i, FinalChar = 0; + UINTN i, Length, FinalChar = 0; BOOLEAN LastWasSlash = FALSE; - NewName = AllocateZeroPool(sizeof(CHAR16) * (StrLen(PathName) + 2)); + Length = StrLen(PathName); + NewName = AllocateZeroPool(sizeof(CHAR16) * (Length + 2)); if (NewName != NULL) { for (i = 0; i < StrLen(PathName); i++) { if ((PathName[i] == L'/') || (PathName[i] == L'\\')) { @@ -153,24 +153,26 @@ VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) { // 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. +// unmodified and also returns that string. If InString is NULL, this function returns NULL. 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); + if (InString != NULL) { + 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); + } // if return FileName; } // static CHAR16* SplitDeviceString() @@ -199,6 +201,11 @@ EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle) // called before running external programs to close open file handles VOID UninitRefitLib(VOID) { + // This piece of code was made to correspond to weirdness in ReinitRefitLib(). + // See the comment on it there. + if(SelfRootDir == SelfVolume->RootDir) + SelfRootDir=0; + UninitVolumes(); if (SelfDir != NULL) { @@ -407,6 +414,9 @@ static CHAR16 *FSTypeName(IN UINT32 TypeCode) { case FS_TYPE_REISERFS: retval = L" ReiserFS"; break; + case FS_TYPE_BTRFS: + retval = L" Btrfs"; + break; case FS_TYPE_ISO9660: retval = L" ISO-9660"; break; @@ -417,21 +427,31 @@ static CHAR16 *FSTypeName(IN UINT32 TypeCode) { return retval; } // CHAR16 *FSTypeName() -// Identify the filesystem type, if possible. Expects a Buffer containing -// the first few (normally 4096) bytes of the filesystem, and outputs a -// code representing the identified filesystem type. -static UINT32 IdentifyFilesystemType(IN UINT8 *Buffer, IN UINTN BufferSize) { - UINT32 FoundType = FS_TYPE_UNKNOWN; +// 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.) +static VOID SetFilesystemData(IN UINT8 *Buffer, IN UINTN BufferSize, IN OUT REFIT_VOLUME *Volume) { UINT32 *Ext2Incompat, *Ext2Compat; UINT16 *Magic16; char *MagicString; - if (Buffer != NULL) { + if ((Buffer != NULL) && (Volume != NULL)) { + SetMem(&(Volume->VolUuid), sizeof(EFI_GUID), 0); + Volume->FSType = FS_TYPE_UNKNOWN; if (BufferSize >= 512) { Magic16 = (UINT16*) (Buffer + 510); - if (*Magic16 == FAT_MAGIC) - return FS_TYPE_FAT; + if (*Magic16 == FAT_MAGIC) { + Volume->FSType = FS_TYPE_FAT; + return; + } // if } // search for FAT magic if (BufferSize >= (1024 + 100)) { @@ -440,34 +460,46 @@ static UINT32 IdentifyFilesystemType(IN UINT8 *Buffer, IN UINTN BufferSize) { Ext2Compat = (UINT32*) (Buffer + 1024 + 92); Ext2Incompat = (UINT32*) (Buffer + 1024 + 96); if ((*Ext2Incompat & 0x0040) || (*Ext2Incompat & 0x0200)) { // check for extents or flex_bg - return FS_TYPE_EXT4; + Volume->FSType = FS_TYPE_EXT4; } else if (*Ext2Compat & 0x0004) { // check for journal - return FS_TYPE_EXT3; + Volume->FSType = FS_TYPE_EXT3; } else { // none of these features; presume it's ext2... - return FS_TYPE_EXT2; + Volume->FSType = FS_TYPE_EXT2; } + CopyMem(&(Volume->VolUuid), Buffer + 1024 + 104, sizeof(EFI_GUID)); + return; } } // search for ext2/3/4 magic - if (BufferSize >= (65536 + 62)) { + if (BufferSize >= (65536 + 100)) { 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; + Volume->FSType = FS_TYPE_REISERFS; + CopyMem(&(Volume->VolUuid), Buffer + 65536 + 84, sizeof(EFI_GUID)); + return; } // if } // search for ReiserFS magic + if (BufferSize >= (65536 + 64 + 8)) { + MagicString = (char*) (Buffer + 65536 + 64); + if (CompareMem(MagicString, BTRFS_SIGNATURE, 8) == 0) { + Volume->FSType = FS_TYPE_BTRFS; + return; + } // if + } // search for Btrfs magic + if (BufferSize >= (1024 + 2)) { Magic16 = (UINT16*) (Buffer + 1024); if ((*Magic16 == HFSPLUS_MAGIC1) || (*Magic16 == HFSPLUS_MAGIC2)) { - return FS_TYPE_HFSPLUS; + Volume->FSType = FS_TYPE_HFSPLUS; + return; } } // search for HFS+ magic } // if (Buffer != NULL) - return FoundType; -} +} // UINT32 SetFilesystemData() static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable) { @@ -493,8 +525,8 @@ static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable) Volume->BlockIOOffset, SAMPLE_SIZE, Buffer); if (!EFI_ERROR(Status)) { - Volume->FSType = IdentifyFilesystemType(Buffer, SAMPLE_SIZE); - if (*((UINT16 *)(Buffer + 510)) == 0xaa55 && Buffer[0] != 0) { + SetFilesystemData(Buffer, SAMPLE_SIZE, Volume); + if ((*((UINT16 *)(Buffer + 510)) == 0xaa55 && Buffer[0] != 0) && (FindMem(Buffer, 512, "EXFAT", 5) == -1)) { *Bootable = TRUE; Volume->HasBootCode = TRUE; } @@ -626,21 +658,27 @@ static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable) } } /* VOID ScanVolumeBootcode() */ -// default volume badge icon based on disk kind -static VOID ScanVolumeDefaultIcon(IN OUT REFIT_VOLUME *Volume) +// Set default volume badge icon based on /.VolumeBadge.{icns|png} file or disk kind +VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume) { - switch (Volume->DiskKind) { - case DISK_KIND_INTERNAL: - Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_INTERNAL); - break; - case DISK_KIND_EXTERNAL: - Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_EXTERNAL); - break; - case DISK_KIND_OPTICAL: - Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL); - break; - } // switch() -} + if (Volume->VolBadgeImage == NULL) { + Volume->VolBadgeImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeBadge", 128); + } + + if (Volume->VolBadgeImage == NULL) { + switch (Volume->DiskKind) { + case DISK_KIND_INTERNAL: + Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_INTERNAL); + break; + case DISK_KIND_EXTERNAL: + Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_EXTERNAL); + break; + case DISK_KIND_OPTICAL: + Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL); + break; + } // switch() + } +} // VOID SetVolumeBadgeIcon() // Return a string representing the input size in IEEE-1541 units. // The calling function is responsible for freeing the allocated memory. @@ -834,11 +872,12 @@ VOID ScanVolume(REFIT_VOLUME *Volume) Volume->HasBootCode = FALSE; } - // default volume icon based on disk kind - ScanVolumeDefaultIcon(Volume); - // open the root directory of the volume Volume->RootDir = LibOpenRoot(Volume->DeviceHandle); + + // Set volume icon based on .VolumeBadge icon or disk kind + SetVolumeBadgeIcon(Volume); + if (Volume->RootDir == NULL) { Volume->IsReadable = FALSE; return; @@ -848,12 +887,9 @@ VOID ScanVolume(REFIT_VOLUME *Volume) Volume->VolName = GetVolumeName(Volume); - // get custom volume icon if present - if (FileExists(Volume->RootDir, VOLUME_BADGE_NAME)) - Volume->VolBadgeImage = LoadIcns(Volume->RootDir, VOLUME_BADGE_NAME, 32); - if (FileExists(Volume->RootDir, VOLUME_ICON_NAME)) { - Volume->VolIconImage = LoadIcns(Volume->RootDir, VOLUME_ICON_NAME, 128); - } + // get custom volume icons if present + if (!Volume->VolIconImage) + Volume->VolIconImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeIcon", 128); } // ScanVolume() static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry) @@ -909,7 +945,7 @@ static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_I if (!Bootable) Volume->HasBootCode = FALSE; - ScanVolumeDefaultIcon(Volume); + SetVolumeBadgeIcon(Volume); AddListElement((VOID ***) &Volumes, &VolumesCount, Volume); @@ -921,15 +957,17 @@ static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_I VOID ScanVolumes(VOID) { EFI_STATUS Status; - UINTN HandleCount = 0; - UINTN HandleIndex; EFI_HANDLE *Handles; REFIT_VOLUME *Volume, *WholeDiskVolume; - UINTN VolumeIndex, VolumeIndex2; MBR_PARTITION_INFO *MbrTable; + UINTN HandleCount = 0; + UINTN HandleIndex; + UINTN VolumeIndex, VolumeIndex2; UINTN PartitionIndex; - UINT8 *SectorBuffer1, *SectorBuffer2; UINTN SectorSum, i, VolNumber = 0; + UINT8 *SectorBuffer1, *SectorBuffer2; + EFI_GUID *UuidList; + EFI_GUID NullUuid = { 00000000, 0000, 0000, {0000, 0000, 0000, 0000} }; MyFreePool(Volumes); Volumes = NULL; @@ -937,6 +975,7 @@ VOID ScanVolumes(VOID) // 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... @@ -949,8 +988,19 @@ VOID ScanVolumes(VOID) Volume = AllocateZeroPool(sizeof(REFIT_VOLUME)); Volume->DeviceHandle = Handles[HandleIndex]; ScanVolume(Volume); + if (UuidList) { + UuidList[HandleIndex] = Volume->VolUuid; + for (i = 0; i < HandleIndex; i++) { + if ((CompareMem(&(Volume->VolUuid), &(UuidList[i]), sizeof(EFI_GUID)) == 0) && + (CompareMem(&(Volume->VolUuid), &NullUuid, sizeof(EFI_GUID)) != 0)) { // Duplicate filesystem UUID + Volume->IsReadable = FALSE; + } // if + } // for + } // if if (Volume->IsReadable) Volume->VolNumber = VolNumber++; + else + Volume->VolNumber = VOL_UNREADABLE; AddListElement((VOID ***) &Volumes, &VolumesCount, Volume); @@ -1150,13 +1200,15 @@ EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, LastBufferSize = BufferSize; } if (EFI_ERROR(Status)) { - FreePool(Buffer); + MyFreePool(Buffer); + Buffer = NULL; break; } // check for end of listing if (BufferSize == 0) { // end of directory listing - FreePool(Buffer); + MyFreePool(Buffer); + Buffer = NULL; break; } @@ -1276,7 +1328,7 @@ BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR // else continue loop } else break; - } while (KeepGoing); + } while (KeepGoing && FilePattern); *DirEntry = DirIter->LastFileInfo; return TRUE; @@ -1318,20 +1370,22 @@ CHAR16 * Basename(IN CHAR16 *Path) return FileName; } -// Replaces a filename extension of ".efi" with the specified string -// (Extension). If the input Path doesn't end in ".efi", Extension -// is added to the existing filename. -VOID ReplaceEfiExtension(IN OUT CHAR16 *Path, IN CHAR16 *Extension) -{ - UINTN PathLen; - - PathLen = StrLen(Path); - // Note: Do StriCmp() twice to work around Gigabyte Hybrid EFI case-sensitivity bug.... - if ((PathLen >= 4) && ((StriCmp(&Path[PathLen - 4], L".efi") == 0) || (StriCmp(&Path[PathLen - 4], L".EFI") == 0))) { - Path[PathLen - 4] = 0; - } // if - StrCat(Path, Extension); -} // VOID ReplaceEfiExtension() +// Remove the .efi extension from FileName -- for instance, if FileName is +// "fred.efi", returns "fred". If the filename contains no .efi extension, +// returns a copy of the original input. +CHAR16 * StripEfiExtension(CHAR16 *FileName) { + UINTN Length; + CHAR16 *Copy = NULL; + + if ((FileName != NULL) && ((Copy = StrDuplicate(FileName)) != NULL)) { + Length = StrLen(Copy); + // Note: Do StriCmp() twice to work around Gigabyte Hybrid EFI case-sensitivity bug.... + if ((Length >= 4) && ((StriCmp(&Copy[Length - 4], L".efi") == 0) || (StriCmp(&Copy[Length - 4], L".EFI") == 0))) { + Copy[Length - 4] = 0; + } // if + } // if + return Copy; +} // CHAR16 * StripExtension() // // memory string search @@ -1424,7 +1478,7 @@ VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar) { CHAR16 *FindExtension(IN CHAR16 *Path) { CHAR16 *Extension; BOOLEAN Found = FALSE, FoundSlash = FALSE; - UINTN i; + INTN i; Extension = AllocateZeroPool(sizeof(CHAR16)); if (Path) { @@ -1453,6 +1507,9 @@ CHAR16 *FindLastDirName(IN CHAR16 *Path) { UINTN i, StartOfElement = 0, EndOfElement = 0, PathLength, CopyLength; CHAR16 *Found = NULL; + if (Path == NULL) + return NULL; + PathLength = StrLen(Path); // Find start & end of target element for (i = 0; i < PathLength; i++) { @@ -1483,14 +1540,16 @@ CHAR16 *FindLastDirName(IN CHAR16 *Path) { // freeing the returned string's memory. CHAR16 *FindPath(IN CHAR16* FullPath) { UINTN i, LastBackslash = 0; - CHAR16 *PathOnly; + CHAR16 *PathOnly = NULL; - for (i = 0; i < StrLen(FullPath); i++) { - if (FullPath[i] == '\\') - LastBackslash = i; - } // for - PathOnly = StrDuplicate(FullPath); - PathOnly[LastBackslash] = 0; + if (FullPath != NULL) { + for (i = 0; i < StrLen(FullPath); i++) { + if (FullPath[i] == '\\') + LastBackslash = i; + } // for + PathOnly = StrDuplicate(FullPath); + PathOnly[LastBackslash] = 0; + } // if return (PathOnly); } @@ -1563,6 +1622,9 @@ CHAR16 *FindNumbers(IN CHAR16 *InString) { UINTN i, StartOfElement, EndOfElement = 0, InLength, CopyLength; CHAR16 *Found = NULL; + if (InString == NULL) + return NULL; + InLength = StartOfElement = StrLen(InString); // Find start & end of target element for (i = 0; i < InLength; i++) { @@ -1619,6 +1681,31 @@ CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index) { return (FoundString); } // CHAR16 *FindCommaDelimited() +// Return the position of SmallString within BigString, or -1 if +// not found. +INTN FindSubString(IN CHAR16 *SmallString, IN CHAR16 *BigString) { + INTN Position = -1; + UINTN i = 0, SmallSize, BigSize; + BOOLEAN Found = FALSE; + + if ((SmallString == NULL) || (BigString == NULL)) + return -1; + + SmallSize = StrLen(SmallString); + BigSize = StrLen(BigString); + if ((SmallSize > BigSize) || (SmallSize == 0) || (BigSize == 0)) + return -1; + + while ((i <= (BigSize - SmallSize) && !Found)) { + if (CompareMem(BigString + i, SmallString, SmallSize) == 0) { + Found = TRUE; + Position = i; + } // if + i++; + } // while() + return Position; +} // INTN FindSubString() + // 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). @@ -1638,7 +1725,7 @@ BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List) { // 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) { +VOID MyFreePool(IN VOID *Pointer) { if (Pointer != NULL) FreePool(Pointer); }