* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
- * Modifications copyright (c) 2012-2013 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
- * with this source code or binaries made from it.
+ * License (GPL) version 3 (GPLv3), or (at your option) any later version.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "global.h"
#include "screen.h"
#include "../include/refit_call_wrapper.h"
#include "../include/RemovableMedia.h"
-//#include "../include/UsbMass.h"
+#include "gpt.h"
+#include "config.h"
+#include "mystrings.h"
#ifdef __MAKEWITH_GNUEFI
#define EfiReallocatePool ReallocatePool
EFI_DEVICE_PATH EndDevicePath[] = {
{END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}}
};
-
-//#define EndDevicePath DevicePath
#endif
// "Magic" signatures for various filesystems
#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
#define BTRFS_SIGNATURE "_BHRfS_M"
+#define XFS_SIGNATURE "XFSB"
+#define NTFS_SIGNATURE "NTFS "
// variables
REFIT_VOLUME *SelfVolume = NULL;
REFIT_VOLUME **Volumes = NULL;
UINTN VolumesCount = 0;
+extern GPT_DATA *gPartitions;
// Maximum size for disk sectors
#define SECTOR_SIZE 4096
// and identify its boot loader, and hence probable BIOS-mode OS installation
#define SAMPLE_SIZE 69632 /* 68 KiB -- ReiserFS superblock begins at 64 KiB */
-
-// functions
-
-static EFI_STATUS FinishInitRefitLib(VOID);
-
-static VOID UninitVolumes(VOID);
-
//
-// self recognition stuff
+// Pathname manipulations
//
// Converts forward slashes to backslashes, removes duplicate slashes, and
// return "/", since some firmware implementations flake out if this
// isn't present.
VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) {
- CHAR16 *NewName;
- UINTN i, Length, FinalChar = 0;
- BOOLEAN LastWasSlash = FALSE;
-
- 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'\\')) {
- if ((!LastWasSlash) && (FinalChar != 0))
- NewName[FinalChar++] = L'\\';
- LastWasSlash = TRUE;
- } else {
- NewName[FinalChar++] = PathName[i];
- LastWasSlash = FALSE;
- } // if/else
- } // for
- NewName[FinalChar] = 0;
- if ((FinalChar > 0) && (NewName[FinalChar - 1] == L'\\'))
- NewName[--FinalChar] = 0;
- if (FinalChar == 0) {
- NewName[0] = L'\\';
- NewName[1] = 0;
- }
- // Copy the transformed name back....
- StrCpy(PathName, NewName);
- FreePool(NewName);
- } // if allocation OK
+ CHAR16 *NewName;
+ UINTN i, Length, FinalChar = 0;
+ BOOLEAN LastWasSlash = FALSE;
+
+ Length = StrLen(PathName);
+ NewName = AllocateZeroPool(sizeof(CHAR16) * (Length + 2));
+ if (NewName != NULL) {
+ for (i = 0; i < Length; i++) {
+ if ((PathName[i] == L'/') || (PathName[i] == L'\\')) {
+ if ((!LastWasSlash) && (FinalChar != 0))
+ NewName[FinalChar++] = L'\\';
+ LastWasSlash = TRUE;
+ } else {
+ NewName[FinalChar++] = PathName[i];
+ LastWasSlash = FALSE;
+ } // if/else
+ } // for
+ NewName[FinalChar] = 0;
+ if ((FinalChar > 0) && (NewName[FinalChar - 1] == L'\\'))
+ NewName[--FinalChar] = 0;
+ if (FinalChar == 0) {
+ NewName[0] = L'\\';
+ NewName[1] = 0;
+ }
+ // Copy the transformed name back....
+ StrCpy(PathName, NewName);
+ FreePool(NewName);
+ } // if allocation OK
} // CleanUpPathNameSlashes()
// Splits an EFI device path into device and filename components. For instance, if InString is
// If InString contains no ")" character, this function leaves the original input 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;
-
- 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;
+ INTN i;
+ CHAR16 *FileName = NULL;
+ BOOLEAN Found = FALSE;
+
+ 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()
+//
+// Library initialization and de-initialization
+//
+
+static EFI_STATUS FinishInitRefitLib(VOID)
+{
+ EFI_STATUS Status;
+
+ if (SelfRootDir == NULL) {
+ SelfRootDir = LibOpenRoot(SelfLoadedImage->DeviceHandle);
+ if (SelfRootDir == NULL) {
+ CheckError(EFI_LOAD_ERROR, L"while (re)opening our installation volume");
+ return EFI_LOAD_ERROR;
+ }
+ }
+
+ Status = refit_call5_wrapper(SelfRootDir->Open, SelfRootDir, &SelfDir, SelfDirPath, EFI_FILE_MODE_READ, 0);
+ if (CheckFatalError(Status, L"while opening our installation directory"))
+ return EFI_LOAD_ERROR;
+
+ return EFI_SUCCESS;
+}
+
EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle)
{
EFI_STATUS Status;
// find the current directory
DevicePathAsString = DevicePathToStr(SelfLoadedImage->FilePath);
+ GlobalConfig.SelfDevicePath = FileDevicePath(SelfLoadedImage->DeviceHandle, DevicePathAsString);
CleanUpPathNameSlashes(DevicePathAsString);
MyFreePool(SelfDirPath);
Temp = FindPath(DevicePathAsString);
return FinishInitRefitLib();
}
+static VOID UninitVolumes(VOID)
+{
+ REFIT_VOLUME *Volume;
+ UINTN VolumeIndex;
+
+ for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+ Volume = Volumes[VolumeIndex];
+
+ if (Volume->RootDir != NULL) {
+ refit_call1_wrapper(Volume->RootDir->Close, Volume->RootDir);
+ Volume->RootDir = NULL;
+ }
+
+ Volume->DeviceHandle = NULL;
+ Volume->BlockIO = NULL;
+ Volume->WholeDiskBlockIO = NULL;
+ }
+} /* VOID UninitVolumes() */
+
+VOID ReinitVolumes(VOID)
+{
+ EFI_STATUS Status;
+ REFIT_VOLUME *Volume;
+ UINTN VolumeIndex;
+ EFI_DEVICE_PATH *RemainingDevicePath;
+ EFI_HANDLE DeviceHandle, WholeDiskHandle;
+
+ for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+ Volume = Volumes[VolumeIndex];
+
+ if (Volume->DevicePath != NULL) {
+ // get the handle for that path
+ RemainingDevicePath = Volume->DevicePath;
+ Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &DeviceHandle);
+
+ if (!EFI_ERROR(Status)) {
+ Volume->DeviceHandle = DeviceHandle;
+
+ // get the root directory
+ Volume->RootDir = LibOpenRoot(Volume->DeviceHandle);
+
+ } else
+ CheckError(Status, L"from LocateDevicePath");
+ }
+
+ if (Volume->WholeDiskDevicePath != NULL) {
+ // get the handle for that path
+ RemainingDevicePath = Volume->WholeDiskDevicePath;
+ Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle);
+
+ if (!EFI_ERROR(Status)) {
+ // get the BlockIO protocol
+ Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol,
+ (VOID **) &Volume->WholeDiskBlockIO);
+ if (EFI_ERROR(Status)) {
+ Volume->WholeDiskBlockIO = NULL;
+ CheckError(Status, L"from HandleProtocol");
+ }
+ } else
+ CheckError(Status, L"from LocateDevicePath");
+ }
+ }
+} /* VOID ReinitVolumes(VOID) */
+
// called before running external programs to close open file handles
VOID UninitRefitLib(VOID)
{
refit_call1_wrapper(SelfRootDir->Close, SelfRootDir);
SelfRootDir = NULL;
}
-}
+} /* VOID UninitRefitLib() */
// called after running external programs to re-open file handles
EFI_STATUS ReinitRefitLib(VOID)
return FinishInitRefitLib();
}
-static EFI_STATUS FinishInitRefitLib(VOID)
-{
- EFI_STATUS Status;
-
- if (SelfRootDir == NULL) {
- SelfRootDir = LibOpenRoot(SelfLoadedImage->DeviceHandle);
- if (SelfRootDir == NULL) {
- CheckError(EFI_LOAD_ERROR, L"while (re)opening our installation volume");
- return EFI_LOAD_ERROR;
- }
- }
-
- Status = refit_call5_wrapper(SelfRootDir->Open, SelfRootDir, &SelfDir, SelfDirPath, EFI_FILE_MODE_READ, 0);
- if (CheckFatalError(Status, L"while opening our installation directory"))
- return EFI_LOAD_ERROR;
+//
+// EFI variable read and write functions
+//
- return EFI_SUCCESS;
-}
+// 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
//
-VOID CreateList(OUT VOID ***ListPtr, OUT UINTN *ElementCount, IN UINTN InitialElementCount)
-{
- UINTN AllocateCount;
-
- *ElementCount = InitialElementCount;
- if (*ElementCount > 0) {
- AllocateCount = (*ElementCount + 7) & ~7; // next multiple of 8
- *ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount);
- } else {
- *ListPtr = NULL;
- }
-}
-
VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement)
{
UINTN AllocateCount;
- if ((*ElementCount & 7) == 0) {
- AllocateCount = *ElementCount + 8;
+ if ((*ElementCount & 15) == 0) {
+ AllocateCount = *ElementCount + 16;
if (*ElementCount == 0)
*ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount);
else
}
} // VOID FreeList()
-//
-// firmware device path discovery
-//
-
-static UINT8 LegacyLoaderMediaPathData[] = {
- 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
- 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
- 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
-};
-static EFI_DEVICE_PATH *LegacyLoaderMediaPath = (EFI_DEVICE_PATH *)LegacyLoaderMediaPathData;
-
-VOID ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DEVICE_PATH **HardcodedPathList)
-{
- EFI_STATUS Status;
- UINTN HandleCount = 0;
- UINTN HandleIndex, HardcodedIndex;
- EFI_HANDLE *Handles;
- EFI_HANDLE Handle;
- UINTN PathCount = 0;
- UINTN PathIndex;
- EFI_LOADED_IMAGE *LoadedImage;
- EFI_DEVICE_PATH *DevicePath;
- BOOLEAN Seen;
-
- MaxPaths--; // leave space for the terminating NULL pointer
-
- // get all LoadedImage handles
- Status = LibLocateHandle(ByProtocol, &LoadedImageProtocol, NULL, &HandleCount, &Handles);
- if (CheckError(Status, L"while listing LoadedImage handles")) {
- if (HardcodedPathList) {
- for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++)
- PathList[PathCount++] = HardcodedPathList[HardcodedIndex];
- }
- PathList[PathCount] = NULL;
- return;
- }
- for (HandleIndex = 0; HandleIndex < HandleCount && PathCount < MaxPaths; HandleIndex++) {
- Handle = Handles[HandleIndex];
-
- Status = refit_call3_wrapper(BS->HandleProtocol, Handle, &LoadedImageProtocol, (VOID **) &LoadedImage);
- if (EFI_ERROR(Status))
- continue; // This can only happen if the firmware scewed up, ignore it.
-
- Status = refit_call3_wrapper(BS->HandleProtocol, LoadedImage->DeviceHandle, &DevicePathProtocol, (VOID **) &DevicePath);
- if (EFI_ERROR(Status))
- continue; // This happens, ignore it.
-
- // Only grab memory range nodes
- if (DevicePathType(DevicePath) != HARDWARE_DEVICE_PATH || DevicePathSubType(DevicePath) != HW_MEMMAP_DP)
- continue;
-
- // Check if we have this device path in the list already
- // WARNING: This assumes the first node in the device path is unique!
- Seen = FALSE;
- for (PathIndex = 0; PathIndex < PathCount; PathIndex++) {
- if (DevicePathNodeLength(DevicePath) != DevicePathNodeLength(PathList[PathIndex]))
- continue;
- if (CompareMem(DevicePath, PathList[PathIndex], DevicePathNodeLength(DevicePath)) == 0) {
- Seen = TRUE;
- break;
- }
- }
- if (Seen)
- continue;
-
- PathList[PathCount++] = AppendDevicePath(DevicePath, LegacyLoaderMediaPath);
- }
- MyFreePool(Handles);
-
- if (HardcodedPathList) {
- for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++)
- PathList[PathCount++] = HardcodedPathList[HardcodedIndex];
- }
- PathList[PathCount] = NULL;
-}
-
//
// volume functions
//
CHAR16 *retval = NULL;
switch (TypeCode) {
+ case FS_TYPE_WHOLEDISK:
+ retval = L" whole disk";
+ break;
case FS_TYPE_FAT:
retval = L" FAT";
break;
case FS_TYPE_BTRFS:
retval = L" Btrfs";
break;
+ case FS_TYPE_XFS:
+ retval = L" XFS";
+ break;
case FS_TYPE_ISO9660:
retval = L" ISO-9660";
break;
+ case FS_TYPE_NTFS:
+ retval = L" NTFS";
+ break;
default:
retval = L"";
break;
} // 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;
char *MagicString;
+ EFI_FILE *RootDir;
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) {
- Volume->FSType = FS_TYPE_FAT;
- return;
- } // if
- } // search for FAT magic
-
if (BufferSize >= (1024 + 100)) {
Magic16 = (UINT16*) (Buffer + 1024 + 56);
if (*Magic16 == EXT2_SUPER_MAGIC) { // ext2/3/4
} // if
} // search for Btrfs magic
+ if (BufferSize >= 512) {
+ MagicString = (char*) Buffer;
+ if (CompareMem(MagicString, XFS_SIGNATURE, 4) == 0) {
+ Volume->FSType = FS_TYPE_XFS;
+ return;
+ }
+ } // search for XFS magic
+
if (BufferSize >= (1024 + 2)) {
Magic16 = (UINT16*) (Buffer + 1024);
if ((*Magic16 == HFSPLUS_MAGIC1) || (*Magic16 == HFSPLUS_MAGIC2)) {
return;
}
} // search for HFS+ magic
- } // if (Buffer != NULL)
+ if (BufferSize >= 512) {
+ // Search for NTFS, FAT, and MBR/EBR.
+ // These all have 0xAA55 at the end of the first sector, but FAT and
+ // MBR/EBR are not easily distinguished. Thus, we first look for NTFS
+ // "magic"; then check to see if the volume can be mounted, thus
+ // relying on the EFI's built-in FAT driver to identify FAT; and then
+ // check to see if the "volume" is in fact a whole-disk device.
+ Magic16 = (UINT16*) (Buffer + 510);
+ if (*Magic16 == FAT_MAGIC) {
+ MagicString = (char*) (Buffer + 3);
+ if (CompareMem(MagicString, NTFS_SIGNATURE, 8) == 0) {
+ Volume->FSType = FS_TYPE_NTFS;
+ CopyMem(&(Volume->VolUuid), Buffer + 0x48, sizeof(UINT64));
+ } else {
+ RootDir = LibOpenRoot(Volume->DeviceHandle);
+ if (RootDir != NULL) {
+ Volume->FSType = FS_TYPE_FAT;
+ } else if (!Volume->BlockIO->Media->LogicalPartition) {
+ Volume->FSType = FS_TYPE_WHOLEDISK;
+ } // if/elseif/else
+ } // if/else
+ return;
+ } // if
+ } // search for FAT and NTFS magic
+
+ // If no other filesystem is identified and block size is right, assume
+ // it's ISO-9660....
+ if (Volume->BlockIO->Media->BlockSize == 2048) {
+ Volume->FSType = FS_TYPE_ISO9660;
+ return;
+ }
+ } // if ((Buffer != NULL) && (Volume != NULL))
} // UINT32 SetFilesystemData()
static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable)
UINT8 Buffer[SAMPLE_SIZE];
UINTN i;
MBR_PARTITION_INFO *MbrTable;
- BOOLEAN MbrTableFound;
+ BOOLEAN MbrTableFound = FALSE;
Volume->HasBootCode = FALSE;
Volume->OSIconName = NULL;
Volume->BlockIO, Volume->BlockIO->Media->MediaId,
Volume->BlockIOOffset, SAMPLE_SIZE, Buffer);
if (!EFI_ERROR(Status)) {
-
SetFilesystemData(Buffer, SAMPLE_SIZE, Volume);
+ }
+ if ((Status == EFI_SUCCESS) && (GlobalConfig.LegacyType == LEGACY_TYPE_MAC)) {
if ((*((UINT16 *)(Buffer + 510)) == 0xaa55 && Buffer[0] != 0) && (FindMem(Buffer, 512, "EXFAT", 5) == -1)) {
*Bootable = TRUE;
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(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 *)(Buffer + 502)) == 0 &&
*((UINT32 *)(Buffer + 506)) == 50000 &&
*((UINT16 *)(Buffer + 510)) == 0xaa55) ||
Volume->OSIconName = L"freebsd";
Volume->OSName = L"FreeBSD";
+ // If more differentiation needed, also search for
+ // "Invalid partition table" &/or "Missing boot loader".
+ } else if ((*((UINT16 *)(Buffer + 510)) == 0xaa55) &&
+ (FindMem(Buffer, SECTOR_SIZE, "Boot loader too large", 21) >= 0) &&
+ (FindMem(Buffer, SECTOR_SIZE, "I/O error loading boot loader", 29) >= 0)) {
+ Volume->HasBootCode = TRUE;
+ Volume->OSIconName = L"freebsd";
+ Volume->OSName = L"FreeBSD";
+
} else if (FindMem(Buffer, 512, "!Loading", 8) >= 0 ||
FindMem(Buffer, SECTOR_SIZE, "/cdboot\0/CDBOOT\0", 16) >= 0) {
Volume->HasBootCode = TRUE;
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 ||
}
// 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",
// check for MBR partition table
if (*((UINT16 *)(Buffer + 510)) == 0xaa55) {
- MbrTableFound = FALSE;
MbrTable = (MBR_PARTITION_INFO *)(Buffer + 446);
for (i = 0; i < 4; i++)
if (MbrTable[i].StartLBA && MbrTable[i].Size)
// 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", 128);
+ Volume->VolBadgeImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeBadge", GlobalConfig.IconSizes[ICON_SIZE_BADGE]);
}
if (Volume->VolBadgeImage == NULL) {
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()
// 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) {
- UINT64 SizeInIeee;
- UINTN Index = 0, NumPrefixes;
- CHAR16 *Units, *Prefixes = L" KMGTPEZ";
- CHAR16 *TheValue;
-
- TheValue = AllocateZeroPool(sizeof(CHAR16) * 256);
- if (TheValue != NULL) {
- NumPrefixes = StrLen(Prefixes);
- SizeInIeee = SizeInBytes;
- while ((SizeInIeee > 1024) && (Index < (NumPrefixes - 1))) {
- Index++;
- SizeInIeee /= 1024;
- } // while
- if (Prefixes[Index] == ' ') {
- Units = StrDuplicate(L"-byte");
- } else {
- Units = StrDuplicate(L" iB");
- Units[1] = Prefixes[Index];
- } // if/else
- SPrint(TheValue, 255, L"%ld%s", SizeInIeee, Units);
- } // if
- return TheValue;
-} // CHAR16 *SizeInSIUnits()
+ UINT64 SizeInIeee;
+ UINTN Index = 0, NumPrefixes;
+ CHAR16 *Units, *Prefixes = L" KMGTPEZ";
+ CHAR16 *TheValue;
+
+ TheValue = AllocateZeroPool(sizeof(CHAR16) * 256);
+ if (TheValue != NULL) {
+ NumPrefixes = StrLen(Prefixes);
+ SizeInIeee = SizeInBytes;
+ while ((SizeInIeee > 1024) && (Index < (NumPrefixes - 1))) {
+ Index++;
+ SizeInIeee /= 1024;
+ } // while
+ if (Prefixes[Index] == ' ') {
+ Units = StrDuplicate(L"-byte");
+ } else {
+ Units = StrDuplicate(L" iB");
+ Units[1] = Prefixes[Index];
+ } // if/else
+ SPrint(TheValue, 255, L"%ld%s", SizeInIeee, Units);
+ } // if
+ return TheValue;
+} // CHAR16 *SizeInIEEEUnits()
// Return a name for the volume. Ideally this should be the label for the
-// filesystem it contains, but this function falls back to describing the
+// filesystem or volume, but this function falls back to describing the
// filesystem by size (200 MiB, etc.) and/or type (ext2, HFS+, etc.), if
// 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;
- 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....
- FoundName = AllocateZeroPool(sizeof(CHAR16) * 256);
- if (FoundName != NULL) {
- 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
- SPrint(FoundName, 255, L"unknown volume");
- } // if allocated memory OK
- } // if
+static CHAR16 *GetVolumeName(REFIT_VOLUME *Volume) {
+ EFI_FILE_SYSTEM_INFO *FileSystemInfoPtr = NULL;
+ CHAR16 *FoundName = NULL;
+ CHAR16 *SISize, *TypeName;
+
+ if (Volume->RootDir != NULL) {
+ FileSystemInfoPtr = LibFileSystemInfo(Volume->RootDir);
+ }
+
+ if ((FileSystemInfoPtr != NULL) && (FileSystemInfoPtr->VolumeLabel != NULL) &&
+ (StrLen(FileSystemInfoPtr->VolumeLabel) > 0)) {
+ FoundName = StrDuplicate(FileSystemInfoPtr->VolumeLabel);
+ }
- // 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)")
+ // 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
+ if (StrLen(TypeName) > 0)
+ SPrint(FoundName, 255, L"%s volume", TypeName);
+ else
+ SPrint(FoundName, 255, L"unknown volume");
+ } // if allocated memory OK
+ } // if
- // Desperate fallback name....
- if (FoundName == NULL) {
- FoundName = StrDuplicate(L"unknown volume");
- }
- return FoundName;
+ // TODO: Above could be improved/extended, in case filesystem name is not found,
+ // such as:
+ // - use or add disk/partition number (e.g., "(hd0,2)")
+
+ // Desperate fallback name....
+ if (FoundName == NULL) {
+ FoundName = StrDuplicate(L"unknown volume");
+ }
+ return FoundName;
} // static CHAR16 *GetVolumeName()
+// Determine the unique GUID, type code GUID, and name of the volume and store them.
+static VOID SetPartGuidAndName(REFIT_VOLUME *Volume, EFI_DEVICE_PATH_PROTOCOL *DevicePath) {
+ HARDDRIVE_DEVICE_PATH *HdDevicePath;
+ GPT_ENTRY *PartInfo;
+
+ if ((Volume == NULL) || (DevicePath == NULL))
+ return;
+
+ if ((DevicePath->Type == MEDIA_DEVICE_PATH) && (DevicePath->SubType == MEDIA_HARDDRIVE_DP)) {
+ HdDevicePath = (HARDDRIVE_DEVICE_PATH*) DevicePath;
+ if (HdDevicePath->SignatureType == SIGNATURE_TYPE_GUID) {
+ Volume->PartGuid = *((EFI_GUID*) HdDevicePath->Signature);
+ PartInfo = FindPartWithGuid(&(Volume->PartGuid));
+ if (PartInfo) {
+ Volume->PartName = StrDuplicate(PartInfo->name);
+ CopyMem(&(Volume->PartTypeGuid), PartInfo->type_guid, sizeof(EFI_GUID));
+ if (GuidsAreEqual(&(Volume->PartTypeGuid), &gFreedesktopRootGuid) &&
+ ((PartInfo->attributes & GPT_NO_AUTOMOUNT) == 0)) {
+ GlobalConfig.DiscoveredRoot = Volume;
+ } // if (GUIDs match && automounting OK)
+ Volume->IsMarkedReadOnly = ((PartInfo->attributes & GPT_READ_ONLY) > 0);
+ } // if (PartInfo exists)
+ } // if (GPT disk)
+ } // if (disk device)
+} // 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;
while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) {
NextDevicePath = NextDevicePathNode(DevicePath);
+ if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH) {
+ SetPartGuidAndName(Volume, DevicePath);
+ }
if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH &&
(DevicePathSubType(DevicePath) == MSG_USB_DP ||
DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP ||
}
// 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
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;
+ return;
+ } else {
+ Volume->IsReadable = TRUE;
+ if ((GlobalConfig.LegacyType == LEGACY_TYPE_MAC) && (Volume->FSType == FS_TYPE_NTFS) && Volume->HasBootCode) {
+ // VBR boot code found on NTFS, but volume is not actually bootable
+ // unless there are actual boot file, so check for them....
+ Volume->HasBootCode = HasWindowsBiosBootFiles(Volume);
+ }
+ } // if/else
- // get custom volume icons if present
- if (!Volume->VolIconImage)
- Volume->VolIconImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeIcon", 128);
+ // 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)
NextExtCurrent = ExtBase + EMbrTable[i].StartLBA;
break;
} else {
-
// found a logical partition
Volume = AllocateZeroPool(sizeof(REFIT_VOLUME));
Volume->DiskKind = WholeDiskVolume->DiskKind;
ScanVolumeBootcode(Volume, &Bootable);
if (!Bootable)
Volume->HasBootCode = FALSE;
-
SetVolumeBadgeIcon(Volume);
-
AddListElement((VOID ***) &Volumes, &VolumesCount, Volume);
-
- }
- }
- }
+ } // if/else
+ } // for
+ } // for
} /* VOID ScanExtendedPartition() */
VOID ScanVolumes(VOID)
UINTN SectorSum, i, VolNumber = 0;
UINT8 *SectorBuffer1, *SectorBuffer2;
EFI_GUID *UuidList;
- EFI_GUID NullUuid = { 00000000, 0000, 0000, {0000, 0000, 0000, 0000} };
+ EFI_GUID NullUuid = NULL_GUID_VALUE;
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...
}
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;
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];
+ }
}
}
MyFreePool(SectorBuffer1);
MyFreePool(SectorBuffer2);
}
-
} // for
} /* VOID ScanVolumes() */
-static VOID UninitVolumes(VOID)
-{
- REFIT_VOLUME *Volume;
- UINTN VolumeIndex;
-
- for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
- Volume = Volumes[VolumeIndex];
-
- if (Volume->RootDir != NULL) {
- refit_call1_wrapper(Volume->RootDir->Close, Volume->RootDir);
- Volume->RootDir = NULL;
- }
-
- Volume->DeviceHandle = NULL;
- Volume->BlockIO = NULL;
- Volume->WholeDiskBlockIO = NULL;
- }
-}
-
-VOID ReinitVolumes(VOID)
-{
- EFI_STATUS Status;
- REFIT_VOLUME *Volume;
- UINTN VolumeIndex;
- EFI_DEVICE_PATH *RemainingDevicePath;
- EFI_HANDLE DeviceHandle, WholeDiskHandle;
-
- for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
- Volume = Volumes[VolumeIndex];
-
- if (Volume->DevicePath != NULL) {
- // get the handle for that path
- RemainingDevicePath = Volume->DevicePath;
- Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &DeviceHandle);
-
- if (!EFI_ERROR(Status)) {
- Volume->DeviceHandle = DeviceHandle;
-
- // get the root directory
- Volume->RootDir = LibOpenRoot(Volume->DeviceHandle);
-
- } else
- CheckError(Status, L"from LocateDevicePath");
- }
-
- if (Volume->WholeDiskDevicePath != NULL) {
- // get the handle for that path
- RemainingDevicePath = Volume->WholeDiskDevicePath;
- Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle);
-
- if (!EFI_ERROR(Status)) {
- // get the BlockIO protocol
- Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol, (VOID **) &Volume->WholeDiskBlockIO);
- if (EFI_ERROR(Status)) {
- Volume->WholeDiskBlockIO = NULL;
- CheckError(Status, L"from HandleProtocol");
- }
- } else
- CheckError(Status, L"from LocateDevicePath");
- }
- }
-}
-
//
// file and dir functions
//
EFI_STATUS Status;
EFI_FILE_HANDLE TestFile;
- Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &TestFile, RelativePath, EFI_FILE_MODE_READ, 0);
- if (Status == EFI_SUCCESS) {
- refit_call1_wrapper(TestFile->Close, TestFile);
- return TRUE;
+ if (BaseDir != NULL) {
+ Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &TestFile, RelativePath, EFI_FILE_MODE_READ, 0);
+ if (Status == EFI_SUCCESS) {
+ refit_call1_wrapper(TestFile->Close, TestFile);
+ return TRUE;
+ }
}
return FALSE;
}
return FALSE; // Shouldn't happen
}
-static VOID StrLwr (IN OUT CHAR16 *Str) {
- if (!mUnicodeCollation) {
- InitializeUnicodeCollationProtocol();
- }
- if (mUnicodeCollation)
- mUnicodeCollation->StrLwr (mUnicodeCollation, Str);
-}
-
#endif
BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL,
// 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 * StripEfiExtension(IN CHAR16 *FileName) {
+ UINTN Length;
+ CHAR16 *Copy = NULL;
+
+ if ((FileName != NULL) && ((Copy = StrDuplicate(FileName)) != NULL)) {
+ Length = StrLen(Copy);
+ if ((Length >= 4) && MyStriCmp(&Copy[Length - 4], L".efi")) {
+ Copy[Length - 4] = 0;
+ } // if
+ } // if
+ return Copy;
} // CHAR16 * StripExtension()
//
return -1;
}
-// Performs a case-insensitive search of BigStr for SmallStr.
-// Returns TRUE if found, FALSE if not.
-BOOLEAN StriSubCmp(IN CHAR16 *SmallStr, IN CHAR16 *BigStr) {
- CHAR16 *SmallCopy, *BigCopy;
- BOOLEAN Found = FALSE;
- UINTN StartPoint = 0, NumCompares = 0, SmallLen = 0;
-
- if ((SmallStr != NULL) && (BigStr != NULL) && (StrLen(BigStr) >= StrLen(SmallStr))) {
- SmallCopy = StrDuplicate(SmallStr);
- BigCopy = StrDuplicate(BigStr);
- StrLwr(SmallCopy);
- StrLwr(BigCopy);
- SmallLen = StrLen(SmallCopy);
- NumCompares = StrLen(BigCopy) - SmallLen + 1;
- while ((!Found) && (StartPoint < NumCompares)) {
- Found = (StrnCmp(SmallCopy, &BigCopy[StartPoint++], SmallLen) == 0);
- } // while
- MyFreePool(SmallCopy);
- MyFreePool(BigCopy);
- } // if
-
- return (Found);
-} // BOOLEAN StriSubCmp()
-
-// 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 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
-// up the old memory. It should *NOT* be used with a constant
-// *First, though....
-VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar) {
- UINTN Length1 = 0, Length2 = 0;
- CHAR16* NewString;
-
- if (*First != NULL)
- Length1 = StrLen(*First);
- if (Second != NULL)
- 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);
- if (AddChar) {
- NewString[Length1] = AddChar;
- NewString[Length1 + 1] = '\0';
- } // if (AddChar)
- } // if (*First != NULL)
- if (Second != NULL)
- StrCat(NewString, Second);
- MyFreePool(*First);
- *First = NewString;
- } else {
- Print(L"Error! Unable to allocate memory in MergeStrings()!\n");
- } // if/else
-} // static CHAR16* MergeStrings()
-
// Takes an input pathname (*Path) and returns the part of the filename from
// the final dot onwards, converted to lowercase. If the filename includes
// no dots, or if the input is NULL, returns an empty (but allocated) string.
// The calling function is responsible for freeing the memory associated with
// the return value.
CHAR16 *FindExtension(IN CHAR16 *Path) {
- CHAR16 *Extension;
- BOOLEAN Found = FALSE, FoundSlash = FALSE;
- INTN i;
-
- Extension = AllocateZeroPool(sizeof(CHAR16));
- if (Path) {
- i = StrLen(Path);
- while ((!Found) && (!FoundSlash) && (i >= 0)) {
- if (Path[i] == L'.')
- Found = TRUE;
- else if ((Path[i] == L'/') || (Path[i] == L'\\'))
- FoundSlash = TRUE;
- if (!Found)
- i--;
- } // while
- if (Found) {
- MergeStrings(&Extension, &Path[i], 0);
- StrLwr(Extension);
- } // if (Found)
- } // if
- return (Extension);
-} // CHAR16 *FindExtension
+ CHAR16 *Extension;
+ BOOLEAN Found = FALSE, FoundSlash = FALSE;
+ INTN i;
+
+ Extension = AllocateZeroPool(sizeof(CHAR16));
+ if (Path) {
+ i = StrLen(Path);
+ while ((!Found) && (!FoundSlash) && (i >= 0)) {
+ if (Path[i] == L'.')
+ Found = TRUE;
+ else if ((Path[i] == L'/') || (Path[i] == L'\\'))
+ FoundSlash = TRUE;
+ if (!Found)
+ i--;
+ } // while
+ if (Found) {
+ MergeStrings(&Extension, &Path[i], 0);
+ ToLower(Extension);
+ } // if (Found)
+ } // if
+ return (Extension);
+} // CHAR16 *FindExtension()
// Takes an input pathname (*Path) and locates the final directory component
// of that name. For instance, if the input path is 'EFI\foo\bar.efi', this
// function returns the string 'foo'.
// Assumes the pathname is separated with backslashes.
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++) {
- if (Path[i] == '\\') {
- StartOfElement = EndOfElement;
- EndOfElement = i;
- } // if
- } // for
- // Extract the target element
- if (EndOfElement > 0) {
- while ((StartOfElement < PathLength) && (Path[StartOfElement] == '\\')) {
- StartOfElement++;
- } // while
- EndOfElement--;
- if (EndOfElement >= StartOfElement) {
- CopyLength = EndOfElement - StartOfElement + 1;
- Found = StrDuplicate(&Path[StartOfElement]);
- if (Found != NULL)
- Found[CopyLength] = 0;
- } // if (EndOfElement >= StartOfElement)
- } // if (EndOfElement > 0)
- return (Found);
-} // CHAR16 *FindLastDirName
+ 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++) {
+ if (Path[i] == '\\') {
+ StartOfElement = EndOfElement;
+ EndOfElement = i;
+ } // if
+ } // for
+ // Extract the target element
+ if (EndOfElement > 0) {
+ while ((StartOfElement < PathLength) && (Path[StartOfElement] == '\\')) {
+ StartOfElement++;
+ } // while
+ EndOfElement--;
+ if (EndOfElement >= StartOfElement) {
+ CopyLength = EndOfElement - StartOfElement + 1;
+ Found = StrDuplicate(&Path[StartOfElement]);
+ if (Found != NULL)
+ Found[CopyLength] = 0;
+ } // if (EndOfElement >= StartOfElement)
+ } // if (EndOfElement > 0)
+ return (Found);
+} // CHAR16 *FindLastDirName()
// Returns the directory portion of a pathname. For instance,
// if FullPath is 'EFI\foo\bar.efi', this function returns the
// 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
+ 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 (MyStriCmp(DeviceString, VolumeDeviceString)) {
+ Found = TRUE;
+ *DeviceVolume = Volumes[i];
+ }
+ MyFreePool(Temp);
+ MyFreePool(VolumeDeviceString);
+ i++;
+ } // while
- MyFreePool(DeviceString);
+ MyFreePool(DeviceString);
} // VOID FindVolumeAndFilename()
// Splits a volume/filename string (e.g., "fs0:\EFI\BOOT") into separate
// 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;
+ UINTN i = 0, Length;
+ CHAR16 *Filename;
- if (*Path == NULL)
- return FALSE;
+ if (*Path == NULL)
+ return FALSE;
- if (*VolName != NULL) {
- MyFreePool(*VolName);
- *VolName = NULL;
- }
+ 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()
+ Length = StrLen(*Path);
+ while ((i < Length) && ((*Path)[i] != L':')) {
+ i++;
+ } // while
-// 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,
-// the return value is NULL.
-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++) {
- if ((InString[i] >= '0') && (InString[i] <= '9')) {
- if (StartOfElement > i)
- StartOfElement = i;
- if (EndOfElement < i)
- EndOfElement = i;
- } // if
- } // for
- // Extract the target element
- if (EndOfElement > 0) {
- if (EndOfElement >= StartOfElement) {
- CopyLength = EndOfElement - StartOfElement + 1;
- Found = StrDuplicate(&InString[StartOfElement]);
- if (Found != NULL)
- Found[CopyLength] = 0;
- } // if (EndOfElement >= StartOfElement)
- } // if (EndOfElement > 0)
- return (Found);
-} // CHAR16 *FindNumbers()
-
-// Find the #Index element (numbered from 0) in a comma-delimited string
-// of elements.
-// Returns the found element, or NULL if Index is out of range or InString
-// is NULL. Note that the calling function is responsible for freeing the
-// memory associated with the returned string pointer.
-CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index) {
- UINTN StartPos = 0, CurPos = 0;
- BOOLEAN Found = FALSE;
- CHAR16 *FoundString = NULL;
-
- if (InString != NULL) {
- // After while() loop, StartPos marks start of item #Index
- while ((Index > 0) && (CurPos < StrLen(InString))) {
- if (InString[CurPos] == L',') {
- Index--;
- StartPos = CurPos + 1;
- } // if
- CurPos++;
- } // while
- // After while() loop, CurPos is one past the end of the element
- while ((CurPos < StrLen(InString)) && (!Found)) {
- if (InString[CurPos] == L',')
- Found = TRUE;
- else
- CurPos++;
- } // while
- if (Index == 0)
- FoundString = StrDuplicate(&InString[StartPos]);
- if (FoundString != NULL)
- FoundString[CurPos - StartPos] = 0;
- } // if
- 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()
+ if (i < Length) {
+ Filename = StrDuplicate((*Path) + i + 1);
+ (*Path)[i] = 0;
+ *VolName = *Path;
+ *Path = Filename;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+} // BOOLEAN SplitVolumeAndFilename()
// Take an input path name, which may include a volume specification and/or
// a path, and return separate volume, path, and file names. For instance,
// the returned pointer is NULL. The calling function is responsible for
// freeing the allocated memory.
VOID SplitPathName(CHAR16 *InPath, CHAR16 **VolName, CHAR16 **Path, CHAR16 **Filename) {
- CHAR16 *Temp = NULL;
-
- MyFreePool(*VolName);
- MyFreePool(*Path);
- MyFreePool(*Filename);
- *VolName = *Path = *Filename = NULL;
- Temp = StrDuplicate(InPath);
- SplitVolumeAndFilename(&Temp, VolName); // VolName is NULL or has volume; Temp has rest of path
- CleanUpPathNameSlashes(Temp);
- *Path = FindPath(Temp); // *Path has path (may be 0-length); Temp unchanged.
- *Filename = StrDuplicate(Temp + StrLen(*Path));
- CleanUpPathNameSlashes(*Filename);
- if (StrLen(*Path) == 0) {
- MyFreePool(*Path);
- *Path = NULL;
- }
- if (StrLen(*Filename) == 0) {
- MyFreePool(*Filename);
- *Filename = NULL;
- }
- MyFreePool(Temp);
-} // VOID SplitPathName
-
-// 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).
-BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List) {
- UINTN i = 0;
- BOOLEAN Found = FALSE;
- CHAR16 *OneElement;
-
- if (SmallString && List) {
- while (!Found && (OneElement = FindCommaDelimited(List, i++))) {
- if (StriCmp(OneElement, SmallString) == 0)
- Found = TRUE;
- } // while
- } // if
- return Found;
-} // BOOLEAN IsIn()
+ CHAR16 *Temp = NULL;
+
+ MyFreePool(*VolName);
+ MyFreePool(*Path);
+ MyFreePool(*Filename);
+ *VolName = *Path = *Filename = NULL;
+ Temp = StrDuplicate(InPath);
+ SplitVolumeAndFilename(&Temp, VolName); // VolName is NULL or has volume; Temp has rest of path
+ CleanUpPathNameSlashes(Temp);
+ *Path = FindPath(Temp); // *Path has path (may be 0-length); Temp unchanged.
+ *Filename = StrDuplicate(Temp + StrLen(*Path));
+ CleanUpPathNameSlashes(*Filename);
+ if (StrLen(*Path) == 0) {
+ MyFreePool(*Path);
+ *Path = NULL;
+ }
+ if (StrLen(*Filename) == 0) {
+ MyFreePool(*Filename);
+ *Filename = NULL;
+ }
+ MyFreePool(Temp);
+} // VOID SplitPathName()
// 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
// the Volume variable), but the List elements may. Performs comparison
-// case-insensitively (except on buggy EFIs with case-sensitive StriCmp()
-// functions).
+// case-insensitively.
BOOLEAN FilenameIn(REFIT_VOLUME *Volume, CHAR16 *Directory, CHAR16 *Filename, CHAR16 *List) {
- UINTN i = 0;
- BOOLEAN Found = FALSE;
- CHAR16 *OneElement;
- CHAR16 *TargetVolName = NULL, *TargetPath = NULL, *TargetFilename = NULL;
-
- if (Filename && List) {
- while (!Found && (OneElement = FindCommaDelimited(List, i++))) {
- Found = TRUE;
- SplitPathName(OneElement, &TargetVolName, &TargetPath, &TargetFilename);
- VolumeNumberToName(Volume, &TargetVolName);
- if (((TargetVolName != NULL) && ((Volume == NULL) || (StriCmp(TargetVolName, Volume->VolName) != 0))) ||
- ((TargetPath != NULL) && (StriCmp(TargetPath, Directory) != 0)) ||
- ((TargetFilename != NULL) && (StriCmp(TargetFilename, Filename) != 0))) {
- Found = FALSE;
- } // if
- MyFreePool(OneElement);
- } // while
- } // if
+ UINTN i = 0;
+ BOOLEAN Found = FALSE;
+ CHAR16 *OneElement;
+ CHAR16 *TargetVolName = NULL, *TargetPath = NULL, *TargetFilename = NULL;
+
+ if (Filename && List) {
+ while (!Found && (OneElement = FindCommaDelimited(List, i++))) {
+ Found = TRUE;
+ SplitPathName(OneElement, &TargetVolName, &TargetPath, &TargetFilename);
+ VolumeNumberToName(Volume, &TargetVolName);
+ if (((TargetVolName != NULL) && ((Volume == NULL) || (!MyStriCmp(TargetVolName, Volume->VolName)))) ||
+ ((TargetPath != NULL) && (!MyStriCmp(TargetPath, Directory))) ||
+ ((TargetFilename != NULL) && (!MyStriCmp(TargetFilename, Filename)))) {
+ Found = FALSE;
+ } // if
+ MyFreePool(OneElement);
+ } // while
+ } // if
- MyFreePool(TargetVolName);
- MyFreePool(TargetPath);
- MyFreePool(TargetFilename);
- return Found;
+ MyFreePool(TargetVolName);
+ MyFreePool(TargetPath);
+ MyFreePool(TargetFilename);
+ return Found;
} // BOOLEAN FilenameIn()
// If *VolName is of the form "fs#", where "#" is a number, and if Volume points
// 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 VOID *Pointer) {
- if (Pointer != NULL)
- FreePool(Pointer);
+ if (Pointer != NULL)
+ FreePool(Pointer);
}
static EFI_GUID AppleRemovableMediaGuid = APPLE_REMOVABLE_MEDIA_PROTOCOL_GUID;
// Eject all removable media.
// Returns TRUE if any media were ejected, FALSE otherwise.
BOOLEAN EjectMedia(VOID) {
- EFI_STATUS Status;
- UINTN HandleIndex, HandleCount = 0, Ejected = 0;
- EFI_HANDLE *Handles, Handle;
- APPLE_REMOVABLE_MEDIA_PROTOCOL *Ejectable;
-
- Status = LibLocateHandle(ByProtocol, &AppleRemovableMediaGuid, NULL, &HandleCount, &Handles);
- if (EFI_ERROR(Status) || HandleCount == 0)
- return (FALSE); // probably not an Apple system
-
- for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
- Handle = Handles[HandleIndex];
- Status = refit_call3_wrapper(BS->HandleProtocol, Handle, &AppleRemovableMediaGuid, (VOID **) &Ejectable);
- if (EFI_ERROR(Status))
- continue;
- Status = refit_call1_wrapper(Ejectable->Eject, Ejectable);
- if (!EFI_ERROR(Status))
- Ejected++;
- }
- MyFreePool(Handles);
- return (Ejected > 0);
+ EFI_STATUS Status;
+ UINTN HandleIndex, HandleCount = 0, Ejected = 0;
+ EFI_HANDLE *Handles, Handle;
+ APPLE_REMOVABLE_MEDIA_PROTOCOL *Ejectable;
+
+ Status = LibLocateHandle(ByProtocol, &AppleRemovableMediaGuid, NULL, &HandleCount, &Handles);
+ if (EFI_ERROR(Status) || HandleCount == 0)
+ return (FALSE); // probably not an Apple system
+
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ Handle = Handles[HandleIndex];
+ Status = refit_call3_wrapper(BS->HandleProtocol, Handle, &AppleRemovableMediaGuid, (VOID **) &Ejectable);
+ if (EFI_ERROR(Status))
+ continue;
+ Status = refit_call1_wrapper(Ejectable->Eject, Ejectable);
+ if (!EFI_ERROR(Status))
+ Ejected++;
+ }
+ MyFreePool(Handles);
+ return (Ejected > 0);
} // VOID EjectMedia()
+// Returns TRUE if the two GUIDs are equal, FALSE otherwise
+BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2) {
+ return (CompareMem(Guid1, Guid2, 16) == 0);
+} // BOOLEAN GuidsAreEqual()
-// 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;
+// Erase linked-list of UINT32 values....
+VOID EraseUint32List(UINT32_LIST **TheList) {
+ UINT32_LIST *NextItem;
- 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)
+ while (*TheList) {
+ NextItem = (*TheList)->Next;
+ FreePool(*TheList);
+ *TheList = NextItem;
+ } // while
+} // EraseUin32List()