]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/FileExplorerLib/FileExplorer.c
FileExplorerLib: Update copyright, use BSD license instead of Intel license.
[mirror_edk2.git] / MdeModulePkg / Library / FileExplorerLib / FileExplorer.c
CommitLineData
ba529e7e 1/** @file
5ea71787 2File explorer related functions.
ba529e7e 3
5ea71787
ED
4Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials are licensed and made available under
6the terms and conditions of the BSD License that accompanies this distribution.
7The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php.
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
ba529e7e
ED
12
13**/
14
5ea71787 15
ba529e7e
ED
16#include "FileExplorer.h"
17
18EFI_GUID FileExplorerGuid = EFI_FILE_EXPLORE_FORMSET_GUID;
19
20///
21/// File system selection menu
22///
23MENU_OPTION mFsOptionMenu = {
24 MENU_OPTION_SIGNATURE,
25 {NULL},
26 0,
27 FALSE
28};
29
30FILE_EXPLORER_CALLBACK_DATA gFileExplorerPrivate = {
31 FILE_EXPLORER_CALLBACK_DATA_SIGNATURE,
32 NULL,
33 NULL,
34 {
35 LibExtractConfig,
36 LibRouteConfig,
37 LibCallback
38 },
39 NULL,
40 &mFsOptionMenu,
41 0
42};
43
44HII_VENDOR_DEVICE_PATH *gHiiVendorDevicePath;
45
46HII_VENDOR_DEVICE_PATH FeHiiVendorDevicePath = {
47 {
48 {
49 HARDWARE_DEVICE_PATH,
50 HW_VENDOR_DP,
51 {
52 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
53 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
54 }
55 },
56 //
57 // Will be replace with gEfiCallerIdGuid in code.
58 //
59 { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }
60 },
61 {
62 END_DEVICE_PATH_TYPE,
63 END_ENTIRE_DEVICE_PATH_SUBTYPE,
64 {
65 (UINT8) (END_DEVICE_PATH_LENGTH),
66 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
67 }
68 }
69};
70
71VOID *mLibStartOpCodeHandle = NULL;
72VOID *mLibEndOpCodeHandle = NULL;
73EFI_IFR_GUID_LABEL *mLibStartLabel = NULL;
74EFI_IFR_GUID_LABEL *mLibEndLabel = NULL;
75
76/**
77 This function allows a caller to extract the current configuration for one
78 or more named elements from the target driver.
79
80
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.
91
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.
94
95**/
96EFI_STATUS
97EFIAPI
98LibExtractConfig (
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
103 )
104{
105 if (Progress == NULL || Results == NULL) {
106 return EFI_INVALID_PARAMETER;
107 }
108
109 *Progress = Request;
110 return EFI_NOT_FOUND;
111}
112
113/**
114 This function processes the results of changes in configuration.
115
116
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.
123
124 @retval EFI_INVALID_PARAMETER Configuration is NULL.
125 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
126
127**/
128EFI_STATUS
129EFIAPI
130LibRouteConfig (
131 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
132 IN CONST EFI_STRING Configuration,
133 OUT EFI_STRING *Progress
134 )
135{
136 if (Configuration == NULL || Progress == NULL) {
137 return EFI_INVALID_PARAMETER;
138 }
139
140 *Progress = Configuration;
141 return EFI_NOT_FOUND;
142}
143
144/**
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:
149
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.
152
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.
160
161 @retval EFI_SUCCESS The callback successfully handled the action.
162 @retval other error Error occur when parse one directory.
163**/
164EFI_STATUS
165EFIAPI
166LibCallback (
167 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
168 IN EFI_BROWSER_ACTION Action,
169 IN EFI_QUESTION_ID QuestionId,
170 IN UINT8 Type,
171 IN EFI_IFR_TYPE_VALUE *Value,
172 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
173 )
174{
175 EFI_STATUS Status;
176 BOOLEAN NeedExit;
177
178 NeedExit = TRUE;
179
180 if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
181 //
182 // Do nothing for other UEFI Action. Only do call back when data is changed.
183 //
184 return EFI_UNSUPPORTED;
185 }
186
187 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
188
189 if (Action == EFI_BROWSER_ACTION_CHANGED) {
190 if ((Value == NULL) || (ActionRequest == NULL)) {
191 return EFI_INVALID_PARAMETER;
192 }
193
194 if (QuestionId >= FILE_OPTION_OFFSET) {
195 LibGetDevicePath(QuestionId);
196
197 //
198 // Process the extra action.
199 //
200 if (gFileExplorerPrivate.ChooseHandler != NULL) {
201 NeedExit = gFileExplorerPrivate.ChooseHandler (gFileExplorerPrivate.RetDevicePath);
202 }
203
204 if (NeedExit) {
205 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
206 }
207 }
208 } else if (Action == EFI_BROWSER_ACTION_CHANGING) {
209 if (Value == NULL) {
210 return EFI_INVALID_PARAMETER;
211 }
212
213 if (QuestionId >= FILE_OPTION_OFFSET) {
214 Status = LibUpdateFileExplorer (QuestionId);
215 if (EFI_ERROR (Status)) {
216 return Status;
217 }
218 }
219 }
220
221 return EFI_SUCCESS;
222}
223
224/**
225 Create a menu entry by given menu type.
226
227 @retval NULL If failed to create the menu.
228 @return the new menu entry.
229
230**/
231MENU_ENTRY *
232LibCreateMenuEntry (
233 VOID
234 )
235{
236 MENU_ENTRY *MenuEntry;
237
238 //
239 // Create new menu entry
240 //
241 MenuEntry = AllocateZeroPool (sizeof (MENU_ENTRY));
242 if (MenuEntry == NULL) {
243 return NULL;
244 }
245
246 MenuEntry->VariableContext = AllocateZeroPool (sizeof (FILE_CONTEXT));
247 if (MenuEntry->VariableContext == NULL) {
248 FreePool (MenuEntry);
249 return NULL;
250 }
251
252 MenuEntry->Signature = MENU_ENTRY_SIGNATURE;
253 return MenuEntry;
254}
255
256
257/**
258 Get the Menu Entry from the list in Menu Entry List.
259
260 If MenuNumber is great or equal to the number of Menu
261 Entry in the list, then ASSERT.
262
263 @param MenuOption The Menu Entry List to read the menu entry.
264 @param MenuNumber The index of Menu Entry.
265
266 @return The Menu Entry.
267
268**/
269MENU_ENTRY *
270LibGetMenuEntry (
271 MENU_OPTION *MenuOption,
272 UINTN MenuNumber
273 )
274{
275 MENU_ENTRY *NewMenuEntry;
276 UINTN Index;
277 LIST_ENTRY *List;
278
279 ASSERT (MenuNumber < MenuOption->MenuNumber);
280
281 List = MenuOption->Head.ForwardLink;
282 for (Index = 0; Index < MenuNumber; Index++) {
283 List = List->ForwardLink;
284 }
285
286 NewMenuEntry = CR (List, MENU_ENTRY, Link, MENU_ENTRY_SIGNATURE);
287
288 return NewMenuEntry;
289}
290
291/**
292 Free up all resource allocated for a BM_MENU_ENTRY.
293
294 @param MenuEntry A pointer to BM_MENU_ENTRY.
295
296**/
297VOID
298LibDestroyMenuEntry (
299 MENU_ENTRY *MenuEntry
300 )
301{
302 FILE_CONTEXT *FileContext;
303
304 FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
305
306 if (!FileContext->IsRoot) {
307 FreePool (FileContext->DevicePath);
308 } else {
309 if (FileContext->FileHandle != NULL) {
310 FileContext->FileHandle->Close (FileContext->FileHandle);
311 }
312 }
313
314 if (FileContext->FileName != NULL) {
315 FreePool (FileContext->FileName);
316 }
317
318 FreePool (FileContext);
319
320 FreePool (MenuEntry->DisplayString);
321 if (MenuEntry->HelpString != NULL) {
322 FreePool (MenuEntry->HelpString);
323 }
324
325 FreePool (MenuEntry);
326}
327
328
329/**
330 Free resources allocated in Allocate Rountine.
331
332 @param FreeMenu Menu to be freed
333**/
334VOID
335LibFreeMenu (
336 MENU_OPTION *FreeMenu
337 )
338{
339 MENU_ENTRY *MenuEntry;
340 while (!IsListEmpty (&FreeMenu->Head)) {
341 MenuEntry = CR (
342 FreeMenu->Head.ForwardLink,
343 MENU_ENTRY,
344 Link,
345 MENU_ENTRY_SIGNATURE
346 );
347 RemoveEntryList (&MenuEntry->Link);
348 LibDestroyMenuEntry (MenuEntry);
349 }
350 FreeMenu->MenuNumber = 0;
351}
352
353/**
354
355 Function opens and returns a file handle to the root directory of a volume.
356
357 @param DeviceHandle A handle for a device
358
359 @return A valid file handle or NULL is returned
360
361**/
362EFI_FILE_HANDLE
363LibOpenRoot (
364 IN EFI_HANDLE DeviceHandle
365 )
366{
367 EFI_STATUS Status;
368 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
369 EFI_FILE_HANDLE File;
370
371 File = NULL;
372
373 //
374 // File the file system interface to the device
375 //
376 Status = gBS->HandleProtocol (
377 DeviceHandle,
378 &gEfiSimpleFileSystemProtocolGuid,
379 (VOID *) &Volume
380 );
381
382 //
383 // Open the root directory of the volume
384 //
385 if (!EFI_ERROR (Status)) {
386 Status = Volume->OpenVolume (
387 Volume,
388 &File
389 );
390 }
391 //
392 // Done
393 //
394 return EFI_ERROR (Status) ? NULL : File;
395}
396
397/**
398 This function converts an input device structure to a Unicode string.
399
400 @param DevPath A pointer to the device path structure.
401
402 @return A new allocated Unicode string that represents the device path.
403
404**/
405CHAR16 *
406LibDevicePathToStr (
407 IN EFI_DEVICE_PATH_PROTOCOL *DevPath
408 )
409{
410 EFI_STATUS Status;
411 CHAR16 *ToText;
412 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
413
414 if (DevPath == NULL) {
415 return NULL;
416 }
417
418 Status = gBS->LocateProtocol (
419 &gEfiDevicePathToTextProtocolGuid,
420 NULL,
421 (VOID **) &DevPathToText
422 );
423 ASSERT_EFI_ERROR (Status);
424 ToText = DevPathToText->ConvertDevicePathToText (
425 DevPath,
426 FALSE,
427 TRUE
428 );
429 ASSERT (ToText != NULL);
430
431 return ToText;
432}
433
434/**
435 Duplicate a string.
436
437 @param Src The source.
438
439 @return A new string which is duplicated copy of the source.
440 @retval NULL If there is not enough memory.
441
442**/
443CHAR16 *
444LibStrDuplicate (
445 IN CHAR16 *Src
446 )
447{
448 CHAR16 *Dest;
449 UINTN Size;
450
451 Size = StrSize (Src);
452 Dest = AllocateZeroPool (Size);
453 ASSERT (Dest != NULL);
454 if (Dest != NULL) {
455 CopyMem (Dest, Src, Size);
456 }
457
458 return Dest;
459}
460
461/**
462
463 Function gets the file information from an open file descriptor, and stores it
464 in a buffer allocated from pool.
465
466 @param FHand File Handle.
467 @param InfoType Info type need to get.
468
469 @retval A pointer to a buffer with file information or NULL is returned
470
471**/
472VOID *
473LibFileInfo (
474 IN EFI_FILE_HANDLE FHand,
475 IN EFI_GUID *InfoType
476 )
477{
478 EFI_STATUS Status;
479 EFI_FILE_INFO *Buffer;
480 UINTN BufferSize;
481
482 Buffer = NULL;
483 BufferSize = 0;
484
485 Status = FHand->GetInfo (
486 FHand,
487 InfoType,
488 &BufferSize,
489 Buffer
490 );
491 if (Status == EFI_BUFFER_TOO_SMALL) {
492 Buffer = AllocatePool (BufferSize);
493 ASSERT (Buffer != NULL);
494 }
495
496 Status = FHand->GetInfo (
497 FHand,
498 InfoType,
499 &BufferSize,
500 Buffer
501 );
502
503 return Buffer;
504}
505
506/**
507
508 Get file type base on the file name.
509 Just cut the file name, from the ".". eg ".efi"
510
511 @param FileName File need to be checked.
512
513 @retval the file type string.
514
515**/
516CHAR16*
517LibGetTypeFromName (
518 IN CHAR16 *FileName
519 )
520{
521 UINTN Index;
522
523 Index = StrLen (FileName) - 1;
524 while ((FileName[Index] != L'.') && (Index != 0)) {
525 Index--;
526 }
527
528 return Index == 0 ? NULL : &FileName[Index];
529}
530
531/**
532 Converts the unicode character of the string from uppercase to lowercase.
533 This is a internal function.
534
535 @param ConfigString String to be converted
536
537**/
538VOID
539LibToLowerString (
540 IN CHAR16 *String
541 )
542{
543 CHAR16 *TmpStr;
544
545 for (TmpStr = String; *TmpStr != L'\0'; TmpStr++) {
546 if (*TmpStr >= L'A' && *TmpStr <= L'Z') {
547 *TmpStr = (CHAR16) (*TmpStr - L'A' + L'a');
548 }
549 }
550}
551
552/**
553
554 Check whether current FileName point to a valid
555 Efi Image File.
556
557 @param FileName File need to be checked.
558
559 @retval TRUE Is Efi Image
560 @retval FALSE Not a valid Efi Image
561
562**/
563BOOLEAN
564LibIsSupportedFileType (
565 IN UINT16 *FileName
566 )
567{
568 CHAR16 *InputFileType;
569 CHAR16 *TmpStr;
570 BOOLEAN IsSupported;
571
572 if (gFileExplorerPrivate.FileType == NULL) {
573 return TRUE;
574 }
575
576 InputFileType = LibGetTypeFromName (FileName);
577 //
578 // If the file not has *.* style, always return TRUE.
579 //
580 if (InputFileType == NULL) {
581 return TRUE;
582 }
583
584 TmpStr = AllocateCopyPool (StrSize (InputFileType), InputFileType);
585 LibToLowerString(TmpStr);
586
587 IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE);
588
589 FreePool (TmpStr);
590 return IsSupported;
591}
592
593/**
594
595 Append file name to existing file name.
596
597 @param Str1 The existing file name
598 @param Str2 The file name to be appended
599
600 @return Allocate a new string to hold the appended result.
601 Caller is responsible to free the returned string.
602
603**/
604CHAR16 *
605LibAppendFileName (
606 IN CHAR16 *Str1,
607 IN CHAR16 *Str2
608 )
609{
610 UINTN Size1;
611 UINTN Size2;
cd32c66f 612 UINTN MaxLen;
ba529e7e
ED
613 CHAR16 *Str;
614 CHAR16 *TmpStr;
615 CHAR16 *Ptr;
616 CHAR16 *LastSlash;
617
618 Size1 = StrSize (Str1);
619 Size2 = StrSize (Str2);
cd32c66f 620 MaxLen = (Size1 + Size2 + sizeof (CHAR16))/ sizeof (CHAR16);
ba529e7e
ED
621 Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
622 ASSERT (Str != NULL);
623
624 TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
625 ASSERT (TmpStr != NULL);
626
cd32c66f 627 StrCpyS (Str, MaxLen, Str1);
ba529e7e 628 if (!((*Str == '\\') && (*(Str + 1) == 0))) {
cd32c66f 629 StrCatS (Str, MaxLen, L"\\");
ba529e7e
ED
630 }
631
cd32c66f 632 StrCatS (Str, MaxLen, Str2);
ba529e7e
ED
633
634 Ptr = Str;
635 LastSlash = Str;
636 while (*Ptr != 0) {
637 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
638 //
639 // Convert "\Name\..\" to "\"
640 // DO NOT convert the .. if it is at the end of the string. This will
641 // break the .. behavior in changing directories.
642 //
643
644 //
cd32c66f 645 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
ba529e7e
ED
646 // that overlap.
647 //
cd32c66f
DB
648 StrCpyS (TmpStr, MaxLen, Ptr + 3);
649 StrCpyS (LastSlash, MaxLen - (UINTN) (LastSlash - Str), TmpStr);
ba529e7e
ED
650 Ptr = LastSlash;
651 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
652 //
653 // Convert a "\.\" to a "\"
654 //
655
656 //
cd32c66f 657 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
ba529e7e
ED
658 // that overlap.
659 //
cd32c66f
DB
660 StrCpyS (TmpStr, MaxLen, Ptr + 2);
661 StrCpyS (Ptr, MaxLen - (UINTN) (Ptr - Str), TmpStr);
ba529e7e
ED
662 Ptr = LastSlash;
663 } else if (*Ptr == '\\') {
664 LastSlash = Ptr;
665 }
666
667 Ptr++;
668 }
669
670 FreePool (TmpStr);
671
672 return Str;
673}
674
675/**
676 This function build the FsOptionMenu list which records all
677 available file system in the system. They includes all instances
678 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM.
679
680
681 @retval EFI_SUCCESS Success find the file system
682 @retval EFI_OUT_OF_RESOURCES Can not create menu entry
683
684**/
685EFI_STATUS
686LibFindFileSystem (
687 VOID
688 )
689{
690 UINTN NoSimpleFsHandles;
691 UINTN NoLoadFileHandles;
692 EFI_HANDLE *SimpleFsHandle;
693 EFI_HANDLE *LoadFileHandle;
694 UINT16 *VolumeLabel;
695 UINTN Index;
696 EFI_STATUS Status;
697 MENU_ENTRY *MenuEntry;
698 FILE_CONTEXT *FileContext;
699 UINTN OptionNumber;
700 EFI_FILE_SYSTEM_VOLUME_LABEL *Info;
701
702 NoSimpleFsHandles = 0;
703 NoLoadFileHandles = 0;
704 OptionNumber = 0;
705
706 //
707 // Locate Handles that support Simple File System protocol
708 //
709 Status = gBS->LocateHandleBuffer (
710 ByProtocol,
711 &gEfiSimpleFileSystemProtocolGuid,
712 NULL,
713 &NoSimpleFsHandles,
714 &SimpleFsHandle
715 );
716 if (!EFI_ERROR (Status)) {
717 //
718 // Find all the instances of the File System prototocol
719 //
720 for (Index = 0; Index < NoSimpleFsHandles; Index++) {
721 //
722 // Allocate pool for this load option
723 //
724 MenuEntry = LibCreateMenuEntry ();
725 if (NULL == MenuEntry) {
726 FreePool (SimpleFsHandle);
727 return EFI_OUT_OF_RESOURCES;
728 }
729
730 FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
731 FileContext->DeviceHandle = SimpleFsHandle[Index];
732 FileContext->FileHandle = LibOpenRoot (FileContext->DeviceHandle);
733 if (FileContext->FileHandle == NULL) {
734 LibDestroyMenuEntry (MenuEntry);
735 continue;
736 }
737
738 MenuEntry->HelpString = LibDevicePathToStr (DevicePathFromHandle (FileContext->DeviceHandle));
739 FileContext->FileName = LibStrDuplicate (L"\\");
740 FileContext->DevicePath = FileDevicePath (FileContext->DeviceHandle, FileContext->FileName);
741 FileContext->IsDir = TRUE;
742 FileContext->IsRoot = TRUE;
743
744 //
745 // Get current file system's Volume Label
746 //
747 Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) LibFileInfo (FileContext->FileHandle, &gEfiFileSystemVolumeLabelInfoIdGuid);
748 if (Info == NULL) {
749 VolumeLabel = L"NO FILE SYSTEM INFO";
750 } else {
751 if (Info->VolumeLabel == NULL) {
752 VolumeLabel = L"NULL VOLUME LABEL";
753 } else {
754 VolumeLabel = Info->VolumeLabel;
755 if (*VolumeLabel == 0x0000) {
756 VolumeLabel = L"NO VOLUME LABEL";
757 }
758 }
759 }
760 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
761 ASSERT (MenuEntry->DisplayString != NULL);
762 UnicodeSPrint (
763 MenuEntry->DisplayString,
764 MAX_CHAR,
765 L"%s, [%s]",
766 VolumeLabel,
767 MenuEntry->HelpString
768 );
769 MenuEntry->DisplayStringToken = HiiSetString (
770 gFileExplorerPrivate.FeHiiHandle,
771 0,
772 MenuEntry->DisplayString,
773 NULL
774 );
775 FreePool (Info);
776
777 OptionNumber++;
778 InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);
779 }
780 }
781
782 if (NoSimpleFsHandles != 0) {
783 FreePool (SimpleFsHandle);
784 }
785
786 //
787 // Searching for handles that support Load File protocol
788 //
789 Status = gBS->LocateHandleBuffer (
790 ByProtocol,
791 &gEfiLoadFileProtocolGuid,
792 NULL,
793 &NoLoadFileHandles,
794 &LoadFileHandle
795 );
796
797 if (!EFI_ERROR (Status)) {
798 for (Index = 0; Index < NoLoadFileHandles; Index++) {
799 MenuEntry = LibCreateMenuEntry ();
800 if (NULL == MenuEntry) {
801 FreePool (LoadFileHandle);
802 return EFI_OUT_OF_RESOURCES;
803 }
804
805 FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
806 FileContext->DeviceHandle = LoadFileHandle[Index];
807 FileContext->IsRoot = TRUE;
808
809 FileContext->DevicePath = DevicePathFromHandle (FileContext->DeviceHandle);
810 FileContext->FileName = LibDevicePathToStr (FileContext->DevicePath);
811
812 MenuEntry->HelpString = LibDevicePathToStr (FileContext->DevicePath);
813 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
814 ASSERT (MenuEntry->DisplayString != NULL);
815 UnicodeSPrint (
816 MenuEntry->DisplayString,
817 MAX_CHAR,
818 L"Load File [%s]",
819 MenuEntry->HelpString
820 );
821 MenuEntry->DisplayStringToken = HiiSetString (
822 gFileExplorerPrivate.FeHiiHandle,
823 0,
824 MenuEntry->DisplayString,
825 NULL
826 );
827
828 OptionNumber++;
829 InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);
830 }
831 }
832
833 if (NoLoadFileHandles != 0) {
834 FreePool (LoadFileHandle);
835 }
836
837 gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
838
839 return EFI_SUCCESS;
840}
841
842/**
843 Find the file handle from the input menu info.
844
845 @param MenuEntry Input Menu info.
846 @param RetFileHandle Return the file handle for the input device path.
847
848 @retval EFI_SUCESS Find the file handle success.
849 @retval Other Find the file handle failure.
850**/
851EFI_STATUS
852LibGetFileHandleFromMenu (
853 IN MENU_ENTRY *MenuEntry,
854 OUT EFI_FILE_HANDLE *RetFileHandle
855 )
856{
857 EFI_FILE_HANDLE Dir;
858 EFI_FILE_HANDLE NewDir;
859 FILE_CONTEXT *FileContext;
860 EFI_STATUS Status;
861
862 FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
863 Dir = FileContext->FileHandle;
864
865 //
866 // Open current directory to get files from it
867 //
868 Status = Dir->Open (
869 Dir,
870 &NewDir,
871 FileContext->FileName,
872 EFI_FILE_READ_ONLY,
873 0
874 );
875 if (EFI_ERROR (Status)) {
876 return Status;
877 }
878
879 if (!FileContext->IsRoot) {
880 Dir->Close (Dir);
881 }
882
883 *RetFileHandle = NewDir;
884
885 return EFI_SUCCESS;
886}
887
888/**
889 Find the file handle from the input device path info.
890
891 @param RootDirectory Device path info.
892 @param RetFileHandle Return the file handle for the input device path.
893 @param ParentFileName Parent file name.
894 @param DeviceHandle Driver handle for this partition.
895
896 @retval EFI_SUCESS Find the file handle success.
897 @retval Other Find the file handle failure.
898**/
899EFI_STATUS
900LibGetFileHandleFromDevicePath (
901 IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
902 OUT EFI_FILE_HANDLE *RetFileHandle,
903 OUT UINT16 **ParentFileName,
904 OUT EFI_HANDLE *DeviceHandle
905 )
906{
907 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
908 EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
909 EFI_STATUS Status;
910 EFI_HANDLE Handle;
911 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
912 EFI_FILE_HANDLE FileHandle;
913 EFI_FILE_HANDLE LastHandle;
914 CHAR16 *TempPath;
915
916 *ParentFileName = NULL;
917
918 //
919 // Attempt to access the file via a file system interface
920 //
921 DevicePathNode = RootDirectory;
922 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);
923 if (EFI_ERROR (Status)) {
924 return Status;
925 }
926
927 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);
928 if (EFI_ERROR (Status)) {
929 return Status;
930 }
931
932 //
933 // Open the Volume to get the File System handle
934 //
935 Status = Volume->OpenVolume (Volume, &FileHandle);
936 if (EFI_ERROR (Status)) {
937 return Status;
938 }
939
940 *DeviceHandle = Handle;
941
942 if (IsDevicePathEnd(DevicePathNode)) {
943 *ParentFileName = AllocateCopyPool (StrSize (L"\\"), L"\\");
944 *RetFileHandle = FileHandle;
945 return EFI_SUCCESS;
946 }
947
948 //
949 // Duplicate the device path to avoid the access to unaligned device path node.
950 // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
951 // nodes, It assures the fields in device path nodes are 2 byte aligned.
952 //
953 TempDevicePathNode = DuplicateDevicePath (DevicePathNode);
954 if (TempDevicePathNode == NULL) {
955
956 //
957 // Setting Status to an EFI_ERROR value will cause the rest of
958 // the file system support below to be skipped.
959 //
960 Status = EFI_OUT_OF_RESOURCES;
961 }
962
963 //
964 // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
965 // directory information and filename can be seperate. The goal is to inch
966 // our way down each device path node and close the previous node
967 //
968 DevicePathNode = TempDevicePathNode;
969 while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) {
970 if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH ||
971 DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) {
972 Status = EFI_UNSUPPORTED;
973 goto Done;
974 }
975
976 LastHandle = FileHandle;
977 FileHandle = NULL;
978
979 Status = LastHandle->Open (
980 LastHandle,
981 &FileHandle,
982 ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName,
983 EFI_FILE_MODE_READ,
984 0
985 );
986 if (*ParentFileName == NULL) {
987 *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);
988 } else {
989 TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);
990 FreePool (*ParentFileName);
991 *ParentFileName = TempPath;
992 }
993
994 //
995 // Close the previous node
996 //
997 LastHandle->Close (LastHandle);
998
999 DevicePathNode = NextDevicePathNode (DevicePathNode);
1000 }
1001
1002 if (EFI_ERROR (Status)) {
1003 goto Done;
1004 }
1005
1006 *RetFileHandle = FileHandle;
1007
1008 Status = EFI_SUCCESS;
1009
1010Done:
1011 if (TempDevicePathNode != NULL) {
1012 FreePool (TempDevicePathNode);
1013 }
1014
1015 if ((FileHandle != NULL) && (EFI_ERROR (Status))) {
1016 FileHandle->Close (FileHandle);
1017 }
1018
1019 return Status;
1020}
1021
1022/**
1023 Find files under current directory.
1024
1025 All files and sub-directories in current directory
1026 will be stored in DirectoryMenu for future use.
1027
1028 @param FileHandle Parent file handle.
1029 @param FileName Parent file name.
1030 @param DeviceHandle Driver handle for this partition.
1031
1032 @retval EFI_SUCCESS Get files from current dir successfully.
1033 @return Other value if can't get files from current dir.
1034
1035**/
1036EFI_STATUS
1037LibFindFiles (
1038 IN EFI_FILE_HANDLE FileHandle,
1039 IN UINT16 *FileName,
1040 IN EFI_HANDLE DeviceHandle
1041 )
1042{
1043 EFI_FILE_INFO *DirInfo;
1044 UINTN BufferSize;
1045 UINTN DirBufferSize;
1046 MENU_ENTRY *NewMenuEntry;
1047 FILE_CONTEXT *NewFileContext;
1048 UINTN Pass;
1049 EFI_STATUS Status;
1050 UINTN OptionNumber;
1051
1052 OptionNumber = 0;
1053
1054 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
1055 DirInfo = AllocateZeroPool (DirBufferSize);
1056 if (DirInfo == NULL) {
1057 return EFI_OUT_OF_RESOURCES;
1058 }
1059
1060 //
1061 // Get all files in current directory
1062 // Pass 1 to get Directories
1063 // Pass 2 to get files that are EFI images
1064 //
1065 for (Pass = 1; Pass <= 2; Pass++) {
1066 FileHandle->SetPosition (FileHandle, 0);
1067 for (;;) {
1068 BufferSize = DirBufferSize;
1069 Status = FileHandle->Read (FileHandle, &BufferSize, DirInfo);
1070 if (EFI_ERROR (Status) || BufferSize == 0) {
1071 break;
1072 }
1073
1074 if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
1075 ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
1076 ) {
1077 //
1078 // Pass 1 is for Directories
1079 // Pass 2 is for file names
1080 //
1081 continue;
1082 }
1083
1084 if (!((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 || LibIsSupportedFileType (DirInfo->FileName))) {
1085 //
1086 // Slip file unless it is a directory entry or a .EFI file
1087 //
1088 continue;
1089 }
1090
1091 NewMenuEntry = LibCreateMenuEntry ();
1092 if (NULL == NewMenuEntry) {
1093 return EFI_OUT_OF_RESOURCES;
1094 }
1095
1096 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1097 NewFileContext->DeviceHandle = DeviceHandle;
1098 NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName);
1099 NewFileContext->FileHandle = FileHandle;
1100 NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName);
1101 NewMenuEntry->HelpString = NULL;
1102 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
1103
1104 if (NewFileContext->IsDir) {
1105 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
1106 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
1107 UnicodeSPrint (
1108 NewMenuEntry->DisplayString,
1109 BufferSize,
1110 L"<%s>",
1111 DirInfo->FileName
1112 );
1113 } else {
1114 NewMenuEntry->DisplayString = LibStrDuplicate (DirInfo->FileName);
1115 }
1116
1117 NewMenuEntry->DisplayStringToken = HiiSetString (
1118 gFileExplorerPrivate.FeHiiHandle,
1119 0,
1120 NewMenuEntry->DisplayString,
1121 NULL
1122 );
1123
1124 NewFileContext->IsRoot = FALSE;
1125
1126 OptionNumber++;
1127 InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &NewMenuEntry->Link);
1128 }
1129 }
1130
1131 gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
1132
1133 FreePool (DirInfo);
1134
1135 return EFI_SUCCESS;
1136}
1137
1138/**
1139 Refresh the global UpdateData structure.
1140
1141**/
1142VOID
1143LibRefreshUpdateData (
1144 VOID
1145 )
1146{
1147 //
1148 // Free current updated date
1149 //
1150 if (mLibStartOpCodeHandle != NULL) {
1151 HiiFreeOpCodeHandle (mLibStartOpCodeHandle);
1152 }
1153 if (mLibEndOpCodeHandle != NULL) {
1154 HiiFreeOpCodeHandle (mLibEndOpCodeHandle);
1155 }
1156
1157 //
1158 // Create new OpCode Handle
1159 //
1160 mLibStartOpCodeHandle = HiiAllocateOpCodeHandle ();
1161 mLibEndOpCodeHandle = HiiAllocateOpCodeHandle ();
1162
1163 //
1164 // Create Hii Extend Label OpCode as the start opcode
1165 //
1166 mLibStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
1167 mLibStartOpCodeHandle,
1168 &gEfiIfrTianoGuid,
1169 NULL,
1170 sizeof (EFI_IFR_GUID_LABEL)
1171 );
1172 mLibStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1173
1174 mLibStartLabel->Number = FORM_FILE_EXPLORER_ID;
1175
1176 //
1177 // Create Hii Extend Label OpCode as the start opcode
1178 //
1179 mLibEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
1180 mLibEndOpCodeHandle,
1181 &gEfiIfrTianoGuid,
1182 NULL,
1183 sizeof (EFI_IFR_GUID_LABEL)
1184 );
1185 mLibEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1186
1187 mLibEndLabel->Number = LABEL_END;
1188}
1189
1190/**
1191
1192 Update the File Explore page.
1193
1194**/
1195VOID
1196LibUpdateFileExplorePage (
1197 VOID
1198 )
1199{
1200 UINTN Index;
1201 MENU_ENTRY *NewMenuEntry;
1202 FILE_CONTEXT *NewFileContext;
1203 MENU_OPTION *MenuOption;
1204
1205 NewMenuEntry = NULL;
1206 NewFileContext = NULL;
1207
1208 LibRefreshUpdateData ();
1209 MenuOption = gFileExplorerPrivate.FsOptionMenu;
1210
1211 for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
1212 NewMenuEntry = LibGetMenuEntry (MenuOption, Index);
1213 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1214
1215 if (!NewFileContext->IsDir) {
1216 //
1217 // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile.
1218 //
1219 HiiCreateActionOpCode (
1220 mLibStartOpCodeHandle,
1221 (UINT16) (FILE_OPTION_OFFSET + Index),
1222 NewMenuEntry->DisplayStringToken,
1223 STRING_TOKEN (STR_NULL_STRING),
1224 EFI_IFR_FLAG_CALLBACK,
1225 0
1226 );
1227 } else {
1228 //
1229 // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState.
1230 //
1231 HiiCreateGotoOpCode (
1232 mLibStartOpCodeHandle,
1233 FORM_FILE_EXPLORER_ID,
1234 NewMenuEntry->DisplayStringToken,
1235 STRING_TOKEN (STR_NULL_STRING),
1236 EFI_IFR_FLAG_CALLBACK,
1237 (UINT16) (FILE_OPTION_OFFSET + Index)
1238 );
1239 }
1240 }
1241
1242 HiiUpdateForm (
1243 gFileExplorerPrivate.FeHiiHandle,
1244 &FileExplorerGuid,
1245 FORM_FILE_EXPLORER_ID,
1246 mLibStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
1247 mLibEndOpCodeHandle // LABEL_END
1248 );
1249}
1250
1251/**
1252 Update the file explower page with the refershed file system.
1253
1254 @param KeyValue Key value to identify the type of data to expect.
1255
1256 @retval EFI_SUCCESS Update the file explorer form success.
1257 @retval other errors Error occur when parse one directory.
1258
1259**/
1260EFI_STATUS
1261LibUpdateFileExplorer (
1262 IN UINT16 KeyValue
1263 )
1264{
1265 UINT16 FileOptionMask;
1266 MENU_ENTRY *NewMenuEntry;
1267 FILE_CONTEXT *NewFileContext;
1268 EFI_STATUS Status;
1269 EFI_FILE_HANDLE FileHandle;
1270
1271 Status = EFI_SUCCESS;
1272 FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);
1273 NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
1274 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1275
1276 if (NewFileContext->IsDir) {
1277 RemoveEntryList (&NewMenuEntry->Link);
1278 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1279 LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle);
1280 Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle);
1281 if (!EFI_ERROR (Status)) {
1282 LibUpdateFileExplorePage ();
1283 } else {
1284 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1285 }
1286 LibDestroyMenuEntry (NewMenuEntry);
1287 }
1288
1289 return Status;
1290}
1291
1292/**
1293 Get the device path info saved in the menu structure.
1294
1295 @param KeyValue Key value to identify the type of data to expect.
1296
1297**/
1298VOID
1299LibGetDevicePath (
1300 IN UINT16 KeyValue
1301 )
1302{
1303 UINT16 FileOptionMask;
1304 MENU_ENTRY *NewMenuEntry;
1305 FILE_CONTEXT *NewFileContext;
1306
1307 FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);
1308
1309 NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
1310
1311 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1312
1313 if (gFileExplorerPrivate.RetDevicePath != NULL) {
1314 FreePool (gFileExplorerPrivate.RetDevicePath);
1315 }
1316 gFileExplorerPrivate.RetDevicePath = DuplicateDevicePath (NewFileContext->DevicePath);
1317}
1318
1319/**
1320 Choose a file in the specified directory.
1321
1322 If user input NULL for the RootDirectory, will choose file in the system.
1323
1324 If user input *File != NULL, function will return the allocate device path
1325 info for the choosed file, caller has to free the memory after use it.
1326
1327 @param RootDirectory Pointer to the root directory.
1328 @param FileType The file type need to choose.
1329 @param ChooseHandler Function pointer to the extra task need to do
1330 after choose one file.
1331 @param File Return the device path for the last time chosed file.
1332
1333 @retval EFI_SUCESS Choose file success.
1334 @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL
1335 One of them must not NULL.
1336 @retval Other errors Choose file failed.
1337**/
1338EFI_STATUS
1339EFIAPI
1340ChooseFile (
1341 IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
1342 IN CHAR16 *FileType, OPTIONAL
1343 IN CHOOSE_HANDLER ChooseHandler, OPTIONAL
1344 OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL
1345 )
1346{
1347 EFI_FILE_HANDLE FileHandle;
1348 EFI_STATUS Status;
1349 UINT16 *FileName;
1350 EFI_HANDLE DeviceHandle;
1351
1352 if ((ChooseHandler == NULL) && (File == NULL)) {
1353 return EFI_INVALID_PARAMETER;
1354 }
1355
1356 FileName = NULL;
1357
1358 gFileExplorerPrivate.RetDevicePath = NULL;
1359 gFileExplorerPrivate.ChooseHandler = ChooseHandler;
1360 if (FileType != NULL) {
1361 gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType);
1362 LibToLowerString(gFileExplorerPrivate.FileType);
1363 } else {
1364 gFileExplorerPrivate.FileType = NULL;
1365 }
1366
1367 if (RootDirectory == NULL) {
1368 Status = LibFindFileSystem();
1369 } else {
1370 Status = LibGetFileHandleFromDevicePath(RootDirectory, &FileHandle, &FileName, &DeviceHandle);
1371 if (EFI_ERROR (Status)) {
1372 goto Done;
1373 }
1374
1375 Status = LibFindFiles (FileHandle, FileName, DeviceHandle);
1376 }
1377 if (EFI_ERROR (Status)) {
1378 goto Done;
1379 }
1380
1381 LibUpdateFileExplorePage();
1382
1383 gFileExplorerPrivate.FormBrowser2->SendForm (
1384 gFileExplorerPrivate.FormBrowser2,
1385 &gFileExplorerPrivate.FeHiiHandle,
1386 1,
1387 &FileExplorerGuid,
1388 0,
1389 NULL,
1390 NULL
1391 );
1392
1393Done:
1394 if ((Status == EFI_SUCCESS) && (File != NULL)) {
1395 *File = gFileExplorerPrivate.RetDevicePath;
1396 } else if (gFileExplorerPrivate.RetDevicePath != NULL) {
1397 FreePool (gFileExplorerPrivate.RetDevicePath);
1398 }
1399
1400 if (gFileExplorerPrivate.FileType != NULL) {
1401 FreePool (gFileExplorerPrivate.FileType);
1402 }
1403
1404 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1405
1406 if (FileName != NULL) {
1407 FreePool (FileName);
1408 }
1409
1410 return Status;
1411}
1412
1413/**
1414
1415 Install Boot Manager Menu driver.
1416
1417 @param ImageHandle The image handle.
1418 @param SystemTable The system table.
1419
1420 @retval EFI_SUCEESS Install File explorer library success.
1421
1422**/
1423EFI_STATUS
1424EFIAPI
1425FileExplorerLibConstructor (
1426 IN EFI_HANDLE ImageHandle,
1427 IN EFI_SYSTEM_TABLE *SystemTable
1428 )
1429{
1430 EFI_STATUS Status;
1431
1432 gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath);
1433 ASSERT (gHiiVendorDevicePath != NULL);
1434 CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid);
1435
1436 //
1437 // Install Device Path Protocol and Config Access protocol to driver handle
1438 //
1439 Status = gBS->InstallMultipleProtocolInterfaces (
1440 &gFileExplorerPrivate.FeDriverHandle,
1441 &gEfiDevicePathProtocolGuid,
1442 gHiiVendorDevicePath,
1443 &gEfiHiiConfigAccessProtocolGuid,
1444 &gFileExplorerPrivate.FeConfigAccess,
1445 NULL
1446 );
1447 ASSERT_EFI_ERROR (Status);
1448
1449 //
1450 // Post our File Explorer VFR binary to the HII database.
1451 //
1452 gFileExplorerPrivate.FeHiiHandle = HiiAddPackages (
1453 &FileExplorerGuid,
1454 gFileExplorerPrivate.FeDriverHandle,
1455 FileExplorerVfrBin,
1456 FileExplorerLibStrings,
1457 NULL
1458 );
1459 ASSERT (gFileExplorerPrivate.FeHiiHandle != NULL);
1460
1461 //
1462 // Locate Formbrowser2 protocol
1463 //
1464 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFileExplorerPrivate.FormBrowser2);
1465 ASSERT_EFI_ERROR (Status);
1466
1467 InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head);
1468
1469 return EFI_SUCCESS;
1470}
1471
1472/**
1473 Unloads the application and its installed protocol.
1474
1475 @param[in] ImageHandle Handle that identifies the image to be unloaded.
1476 @param[in] SystemTable The system table.
1477
1478 @retval EFI_SUCCESS The image has been unloaded.
1479**/
1480EFI_STATUS
1481EFIAPI
1482FileExplorerLibDestructor (
1483 IN EFI_HANDLE ImageHandle,
1484 IN EFI_SYSTEM_TABLE *SystemTable
1485 )
1486{
1487 EFI_STATUS Status;
1488
1489 ASSERT (gHiiVendorDevicePath != NULL);
1490
1491 Status = gBS->UninstallMultipleProtocolInterfaces (
1492 gFileExplorerPrivate.FeDriverHandle,
1493 &gEfiDevicePathProtocolGuid,
1494 gHiiVendorDevicePath,
1495 &gEfiHiiConfigAccessProtocolGuid,
1496 &gFileExplorerPrivate.FeConfigAccess,
1497 NULL
1498 );
1499 ASSERT_EFI_ERROR (Status);
1500
1501 HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle);
1502
1503 FreePool (gHiiVendorDevicePath);
1504
1505 return EFI_SUCCESS;
1506}
1507