// Maximum size for disk sectors
#define SECTOR_SIZE 4096
+// 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
static EFI_STATUS FinishInitRefitLib(VOID);
// self recognition stuff
//
+// Converts forward slashes to backslashes, removes duplicate slashes, and
+// removes slashes from both the start and end of the pathname.
+// Necessary because some (buggy?) EFI implementations produce "\/" strings
+// in pathnames, because some user inputs can produce duplicate directory
+// separators, and because we want consistent start and end slashes for
+// directory comparisons. A special case: If the PathName refers to root,
+// return "/", since some firmware implementations flake out if this
+// isn't present.
+VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) {
+ CHAR16 *NewName;
+ UINTN i, FinalChar = 0;
+ BOOLEAN LastWasSlash = FALSE;
+
+ NewName = AllocateZeroPool(sizeof(CHAR16) * (StrLen(PathName) + 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
+} // CleanUpPathNameSlashes()
+
EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle)
{
EFI_STATUS Status;
CHAR16 *DevicePathAsString;
- CHAR16 BaseDirectory[256];
- UINTN i;
-
+
SelfImageHandle = ImageHandle;
Status = refit_call3_wrapper(BS->HandleProtocol, SelfImageHandle, &LoadedImageProtocol, (VOID **) &SelfLoadedImage);
if (CheckFatalError(Status, L"while getting a LoadedImageProtocol handle"))
// find the current directory
DevicePathAsString = DevicePathToStr(SelfLoadedImage->FilePath);
- if (DevicePathAsString != NULL) {
- StrCpy(BaseDirectory, DevicePathAsString);
- FreePool(DevicePathAsString);
- for (i = StrLen(BaseDirectory); i > 0 && BaseDirectory[i] != '\\'; i--) ;
- BaseDirectory[i] = 0;
- } else
- BaseDirectory[0] = 0;
- SelfDirPath = StrDuplicate(BaseDirectory);
-
+ CleanUpPathNameSlashes(DevicePathAsString);
+ if (SelfDirPath != NULL)
+ FreePool(SelfDirPath);
+ SelfDirPath = FindPath(DevicePathAsString);
+ FreePool(DevicePathAsString);
+
return FinishInitRefitLib();
}
VOID UninitRefitLib(VOID)
{
UninitVolumes();
-
+
if (SelfDir != NULL) {
refit_call1_wrapper(SelfDir->Close, SelfDir);
SelfDir = NULL;
}
-
+
if (SelfRootDir != NULL) {
- refit_call1_wrapper(SelfRootDir->Close, SelfRootDir);
- SelfRootDir = NULL;
+ refit_call1_wrapper(SelfRootDir->Close, SelfRootDir);
+ SelfRootDir = NULL;
}
}
EFI_STATUS ReinitRefitLib(VOID)
{
ReinitVolumes();
-
- if (SelfVolume != NULL && SelfVolume->RootDir != NULL)
- SelfRootDir = SelfVolume->RootDir;
-
+
+ // Below two lines were in rEFIt, but seem to cause problems on
+ // most systems. OTOH, my Mac Mini produces (apparently harmless)
+ // errors about "(re)opening our installation volume" (see the
+ // next function) when returning from programs when these two lines
+ // are removed. On the gripping hand, the Mac SOMETIMES crashes
+ // when launching a second program even with these lines removed.
+ // TODO: Figure out cause of above weirdness and fix it more
+ // reliably!
+ /* if (SelfVolume != NULL && SelfVolume->RootDir != NULL)
+ SelfRootDir = SelfVolume->RootDir; */
+
return FinishInitRefitLib();
}
static EFI_STATUS FinishInitRefitLib(VOID)
-{
+{
EFI_STATUS Status;
if (SelfRootDir == NULL) {
}
if (Seen)
continue;
-
+
PathList[PathCount++] = AppendDevicePath(DevicePath, LegacyLoaderMediaPath);
}
FreePool(Handles);
-
+
if (HardcodedPathList) {
for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++)
PathList[PathCount++] = HardcodedPathList[HardcodedIndex];
UINTN i;
MBR_PARTITION_INFO *MbrTable;
BOOLEAN MbrTableFound;
-
+
Volume->HasBootCode = FALSE;
Volume->OSIconName = NULL;
Volume->OSName = NULL;
*Bootable = FALSE;
-
+
if (Volume->BlockIO == NULL)
return;
if (Volume->BlockIO->Media->BlockSize > SECTOR_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,
CopyMem(Volume->MbrPartitionTable, MbrTable, 4 * 16);
}
}
-
+
} else {
#if REFIT_DEBUG > 0
CheckError(Status, L"while reading boot sector");
UINTN PartialLength;
EFI_FILE_SYSTEM_INFO *FileSystemInfoPtr;
BOOLEAN Bootable;
-
+
// get device path
Volume->DevicePath = DuplicateDevicePath(DevicePathFromHandle(Volume->DeviceHandle));
#if REFIT_DEBUG > 0
#endif
}
#endif
-
+
Volume->DiskKind = DISK_KIND_INTERNAL; // default
-
+
// get block i/o
Status = refit_call3_wrapper(BS->HandleProtocol, Volume->DeviceHandle, &BlockIoProtocol, (VOID **) &(Volume->BlockIO));
if (EFI_ERROR(Status)) {
if (Volume->BlockIO->Media->BlockSize == 2048)
Volume->DiskKind = DISK_KIND_OPTICAL;
}
-
+
// scan for bootcode and MBR table
Bootable = FALSE;
ScanVolumeBootcode(Volume, &Bootable);
-
+
// detect device type
DevicePath = Volume->DevicePath;
while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) {
NextDevicePath = NextDevicePathNode(DevicePath);
-
+
if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH &&
(DevicePathSubType(DevicePath) == MSG_USB_DP ||
DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP ||
Volume->DiskKind = DISK_KIND_OPTICAL; // El Torito entry -> optical disk
Bootable = TRUE;
}
-
+
if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH && DevicePathSubType(DevicePath) == MEDIA_VENDOR_DP) {
Volume->IsAppleLegacy = TRUE; // legacy BIOS device entry
// TODO: also check for Boot Camp GUID
Bootable = FALSE; // this handle's BlockIO is just an alias for the whole device
}
-
+
if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH) {
// make a device path for the whole device
PartialLength = (UINT8 *)NextDevicePath - (UINT8 *)(Volume->DevicePath);
DiskDevicePath = (EFI_DEVICE_PATH *)AllocatePool(PartialLength + sizeof(EFI_DEVICE_PATH));
CopyMem(DiskDevicePath, Volume->DevicePath, PartialLength);
CopyMem((UINT8 *)DiskDevicePath + PartialLength, EndDevicePath, sizeof(EFI_DEVICE_PATH));
-
+
// get the handle for that path
RemainingDevicePath = DiskDevicePath;
//Print(L" * looking at %s\n", DevicePathToStr(RemainingDevicePath));
Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle);
//Print(L" * remaining: %s\n", DevicePathToStr(RemainingDevicePath));
FreePool(DiskDevicePath);
-
+
if (!EFI_ERROR(Status)) {
//Print(L" - original handle: %08x - disk handle: %08x\n", (UINT32)DeviceHandle, (UINT32)WholeDiskHandle);
-
+
// get the device path for later
Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &DevicePathProtocol, (VOID **) &DiskDevicePath);
if (!EFI_ERROR(Status)) {
Volume->WholeDiskDevicePath = DuplicateDevicePath(DiskDevicePath);
}
-
+
// look at the BlockIO protocol
Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol, (VOID **) &Volume->WholeDiskBlockIO);
if (!EFI_ERROR(Status)) {
-
+
// check the media block size
if (Volume->WholeDiskBlockIO->Media->BlockSize == 2048)
Volume->DiskKind = DISK_KIND_OPTICAL;
-
+
} else {
Volume->WholeDiskBlockIO = NULL;
//CheckError(Status, L"from HandleProtocol");
} //else
// CheckError(Status, L"from LocateDevicePath");
}
-
+
DevicePath = NextDevicePath;
} // while
-
+
if (!Bootable) {
#if REFIT_DEBUG > 0
if (Volume->HasBootCode)
#endif
Volume->HasBootCode = FALSE;
}
-
+
// default volume icon based on disk kind
ScanVolumeDefaultIcon(Volume);
-
+
// open the root directory of the volume
Volume->RootDir = LibOpenRoot(Volume->DeviceHandle);
if (Volume->RootDir == NULL) {
+ Volume->IsReadable = FALSE;
return;
+ } else {
+ Volume->IsReadable = TRUE;
}
-
+
// get volume name
FileSystemInfoPtr = LibFileSystemInfo(Volume->RootDir);
if (FileSystemInfoPtr != NULL) {
FreePool(FileSystemInfoPtr);
}
+ if (Volume->VolName == NULL) {
+ Volume->VolName = StrDuplicate(L"Unknown");
+ }
// TODO: if no official volume name is found or it is empty, use something else, e.g.:
// - name from bytes 3 to 10 of the boot sector
// - partition number
// - name derived from file system type or partition type
// get custom volume icon if present
- if (FileExists(Volume->RootDir, L".VolumeIcon.icns"))
- Volume->VolBadgeImage = LoadIcns(Volume->RootDir, L".VolumeIcon.icns", 32);
+ 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);
+ }
}
static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry)
UINT8 SectorBuffer[512];
BOOLEAN Bootable;
MBR_PARTITION_INFO *EMbrTable;
-
+
ExtBase = MbrEntry->StartLBA;
-
+
for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) {
// read current EMBR
Status = refit_call5_wrapper(WholeDiskVolume->BlockIO->ReadBlocks,
if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55)
break;
EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446);
-
+
// scan logical partitions in this EMBR
NextExtCurrent = 0;
for (i = 0; i < 4; i++) {
NextExtCurrent = ExtBase + EMbrTable[i].StartLBA;
break;
} else {
-
+
// found a logical partition
Volume = AllocateZeroPool(sizeof(REFIT_VOLUME));
Volume->DiskKind = WholeDiskVolume->DiskKind;
Volume->BlockIO = WholeDiskVolume->BlockIO;
Volume->BlockIOOffset = ExtCurrent + EMbrTable[i].StartLBA;
Volume->WholeDiskBlockIO = WholeDiskVolume->BlockIO;
-
+
Bootable = FALSE;
ScanVolumeBootcode(Volume, &Bootable);
if (!Bootable)
Volume->HasBootCode = FALSE;
-
+
ScanVolumeDefaultIcon(Volume);
-
+
AddListElement((VOID ***) &Volumes, &VolumesCount, Volume);
-
+
}
}
}
if (SelfVolume == NULL)
Print(L"WARNING: SelfVolume not found");
-
+
// second pass: relate partitions and whole disk devices
for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
Volume = Volumes[VolumeIndex];
// check size
if ((UINT64)(MbrTable[PartitionIndex].Size) != Volume->BlockIO->Media->LastBlock + 1)
continue;
-
+
// compare boot sector read through offset vs. directly
Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks,
Volume->BlockIO, Volume->BlockIO->Media->MediaId,
SectorSum += SectorBuffer1[i];
if (SectorSum < 1000)
continue;
-
+
// TODO: mark entry as non-bootable if it is an extended partition
-
+
// now we're reasonably sure the association is correct...
Volume->IsMbrPartition = TRUE;
Volume->MbrPartitionIndex = PartitionIndex;
Volume->VolName = PoolPrint(L"Partition %d", PartitionIndex + 1);
break;
}
-
+
FreePool(SectorBuffer1);
FreePool(SectorBuffer2);
}
-
+
}
} /* VOID ScanVolumes() */
{
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;
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;
VOID *Buffer;
UINTN LastBufferSize, BufferSize;
INTN IterCount;
-
+
for (;;) {
-
+
// free pointer from last call
if (*DirEntry != NULL) {
FreePool(*DirEntry);
*DirEntry = NULL;
}
-
+
// read next directory entry
LastBufferSize = BufferSize = 256;
Buffer = AllocatePool(BufferSize);
FreePool(Buffer);
break;
}
-
+
// check for end of listing
if (BufferSize == 0) { // end of directory listing
FreePool(Buffer);
break;
}
-
+
// entry is ready to be returned
*DirEntry = (EFI_FILE_INFO *)Buffer;
-
+
// filter results
if (FilterMode == 1) { // only return directories
if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY))
break;
} else // no filter or unknown filter -> return everything
break;
-
+
}
return Status;
}
FreePool(DirIter->LastFileInfo);
DirIter->LastFileInfo = NULL;
}
-
+
if (EFI_ERROR(DirIter->LastStatus))
return FALSE; // stop iteration
-
+
for (;;) {
DirIter->LastStatus = DirNextEntry(DirIter->DirHandle, &(DirIter->LastFileInfo), FilterMode);
if (EFI_ERROR(DirIter->LastStatus))
} else
break;
}
-
+
*DirEntry = DirIter->LastFileInfo;
return TRUE;
}
{
CHAR16 *FileName;
UINTN i;
-
+
FileName = Path;
-
+
if (Path != NULL) {
for (i = StrLen(Path); i > 0; i--) {
if (Path[i-1] == '\\' || Path[i-1] == '/') {
}
}
}
-
+
return FileName;
}
VOID ReplaceExtension(IN OUT CHAR16 *Path, IN CHAR16 *Extension)
{
UINTN i;
-
+
for (i = StrLen(Path); i >= 0; i--) {
if (Path[i] == '.') {
Path[i] = 0;
{
UINT8 *BufferPtr;
UINTN Offset;
-
+
BufferPtr = Buffer;
BufferLength -= SearchStringLength;
for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) {
if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0)
return (INTN)Offset;
}
-
+
return -1;
}
FreePool(SmallCopy);
FreePool(BigCopy);
} // if
-
+
return (Found);
} // BOOLEAN StriSubCmp()
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));
- NewString[0] = 0;
if (NewString != 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 (First != NULL)
+ } // if (*First != NULL)
+ if (Second != NULL)
StrCat(NewString, Second);
FreePool(*First);
*First = NewString;
CHAR16 *FindLastDirName(IN CHAR16 *Path) {
UINTN i, StartOfElement = 0, EndOfElement = 0, PathLength, CopyLength;
CHAR16 *Found = NULL;
-
+
PathLength = StrLen(Path);
// Find start & end of target element
for (i = 0; i < PathLength; i++) {
CHAR16 *FindNumbers(IN CHAR16 *InString) {
UINTN i, StartOfElement, EndOfElement = 0, InLength, CopyLength;
CHAR16 *Found = NULL;
-
+
InLength = StartOfElement = StrLen(InString);
// Find start & end of target element
for (i = 0; i < InLength; i++) {
// 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 of InString
+// Returns the found element, or NULL if Index is out of range or InString
// is NULL.
CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index) {
UINTN StartPos = 0, CurPos = 0;
else
CurPos++;
} // while
+ if (Index == 0)
+ FoundString = StrDuplicate(&InString[StartPos]);
+ if (FoundString != NULL)
+ FoundString[CurPos - StartPos] = 0;
} // if
- if (Index == 0)
- FoundString = StrDuplicate(&InString[StartPos]);
- if (FoundString != NULL)
- FoundString[CurPos - StartPos] = 0;
return (FoundString);
} // CHAR16 *FindCommaDelimited()