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