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