2019-09-03 11:58:42 +02:00
/*
* refit / scan / common . c
*
* Copyright ( c ) 2006 - 2010 Christoph Pfisterer
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are
* met :
*
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
*
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the
* distribution .
*
* * Neither the name of Christoph Pfisterer nor the names of the
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
* LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2020-08-17 21:40:52 +02:00
# include <Platform.h> // Only use angled for Platform, else, xcode project won't compile
2019-09-03 11:58:42 +02:00
# include "entry_scan.h"
2020-02-29 08:30:21 +01:00
# include "../refit/menu.h"
2020-04-16 09:15:26 +02:00
# include "../Platform/guid.h"
# include "../Platform/APFS.h"
# include "../Platform/cpu.h"
2020-08-09 17:55:30 +02:00
# include "../gui/REFIT_MENU_SCREEN.h"
2021-02-06 18:16:46 +01:00
# include "../include/OSTypes.h"
# include "../libeg/XTheme.h"
2019-09-03 11:58:42 +02:00
# ifndef DEBUG_ALL
# define DEBUG_COMMON_MENU 1
# else
# define DEBUG_COMMON_MENU DEBUG_ALL
# endif
# if DEBUG_COMMON_MENU == 0
# define DBG(...)
# else
# define DBG(...) DebugLog(DEBUG_COMMON_MENU, __VA_ARGS__)
# endif
2020-04-10 16:35:24 +02:00
extern CONST CHAR8 * IconsNames [ ] ;
2020-09-28 17:57:50 +02:00
const XIcon & ScanVolumeDefaultIcon ( REFIT_VOLUME * Volume , IN UINT8 OSType , const EFI_DEVICE_PATH_PROTOCOL * DevicePath )
2020-04-10 12:04:21 +02:00
2019-09-03 11:58:42 +02:00
{
UINTN IconNum = 0 ;
2020-05-16 21:30:29 +02:00
const XIcon * IconX ;
2019-09-03 11:58:42 +02:00
// default volume icon based on disk kind
switch ( Volume - > DiskKind ) {
case DISK_KIND_INTERNAL :
switch ( OSType ) {
case OSTYPE_OSX :
case OSTYPE_OSX_INSTALLER :
while ( ! IsDevicePathEndType ( DevicePath ) & &
! ( DevicePathType ( DevicePath ) = = MEDIA_DEVICE_PATH & & DevicePathSubType ( DevicePath ) = = MEDIA_VENDOR_DP ) ) {
DevicePath = NextDevicePathNode ( DevicePath ) ;
}
if ( DevicePathType ( DevicePath ) = = MEDIA_DEVICE_PATH & & DevicePathSubType ( DevicePath ) = = MEDIA_VENDOR_DP ) {
2021-04-11 07:18:52 +02:00
if ( GuidLEToXString8 ( * ( EFI_GUID * ) ( ( UINT8 * ) DevicePath + 0x04 ) ) . isEqualIC ( ApfsSignatureUUID ) ) {
2019-09-03 11:58:42 +02:00
IconNum = BUILTIN_ICON_VOL_INTERNAL_APFS ;
}
} else {
IconNum = BUILTIN_ICON_VOL_INTERNAL_HFS ;
}
break ;
case OSTYPE_RECOVERY :
IconNum = BUILTIN_ICON_VOL_INTERNAL_REC ;
break ;
case OSTYPE_LIN :
case OSTYPE_LINEFI :
IconNum = BUILTIN_ICON_VOL_INTERNAL_EXT3 ;
break ;
case OSTYPE_WIN :
case OSTYPE_WINEFI :
IconNum = BUILTIN_ICON_VOL_INTERNAL_NTFS ;
break ;
default :
IconNum = BUILTIN_ICON_VOL_INTERNAL ;
break ;
}
2020-03-30 10:34:16 +02:00
break ;
case DISK_KIND_EXTERNAL :
2020-04-06 17:40:45 +02:00
IconNum = BUILTIN_ICON_VOL_EXTERNAL ;
2020-03-30 10:34:16 +02:00
break ;
case DISK_KIND_OPTICAL :
2020-04-06 17:40:45 +02:00
IconNum = BUILTIN_ICON_VOL_OPTICAL ;
2020-03-30 10:34:16 +02:00
break ;
case DISK_KIND_FIREWIRE :
2020-04-06 17:40:45 +02:00
IconNum = BUILTIN_ICON_VOL_FIREWIRE ;
2020-03-30 10:34:16 +02:00
break ;
case DISK_KIND_BOOTER :
2020-04-06 17:40:45 +02:00
IconNum = BUILTIN_ICON_VOL_BOOTER ;
2020-03-30 10:34:16 +02:00
break ;
default :
2020-04-06 17:40:45 +02:00
IconNum = BUILTIN_ICON_VOL_INTERNAL ;
2020-04-05 20:56:36 +02:00
break ;
2020-03-30 10:34:16 +02:00
}
2020-04-10 16:35:24 +02:00
// DBG("asked IconNum = %llu Volume->DiskKind=%d OSType=%d\n", IconNum, Volume->DiskKind, OSType);
IconX = & ThemeX . GetIcon ( IconNum ) ; //asked IconNum = BUILTIN_ICON_VOL_INTERNAL_HFS, got day icon
2020-05-16 21:30:29 +02:00
if ( IconX - > Image . isEmpty ( ) ) {
2020-04-10 16:35:24 +02:00
DBG ( " asked Icon %s not found, took internal \n " , IconsNames [ IconNum ] ) ;
2020-04-06 17:40:45 +02:00
IconX = & ThemeX . GetIcon ( BUILTIN_ICON_VOL_INTERNAL ) ; //including embedded which is really present
}
2020-04-05 20:56:36 +02:00
return * IconX ;
2019-09-03 11:58:42 +02:00
}
# define TO_LOWER(ch) (((ch >= L'A') && (ch <= L'Z')) ? ((ch - L'A') + L'a') : ch)
2020-02-17 21:41:09 +01:00
INTN StrniCmp ( IN CONST CHAR16 * Str1 ,
IN CONST CHAR16 * Str2 ,
2019-09-03 11:58:42 +02:00
IN UINTN Count )
{
CHAR16 Ch1 , Ch2 ;
if ( Count = = 0 ) {
return 0 ;
}
if ( Str1 = = NULL ) {
if ( Str2 = = NULL ) {
return 0 ;
} else {
return - 1 ;
}
} else if ( Str2 = = NULL ) {
return 1 ;
}
do {
Ch1 = TO_LOWER ( * Str1 ) ;
Ch2 = TO_LOWER ( * Str2 ) ;
Str1 + + ;
Str2 + + ;
if ( Ch1 ! = Ch2 ) {
return ( Ch1 - Ch2 ) ;
}
if ( Ch1 = = 0 ) {
return 0 ;
}
} while ( - - Count > 0 ) ;
return 0 ;
}
2020-02-17 21:41:09 +01:00
CONST CHAR16 * StriStr ( IN CONST CHAR16 * Str ,
IN CONST CHAR16 * SearchFor )
2019-09-03 11:58:42 +02:00
{
2020-02-17 21:41:09 +01:00
CONST CHAR16 * End ;
2019-09-03 11:58:42 +02:00
UINTN Length ;
UINTN SearchLength ;
if ( ( Str = = NULL ) | | ( SearchFor = = NULL ) ) {
return NULL ;
}
Length = StrLen ( Str ) ;
if ( Length = = 0 ) {
return NULL ;
}
SearchLength = StrLen ( SearchFor ) ;
if ( SearchLength > Length ) {
return NULL ;
}
End = Str + ( Length - SearchLength ) + 1 ;
while ( Str < End ) {
if ( StrniCmp ( Str , SearchFor , SearchLength ) = = 0 ) {
return Str ;
}
+ + Str ;
}
return NULL ;
}
2020-10-03 19:02:31 +02:00
void StrToLower ( IN CHAR16 * Str )
2019-09-03 11:58:42 +02:00
{
while ( * Str ) {
* Str = TO_LOWER ( * Str ) ;
+ + Str ;
}
}
2020-02-28 21:28:33 +01:00
// TODO remove that and AlertMessage with a printf-like format
2020-04-10 12:04:21 +02:00
2020-03-21 20:52:28 +01:00
STATIC void CreateInfoLines ( IN CONST XStringW & Message , OUT XStringWArray * Information )
{
if ( Message . isEmpty ( ) ) {
return ;
}
2020-04-26 12:12:05 +02:00
Information - > setEmpty ( ) ;
2020-03-21 20:52:28 +01:00
//TODO will fill later
}
2020-04-10 12:04:21 +02:00
#if 0 //not needed?
2020-02-28 21:28:33 +01:00
STATIC void CreateInfoLines ( IN CONST CHAR16 * Message , OUT XStringWArray * Information )
2019-09-03 11:58:42 +02:00
{
2020-02-17 21:41:09 +01:00
CONST CHAR16 * Ptr ;
2020-02-28 21:28:33 +01:00
// CHAR16 **Information;
2019-09-03 11:58:42 +02:00
UINTN Index = 0 , Total = 0 ;
UINTN Length = ( ( Message = = NULL ) ? 0 : StrLen ( Message ) ) ;
// Check parameters
if ( Length = = 0 ) {
2020-02-28 21:28:33 +01:00
return ;
2019-09-03 11:58:42 +02:00
}
// Count how many new lines
Ptr = Message - 1 ;
while ( Ptr ! = NULL ) {
+ + Total ;
Ptr = StrStr ( + + Ptr , L " \n " ) ;
}
2020-02-28 21:28:33 +01:00
// // Create information
// Information = (CHAR16 **)AllocatePool((Total * sizeof(CHAR16 *)) + ((Length + 1) * sizeof(CHAR16)));
// if (Information == NULL) {
// return NULL;
// }
Information - > Empty ( ) ;
2019-09-03 11:58:42 +02:00
// Copy strings
2020-03-04 17:33:30 +01:00
CHAR16 * Ptr2 = NULL ; // VS2017 complains about uninitialized var.
2020-02-28 21:28:33 +01:00
// CHAR16* Ptr2 = Information[Index++] = (CHAR16 *)(Information + Total);
// StrCpyS(Ptr2, Length + 1, Message);
2019-09-03 11:58:42 +02:00
while ( ( Index < Total ) & &
2020-02-17 21:41:09 +01:00
( ( Ptr2 = ( CHAR16 * ) StrStr ( Ptr2 , L " \n " ) ) ! = NULL ) ) { // cast is ok because FilePath is not const, and we know that StrStr returns a pointer in FilePath. Will disappear when using a string object instead of CHAR16*
* Ptr2 + + = 0 ;
2020-03-10 17:50:55 +01:00
XStringW * s = new XStringW ;
s - > takeValueFrom ( Ptr2 ) ;
Information - > AddReference ( s , true ) ;
2020-02-28 21:28:33 +01:00
// Information[Index++] = Ptr2;
2019-09-03 11:58:42 +02:00
}
2020-02-28 21:28:33 +01:00
// // Return the info lines
// if (Count != NULL) {
// *Count = Total;
// }
// return Information;
2019-09-03 11:58:42 +02:00
}
2020-03-21 20:52:28 +01:00
# endif
2020-02-28 21:28:33 +01:00
extern REFIT_MENU_ITEM_RETURN MenuEntryReturn ;
2019-09-03 11:58:42 +02:00
2020-03-21 08:34:28 +01:00
// it is not good to use Options menu style for messages and one line dialogs
// it can be a semitransparent rectangular at the screen centre as it was in Clover v1.0
STATIC REFIT_MENU_SCREEN AlertMessageMenu ( 0 , XStringW ( ) , XStringW ( ) , & MenuEntryReturn , NULL ) ;
2021-02-11 12:41:59 +01:00
void AlertMessage ( const XStringW & Title , const XStringW & Message )
2020-03-21 08:34:28 +01:00
{
2020-03-21 20:52:28 +01:00
CreateInfoLines ( Message , & AlertMessageMenu . InfoLines ) ;
2020-03-21 08:34:28 +01:00
AlertMessageMenu . Title = Title ;
AlertMessageMenu . RunMenu ( NULL ) ;
2020-04-26 12:12:05 +02:00
AlertMessageMenu . InfoLines . setEmpty ( ) ;
2020-03-21 08:34:28 +01:00
}
2019-09-03 11:58:42 +02:00
# define TAG_YES 1
# define TAG_NO 2
2020-03-10 10:45:17 +01:00
//REFIT_SIMPLE_MENU_ENTRY_TAG(CONST CHAR16 *Title_, UINTN Tag_, ACTION AtClick_)
2020-03-21 20:52:28 +01:00
STATIC REFIT_SIMPLE_MENU_ENTRY_TAG YesMessageEntry ( XStringW ( ) . takeValueFrom ( L " Yes " ) , TAG_YES , ActionEnter ) ;
STATIC REFIT_SIMPLE_MENU_ENTRY_TAG NoMessageEntry ( XStringW ( ) . takeValueFrom ( L " No " ) , TAG_NO , ActionEnter ) ;
2020-03-10 10:45:17 +01:00
//REFIT_MENU_SCREEN(UINTN ID, CONST CHAR16* Title, CONST CHAR16* TimeoutText, REFIT_ABSTRACT_MENU_ENTRY* entry1, REFIT_ABSTRACT_MENU_ENTRY* entry2)
2020-03-21 08:34:28 +01:00
STATIC REFIT_MENU_SCREEN YesNoMessageMenu ( 0 , XStringW ( ) , XStringW ( ) , & YesMessageEntry , & NoMessageEntry ) ;
2019-09-03 11:58:42 +02:00
// Display a yes/no prompt
2021-09-28 10:28:45 +02:00
XBool YesNoMessage ( IN XStringW & Title , IN CONST XStringW & Message )
2020-03-21 20:52:28 +01:00
{
2021-09-28 15:54:31 +02:00
XBool Result = false ;
2020-03-21 20:52:28 +01:00
UINTN MenuExit ;
CreateInfoLines ( Message , & YesNoMessageMenu . InfoLines ) ;
YesNoMessageMenu . Title = Title ;
do
{
REFIT_ABSTRACT_MENU_ENTRY * ChosenEntry = NULL ;
MenuExit = YesNoMessageMenu . RunMenu ( & ChosenEntry ) ;
if ( ChosenEntry ! = NULL & & ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) & & ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) - > Tag = = TAG_YES & &
( ( MenuExit = = MENU_EXIT_ENTER ) | | ( MenuExit = = MENU_EXIT_DETAILS ) ) ) {
2021-09-28 10:28:45 +02:00
Result = true ;
2020-03-21 20:52:28 +01:00
MenuExit = MENU_EXIT_ENTER ;
}
} while ( MenuExit ! = MENU_EXIT_ENTER ) ;
2020-04-26 12:12:05 +02:00
YesNoMessageMenu . InfoLines . setEmpty ( ) ;
2020-03-21 20:52:28 +01:00
return Result ;
}
2019-09-03 11:58:42 +02:00
// Ask user for file path from directory menu
2021-09-28 10:28:45 +02:00
XBool AskUserForFilePathFromDir ( const CHAR16 * Title OPTIONAL , IN REFIT_VOLUME * Volume ,
2021-04-08 17:07:05 +02:00
const CHAR16 * ParentPath OPTIONAL , const EFI_FILE * Dir ,
2019-09-03 11:58:42 +02:00
OUT EFI_DEVICE_PATH_PROTOCOL * * Result )
{
//REFIT_MENU_SCREEN Menu = { 0, L"Please Select File...", NULL, 0, NULL, 0, NULL,
2021-09-28 10:28:45 +02:00
// 0, NULL, false, false, 0, 0, 0, 0, { 0, 0, 0, 0 }, NULL};
2019-09-03 11:58:42 +02:00
// Check parameters
if ( ( Volume = = NULL ) | | ( Dir = = NULL ) | | ( Result = = NULL ) ) {
2021-09-28 10:28:45 +02:00
return false ;
2019-09-03 11:58:42 +02:00
}
// TODO: Generate directory menu
2021-09-28 10:28:45 +02:00
return false ;
2019-09-03 11:58:42 +02:00
}
# define TAG_OFFSET 1000
2020-03-04 16:27:41 +01:00
//STATIC REFIT_MENU_SCREEN InitialMenu = {0, L"Please Select File...", NULL, 0, NULL,
2021-09-28 10:28:45 +02:00
// 0, NULL, NULL, false, false, 0, 0, 0, 0,
2020-03-04 16:27:41 +01:00
// { 0, 0, 0, 0 }, NULL};
2020-08-11 14:43:53 +02:00
//STATIC REFIT_MENU_SCREEN InitialMenu(0, L"Please Select File..."_XSW, XStringW());
2019-09-03 11:58:42 +02:00
// Ask user for file path from volumes menu
2021-09-28 10:28:45 +02:00
XBool AskUserForFilePathFromVolumes ( const CHAR16 * Title OPTIONAL , OUT EFI_DEVICE_PATH_PROTOCOL * * Result )
2019-09-03 11:58:42 +02:00
{
2020-08-11 14:43:53 +02:00
REFIT_MENU_SCREEN Menu ( 0 , L " Please Select File... " _XSW , XStringW ( ) ) ;
2020-02-28 21:28:33 +01:00
UINTN Index = 0 , /*Count = 0,*/ MenuExit ;
2021-09-28 15:54:31 +02:00
XBool Responded = false ;
2019-09-03 11:58:42 +02:00
if ( Result = = NULL ) {
2021-09-28 10:28:45 +02:00
return false ;
2019-09-03 11:58:42 +02:00
}
// Create volume entries
2020-02-27 15:34:29 +01:00
for ( Index = 0 ; Index < Volumes . size ( ) ; + + Index ) {
REFIT_VOLUME * Volume = & Volumes [ Index ] ;
2019-09-03 11:58:42 +02:00
if ( ( Volume = = NULL ) | | ( Volume - > RootDir = = NULL ) | |
2020-08-09 17:55:30 +02:00
( ( Volume - > DevicePathString . isEmpty ( ) ) & & ( Volume - > VolName . isEmpty ( ) ) ) ) {
2019-09-03 11:58:42 +02:00
continue ;
}
2020-08-09 17:55:30 +02:00
REFIT_SIMPLE_MENU_ENTRY_TAG * Entry = new REFIT_SIMPLE_MENU_ENTRY_TAG ( SWPrintf ( " %ls " , ( Volume - > VolName . isEmpty ( ) ) ? Volume - > DevicePathString . wc_str ( ) : Volume - > VolName . wc_str ( ) ) , TAG_OFFSET + Index , MENU_EXIT_ENTER ) ;
2020-02-28 21:28:33 +01:00
Menu . Entries . AddReference ( Entry , true ) ;
2019-09-03 11:58:42 +02:00
}
// Setup menu
2020-02-28 21:28:33 +01:00
Menu . Entries . AddReference ( & MenuEntryReturn , false ) ;
2020-03-21 20:52:28 +01:00
Menu . Title . takeValueFrom ( Title ) ;
2020-04-10 12:04:21 +02:00
2019-09-03 11:58:42 +02:00
do
{
2020-02-28 21:28:33 +01:00
REFIT_ABSTRACT_MENU_ENTRY * ChosenEntry = NULL ;
2019-09-03 11:58:42 +02:00
// Run the volume chooser menu
2020-03-03 21:44:07 +01:00
MenuExit = Menu . RunMenu ( & ChosenEntry ) ;
2020-02-28 21:28:33 +01:00
if ( ( ChosenEntry ! = NULL ) & & ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) & &
2019-09-03 11:58:42 +02:00
( ( MenuExit = = MENU_EXIT_ENTER ) | | ( MenuExit = = MENU_EXIT_DETAILS ) ) ) {
2020-02-28 21:28:33 +01:00
if ( ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) - > Tag > = TAG_OFFSET ) {
Index = ( ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) - > Tag - TAG_OFFSET ) ;
2020-02-27 15:34:29 +01:00
if ( Index < Volumes . size ( ) ) {
2019-09-03 11:58:42 +02:00
// Run directory chooser menu
2020-02-27 15:34:29 +01:00
if ( ! AskUserForFilePathFromDir ( Title , & Volumes [ Index ] , NULL , Volumes [ Index ] . RootDir , Result ) ) {
2019-09-03 11:58:42 +02:00
continue ;
}
2021-09-28 10:28:45 +02:00
Responded = true ;
2019-09-03 11:58:42 +02:00
}
}
break ;
}
} while ( MenuExit ! = MENU_EXIT_ESCAPE ) ;
2020-02-28 21:28:33 +01:00
// FreePool(Entries);
2019-09-03 11:58:42 +02:00
return Responded ;
}
// Ask user for file path
2021-09-28 10:28:45 +02:00
XBool AskUserForFilePath ( IN CHAR16 * Title OPTIONAL , IN EFI_DEVICE_PATH_PROTOCOL * Root OPTIONAL , OUT EFI_DEVICE_PATH_PROTOCOL * * Result )
2019-09-03 11:58:42 +02:00
{
EFI_FILE * Dir = NULL ;
if ( Result = = NULL ) {
2021-09-28 10:28:45 +02:00
return false ;
2019-09-03 11:58:42 +02:00
}
if ( Root ! = NULL ) {
// Get the file path
2020-08-09 17:55:30 +02:00
XStringW DevicePathStr = FileDevicePathToXStringW ( Root ) ;
if ( DevicePathStr . notEmpty ( ) ) {
2019-09-03 11:58:42 +02:00
UINTN Index = 0 ;
// Check the volumes for a match
2020-02-27 15:34:29 +01:00
for ( Index = 0 ; Index < Volumes . size ( ) ; + + Index ) {
REFIT_VOLUME * Volume = & Volumes [ Index ] ;
2019-09-03 11:58:42 +02:00
if ( ( Volume = = NULL ) | | ( Volume - > RootDir = = NULL ) | |
2020-08-09 17:55:30 +02:00
( Volume - > DevicePathString . isEmpty ( ) ) ) {
2019-09-03 11:58:42 +02:00
continue ;
}
2020-08-09 17:55:30 +02:00
if ( Volume - > DevicePathString . length ( ) = = 0 ) {
2019-09-03 11:58:42 +02:00
continue ;
}
// If the path begins with this volumes path it matches
2020-08-09 17:55:30 +02:00
if ( StrniCmp ( DevicePathStr . wc_str ( ) , Volume - > DevicePathString . wc_str ( ) , Volume - > DevicePathString . length ( ) ) ) {
2019-09-03 11:58:42 +02:00
// Need to
2021-04-08 17:07:05 +02:00
const CHAR16 * FilePath = DevicePathStr . data ( Volume - > DevicePathString . length ( ) ) ;
2019-09-03 11:58:42 +02:00
UINTN FileLength = StrLen ( FilePath ) ;
if ( FileLength = = 0 ) {
// If there is no path left then open the root
return AskUserForFilePathFromDir ( Title , Volume , NULL , Volume - > RootDir , Result ) ;
} else {
// Check to make sure this is directory
if ( ! EFI_ERROR ( Volume - > RootDir - > Open ( Volume - > RootDir , & Dir , FilePath , EFI_FILE_MODE_READ , 0 ) ) & &
( Dir ! = NULL ) ) {
// Get file information
EFI_FILE_INFO * Info = EfiLibFileInfo ( Dir ) ;
if ( Info ! = NULL ) {
// Check if the file is a directory
if ( ( Info - > Attribute & EFI_FILE_DIRECTORY ) = = 0 ) {
// Return the passed device path if it is a file
FreePool ( Info ) ;
Dir - > Close ( Dir ) ;
* Result = Root ;
2021-09-28 10:28:45 +02:00
return true ;
2019-09-03 11:58:42 +02:00
} else {
// Ask user other wise
2021-09-28 10:28:45 +02:00
XBool Success = AskUserForFilePathFromDir ( Title , Volume , FilePath , Dir , Result ) ;
2019-09-03 11:58:42 +02:00
FreePool ( Info ) ;
Dir - > Close ( Dir ) ;
return Success ;
}
//FreePool(Info);
}
Dir - > Close ( Dir ) ;
}
}
}
}
}
}
return AskUserForFilePathFromVolumes ( Title , Result ) ;
}
2020-04-16 09:15:26 +02:00
// input - tsc
// output - milliseconds
// the caller is responsible for t1 > t0
UINT64 TimeDiff ( UINT64 t0 , UINT64 t1 )
{
return DivU64x64Remainder ( ( t1 - t0 ) , DivU64x32 ( gCPUStructure . TSCFrequency , 1000 ) , 0 ) ;
}