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