]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/FileExplorerLib/FileExplorer.c
MdeModulePkg FileExplorerLib: Fix potential Integer Overflow.
[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 ASSERT(TmpStr != NULL);
588 LibToLowerString(TmpStr);
589
590 IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE);
591
592 FreePool (TmpStr);
593 return IsSupported;
594 }
595
596 /**
597
598 Append file name to existing file name.
599
600 @param Str1 The existing file name
601 @param Str2 The file name to be appended
602
603 @return Allocate a new string to hold the appended result.
604 Caller is responsible to free the returned string.
605
606 **/
607 CHAR16 *
608 LibAppendFileName (
609 IN CHAR16 *Str1,
610 IN CHAR16 *Str2
611 )
612 {
613 UINTN Size1;
614 UINTN Size2;
615 UINTN MaxLen;
616 CHAR16 *Str;
617 CHAR16 *TmpStr;
618 CHAR16 *Ptr;
619 CHAR16 *LastSlash;
620
621 Size1 = StrSize (Str1);
622 Size2 = StrSize (Str2);
623
624 //
625 // Check overflow
626 //
627 if (((MAX_UINTN - Size1) < Size2) || ((MAX_UINTN - Size1 - Size2) < sizeof(CHAR16))) {
628 return NULL;
629 }
630
631 MaxLen = (Size1 + Size2 + sizeof (CHAR16))/ sizeof (CHAR16);
632 Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
633 ASSERT (Str != NULL);
634
635 TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
636 ASSERT (TmpStr != NULL);
637
638 StrCpyS (Str, MaxLen, Str1);
639 if (!((*Str == '\\') && (*(Str + 1) == 0))) {
640 StrCatS (Str, MaxLen, L"\\");
641 }
642
643 StrCatS (Str, MaxLen, Str2);
644
645 Ptr = Str;
646 LastSlash = Str;
647 while (*Ptr != 0) {
648 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
649 //
650 // Convert "\Name\..\" to "\"
651 // DO NOT convert the .. if it is at the end of the string. This will
652 // break the .. behavior in changing directories.
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 + 3);
660 StrCpyS (LastSlash, MaxLen - (UINTN) (LastSlash - Str), TmpStr);
661 Ptr = LastSlash;
662 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
663 //
664 // Convert a "\.\" to a "\"
665 //
666
667 //
668 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
669 // that overlap.
670 //
671 StrCpyS (TmpStr, MaxLen, Ptr + 2);
672 StrCpyS (Ptr, MaxLen - (UINTN) (Ptr - Str), TmpStr);
673 Ptr = LastSlash;
674 } else if (*Ptr == '\\') {
675 LastSlash = Ptr;
676 }
677
678 Ptr++;
679 }
680
681 FreePool (TmpStr);
682
683 return Str;
684 }
685
686 /**
687 This function build the FsOptionMenu list which records all
688 available file system in the system. They includes all instances
689 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM.
690
691
692 @retval EFI_SUCCESS Success find the file system
693 @retval EFI_OUT_OF_RESOURCES Can not create menu entry
694
695 **/
696 EFI_STATUS
697 LibFindFileSystem (
698 VOID
699 )
700 {
701 UINTN NoSimpleFsHandles;
702 UINTN NoLoadFileHandles;
703 EFI_HANDLE *SimpleFsHandle;
704 EFI_HANDLE *LoadFileHandle;
705 UINT16 *VolumeLabel;
706 UINTN Index;
707 EFI_STATUS Status;
708 MENU_ENTRY *MenuEntry;
709 FILE_CONTEXT *FileContext;
710 UINTN OptionNumber;
711 EFI_FILE_SYSTEM_VOLUME_LABEL *Info;
712
713 NoSimpleFsHandles = 0;
714 NoLoadFileHandles = 0;
715 OptionNumber = 0;
716
717 //
718 // Locate Handles that support Simple File System protocol
719 //
720 Status = gBS->LocateHandleBuffer (
721 ByProtocol,
722 &gEfiSimpleFileSystemProtocolGuid,
723 NULL,
724 &NoSimpleFsHandles,
725 &SimpleFsHandle
726 );
727 if (!EFI_ERROR (Status)) {
728 //
729 // Find all the instances of the File System prototocol
730 //
731 for (Index = 0; Index < NoSimpleFsHandles; Index++) {
732 //
733 // Allocate pool for this load option
734 //
735 MenuEntry = LibCreateMenuEntry ();
736 if (NULL == MenuEntry) {
737 FreePool (SimpleFsHandle);
738 return EFI_OUT_OF_RESOURCES;
739 }
740
741 FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
742 FileContext->DeviceHandle = SimpleFsHandle[Index];
743 FileContext->FileHandle = LibOpenRoot (FileContext->DeviceHandle);
744 if (FileContext->FileHandle == NULL) {
745 LibDestroyMenuEntry (MenuEntry);
746 continue;
747 }
748
749 MenuEntry->HelpString = LibDevicePathToStr (DevicePathFromHandle (FileContext->DeviceHandle));
750 FileContext->FileName = LibStrDuplicate (L"\\");
751 FileContext->DevicePath = FileDevicePath (FileContext->DeviceHandle, FileContext->FileName);
752 FileContext->IsDir = TRUE;
753 FileContext->IsRoot = TRUE;
754
755 //
756 // Get current file system's Volume Label
757 //
758 Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) LibFileInfo (FileContext->FileHandle, &gEfiFileSystemVolumeLabelInfoIdGuid);
759 if (Info == NULL) {
760 VolumeLabel = L"NO FILE SYSTEM INFO";
761 } else {
762 if (Info->VolumeLabel == NULL) {
763 VolumeLabel = L"NULL VOLUME LABEL";
764 } else {
765 VolumeLabel = Info->VolumeLabel;
766 if (*VolumeLabel == 0x0000) {
767 VolumeLabel = L"NO VOLUME LABEL";
768 }
769 }
770 }
771 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
772 ASSERT (MenuEntry->DisplayString != NULL);
773 UnicodeSPrint (
774 MenuEntry->DisplayString,
775 MAX_CHAR,
776 L"%s, [%s]",
777 VolumeLabel,
778 MenuEntry->HelpString
779 );
780 MenuEntry->DisplayStringToken = HiiSetString (
781 gFileExplorerPrivate.FeHiiHandle,
782 0,
783 MenuEntry->DisplayString,
784 NULL
785 );
786
787 if (Info != NULL)
788 FreePool (Info);
789
790 OptionNumber++;
791 InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);
792 }
793 }
794
795 if (NoSimpleFsHandles != 0) {
796 FreePool (SimpleFsHandle);
797 }
798
799 //
800 // Searching for handles that support Load File protocol
801 //
802 Status = gBS->LocateHandleBuffer (
803 ByProtocol,
804 &gEfiLoadFileProtocolGuid,
805 NULL,
806 &NoLoadFileHandles,
807 &LoadFileHandle
808 );
809
810 if (!EFI_ERROR (Status)) {
811 for (Index = 0; Index < NoLoadFileHandles; Index++) {
812 MenuEntry = LibCreateMenuEntry ();
813 if (NULL == MenuEntry) {
814 FreePool (LoadFileHandle);
815 return EFI_OUT_OF_RESOURCES;
816 }
817
818 FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
819 FileContext->DeviceHandle = LoadFileHandle[Index];
820 FileContext->IsRoot = TRUE;
821
822 FileContext->DevicePath = DevicePathFromHandle (FileContext->DeviceHandle);
823 FileContext->FileName = LibDevicePathToStr (FileContext->DevicePath);
824
825 MenuEntry->HelpString = LibDevicePathToStr (FileContext->DevicePath);
826 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
827 ASSERT (MenuEntry->DisplayString != NULL);
828 UnicodeSPrint (
829 MenuEntry->DisplayString,
830 MAX_CHAR,
831 L"Load File [%s]",
832 MenuEntry->HelpString
833 );
834 MenuEntry->DisplayStringToken = HiiSetString (
835 gFileExplorerPrivate.FeHiiHandle,
836 0,
837 MenuEntry->DisplayString,
838 NULL
839 );
840
841 OptionNumber++;
842 InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);
843 }
844 }
845
846 if (NoLoadFileHandles != 0) {
847 FreePool (LoadFileHandle);
848 }
849
850 gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
851
852 return EFI_SUCCESS;
853 }
854
855 /**
856 Find the file handle from the input menu info.
857
858 @param MenuEntry Input Menu info.
859 @param RetFileHandle Return the file handle for the input device path.
860
861 @retval EFI_SUCESS Find the file handle success.
862 @retval Other Find the file handle failure.
863 **/
864 EFI_STATUS
865 LibGetFileHandleFromMenu (
866 IN MENU_ENTRY *MenuEntry,
867 OUT EFI_FILE_HANDLE *RetFileHandle
868 )
869 {
870 EFI_FILE_HANDLE Dir;
871 EFI_FILE_HANDLE NewDir;
872 FILE_CONTEXT *FileContext;
873 EFI_STATUS Status;
874
875 FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
876 Dir = FileContext->FileHandle;
877
878 //
879 // Open current directory to get files from it
880 //
881 Status = Dir->Open (
882 Dir,
883 &NewDir,
884 FileContext->FileName,
885 EFI_FILE_READ_ONLY,
886 0
887 );
888 if (EFI_ERROR (Status)) {
889 return Status;
890 }
891
892 if (!FileContext->IsRoot) {
893 Dir->Close (Dir);
894 }
895
896 *RetFileHandle = NewDir;
897
898 return EFI_SUCCESS;
899 }
900
901 /**
902 Find the file handle from the input device path info.
903
904 @param RootDirectory Device path info.
905 @param RetFileHandle Return the file handle for the input device path.
906 @param ParentFileName Parent file name.
907 @param DeviceHandle Driver handle for this partition.
908
909 @retval EFI_SUCESS Find the file handle success.
910 @retval Other Find the file handle failure.
911 **/
912 EFI_STATUS
913 LibGetFileHandleFromDevicePath (
914 IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
915 OUT EFI_FILE_HANDLE *RetFileHandle,
916 OUT UINT16 **ParentFileName,
917 OUT EFI_HANDLE *DeviceHandle
918 )
919 {
920 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
921 EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
922 EFI_STATUS Status;
923 EFI_HANDLE Handle;
924 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
925 EFI_FILE_HANDLE FileHandle;
926 EFI_FILE_HANDLE LastHandle;
927 CHAR16 *TempPath;
928
929 *ParentFileName = NULL;
930
931 //
932 // Attempt to access the file via a file system interface
933 //
934 DevicePathNode = RootDirectory;
935 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);
936 if (EFI_ERROR (Status)) {
937 return Status;
938 }
939
940 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);
941 if (EFI_ERROR (Status)) {
942 return Status;
943 }
944
945 //
946 // Open the Volume to get the File System handle
947 //
948 Status = Volume->OpenVolume (Volume, &FileHandle);
949 if (EFI_ERROR (Status)) {
950 return Status;
951 }
952
953 *DeviceHandle = Handle;
954
955 if (IsDevicePathEnd(DevicePathNode)) {
956 *ParentFileName = AllocateCopyPool (StrSize (L"\\"), L"\\");
957 *RetFileHandle = FileHandle;
958 return EFI_SUCCESS;
959 }
960
961 //
962 // Duplicate the device path to avoid the access to unaligned device path node.
963 // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
964 // nodes, It assures the fields in device path nodes are 2 byte aligned.
965 //
966 TempDevicePathNode = DuplicateDevicePath (DevicePathNode);
967 if (TempDevicePathNode == NULL) {
968
969 //
970 // Setting Status to an EFI_ERROR value will cause the rest of
971 // the file system support below to be skipped.
972 //
973 Status = EFI_OUT_OF_RESOURCES;
974 goto Done;
975 }
976
977 //
978 // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
979 // directory information and filename can be seperate. The goal is to inch
980 // our way down each device path node and close the previous node
981 //
982 DevicePathNode = TempDevicePathNode;
983 while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) {
984 if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH ||
985 DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) {
986 Status = EFI_UNSUPPORTED;
987 goto Done;
988 }
989
990 LastHandle = FileHandle;
991 FileHandle = NULL;
992
993 Status = LastHandle->Open (
994 LastHandle,
995 &FileHandle,
996 ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName,
997 EFI_FILE_MODE_READ,
998 0
999 );
1000 if (*ParentFileName == NULL) {
1001 *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);
1002 } else {
1003 TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);
1004 if (TempPath == NULL) {
1005 LastHandle->Close (LastHandle);
1006 Status = EFI_OUT_OF_RESOURCES;
1007 goto Done;
1008 }
1009 FreePool (*ParentFileName);
1010 *ParentFileName = TempPath;
1011 }
1012
1013 //
1014 // Close the previous node
1015 //
1016 LastHandle->Close (LastHandle);
1017
1018 DevicePathNode = NextDevicePathNode (DevicePathNode);
1019 }
1020
1021 if (EFI_ERROR (Status)) {
1022 goto Done;
1023 }
1024
1025 *RetFileHandle = FileHandle;
1026
1027 Status = EFI_SUCCESS;
1028
1029 Done:
1030 if (TempDevicePathNode != NULL) {
1031 FreePool (TempDevicePathNode);
1032 }
1033
1034 if ((FileHandle != NULL) && (EFI_ERROR (Status))) {
1035 FileHandle->Close (FileHandle);
1036 }
1037
1038 return Status;
1039 }
1040
1041 /**
1042 Find files under current directory.
1043
1044 All files and sub-directories in current directory
1045 will be stored in DirectoryMenu for future use.
1046
1047 @param FileHandle Parent file handle.
1048 @param FileName Parent file name.
1049 @param DeviceHandle Driver handle for this partition.
1050
1051 @retval EFI_SUCCESS Get files from current dir successfully.
1052 @return Other value if can't get files from current dir.
1053
1054 **/
1055 EFI_STATUS
1056 LibFindFiles (
1057 IN EFI_FILE_HANDLE FileHandle,
1058 IN UINT16 *FileName,
1059 IN EFI_HANDLE DeviceHandle
1060 )
1061 {
1062 EFI_FILE_INFO *DirInfo;
1063 UINTN BufferSize;
1064 UINTN DirBufferSize;
1065 MENU_ENTRY *NewMenuEntry;
1066 FILE_CONTEXT *NewFileContext;
1067 UINTN Pass;
1068 EFI_STATUS Status;
1069 UINTN OptionNumber;
1070
1071 OptionNumber = 0;
1072
1073 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
1074 DirInfo = AllocateZeroPool (DirBufferSize);
1075 if (DirInfo == NULL) {
1076 return EFI_OUT_OF_RESOURCES;
1077 }
1078
1079 //
1080 // Get all files in current directory
1081 // Pass 1 to get Directories
1082 // Pass 2 to get files that are EFI images
1083 //
1084 Status = EFI_SUCCESS;
1085 for (Pass = 1; Pass <= 2; Pass++) {
1086 FileHandle->SetPosition (FileHandle, 0);
1087 for (;;) {
1088 BufferSize = DirBufferSize;
1089 Status = FileHandle->Read (FileHandle, &BufferSize, DirInfo);
1090 if (EFI_ERROR (Status) || BufferSize == 0) {
1091 Status = EFI_SUCCESS;
1092 break;
1093 }
1094
1095 if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
1096 ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
1097 ) {
1098 //
1099 // Pass 1 is for Directories
1100 // Pass 2 is for file names
1101 //
1102 continue;
1103 }
1104
1105 if (!((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 || LibIsSupportedFileType (DirInfo->FileName))) {
1106 //
1107 // Slip file unless it is a directory entry or a .EFI file
1108 //
1109 continue;
1110 }
1111
1112 NewMenuEntry = LibCreateMenuEntry ();
1113 if (NULL == NewMenuEntry) {
1114 Status = EFI_OUT_OF_RESOURCES;
1115 goto Done;
1116 }
1117
1118 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1119 NewFileContext->DeviceHandle = DeviceHandle;
1120 NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName);
1121 if (NewFileContext->FileName == NULL) {
1122 LibDestroyMenuEntry (NewMenuEntry);
1123 Status = EFI_OUT_OF_RESOURCES;
1124 goto Done;
1125 }
1126 NewFileContext->FileHandle = FileHandle;
1127 NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName);
1128 NewMenuEntry->HelpString = NULL;
1129 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
1130
1131 if (NewFileContext->IsDir) {
1132 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
1133 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
1134 UnicodeSPrint (
1135 NewMenuEntry->DisplayString,
1136 BufferSize,
1137 L"<%s>",
1138 DirInfo->FileName
1139 );
1140 } else {
1141 NewMenuEntry->DisplayString = LibStrDuplicate (DirInfo->FileName);
1142 }
1143
1144 NewMenuEntry->DisplayStringToken = HiiSetString (
1145 gFileExplorerPrivate.FeHiiHandle,
1146 0,
1147 NewMenuEntry->DisplayString,
1148 NULL
1149 );
1150
1151 NewFileContext->IsRoot = FALSE;
1152
1153 OptionNumber++;
1154 InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &NewMenuEntry->Link);
1155 }
1156 }
1157
1158 gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
1159
1160 Done:
1161
1162 FreePool (DirInfo);
1163
1164 return Status;
1165 }
1166
1167 /**
1168 Refresh the global UpdateData structure.
1169
1170 **/
1171 VOID
1172 LibRefreshUpdateData (
1173 VOID
1174 )
1175 {
1176 //
1177 // Free current updated date
1178 //
1179 if (mLibStartOpCodeHandle != NULL) {
1180 HiiFreeOpCodeHandle (mLibStartOpCodeHandle);
1181 }
1182 if (mLibEndOpCodeHandle != NULL) {
1183 HiiFreeOpCodeHandle (mLibEndOpCodeHandle);
1184 }
1185
1186 //
1187 // Create new OpCode Handle
1188 //
1189 mLibStartOpCodeHandle = HiiAllocateOpCodeHandle ();
1190 mLibEndOpCodeHandle = HiiAllocateOpCodeHandle ();
1191
1192 //
1193 // Create Hii Extend Label OpCode as the start opcode
1194 //
1195 mLibStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
1196 mLibStartOpCodeHandle,
1197 &gEfiIfrTianoGuid,
1198 NULL,
1199 sizeof (EFI_IFR_GUID_LABEL)
1200 );
1201 mLibStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1202
1203 mLibStartLabel->Number = FORM_FILE_EXPLORER_ID;
1204
1205 //
1206 // Create Hii Extend Label OpCode as the start opcode
1207 //
1208 mLibEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
1209 mLibEndOpCodeHandle,
1210 &gEfiIfrTianoGuid,
1211 NULL,
1212 sizeof (EFI_IFR_GUID_LABEL)
1213 );
1214 mLibEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1215
1216 mLibEndLabel->Number = LABEL_END;
1217 }
1218
1219 /**
1220
1221 Update the File Explore page.
1222
1223 **/
1224 VOID
1225 LibUpdateFileExplorePage (
1226 VOID
1227 )
1228 {
1229 UINTN Index;
1230 MENU_ENTRY *NewMenuEntry;
1231 FILE_CONTEXT *NewFileContext;
1232 MENU_OPTION *MenuOption;
1233
1234 NewMenuEntry = NULL;
1235 NewFileContext = NULL;
1236
1237 LibRefreshUpdateData ();
1238 MenuOption = gFileExplorerPrivate.FsOptionMenu;
1239
1240 for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
1241 NewMenuEntry = LibGetMenuEntry (MenuOption, Index);
1242 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1243
1244 if (!NewFileContext->IsDir) {
1245 //
1246 // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile.
1247 //
1248 HiiCreateActionOpCode (
1249 mLibStartOpCodeHandle,
1250 (UINT16) (FILE_OPTION_OFFSET + Index),
1251 NewMenuEntry->DisplayStringToken,
1252 STRING_TOKEN (STR_NULL_STRING),
1253 EFI_IFR_FLAG_CALLBACK,
1254 0
1255 );
1256 } else {
1257 //
1258 // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState.
1259 //
1260 HiiCreateGotoOpCode (
1261 mLibStartOpCodeHandle,
1262 FORM_FILE_EXPLORER_ID,
1263 NewMenuEntry->DisplayStringToken,
1264 STRING_TOKEN (STR_NULL_STRING),
1265 EFI_IFR_FLAG_CALLBACK,
1266 (UINT16) (FILE_OPTION_OFFSET + Index)
1267 );
1268 }
1269 }
1270
1271 HiiUpdateForm (
1272 gFileExplorerPrivate.FeHiiHandle,
1273 &FileExplorerGuid,
1274 FORM_FILE_EXPLORER_ID,
1275 mLibStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
1276 mLibEndOpCodeHandle // LABEL_END
1277 );
1278 }
1279
1280 /**
1281 Update the file explower page with the refershed file system.
1282
1283 @param KeyValue Key value to identify the type of data to expect.
1284
1285 @retval EFI_SUCCESS Update the file explorer form success.
1286 @retval other errors Error occur when parse one directory.
1287
1288 **/
1289 EFI_STATUS
1290 LibUpdateFileExplorer (
1291 IN UINT16 KeyValue
1292 )
1293 {
1294 UINT16 FileOptionMask;
1295 MENU_ENTRY *NewMenuEntry;
1296 FILE_CONTEXT *NewFileContext;
1297 EFI_STATUS Status;
1298 EFI_FILE_HANDLE FileHandle;
1299
1300 Status = EFI_SUCCESS;
1301 FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);
1302 NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
1303 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1304
1305 if (NewFileContext->IsDir) {
1306 RemoveEntryList (&NewMenuEntry->Link);
1307 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1308 LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle);
1309 Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle);
1310 if (!EFI_ERROR (Status)) {
1311 LibUpdateFileExplorePage ();
1312 } else {
1313 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1314 }
1315 LibDestroyMenuEntry (NewMenuEntry);
1316 }
1317
1318 return Status;
1319 }
1320
1321 /**
1322 Get the device path info saved in the menu structure.
1323
1324 @param KeyValue Key value to identify the type of data to expect.
1325
1326 **/
1327 VOID
1328 LibGetDevicePath (
1329 IN UINT16 KeyValue
1330 )
1331 {
1332 UINT16 FileOptionMask;
1333 MENU_ENTRY *NewMenuEntry;
1334 FILE_CONTEXT *NewFileContext;
1335
1336 FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);
1337
1338 NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
1339
1340 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1341
1342 if (gFileExplorerPrivate.RetDevicePath != NULL) {
1343 FreePool (gFileExplorerPrivate.RetDevicePath);
1344 }
1345 gFileExplorerPrivate.RetDevicePath = DuplicateDevicePath (NewFileContext->DevicePath);
1346 }
1347
1348 /**
1349 Choose a file in the specified directory.
1350
1351 If user input NULL for the RootDirectory, will choose file in the system.
1352
1353 If user input *File != NULL, function will return the allocate device path
1354 info for the choosed file, caller has to free the memory after use it.
1355
1356 @param RootDirectory Pointer to the root directory.
1357 @param FileType The file type need to choose.
1358 @param ChooseHandler Function pointer to the extra task need to do
1359 after choose one file.
1360 @param File Return the device path for the last time chosed file.
1361
1362 @retval EFI_SUCESS Choose file success.
1363 @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL
1364 One of them must not NULL.
1365 @retval Other errors Choose file failed.
1366 **/
1367 EFI_STATUS
1368 EFIAPI
1369 ChooseFile (
1370 IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
1371 IN CHAR16 *FileType, OPTIONAL
1372 IN CHOOSE_HANDLER ChooseHandler, OPTIONAL
1373 OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL
1374 )
1375 {
1376 EFI_FILE_HANDLE FileHandle;
1377 EFI_STATUS Status;
1378 UINT16 *FileName;
1379 EFI_HANDLE DeviceHandle;
1380
1381 if ((ChooseHandler == NULL) && (File == NULL)) {
1382 return EFI_INVALID_PARAMETER;
1383 }
1384
1385 FileName = NULL;
1386
1387 gFileExplorerPrivate.RetDevicePath = NULL;
1388 gFileExplorerPrivate.ChooseHandler = ChooseHandler;
1389 if (FileType != NULL) {
1390 gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType);
1391 ASSERT(gFileExplorerPrivate.FileType != NULL);
1392 LibToLowerString(gFileExplorerPrivate.FileType);
1393 } else {
1394 gFileExplorerPrivate.FileType = NULL;
1395 }
1396
1397 if (RootDirectory == NULL) {
1398 Status = LibFindFileSystem();
1399 } else {
1400 Status = LibGetFileHandleFromDevicePath(RootDirectory, &FileHandle, &FileName, &DeviceHandle);
1401 if (EFI_ERROR (Status)) {
1402 goto Done;
1403 }
1404
1405 Status = LibFindFiles (FileHandle, FileName, DeviceHandle);
1406 }
1407 if (EFI_ERROR (Status)) {
1408 goto Done;
1409 }
1410
1411 LibUpdateFileExplorePage();
1412
1413 gFileExplorerPrivate.FormBrowser2->SendForm (
1414 gFileExplorerPrivate.FormBrowser2,
1415 &gFileExplorerPrivate.FeHiiHandle,
1416 1,
1417 &FileExplorerGuid,
1418 0,
1419 NULL,
1420 NULL
1421 );
1422
1423 Done:
1424 if ((Status == EFI_SUCCESS) && (File != NULL)) {
1425 *File = gFileExplorerPrivate.RetDevicePath;
1426 } else if (gFileExplorerPrivate.RetDevicePath != NULL) {
1427 FreePool (gFileExplorerPrivate.RetDevicePath);
1428 }
1429
1430 if (gFileExplorerPrivate.FileType != NULL) {
1431 FreePool (gFileExplorerPrivate.FileType);
1432 }
1433
1434 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1435
1436 if (FileName != NULL) {
1437 FreePool (FileName);
1438 }
1439
1440 return Status;
1441 }
1442
1443 /**
1444
1445 Install Boot Manager Menu driver.
1446
1447 @param ImageHandle The image handle.
1448 @param SystemTable The system table.
1449
1450 @retval EFI_SUCEESS Install File explorer library success.
1451
1452 **/
1453 EFI_STATUS
1454 EFIAPI
1455 FileExplorerLibConstructor (
1456 IN EFI_HANDLE ImageHandle,
1457 IN EFI_SYSTEM_TABLE *SystemTable
1458 )
1459 {
1460 EFI_STATUS Status;
1461
1462 gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath);
1463 ASSERT (gHiiVendorDevicePath != NULL);
1464 CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid);
1465
1466 //
1467 // Install Device Path Protocol and Config Access protocol to driver handle
1468 //
1469 Status = gBS->InstallMultipleProtocolInterfaces (
1470 &gFileExplorerPrivate.FeDriverHandle,
1471 &gEfiDevicePathProtocolGuid,
1472 gHiiVendorDevicePath,
1473 &gEfiHiiConfigAccessProtocolGuid,
1474 &gFileExplorerPrivate.FeConfigAccess,
1475 NULL
1476 );
1477 if (Status == EFI_ALREADY_STARTED) {
1478 return EFI_SUCCESS;
1479 }
1480 if (EFI_ERROR (Status)) {
1481 return Status;
1482 }
1483
1484 //
1485 // Post our File Explorer VFR binary to the HII database.
1486 //
1487 gFileExplorerPrivate.FeHiiHandle = HiiAddPackages (
1488 &FileExplorerGuid,
1489 gFileExplorerPrivate.FeDriverHandle,
1490 FileExplorerVfrBin,
1491 FileExplorerLibStrings,
1492 NULL
1493 );
1494 ASSERT (gFileExplorerPrivate.FeHiiHandle != NULL);
1495
1496 //
1497 // Locate Formbrowser2 protocol
1498 //
1499 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFileExplorerPrivate.FormBrowser2);
1500 ASSERT_EFI_ERROR (Status);
1501
1502 InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head);
1503
1504 return EFI_SUCCESS;
1505 }
1506
1507 /**
1508 Unloads the application and its installed protocol.
1509
1510 @param[in] ImageHandle Handle that identifies the image to be unloaded.
1511 @param[in] SystemTable The system table.
1512
1513 @retval EFI_SUCCESS The image has been unloaded.
1514 **/
1515 EFI_STATUS
1516 EFIAPI
1517 FileExplorerLibDestructor (
1518 IN EFI_HANDLE ImageHandle,
1519 IN EFI_SYSTEM_TABLE *SystemTable
1520 )
1521 {
1522 EFI_STATUS Status;
1523
1524 ASSERT (gHiiVendorDevicePath != NULL);
1525
1526 if (gFileExplorerPrivate.FeDriverHandle != NULL) {
1527 Status = gBS->UninstallMultipleProtocolInterfaces (
1528 gFileExplorerPrivate.FeDriverHandle,
1529 &gEfiDevicePathProtocolGuid,
1530 gHiiVendorDevicePath,
1531 &gEfiHiiConfigAccessProtocolGuid,
1532 &gFileExplorerPrivate.FeConfigAccess,
1533 NULL
1534 );
1535 ASSERT_EFI_ERROR (Status);
1536
1537 HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle);
1538 }
1539
1540 FreePool (gHiiVendorDevicePath);
1541
1542 return EFI_SUCCESS;
1543 }
1544