2 File explorer related functions.
4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License that accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "FileExplorer.h"
18 EFI_GUID FileExplorerGuid
= EFI_FILE_EXPLORE_FORMSET_GUID
;
21 /// File system selection menu
23 MENU_OPTION mFsOptionMenu
= {
24 MENU_OPTION_SIGNATURE
,
30 FILE_EXPLORER_CALLBACK_DATA gFileExplorerPrivate
= {
31 FILE_EXPLORER_CALLBACK_DATA_SIGNATURE
,
44 HII_VENDOR_DEVICE_PATH
*gHiiVendorDevicePath
;
46 HII_VENDOR_DEVICE_PATH FeHiiVendorDevicePath
= {
52 (UINT8
) (sizeof (VENDOR_DEVICE_PATH
)),
53 (UINT8
) ((sizeof (VENDOR_DEVICE_PATH
)) >> 8)
57 // Will be replace with gEfiCallerIdGuid in code.
59 { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }
63 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
65 (UINT8
) (END_DEVICE_PATH_LENGTH
),
66 (UINT8
) ((END_DEVICE_PATH_LENGTH
) >> 8)
71 VOID
*mLibStartOpCodeHandle
= NULL
;
72 VOID
*mLibEndOpCodeHandle
= NULL
;
73 EFI_IFR_GUID_LABEL
*mLibStartLabel
= NULL
;
74 EFI_IFR_GUID_LABEL
*mLibEndLabel
= NULL
;
77 This function allows a caller to extract the current configuration for one
78 or more named elements from the target driver.
81 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
82 @param Request A null-terminated Unicode string in <ConfigRequest> format.
83 @param Progress On return, points to a character in the Request string.
84 Points to the string's null terminator if request was successful.
85 Points to the most recent '&' before the first failing name/value
86 pair (or the beginning of the string if the failure is in the
87 first name/value pair) if the request was not successful.
88 @param Results A null-terminated Unicode string in <ConfigAltResp> format which
89 has all values filled in for the names in the Request string.
90 String to be allocated by the called function.
92 @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
93 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
99 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
100 IN CONST EFI_STRING Request
,
101 OUT EFI_STRING
*Progress
,
102 OUT EFI_STRING
*Results
105 if (Progress
== NULL
|| Results
== NULL
) {
106 return EFI_INVALID_PARAMETER
;
110 return EFI_NOT_FOUND
;
114 This function processes the results of changes in configuration.
117 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
118 @param Configuration A null-terminated Unicode string in <ConfigResp> format.
119 @param Progress A pointer to a string filled in with the offset of the most
120 recent '&' before the first failing name/value pair (or the
121 beginning of the string if the failure is in the first
122 name/value pair) or the terminating NULL if all was successful.
124 @retval EFI_INVALID_PARAMETER Configuration is NULL.
125 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
131 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
132 IN CONST EFI_STRING Configuration
,
133 OUT EFI_STRING
*Progress
136 if (Configuration
== NULL
|| Progress
== NULL
) {
137 return EFI_INVALID_PARAMETER
;
140 *Progress
= Configuration
;
141 return EFI_NOT_FOUND
;
145 This function processes the results of changes in configuration.
146 When user select a interactive opcode, this callback will be triggered.
147 Based on the Question(QuestionId) that triggers the callback, the corresponding
148 actions is performed. It handles:
150 1) Process the axtra action or exit file explorer when user select one file .
151 2) update of file content if a dir is selected.
153 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
154 @param Action Specifies the type of action taken by the browser.
155 @param QuestionId A unique value which is sent to the original exporting driver
156 so that it can identify the type of data to expect.
157 @param Type The type of value for the question.
158 @param Value A pointer to the data being sent to the original exporting driver.
159 @param ActionRequest On return, points to the action requested by the callback function.
161 @retval EFI_SUCCESS The callback successfully handled the action.
162 @retval other error Error occur when parse one directory.
167 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
168 IN EFI_BROWSER_ACTION Action
,
169 IN EFI_QUESTION_ID QuestionId
,
171 IN EFI_IFR_TYPE_VALUE
*Value
,
172 OUT EFI_BROWSER_ACTION_REQUEST
*ActionRequest
180 if (Action
!= EFI_BROWSER_ACTION_CHANGING
&& Action
!= EFI_BROWSER_ACTION_CHANGED
) {
182 // Do nothing for other UEFI Action. Only do call back when data is changed.
184 return EFI_UNSUPPORTED
;
187 if (Action
== EFI_BROWSER_ACTION_CHANGED
) {
188 if ((Value
== NULL
) || (ActionRequest
== NULL
)) {
189 return EFI_INVALID_PARAMETER
;
192 if (QuestionId
>= FILE_OPTION_OFFSET
) {
193 LibGetDevicePath(QuestionId
);
196 // Process the extra action.
198 if (gFileExplorerPrivate
.ChooseHandler
!= NULL
) {
199 NeedExit
= gFileExplorerPrivate
.ChooseHandler (gFileExplorerPrivate
.RetDevicePath
);
203 *ActionRequest
= EFI_BROWSER_ACTION_REQUEST_EXIT
;
206 } else if (Action
== EFI_BROWSER_ACTION_CHANGING
) {
208 return EFI_INVALID_PARAMETER
;
211 if (QuestionId
>= FILE_OPTION_OFFSET
) {
212 Status
= LibUpdateFileExplorer (QuestionId
);
213 if (EFI_ERROR (Status
)) {
223 Create a menu entry by given menu type.
225 @retval NULL If failed to create the menu.
226 @return the new menu entry.
234 MENU_ENTRY
*MenuEntry
;
237 // Create new menu entry
239 MenuEntry
= AllocateZeroPool (sizeof (MENU_ENTRY
));
240 if (MenuEntry
== NULL
) {
244 MenuEntry
->VariableContext
= AllocateZeroPool (sizeof (FILE_CONTEXT
));
245 if (MenuEntry
->VariableContext
== NULL
) {
246 FreePool (MenuEntry
);
250 MenuEntry
->Signature
= MENU_ENTRY_SIGNATURE
;
256 Get the Menu Entry from the list in Menu Entry List.
258 If MenuNumber is great or equal to the number of Menu
259 Entry in the list, then ASSERT.
261 @param MenuOption The Menu Entry List to read the menu entry.
262 @param MenuNumber The index of Menu Entry.
264 @return The Menu Entry.
269 MENU_OPTION
*MenuOption
,
273 MENU_ENTRY
*NewMenuEntry
;
277 ASSERT (MenuNumber
< MenuOption
->MenuNumber
);
279 List
= MenuOption
->Head
.ForwardLink
;
280 for (Index
= 0; Index
< MenuNumber
; Index
++) {
281 List
= List
->ForwardLink
;
284 NewMenuEntry
= CR (List
, MENU_ENTRY
, Link
, MENU_ENTRY_SIGNATURE
);
290 Free up all resource allocated for a BM_MENU_ENTRY.
292 @param MenuEntry A pointer to BM_MENU_ENTRY.
296 LibDestroyMenuEntry (
297 MENU_ENTRY
*MenuEntry
300 FILE_CONTEXT
*FileContext
;
302 FileContext
= (FILE_CONTEXT
*) MenuEntry
->VariableContext
;
304 if (!FileContext
->IsRoot
) {
305 if (FileContext
->DevicePath
!= NULL
) {
306 FreePool (FileContext
->DevicePath
);
309 if (FileContext
->FileHandle
!= NULL
) {
310 FileContext
->FileHandle
->Close (FileContext
->FileHandle
);
314 if (FileContext
->FileName
!= NULL
) {
315 FreePool (FileContext
->FileName
);
318 FreePool (FileContext
);
320 if (MenuEntry
->DisplayString
!= NULL
) {
321 FreePool (MenuEntry
->DisplayString
);
323 if (MenuEntry
->HelpString
!= NULL
) {
324 FreePool (MenuEntry
->HelpString
);
327 FreePool (MenuEntry
);
332 Free resources allocated in Allocate Rountine.
334 @param FreeMenu Menu to be freed
338 MENU_OPTION
*FreeMenu
341 MENU_ENTRY
*MenuEntry
;
342 while (!IsListEmpty (&FreeMenu
->Head
)) {
344 FreeMenu
->Head
.ForwardLink
,
349 RemoveEntryList (&MenuEntry
->Link
);
350 LibDestroyMenuEntry (MenuEntry
);
352 FreeMenu
->MenuNumber
= 0;
357 Function opens and returns a file handle to the root directory of a volume.
359 @param DeviceHandle A handle for a device
361 @return A valid file handle or NULL is returned
366 IN EFI_HANDLE DeviceHandle
370 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Volume
;
371 EFI_FILE_HANDLE File
;
376 // File the file system interface to the device
378 Status
= gBS
->HandleProtocol (
380 &gEfiSimpleFileSystemProtocolGuid
,
385 // Open the root directory of the volume
387 if (!EFI_ERROR (Status
)) {
388 Status
= Volume
->OpenVolume (
396 return EFI_ERROR (Status
) ? NULL
: File
;
400 This function converts an input device structure to a Unicode string.
402 @param DevPath A pointer to the device path structure.
404 @return A new allocated Unicode string that represents the device path.
409 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
414 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
*DevPathToText
;
416 if (DevPath
== NULL
) {
420 Status
= gBS
->LocateProtocol (
421 &gEfiDevicePathToTextProtocolGuid
,
423 (VOID
**) &DevPathToText
425 ASSERT_EFI_ERROR (Status
);
426 ToText
= DevPathToText
->ConvertDevicePathToText (
431 ASSERT (ToText
!= NULL
);
439 @param Src The source.
441 @return A new string which is duplicated copy of the source.
442 @retval NULL If there is not enough memory.
453 Size
= StrSize (Src
);
454 Dest
= AllocateZeroPool (Size
);
455 ASSERT (Dest
!= NULL
);
457 CopyMem (Dest
, Src
, Size
);
465 Function gets the file information from an open file descriptor, and stores it
466 in a buffer allocated from pool.
468 @param FHand File Handle.
469 @param InfoType Info type need to get.
471 @retval A pointer to a buffer with file information or NULL is returned
476 IN EFI_FILE_HANDLE FHand
,
477 IN EFI_GUID
*InfoType
481 EFI_FILE_INFO
*Buffer
;
487 Status
= FHand
->GetInfo (
493 if (Status
== EFI_BUFFER_TOO_SMALL
) {
494 Buffer
= AllocatePool (BufferSize
);
495 ASSERT (Buffer
!= NULL
);
498 Status
= FHand
->GetInfo (
510 Get file type base on the file name.
511 Just cut the file name, from the ".". eg ".efi"
513 @param FileName File need to be checked.
515 @retval the file type string.
525 Index
= StrLen (FileName
) - 1;
526 while ((FileName
[Index
] != L
'.') && (Index
!= 0)) {
530 return Index
== 0 ? NULL
: &FileName
[Index
];
534 Converts the unicode character of the string from uppercase to lowercase.
535 This is a internal function.
537 @param ConfigString String to be converted
547 for (TmpStr
= String
; *TmpStr
!= L
'\0'; TmpStr
++) {
548 if (*TmpStr
>= L
'A' && *TmpStr
<= L
'Z') {
549 *TmpStr
= (CHAR16
) (*TmpStr
- L
'A' + L
'a');
556 Check whether current FileName point to a valid
559 @param FileName File need to be checked.
561 @retval TRUE Is Efi Image
562 @retval FALSE Not a valid Efi Image
566 LibIsSupportedFileType (
570 CHAR16
*InputFileType
;
574 if (gFileExplorerPrivate
.FileType
== NULL
) {
578 InputFileType
= LibGetTypeFromName (FileName
);
580 // If the file not has *.* style, always return TRUE.
582 if (InputFileType
== NULL
) {
586 TmpStr
= AllocateCopyPool (StrSize (InputFileType
), InputFileType
);
587 ASSERT(TmpStr
!= NULL
);
588 LibToLowerString(TmpStr
);
590 IsSupported
= (StrStr (gFileExplorerPrivate
.FileType
, TmpStr
) == NULL
? FALSE
: TRUE
);
598 Append file name to existing file name.
600 @param Str1 The existing file name
601 @param Str2 The file name to be appended
603 @return Allocate a new string to hold the appended result.
604 Caller is responsible to free the returned string.
621 Size1
= StrSize (Str1
);
622 Size2
= StrSize (Str2
);
623 MaxLen
= (Size1
+ Size2
+ sizeof (CHAR16
))/ sizeof (CHAR16
);
624 Str
= AllocateZeroPool (Size1
+ Size2
+ sizeof (CHAR16
));
625 ASSERT (Str
!= NULL
);
627 TmpStr
= AllocateZeroPool (Size1
+ Size2
+ sizeof (CHAR16
));
628 ASSERT (TmpStr
!= NULL
);
630 StrCpyS (Str
, MaxLen
, Str1
);
631 if (!((*Str
== '\\') && (*(Str
+ 1) == 0))) {
632 StrCatS (Str
, MaxLen
, L
"\\");
635 StrCatS (Str
, MaxLen
, Str2
);
640 if (*Ptr
== '\\' && *(Ptr
+ 1) == '.' && *(Ptr
+ 2) == '.' && *(Ptr
+ 3) == L
'\\') {
642 // Convert "\Name\..\" to "\"
643 // DO NOT convert the .. if it is at the end of the string. This will
644 // break the .. behavior in changing directories.
648 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
651 StrCpyS (TmpStr
, MaxLen
, Ptr
+ 3);
652 StrCpyS (LastSlash
, MaxLen
- (UINTN
) (LastSlash
- Str
), TmpStr
);
654 } else if (*Ptr
== '\\' && *(Ptr
+ 1) == '.' && *(Ptr
+ 2) == '\\') {
656 // Convert a "\.\" to a "\"
660 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
663 StrCpyS (TmpStr
, MaxLen
, Ptr
+ 2);
664 StrCpyS (Ptr
, MaxLen
- (UINTN
) (Ptr
- Str
), TmpStr
);
666 } else if (*Ptr
== '\\') {
679 This function build the FsOptionMenu list which records all
680 available file system in the system. They includes all instances
681 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM.
684 @retval EFI_SUCCESS Success find the file system
685 @retval EFI_OUT_OF_RESOURCES Can not create menu entry
693 UINTN NoSimpleFsHandles
;
694 UINTN NoLoadFileHandles
;
695 EFI_HANDLE
*SimpleFsHandle
;
696 EFI_HANDLE
*LoadFileHandle
;
700 MENU_ENTRY
*MenuEntry
;
701 FILE_CONTEXT
*FileContext
;
703 EFI_FILE_SYSTEM_VOLUME_LABEL
*Info
;
705 NoSimpleFsHandles
= 0;
706 NoLoadFileHandles
= 0;
710 // Locate Handles that support Simple File System protocol
712 Status
= gBS
->LocateHandleBuffer (
714 &gEfiSimpleFileSystemProtocolGuid
,
719 if (!EFI_ERROR (Status
)) {
721 // Find all the instances of the File System prototocol
723 for (Index
= 0; Index
< NoSimpleFsHandles
; Index
++) {
725 // Allocate pool for this load option
727 MenuEntry
= LibCreateMenuEntry ();
728 if (NULL
== MenuEntry
) {
729 FreePool (SimpleFsHandle
);
730 return EFI_OUT_OF_RESOURCES
;
733 FileContext
= (FILE_CONTEXT
*) MenuEntry
->VariableContext
;
734 FileContext
->DeviceHandle
= SimpleFsHandle
[Index
];
735 FileContext
->FileHandle
= LibOpenRoot (FileContext
->DeviceHandle
);
736 if (FileContext
->FileHandle
== NULL
) {
737 LibDestroyMenuEntry (MenuEntry
);
741 MenuEntry
->HelpString
= LibDevicePathToStr (DevicePathFromHandle (FileContext
->DeviceHandle
));
742 FileContext
->FileName
= LibStrDuplicate (L
"\\");
743 FileContext
->DevicePath
= FileDevicePath (FileContext
->DeviceHandle
, FileContext
->FileName
);
744 FileContext
->IsDir
= TRUE
;
745 FileContext
->IsRoot
= TRUE
;
748 // Get current file system's Volume Label
750 Info
= (EFI_FILE_SYSTEM_VOLUME_LABEL
*) LibFileInfo (FileContext
->FileHandle
, &gEfiFileSystemVolumeLabelInfoIdGuid
);
752 VolumeLabel
= L
"NO FILE SYSTEM INFO";
754 if (Info
->VolumeLabel
== NULL
) {
755 VolumeLabel
= L
"NULL VOLUME LABEL";
757 VolumeLabel
= Info
->VolumeLabel
;
758 if (*VolumeLabel
== 0x0000) {
759 VolumeLabel
= L
"NO VOLUME LABEL";
763 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
764 ASSERT (MenuEntry
->DisplayString
!= NULL
);
766 MenuEntry
->DisplayString
,
770 MenuEntry
->HelpString
772 MenuEntry
->DisplayStringToken
= HiiSetString (
773 gFileExplorerPrivate
.FeHiiHandle
,
775 MenuEntry
->DisplayString
,
781 InsertTailList (&gFileExplorerPrivate
.FsOptionMenu
->Head
, &MenuEntry
->Link
);
785 if (NoSimpleFsHandles
!= 0) {
786 FreePool (SimpleFsHandle
);
790 // Searching for handles that support Load File protocol
792 Status
= gBS
->LocateHandleBuffer (
794 &gEfiLoadFileProtocolGuid
,
800 if (!EFI_ERROR (Status
)) {
801 for (Index
= 0; Index
< NoLoadFileHandles
; Index
++) {
802 MenuEntry
= LibCreateMenuEntry ();
803 if (NULL
== MenuEntry
) {
804 FreePool (LoadFileHandle
);
805 return EFI_OUT_OF_RESOURCES
;
808 FileContext
= (FILE_CONTEXT
*) MenuEntry
->VariableContext
;
809 FileContext
->DeviceHandle
= LoadFileHandle
[Index
];
810 FileContext
->IsRoot
= TRUE
;
812 FileContext
->DevicePath
= DevicePathFromHandle (FileContext
->DeviceHandle
);
813 FileContext
->FileName
= LibDevicePathToStr (FileContext
->DevicePath
);
815 MenuEntry
->HelpString
= LibDevicePathToStr (FileContext
->DevicePath
);
816 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
817 ASSERT (MenuEntry
->DisplayString
!= NULL
);
819 MenuEntry
->DisplayString
,
822 MenuEntry
->HelpString
824 MenuEntry
->DisplayStringToken
= HiiSetString (
825 gFileExplorerPrivate
.FeHiiHandle
,
827 MenuEntry
->DisplayString
,
832 InsertTailList (&gFileExplorerPrivate
.FsOptionMenu
->Head
, &MenuEntry
->Link
);
836 if (NoLoadFileHandles
!= 0) {
837 FreePool (LoadFileHandle
);
840 gFileExplorerPrivate
.FsOptionMenu
->MenuNumber
= OptionNumber
;
846 Find the file handle from the input menu info.
848 @param MenuEntry Input Menu info.
849 @param RetFileHandle Return the file handle for the input device path.
851 @retval EFI_SUCESS Find the file handle success.
852 @retval Other Find the file handle failure.
855 LibGetFileHandleFromMenu (
856 IN MENU_ENTRY
*MenuEntry
,
857 OUT EFI_FILE_HANDLE
*RetFileHandle
861 EFI_FILE_HANDLE NewDir
;
862 FILE_CONTEXT
*FileContext
;
865 FileContext
= (FILE_CONTEXT
*) MenuEntry
->VariableContext
;
866 Dir
= FileContext
->FileHandle
;
869 // Open current directory to get files from it
874 FileContext
->FileName
,
878 if (EFI_ERROR (Status
)) {
882 if (!FileContext
->IsRoot
) {
886 *RetFileHandle
= NewDir
;
892 Find the file handle from the input device path info.
894 @param RootDirectory Device path info.
895 @param RetFileHandle Return the file handle for the input device path.
896 @param ParentFileName Parent file name.
897 @param DeviceHandle Driver handle for this partition.
899 @retval EFI_SUCESS Find the file handle success.
900 @retval Other Find the file handle failure.
903 LibGetFileHandleFromDevicePath (
904 IN EFI_DEVICE_PATH_PROTOCOL
*RootDirectory
,
905 OUT EFI_FILE_HANDLE
*RetFileHandle
,
906 OUT UINT16
**ParentFileName
,
907 OUT EFI_HANDLE
*DeviceHandle
910 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
911 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePathNode
;
914 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Volume
;
915 EFI_FILE_HANDLE FileHandle
;
916 EFI_FILE_HANDLE LastHandle
;
919 *ParentFileName
= NULL
;
922 // Attempt to access the file via a file system interface
924 DevicePathNode
= RootDirectory
;
925 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &DevicePathNode
, &Handle
);
926 if (EFI_ERROR (Status
)) {
930 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Volume
);
931 if (EFI_ERROR (Status
)) {
936 // Open the Volume to get the File System handle
938 Status
= Volume
->OpenVolume (Volume
, &FileHandle
);
939 if (EFI_ERROR (Status
)) {
943 *DeviceHandle
= Handle
;
945 if (IsDevicePathEnd(DevicePathNode
)) {
946 *ParentFileName
= AllocateCopyPool (StrSize (L
"\\"), L
"\\");
947 *RetFileHandle
= FileHandle
;
952 // Duplicate the device path to avoid the access to unaligned device path node.
953 // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
954 // nodes, It assures the fields in device path nodes are 2 byte aligned.
956 TempDevicePathNode
= DuplicateDevicePath (DevicePathNode
);
957 if (TempDevicePathNode
== NULL
) {
960 // Setting Status to an EFI_ERROR value will cause the rest of
961 // the file system support below to be skipped.
963 Status
= EFI_OUT_OF_RESOURCES
;
967 // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
968 // directory information and filename can be seperate. The goal is to inch
969 // our way down each device path node and close the previous node
971 DevicePathNode
= TempDevicePathNode
;
972 while (!EFI_ERROR (Status
) && !IsDevicePathEnd (DevicePathNode
)) {
973 if (DevicePathType (DevicePathNode
) != MEDIA_DEVICE_PATH
||
974 DevicePathSubType (DevicePathNode
) != MEDIA_FILEPATH_DP
) {
975 Status
= EFI_UNSUPPORTED
;
979 LastHandle
= FileHandle
;
982 Status
= LastHandle
->Open (
985 ((FILEPATH_DEVICE_PATH
*) DevicePathNode
)->PathName
,
989 if (*ParentFileName
== NULL
) {
990 *ParentFileName
= AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH
*) DevicePathNode
)->PathName
), ((FILEPATH_DEVICE_PATH
*) DevicePathNode
)->PathName
);
992 TempPath
= LibAppendFileName (*ParentFileName
, ((FILEPATH_DEVICE_PATH
*) DevicePathNode
)->PathName
);
993 FreePool (*ParentFileName
);
994 *ParentFileName
= TempPath
;
998 // Close the previous node
1000 LastHandle
->Close (LastHandle
);
1002 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
1005 if (EFI_ERROR (Status
)) {
1009 *RetFileHandle
= FileHandle
;
1011 Status
= EFI_SUCCESS
;
1014 if (TempDevicePathNode
!= NULL
) {
1015 FreePool (TempDevicePathNode
);
1018 if ((FileHandle
!= NULL
) && (EFI_ERROR (Status
))) {
1019 FileHandle
->Close (FileHandle
);
1026 Find files under current directory.
1028 All files and sub-directories in current directory
1029 will be stored in DirectoryMenu for future use.
1031 @param FileHandle Parent file handle.
1032 @param FileName Parent file name.
1033 @param DeviceHandle Driver handle for this partition.
1035 @retval EFI_SUCCESS Get files from current dir successfully.
1036 @return Other value if can't get files from current dir.
1041 IN EFI_FILE_HANDLE FileHandle
,
1042 IN UINT16
*FileName
,
1043 IN EFI_HANDLE DeviceHandle
1046 EFI_FILE_INFO
*DirInfo
;
1048 UINTN DirBufferSize
;
1049 MENU_ENTRY
*NewMenuEntry
;
1050 FILE_CONTEXT
*NewFileContext
;
1057 DirBufferSize
= sizeof (EFI_FILE_INFO
) + 1024;
1058 DirInfo
= AllocateZeroPool (DirBufferSize
);
1059 if (DirInfo
== NULL
) {
1060 return EFI_OUT_OF_RESOURCES
;
1064 // Get all files in current directory
1065 // Pass 1 to get Directories
1066 // Pass 2 to get files that are EFI images
1068 for (Pass
= 1; Pass
<= 2; Pass
++) {
1069 FileHandle
->SetPosition (FileHandle
, 0);
1071 BufferSize
= DirBufferSize
;
1072 Status
= FileHandle
->Read (FileHandle
, &BufferSize
, DirInfo
);
1073 if (EFI_ERROR (Status
) || BufferSize
== 0) {
1077 if (((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) != 0 && Pass
== 2) ||
1078 ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) == 0 && Pass
== 1)
1081 // Pass 1 is for Directories
1082 // Pass 2 is for file names
1087 if (!((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) != 0 || LibIsSupportedFileType (DirInfo
->FileName
))) {
1089 // Slip file unless it is a directory entry or a .EFI file
1094 NewMenuEntry
= LibCreateMenuEntry ();
1095 if (NULL
== NewMenuEntry
) {
1096 return EFI_OUT_OF_RESOURCES
;
1099 NewFileContext
= (FILE_CONTEXT
*) NewMenuEntry
->VariableContext
;
1100 NewFileContext
->DeviceHandle
= DeviceHandle
;
1101 NewFileContext
->FileName
= LibAppendFileName (FileName
, DirInfo
->FileName
);
1102 NewFileContext
->FileHandle
= FileHandle
;
1103 NewFileContext
->DevicePath
= FileDevicePath (NewFileContext
->DeviceHandle
, NewFileContext
->FileName
);
1104 NewMenuEntry
->HelpString
= NULL
;
1105 NewFileContext
->IsDir
= (BOOLEAN
) ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
);
1107 if (NewFileContext
->IsDir
) {
1108 BufferSize
= StrLen (DirInfo
->FileName
) * 2 + 6;
1109 NewMenuEntry
->DisplayString
= AllocateZeroPool (BufferSize
);
1111 NewMenuEntry
->DisplayString
,
1117 NewMenuEntry
->DisplayString
= LibStrDuplicate (DirInfo
->FileName
);
1120 NewMenuEntry
->DisplayStringToken
= HiiSetString (
1121 gFileExplorerPrivate
.FeHiiHandle
,
1123 NewMenuEntry
->DisplayString
,
1127 NewFileContext
->IsRoot
= FALSE
;
1130 InsertTailList (&gFileExplorerPrivate
.FsOptionMenu
->Head
, &NewMenuEntry
->Link
);
1134 gFileExplorerPrivate
.FsOptionMenu
->MenuNumber
= OptionNumber
;
1142 Refresh the global UpdateData structure.
1146 LibRefreshUpdateData (
1151 // Free current updated date
1153 if (mLibStartOpCodeHandle
!= NULL
) {
1154 HiiFreeOpCodeHandle (mLibStartOpCodeHandle
);
1156 if (mLibEndOpCodeHandle
!= NULL
) {
1157 HiiFreeOpCodeHandle (mLibEndOpCodeHandle
);
1161 // Create new OpCode Handle
1163 mLibStartOpCodeHandle
= HiiAllocateOpCodeHandle ();
1164 mLibEndOpCodeHandle
= HiiAllocateOpCodeHandle ();
1167 // Create Hii Extend Label OpCode as the start opcode
1169 mLibStartLabel
= (EFI_IFR_GUID_LABEL
*) HiiCreateGuidOpCode (
1170 mLibStartOpCodeHandle
,
1173 sizeof (EFI_IFR_GUID_LABEL
)
1175 mLibStartLabel
->ExtendOpCode
= EFI_IFR_EXTEND_OP_LABEL
;
1177 mLibStartLabel
->Number
= FORM_FILE_EXPLORER_ID
;
1180 // Create Hii Extend Label OpCode as the start opcode
1182 mLibEndLabel
= (EFI_IFR_GUID_LABEL
*) HiiCreateGuidOpCode (
1183 mLibEndOpCodeHandle
,
1186 sizeof (EFI_IFR_GUID_LABEL
)
1188 mLibEndLabel
->ExtendOpCode
= EFI_IFR_EXTEND_OP_LABEL
;
1190 mLibEndLabel
->Number
= LABEL_END
;
1195 Update the File Explore page.
1199 LibUpdateFileExplorePage (
1204 MENU_ENTRY
*NewMenuEntry
;
1205 FILE_CONTEXT
*NewFileContext
;
1206 MENU_OPTION
*MenuOption
;
1208 NewMenuEntry
= NULL
;
1209 NewFileContext
= NULL
;
1211 LibRefreshUpdateData ();
1212 MenuOption
= gFileExplorerPrivate
.FsOptionMenu
;
1214 for (Index
= 0; Index
< MenuOption
->MenuNumber
; Index
++) {
1215 NewMenuEntry
= LibGetMenuEntry (MenuOption
, Index
);
1216 NewFileContext
= (FILE_CONTEXT
*) NewMenuEntry
->VariableContext
;
1218 if (!NewFileContext
->IsDir
) {
1220 // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile.
1222 HiiCreateActionOpCode (
1223 mLibStartOpCodeHandle
,
1224 (UINT16
) (FILE_OPTION_OFFSET
+ Index
),
1225 NewMenuEntry
->DisplayStringToken
,
1226 STRING_TOKEN (STR_NULL_STRING
),
1227 EFI_IFR_FLAG_CALLBACK
,
1232 // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState.
1234 HiiCreateGotoOpCode (
1235 mLibStartOpCodeHandle
,
1236 FORM_FILE_EXPLORER_ID
,
1237 NewMenuEntry
->DisplayStringToken
,
1238 STRING_TOKEN (STR_NULL_STRING
),
1239 EFI_IFR_FLAG_CALLBACK
,
1240 (UINT16
) (FILE_OPTION_OFFSET
+ Index
)
1246 gFileExplorerPrivate
.FeHiiHandle
,
1248 FORM_FILE_EXPLORER_ID
,
1249 mLibStartOpCodeHandle
, // Label FORM_FILE_EXPLORER_ID
1250 mLibEndOpCodeHandle
// LABEL_END
1255 Update the file explower page with the refershed file system.
1257 @param KeyValue Key value to identify the type of data to expect.
1259 @retval EFI_SUCCESS Update the file explorer form success.
1260 @retval other errors Error occur when parse one directory.
1264 LibUpdateFileExplorer (
1268 UINT16 FileOptionMask
;
1269 MENU_ENTRY
*NewMenuEntry
;
1270 FILE_CONTEXT
*NewFileContext
;
1272 EFI_FILE_HANDLE FileHandle
;
1274 Status
= EFI_SUCCESS
;
1275 FileOptionMask
= (UINT16
) (FILE_OPTION_MASK
& KeyValue
);
1276 NewMenuEntry
= LibGetMenuEntry (gFileExplorerPrivate
.FsOptionMenu
, FileOptionMask
);
1277 NewFileContext
= (FILE_CONTEXT
*) NewMenuEntry
->VariableContext
;
1279 if (NewFileContext
->IsDir
) {
1280 RemoveEntryList (&NewMenuEntry
->Link
);
1281 LibFreeMenu (gFileExplorerPrivate
.FsOptionMenu
);
1282 LibGetFileHandleFromMenu (NewMenuEntry
, &FileHandle
);
1283 Status
= LibFindFiles (FileHandle
, NewFileContext
->FileName
, NewFileContext
->DeviceHandle
);
1284 if (!EFI_ERROR (Status
)) {
1285 LibUpdateFileExplorePage ();
1287 LibFreeMenu (gFileExplorerPrivate
.FsOptionMenu
);
1289 LibDestroyMenuEntry (NewMenuEntry
);
1296 Get the device path info saved in the menu structure.
1298 @param KeyValue Key value to identify the type of data to expect.
1306 UINT16 FileOptionMask
;
1307 MENU_ENTRY
*NewMenuEntry
;
1308 FILE_CONTEXT
*NewFileContext
;
1310 FileOptionMask
= (UINT16
) (FILE_OPTION_MASK
& KeyValue
);
1312 NewMenuEntry
= LibGetMenuEntry (gFileExplorerPrivate
.FsOptionMenu
, FileOptionMask
);
1314 NewFileContext
= (FILE_CONTEXT
*) NewMenuEntry
->VariableContext
;
1316 if (gFileExplorerPrivate
.RetDevicePath
!= NULL
) {
1317 FreePool (gFileExplorerPrivate
.RetDevicePath
);
1319 gFileExplorerPrivate
.RetDevicePath
= DuplicateDevicePath (NewFileContext
->DevicePath
);
1323 Choose a file in the specified directory.
1325 If user input NULL for the RootDirectory, will choose file in the system.
1327 If user input *File != NULL, function will return the allocate device path
1328 info for the choosed file, caller has to free the memory after use it.
1330 @param RootDirectory Pointer to the root directory.
1331 @param FileType The file type need to choose.
1332 @param ChooseHandler Function pointer to the extra task need to do
1333 after choose one file.
1334 @param File Return the device path for the last time chosed file.
1336 @retval EFI_SUCESS Choose file success.
1337 @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL
1338 One of them must not NULL.
1339 @retval Other errors Choose file failed.
1344 IN EFI_DEVICE_PATH_PROTOCOL
*RootDirectory
,
1345 IN CHAR16
*FileType
, OPTIONAL
1346 IN CHOOSE_HANDLER ChooseHandler
, OPTIONAL
1347 OUT EFI_DEVICE_PATH_PROTOCOL
**File OPTIONAL
1350 EFI_FILE_HANDLE FileHandle
;
1353 EFI_HANDLE DeviceHandle
;
1355 if ((ChooseHandler
== NULL
) && (File
== NULL
)) {
1356 return EFI_INVALID_PARAMETER
;
1361 gFileExplorerPrivate
.RetDevicePath
= NULL
;
1362 gFileExplorerPrivate
.ChooseHandler
= ChooseHandler
;
1363 if (FileType
!= NULL
) {
1364 gFileExplorerPrivate
.FileType
= AllocateCopyPool (StrSize (FileType
), FileType
);
1365 ASSERT(gFileExplorerPrivate
.FileType
!= NULL
);
1366 LibToLowerString(gFileExplorerPrivate
.FileType
);
1368 gFileExplorerPrivate
.FileType
= NULL
;
1371 if (RootDirectory
== NULL
) {
1372 Status
= LibFindFileSystem();
1374 Status
= LibGetFileHandleFromDevicePath(RootDirectory
, &FileHandle
, &FileName
, &DeviceHandle
);
1375 if (EFI_ERROR (Status
)) {
1379 Status
= LibFindFiles (FileHandle
, FileName
, DeviceHandle
);
1381 if (EFI_ERROR (Status
)) {
1385 LibUpdateFileExplorePage();
1387 gFileExplorerPrivate
.FormBrowser2
->SendForm (
1388 gFileExplorerPrivate
.FormBrowser2
,
1389 &gFileExplorerPrivate
.FeHiiHandle
,
1398 if ((Status
== EFI_SUCCESS
) && (File
!= NULL
)) {
1399 *File
= gFileExplorerPrivate
.RetDevicePath
;
1400 } else if (gFileExplorerPrivate
.RetDevicePath
!= NULL
) {
1401 FreePool (gFileExplorerPrivate
.RetDevicePath
);
1404 if (gFileExplorerPrivate
.FileType
!= NULL
) {
1405 FreePool (gFileExplorerPrivate
.FileType
);
1408 LibFreeMenu (gFileExplorerPrivate
.FsOptionMenu
);
1410 if (FileName
!= NULL
) {
1411 FreePool (FileName
);
1419 Install Boot Manager Menu driver.
1421 @param ImageHandle The image handle.
1422 @param SystemTable The system table.
1424 @retval EFI_SUCEESS Install File explorer library success.
1429 FileExplorerLibConstructor (
1430 IN EFI_HANDLE ImageHandle
,
1431 IN EFI_SYSTEM_TABLE
*SystemTable
1436 gHiiVendorDevicePath
= (HII_VENDOR_DEVICE_PATH
*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL
*)&FeHiiVendorDevicePath
);
1437 ASSERT (gHiiVendorDevicePath
!= NULL
);
1438 CopyGuid (&gHiiVendorDevicePath
->VendorDevicePath
.Guid
, &gEfiCallerIdGuid
);
1441 // Install Device Path Protocol and Config Access protocol to driver handle
1443 Status
= gBS
->InstallMultipleProtocolInterfaces (
1444 &gFileExplorerPrivate
.FeDriverHandle
,
1445 &gEfiDevicePathProtocolGuid
,
1446 gHiiVendorDevicePath
,
1447 &gEfiHiiConfigAccessProtocolGuid
,
1448 &gFileExplorerPrivate
.FeConfigAccess
,
1451 if (Status
== EFI_ALREADY_STARTED
) {
1454 if (EFI_ERROR (Status
)) {
1459 // Post our File Explorer VFR binary to the HII database.
1461 gFileExplorerPrivate
.FeHiiHandle
= HiiAddPackages (
1463 gFileExplorerPrivate
.FeDriverHandle
,
1465 FileExplorerLibStrings
,
1468 ASSERT (gFileExplorerPrivate
.FeHiiHandle
!= NULL
);
1471 // Locate Formbrowser2 protocol
1473 Status
= gBS
->LocateProtocol (&gEfiFormBrowser2ProtocolGuid
, NULL
, (VOID
**) &gFileExplorerPrivate
.FormBrowser2
);
1474 ASSERT_EFI_ERROR (Status
);
1476 InitializeListHead (&gFileExplorerPrivate
.FsOptionMenu
->Head
);
1482 Unloads the application and its installed protocol.
1484 @param[in] ImageHandle Handle that identifies the image to be unloaded.
1485 @param[in] SystemTable The system table.
1487 @retval EFI_SUCCESS The image has been unloaded.
1491 FileExplorerLibDestructor (
1492 IN EFI_HANDLE ImageHandle
,
1493 IN EFI_SYSTEM_TABLE
*SystemTable
1498 ASSERT (gHiiVendorDevicePath
!= NULL
);
1500 if (gFileExplorerPrivate
.FeDriverHandle
!= NULL
) {
1501 Status
= gBS
->UninstallMultipleProtocolInterfaces (
1502 gFileExplorerPrivate
.FeDriverHandle
,
1503 &gEfiDevicePathProtocolGuid
,
1504 gHiiVendorDevicePath
,
1505 &gEfiHiiConfigAccessProtocolGuid
,
1506 &gFileExplorerPrivate
.FeConfigAccess
,
1509 ASSERT_EFI_ERROR (Status
);
1511 HiiRemovePackages (gFileExplorerPrivate
.FeHiiHandle
);
1514 FreePool (gHiiVendorDevicePath
);