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