• 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     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
LibFreeMenu(MENU_OPTION * FreeMenu)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
LibOpenRoot(IN EFI_HANDLE DeviceHandle)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 *
LibDevicePathToStr(IN EFI_DEVICE_PATH_PROTOCOL * DevPath)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 *
LibStrDuplicate(IN CHAR16 * Src)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 *
LibFileInfo(IN EFI_FILE_HANDLE FHand,IN EFI_GUID * InfoType)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*
LibGetTypeFromName(IN CHAR16 * FileName)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
LibToLowerString(IN CHAR16 * String)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
LibIsSupportedFileType(IN UINT16 * FileName)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 *
LibAppendFileName(IN CHAR16 * Str1,IN CHAR16 * Str2)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
LibFindFileSystem(VOID)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
LibGetFileHandleFromMenu(IN MENU_ENTRY * MenuEntry,OUT EFI_FILE_HANDLE * RetFileHandle)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
LibGetFileHandleFromDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * RootDirectory,OUT EFI_FILE_HANDLE * RetFileHandle,OUT UINT16 ** ParentFileName,OUT EFI_HANDLE * DeviceHandle)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
LibFindFiles(IN EFI_FILE_HANDLE FileHandle,IN UINT16 * FileName,IN EFI_HANDLE DeviceHandle)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
LibRefreshUpdateData(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
LibUpdateFileExplorePage(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
LibUpdateFileExplorer(IN UINT16 KeyValue)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
LibGetDevicePath(IN UINT16 KeyValue)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
ChooseFile(IN EFI_DEVICE_PATH_PROTOCOL * RootDirectory,IN CHAR16 * FileType,OPTIONAL IN CHOOSE_HANDLER ChooseHandler,OPTIONAL OUT EFI_DEVICE_PATH_PROTOCOL ** File OPTIONAL)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
FileExplorerLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
FileExplorerLibDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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 
1545