2 File explorer related functions.
4 Copyright (c) 2004 - 2015, 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 FreePool (FileContext
->DevicePath
);
307 if (FileContext
->FileHandle
!= NULL
) {
308 FileContext
->FileHandle
->Close (FileContext
->FileHandle
);
312 if (FileContext
->FileName
!= NULL
) {
313 FreePool (FileContext
->FileName
);
316 FreePool (FileContext
);
318 FreePool (MenuEntry
->DisplayString
);
319 if (MenuEntry
->HelpString
!= NULL
) {
320 FreePool (MenuEntry
->HelpString
);
323 FreePool (MenuEntry
);
328 Free resources allocated in Allocate Rountine.
330 @param FreeMenu Menu to be freed
334 MENU_OPTION
*FreeMenu
337 MENU_ENTRY
*MenuEntry
;
338 while (!IsListEmpty (&FreeMenu
->Head
)) {
340 FreeMenu
->Head
.ForwardLink
,
345 RemoveEntryList (&MenuEntry
->Link
);
346 LibDestroyMenuEntry (MenuEntry
);
348 FreeMenu
->MenuNumber
= 0;
353 Function opens and returns a file handle to the root directory of a volume.
355 @param DeviceHandle A handle for a device
357 @return A valid file handle or NULL is returned
362 IN EFI_HANDLE DeviceHandle
366 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Volume
;
367 EFI_FILE_HANDLE File
;
372 // File the file system interface to the device
374 Status
= gBS
->HandleProtocol (
376 &gEfiSimpleFileSystemProtocolGuid
,
381 // Open the root directory of the volume
383 if (!EFI_ERROR (Status
)) {
384 Status
= Volume
->OpenVolume (
392 return EFI_ERROR (Status
) ? NULL
: File
;
396 This function converts an input device structure to a Unicode string.
398 @param DevPath A pointer to the device path structure.
400 @return A new allocated Unicode string that represents the device path.
405 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
410 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
*DevPathToText
;
412 if (DevPath
== NULL
) {
416 Status
= gBS
->LocateProtocol (
417 &gEfiDevicePathToTextProtocolGuid
,
419 (VOID
**) &DevPathToText
421 ASSERT_EFI_ERROR (Status
);
422 ToText
= DevPathToText
->ConvertDevicePathToText (
427 ASSERT (ToText
!= NULL
);
435 @param Src The source.
437 @return A new string which is duplicated copy of the source.
438 @retval NULL If there is not enough memory.
449 Size
= StrSize (Src
);
450 Dest
= AllocateZeroPool (Size
);
451 ASSERT (Dest
!= NULL
);
453 CopyMem (Dest
, Src
, Size
);
461 Function gets the file information from an open file descriptor, and stores it
462 in a buffer allocated from pool.
464 @param FHand File Handle.
465 @param InfoType Info type need to get.
467 @retval A pointer to a buffer with file information or NULL is returned
472 IN EFI_FILE_HANDLE FHand
,
473 IN EFI_GUID
*InfoType
477 EFI_FILE_INFO
*Buffer
;
483 Status
= FHand
->GetInfo (
489 if (Status
== EFI_BUFFER_TOO_SMALL
) {
490 Buffer
= AllocatePool (BufferSize
);
491 ASSERT (Buffer
!= NULL
);
494 Status
= FHand
->GetInfo (
506 Get file type base on the file name.
507 Just cut the file name, from the ".". eg ".efi"
509 @param FileName File need to be checked.
511 @retval the file type string.
521 Index
= StrLen (FileName
) - 1;
522 while ((FileName
[Index
] != L
'.') && (Index
!= 0)) {
526 return Index
== 0 ? NULL
: &FileName
[Index
];
530 Converts the unicode character of the string from uppercase to lowercase.
531 This is a internal function.
533 @param ConfigString String to be converted
543 for (TmpStr
= String
; *TmpStr
!= L
'\0'; TmpStr
++) {
544 if (*TmpStr
>= L
'A' && *TmpStr
<= L
'Z') {
545 *TmpStr
= (CHAR16
) (*TmpStr
- L
'A' + L
'a');
552 Check whether current FileName point to a valid
555 @param FileName File need to be checked.
557 @retval TRUE Is Efi Image
558 @retval FALSE Not a valid Efi Image
562 LibIsSupportedFileType (
566 CHAR16
*InputFileType
;
570 if (gFileExplorerPrivate
.FileType
== NULL
) {
574 InputFileType
= LibGetTypeFromName (FileName
);
576 // If the file not has *.* style, always return TRUE.
578 if (InputFileType
== NULL
) {
582 TmpStr
= AllocateCopyPool (StrSize (InputFileType
), InputFileType
);
583 LibToLowerString(TmpStr
);
585 IsSupported
= (StrStr (gFileExplorerPrivate
.FileType
, TmpStr
) == NULL
? FALSE
: TRUE
);
593 Append file name to existing file name.
595 @param Str1 The existing file name
596 @param Str2 The file name to be appended
598 @return Allocate a new string to hold the appended result.
599 Caller is responsible to free the returned string.
616 Size1
= StrSize (Str1
);
617 Size2
= StrSize (Str2
);
618 MaxLen
= (Size1
+ Size2
+ sizeof (CHAR16
))/ sizeof (CHAR16
);
619 Str
= AllocateZeroPool (Size1
+ Size2
+ sizeof (CHAR16
));
620 ASSERT (Str
!= NULL
);
622 TmpStr
= AllocateZeroPool (Size1
+ Size2
+ sizeof (CHAR16
));
623 ASSERT (TmpStr
!= NULL
);
625 StrCpyS (Str
, MaxLen
, Str1
);
626 if (!((*Str
== '\\') && (*(Str
+ 1) == 0))) {
627 StrCatS (Str
, MaxLen
, L
"\\");
630 StrCatS (Str
, MaxLen
, Str2
);
635 if (*Ptr
== '\\' && *(Ptr
+ 1) == '.' && *(Ptr
+ 2) == '.' && *(Ptr
+ 3) == L
'\\') {
637 // Convert "\Name\..\" to "\"
638 // DO NOT convert the .. if it is at the end of the string. This will
639 // break the .. behavior in changing directories.
643 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
646 StrCpyS (TmpStr
, MaxLen
, Ptr
+ 3);
647 StrCpyS (LastSlash
, MaxLen
- (UINTN
) (LastSlash
- Str
), TmpStr
);
649 } else if (*Ptr
== '\\' && *(Ptr
+ 1) == '.' && *(Ptr
+ 2) == '\\') {
651 // Convert a "\.\" to a "\"
655 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
658 StrCpyS (TmpStr
, MaxLen
, Ptr
+ 2);
659 StrCpyS (Ptr
, MaxLen
- (UINTN
) (Ptr
- Str
), TmpStr
);
661 } else if (*Ptr
== '\\') {
674 This function build the FsOptionMenu list which records all
675 available file system in the system. They includes all instances
676 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM.
679 @retval EFI_SUCCESS Success find the file system
680 @retval EFI_OUT_OF_RESOURCES Can not create menu entry
688 UINTN NoSimpleFsHandles
;
689 UINTN NoLoadFileHandles
;
690 EFI_HANDLE
*SimpleFsHandle
;
691 EFI_HANDLE
*LoadFileHandle
;
695 MENU_ENTRY
*MenuEntry
;
696 FILE_CONTEXT
*FileContext
;
698 EFI_FILE_SYSTEM_VOLUME_LABEL
*Info
;
700 NoSimpleFsHandles
= 0;
701 NoLoadFileHandles
= 0;
705 // Locate Handles that support Simple File System protocol
707 Status
= gBS
->LocateHandleBuffer (
709 &gEfiSimpleFileSystemProtocolGuid
,
714 if (!EFI_ERROR (Status
)) {
716 // Find all the instances of the File System prototocol
718 for (Index
= 0; Index
< NoSimpleFsHandles
; Index
++) {
720 // Allocate pool for this load option
722 MenuEntry
= LibCreateMenuEntry ();
723 if (NULL
== MenuEntry
) {
724 FreePool (SimpleFsHandle
);
725 return EFI_OUT_OF_RESOURCES
;
728 FileContext
= (FILE_CONTEXT
*) MenuEntry
->VariableContext
;
729 FileContext
->DeviceHandle
= SimpleFsHandle
[Index
];
730 FileContext
->FileHandle
= LibOpenRoot (FileContext
->DeviceHandle
);
731 if (FileContext
->FileHandle
== NULL
) {
732 LibDestroyMenuEntry (MenuEntry
);
736 MenuEntry
->HelpString
= LibDevicePathToStr (DevicePathFromHandle (FileContext
->DeviceHandle
));
737 FileContext
->FileName
= LibStrDuplicate (L
"\\");
738 FileContext
->DevicePath
= FileDevicePath (FileContext
->DeviceHandle
, FileContext
->FileName
);
739 FileContext
->IsDir
= TRUE
;
740 FileContext
->IsRoot
= TRUE
;
743 // Get current file system's Volume Label
745 Info
= (EFI_FILE_SYSTEM_VOLUME_LABEL
*) LibFileInfo (FileContext
->FileHandle
, &gEfiFileSystemVolumeLabelInfoIdGuid
);
747 VolumeLabel
= L
"NO FILE SYSTEM INFO";
749 if (Info
->VolumeLabel
== NULL
) {
750 VolumeLabel
= L
"NULL VOLUME LABEL";
752 VolumeLabel
= Info
->VolumeLabel
;
753 if (*VolumeLabel
== 0x0000) {
754 VolumeLabel
= L
"NO VOLUME LABEL";
758 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
759 ASSERT (MenuEntry
->DisplayString
!= NULL
);
761 MenuEntry
->DisplayString
,
765 MenuEntry
->HelpString
767 MenuEntry
->DisplayStringToken
= HiiSetString (
768 gFileExplorerPrivate
.FeHiiHandle
,
770 MenuEntry
->DisplayString
,
776 InsertTailList (&gFileExplorerPrivate
.FsOptionMenu
->Head
, &MenuEntry
->Link
);
780 if (NoSimpleFsHandles
!= 0) {
781 FreePool (SimpleFsHandle
);
785 // Searching for handles that support Load File protocol
787 Status
= gBS
->LocateHandleBuffer (
789 &gEfiLoadFileProtocolGuid
,
795 if (!EFI_ERROR (Status
)) {
796 for (Index
= 0; Index
< NoLoadFileHandles
; Index
++) {
797 MenuEntry
= LibCreateMenuEntry ();
798 if (NULL
== MenuEntry
) {
799 FreePool (LoadFileHandle
);
800 return EFI_OUT_OF_RESOURCES
;
803 FileContext
= (FILE_CONTEXT
*) MenuEntry
->VariableContext
;
804 FileContext
->DeviceHandle
= LoadFileHandle
[Index
];
805 FileContext
->IsRoot
= TRUE
;
807 FileContext
->DevicePath
= DevicePathFromHandle (FileContext
->DeviceHandle
);
808 FileContext
->FileName
= LibDevicePathToStr (FileContext
->DevicePath
);
810 MenuEntry
->HelpString
= LibDevicePathToStr (FileContext
->DevicePath
);
811 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
812 ASSERT (MenuEntry
->DisplayString
!= NULL
);
814 MenuEntry
->DisplayString
,
817 MenuEntry
->HelpString
819 MenuEntry
->DisplayStringToken
= HiiSetString (
820 gFileExplorerPrivate
.FeHiiHandle
,
822 MenuEntry
->DisplayString
,
827 InsertTailList (&gFileExplorerPrivate
.FsOptionMenu
->Head
, &MenuEntry
->Link
);
831 if (NoLoadFileHandles
!= 0) {
832 FreePool (LoadFileHandle
);
835 gFileExplorerPrivate
.FsOptionMenu
->MenuNumber
= OptionNumber
;
841 Find the file handle from the input menu info.
843 @param MenuEntry Input Menu info.
844 @param RetFileHandle Return the file handle for the input device path.
846 @retval EFI_SUCESS Find the file handle success.
847 @retval Other Find the file handle failure.
850 LibGetFileHandleFromMenu (
851 IN MENU_ENTRY
*MenuEntry
,
852 OUT EFI_FILE_HANDLE
*RetFileHandle
856 EFI_FILE_HANDLE NewDir
;
857 FILE_CONTEXT
*FileContext
;
860 FileContext
= (FILE_CONTEXT
*) MenuEntry
->VariableContext
;
861 Dir
= FileContext
->FileHandle
;
864 // Open current directory to get files from it
869 FileContext
->FileName
,
873 if (EFI_ERROR (Status
)) {
877 if (!FileContext
->IsRoot
) {
881 *RetFileHandle
= NewDir
;
887 Find the file handle from the input device path info.
889 @param RootDirectory Device path info.
890 @param RetFileHandle Return the file handle for the input device path.
891 @param ParentFileName Parent file name.
892 @param DeviceHandle Driver handle for this partition.
894 @retval EFI_SUCESS Find the file handle success.
895 @retval Other Find the file handle failure.
898 LibGetFileHandleFromDevicePath (
899 IN EFI_DEVICE_PATH_PROTOCOL
*RootDirectory
,
900 OUT EFI_FILE_HANDLE
*RetFileHandle
,
901 OUT UINT16
**ParentFileName
,
902 OUT EFI_HANDLE
*DeviceHandle
905 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
906 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePathNode
;
909 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Volume
;
910 EFI_FILE_HANDLE FileHandle
;
911 EFI_FILE_HANDLE LastHandle
;
914 *ParentFileName
= NULL
;
917 // Attempt to access the file via a file system interface
919 DevicePathNode
= RootDirectory
;
920 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &DevicePathNode
, &Handle
);
921 if (EFI_ERROR (Status
)) {
925 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Volume
);
926 if (EFI_ERROR (Status
)) {
931 // Open the Volume to get the File System handle
933 Status
= Volume
->OpenVolume (Volume
, &FileHandle
);
934 if (EFI_ERROR (Status
)) {
938 *DeviceHandle
= Handle
;
940 if (IsDevicePathEnd(DevicePathNode
)) {
941 *ParentFileName
= AllocateCopyPool (StrSize (L
"\\"), L
"\\");
942 *RetFileHandle
= FileHandle
;
947 // Duplicate the device path to avoid the access to unaligned device path node.
948 // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
949 // nodes, It assures the fields in device path nodes are 2 byte aligned.
951 TempDevicePathNode
= DuplicateDevicePath (DevicePathNode
);
952 if (TempDevicePathNode
== NULL
) {
955 // Setting Status to an EFI_ERROR value will cause the rest of
956 // the file system support below to be skipped.
958 Status
= EFI_OUT_OF_RESOURCES
;
962 // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
963 // directory information and filename can be seperate. The goal is to inch
964 // our way down each device path node and close the previous node
966 DevicePathNode
= TempDevicePathNode
;
967 while (!EFI_ERROR (Status
) && !IsDevicePathEnd (DevicePathNode
)) {
968 if (DevicePathType (DevicePathNode
) != MEDIA_DEVICE_PATH
||
969 DevicePathSubType (DevicePathNode
) != MEDIA_FILEPATH_DP
) {
970 Status
= EFI_UNSUPPORTED
;
974 LastHandle
= FileHandle
;
977 Status
= LastHandle
->Open (
980 ((FILEPATH_DEVICE_PATH
*) DevicePathNode
)->PathName
,
984 if (*ParentFileName
== NULL
) {
985 *ParentFileName
= AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH
*) DevicePathNode
)->PathName
), ((FILEPATH_DEVICE_PATH
*) DevicePathNode
)->PathName
);
987 TempPath
= LibAppendFileName (*ParentFileName
, ((FILEPATH_DEVICE_PATH
*) DevicePathNode
)->PathName
);
988 FreePool (*ParentFileName
);
989 *ParentFileName
= TempPath
;
993 // Close the previous node
995 LastHandle
->Close (LastHandle
);
997 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
1000 if (EFI_ERROR (Status
)) {
1004 *RetFileHandle
= FileHandle
;
1006 Status
= EFI_SUCCESS
;
1009 if (TempDevicePathNode
!= NULL
) {
1010 FreePool (TempDevicePathNode
);
1013 if ((FileHandle
!= NULL
) && (EFI_ERROR (Status
))) {
1014 FileHandle
->Close (FileHandle
);
1021 Find files under current directory.
1023 All files and sub-directories in current directory
1024 will be stored in DirectoryMenu for future use.
1026 @param FileHandle Parent file handle.
1027 @param FileName Parent file name.
1028 @param DeviceHandle Driver handle for this partition.
1030 @retval EFI_SUCCESS Get files from current dir successfully.
1031 @return Other value if can't get files from current dir.
1036 IN EFI_FILE_HANDLE FileHandle
,
1037 IN UINT16
*FileName
,
1038 IN EFI_HANDLE DeviceHandle
1041 EFI_FILE_INFO
*DirInfo
;
1043 UINTN DirBufferSize
;
1044 MENU_ENTRY
*NewMenuEntry
;
1045 FILE_CONTEXT
*NewFileContext
;
1052 DirBufferSize
= sizeof (EFI_FILE_INFO
) + 1024;
1053 DirInfo
= AllocateZeroPool (DirBufferSize
);
1054 if (DirInfo
== NULL
) {
1055 return EFI_OUT_OF_RESOURCES
;
1059 // Get all files in current directory
1060 // Pass 1 to get Directories
1061 // Pass 2 to get files that are EFI images
1063 for (Pass
= 1; Pass
<= 2; Pass
++) {
1064 FileHandle
->SetPosition (FileHandle
, 0);
1066 BufferSize
= DirBufferSize
;
1067 Status
= FileHandle
->Read (FileHandle
, &BufferSize
, DirInfo
);
1068 if (EFI_ERROR (Status
) || BufferSize
== 0) {
1072 if (((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) != 0 && Pass
== 2) ||
1073 ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) == 0 && Pass
== 1)
1076 // Pass 1 is for Directories
1077 // Pass 2 is for file names
1082 if (!((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) != 0 || LibIsSupportedFileType (DirInfo
->FileName
))) {
1084 // Slip file unless it is a directory entry or a .EFI file
1089 NewMenuEntry
= LibCreateMenuEntry ();
1090 if (NULL
== NewMenuEntry
) {
1091 return EFI_OUT_OF_RESOURCES
;
1094 NewFileContext
= (FILE_CONTEXT
*) NewMenuEntry
->VariableContext
;
1095 NewFileContext
->DeviceHandle
= DeviceHandle
;
1096 NewFileContext
->FileName
= LibAppendFileName (FileName
, DirInfo
->FileName
);
1097 NewFileContext
->FileHandle
= FileHandle
;
1098 NewFileContext
->DevicePath
= FileDevicePath (NewFileContext
->DeviceHandle
, NewFileContext
->FileName
);
1099 NewMenuEntry
->HelpString
= NULL
;
1100 NewFileContext
->IsDir
= (BOOLEAN
) ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
);
1102 if (NewFileContext
->IsDir
) {
1103 BufferSize
= StrLen (DirInfo
->FileName
) * 2 + 6;
1104 NewMenuEntry
->DisplayString
= AllocateZeroPool (BufferSize
);
1106 NewMenuEntry
->DisplayString
,
1112 NewMenuEntry
->DisplayString
= LibStrDuplicate (DirInfo
->FileName
);
1115 NewMenuEntry
->DisplayStringToken
= HiiSetString (
1116 gFileExplorerPrivate
.FeHiiHandle
,
1118 NewMenuEntry
->DisplayString
,
1122 NewFileContext
->IsRoot
= FALSE
;
1125 InsertTailList (&gFileExplorerPrivate
.FsOptionMenu
->Head
, &NewMenuEntry
->Link
);
1129 gFileExplorerPrivate
.FsOptionMenu
->MenuNumber
= OptionNumber
;
1137 Refresh the global UpdateData structure.
1141 LibRefreshUpdateData (
1146 // Free current updated date
1148 if (mLibStartOpCodeHandle
!= NULL
) {
1149 HiiFreeOpCodeHandle (mLibStartOpCodeHandle
);
1151 if (mLibEndOpCodeHandle
!= NULL
) {
1152 HiiFreeOpCodeHandle (mLibEndOpCodeHandle
);
1156 // Create new OpCode Handle
1158 mLibStartOpCodeHandle
= HiiAllocateOpCodeHandle ();
1159 mLibEndOpCodeHandle
= HiiAllocateOpCodeHandle ();
1162 // Create Hii Extend Label OpCode as the start opcode
1164 mLibStartLabel
= (EFI_IFR_GUID_LABEL
*) HiiCreateGuidOpCode (
1165 mLibStartOpCodeHandle
,
1168 sizeof (EFI_IFR_GUID_LABEL
)
1170 mLibStartLabel
->ExtendOpCode
= EFI_IFR_EXTEND_OP_LABEL
;
1172 mLibStartLabel
->Number
= FORM_FILE_EXPLORER_ID
;
1175 // Create Hii Extend Label OpCode as the start opcode
1177 mLibEndLabel
= (EFI_IFR_GUID_LABEL
*) HiiCreateGuidOpCode (
1178 mLibEndOpCodeHandle
,
1181 sizeof (EFI_IFR_GUID_LABEL
)
1183 mLibEndLabel
->ExtendOpCode
= EFI_IFR_EXTEND_OP_LABEL
;
1185 mLibEndLabel
->Number
= LABEL_END
;
1190 Update the File Explore page.
1194 LibUpdateFileExplorePage (
1199 MENU_ENTRY
*NewMenuEntry
;
1200 FILE_CONTEXT
*NewFileContext
;
1201 MENU_OPTION
*MenuOption
;
1203 NewMenuEntry
= NULL
;
1204 NewFileContext
= NULL
;
1206 LibRefreshUpdateData ();
1207 MenuOption
= gFileExplorerPrivate
.FsOptionMenu
;
1209 for (Index
= 0; Index
< MenuOption
->MenuNumber
; Index
++) {
1210 NewMenuEntry
= LibGetMenuEntry (MenuOption
, Index
);
1211 NewFileContext
= (FILE_CONTEXT
*) NewMenuEntry
->VariableContext
;
1213 if (!NewFileContext
->IsDir
) {
1215 // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile.
1217 HiiCreateActionOpCode (
1218 mLibStartOpCodeHandle
,
1219 (UINT16
) (FILE_OPTION_OFFSET
+ Index
),
1220 NewMenuEntry
->DisplayStringToken
,
1221 STRING_TOKEN (STR_NULL_STRING
),
1222 EFI_IFR_FLAG_CALLBACK
,
1227 // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState.
1229 HiiCreateGotoOpCode (
1230 mLibStartOpCodeHandle
,
1231 FORM_FILE_EXPLORER_ID
,
1232 NewMenuEntry
->DisplayStringToken
,
1233 STRING_TOKEN (STR_NULL_STRING
),
1234 EFI_IFR_FLAG_CALLBACK
,
1235 (UINT16
) (FILE_OPTION_OFFSET
+ Index
)
1241 gFileExplorerPrivate
.FeHiiHandle
,
1243 FORM_FILE_EXPLORER_ID
,
1244 mLibStartOpCodeHandle
, // Label FORM_FILE_EXPLORER_ID
1245 mLibEndOpCodeHandle
// LABEL_END
1250 Update the file explower page with the refershed file system.
1252 @param KeyValue Key value to identify the type of data to expect.
1254 @retval EFI_SUCCESS Update the file explorer form success.
1255 @retval other errors Error occur when parse one directory.
1259 LibUpdateFileExplorer (
1263 UINT16 FileOptionMask
;
1264 MENU_ENTRY
*NewMenuEntry
;
1265 FILE_CONTEXT
*NewFileContext
;
1267 EFI_FILE_HANDLE FileHandle
;
1269 Status
= EFI_SUCCESS
;
1270 FileOptionMask
= (UINT16
) (FILE_OPTION_MASK
& KeyValue
);
1271 NewMenuEntry
= LibGetMenuEntry (gFileExplorerPrivate
.FsOptionMenu
, FileOptionMask
);
1272 NewFileContext
= (FILE_CONTEXT
*) NewMenuEntry
->VariableContext
;
1274 if (NewFileContext
->IsDir
) {
1275 RemoveEntryList (&NewMenuEntry
->Link
);
1276 LibFreeMenu (gFileExplorerPrivate
.FsOptionMenu
);
1277 LibGetFileHandleFromMenu (NewMenuEntry
, &FileHandle
);
1278 Status
= LibFindFiles (FileHandle
, NewFileContext
->FileName
, NewFileContext
->DeviceHandle
);
1279 if (!EFI_ERROR (Status
)) {
1280 LibUpdateFileExplorePage ();
1282 LibFreeMenu (gFileExplorerPrivate
.FsOptionMenu
);
1284 LibDestroyMenuEntry (NewMenuEntry
);
1291 Get the device path info saved in the menu structure.
1293 @param KeyValue Key value to identify the type of data to expect.
1301 UINT16 FileOptionMask
;
1302 MENU_ENTRY
*NewMenuEntry
;
1303 FILE_CONTEXT
*NewFileContext
;
1305 FileOptionMask
= (UINT16
) (FILE_OPTION_MASK
& KeyValue
);
1307 NewMenuEntry
= LibGetMenuEntry (gFileExplorerPrivate
.FsOptionMenu
, FileOptionMask
);
1309 NewFileContext
= (FILE_CONTEXT
*) NewMenuEntry
->VariableContext
;
1311 if (gFileExplorerPrivate
.RetDevicePath
!= NULL
) {
1312 FreePool (gFileExplorerPrivate
.RetDevicePath
);
1314 gFileExplorerPrivate
.RetDevicePath
= DuplicateDevicePath (NewFileContext
->DevicePath
);
1318 Choose a file in the specified directory.
1320 If user input NULL for the RootDirectory, will choose file in the system.
1322 If user input *File != NULL, function will return the allocate device path
1323 info for the choosed file, caller has to free the memory after use it.
1325 @param RootDirectory Pointer to the root directory.
1326 @param FileType The file type need to choose.
1327 @param ChooseHandler Function pointer to the extra task need to do
1328 after choose one file.
1329 @param File Return the device path for the last time chosed file.
1331 @retval EFI_SUCESS Choose file success.
1332 @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL
1333 One of them must not NULL.
1334 @retval Other errors Choose file failed.
1339 IN EFI_DEVICE_PATH_PROTOCOL
*RootDirectory
,
1340 IN CHAR16
*FileType
, OPTIONAL
1341 IN CHOOSE_HANDLER ChooseHandler
, OPTIONAL
1342 OUT EFI_DEVICE_PATH_PROTOCOL
**File OPTIONAL
1345 EFI_FILE_HANDLE FileHandle
;
1348 EFI_HANDLE DeviceHandle
;
1350 if ((ChooseHandler
== NULL
) && (File
== NULL
)) {
1351 return EFI_INVALID_PARAMETER
;
1356 gFileExplorerPrivate
.RetDevicePath
= NULL
;
1357 gFileExplorerPrivate
.ChooseHandler
= ChooseHandler
;
1358 if (FileType
!= NULL
) {
1359 gFileExplorerPrivate
.FileType
= AllocateCopyPool (StrSize (FileType
), FileType
);
1360 LibToLowerString(gFileExplorerPrivate
.FileType
);
1362 gFileExplorerPrivate
.FileType
= NULL
;
1365 if (RootDirectory
== NULL
) {
1366 Status
= LibFindFileSystem();
1368 Status
= LibGetFileHandleFromDevicePath(RootDirectory
, &FileHandle
, &FileName
, &DeviceHandle
);
1369 if (EFI_ERROR (Status
)) {
1373 Status
= LibFindFiles (FileHandle
, FileName
, DeviceHandle
);
1375 if (EFI_ERROR (Status
)) {
1379 LibUpdateFileExplorePage();
1381 gFileExplorerPrivate
.FormBrowser2
->SendForm (
1382 gFileExplorerPrivate
.FormBrowser2
,
1383 &gFileExplorerPrivate
.FeHiiHandle
,
1392 if ((Status
== EFI_SUCCESS
) && (File
!= NULL
)) {
1393 *File
= gFileExplorerPrivate
.RetDevicePath
;
1394 } else if (gFileExplorerPrivate
.RetDevicePath
!= NULL
) {
1395 FreePool (gFileExplorerPrivate
.RetDevicePath
);
1398 if (gFileExplorerPrivate
.FileType
!= NULL
) {
1399 FreePool (gFileExplorerPrivate
.FileType
);
1402 LibFreeMenu (gFileExplorerPrivate
.FsOptionMenu
);
1404 if (FileName
!= NULL
) {
1405 FreePool (FileName
);
1413 Install Boot Manager Menu driver.
1415 @param ImageHandle The image handle.
1416 @param SystemTable The system table.
1418 @retval EFI_SUCEESS Install File explorer library success.
1423 FileExplorerLibConstructor (
1424 IN EFI_HANDLE ImageHandle
,
1425 IN EFI_SYSTEM_TABLE
*SystemTable
1430 gHiiVendorDevicePath
= (HII_VENDOR_DEVICE_PATH
*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL
*)&FeHiiVendorDevicePath
);
1431 ASSERT (gHiiVendorDevicePath
!= NULL
);
1432 CopyGuid (&gHiiVendorDevicePath
->VendorDevicePath
.Guid
, &gEfiCallerIdGuid
);
1435 // Install Device Path Protocol and Config Access protocol to driver handle
1437 Status
= gBS
->InstallMultipleProtocolInterfaces (
1438 &gFileExplorerPrivate
.FeDriverHandle
,
1439 &gEfiDevicePathProtocolGuid
,
1440 gHiiVendorDevicePath
,
1441 &gEfiHiiConfigAccessProtocolGuid
,
1442 &gFileExplorerPrivate
.FeConfigAccess
,
1445 ASSERT_EFI_ERROR (Status
);
1448 // Post our File Explorer VFR binary to the HII database.
1450 gFileExplorerPrivate
.FeHiiHandle
= HiiAddPackages (
1452 gFileExplorerPrivate
.FeDriverHandle
,
1454 FileExplorerLibStrings
,
1457 ASSERT (gFileExplorerPrivate
.FeHiiHandle
!= NULL
);
1460 // Locate Formbrowser2 protocol
1462 Status
= gBS
->LocateProtocol (&gEfiFormBrowser2ProtocolGuid
, NULL
, (VOID
**) &gFileExplorerPrivate
.FormBrowser2
);
1463 ASSERT_EFI_ERROR (Status
);
1465 InitializeListHead (&gFileExplorerPrivate
.FsOptionMenu
->Head
);
1471 Unloads the application and its installed protocol.
1473 @param[in] ImageHandle Handle that identifies the image to be unloaded.
1474 @param[in] SystemTable The system table.
1476 @retval EFI_SUCCESS The image has been unloaded.
1480 FileExplorerLibDestructor (
1481 IN EFI_HANDLE ImageHandle
,
1482 IN EFI_SYSTEM_TABLE
*SystemTable
1487 ASSERT (gHiiVendorDevicePath
!= NULL
);
1489 Status
= gBS
->UninstallMultipleProtocolInterfaces (
1490 gFileExplorerPrivate
.FeDriverHandle
,
1491 &gEfiDevicePathProtocolGuid
,
1492 gHiiVendorDevicePath
,
1493 &gEfiHiiConfigAccessProtocolGuid
,
1494 &gFileExplorerPrivate
.FeConfigAccess
,
1497 ASSERT_EFI_ERROR (Status
);
1499 HiiRemovePackages (gFileExplorerPrivate
.FeHiiHandle
);
1501 FreePool (gHiiVendorDevicePath
);