]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/FileExplorerLib/FileExplorer.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Library / FileExplorerLib / FileExplorer.c
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 #include "FileExplorer.h"
10
11 EFI_GUID FileExplorerGuid = EFI_FILE_EXPLORE_FORMSET_GUID;
12
13 ///
14 /// File system selection menu
15 ///
16 MENU_OPTION mFsOptionMenu = {
17 MENU_OPTION_SIGNATURE,
18 { NULL },
19 0,
20 FALSE
21 };
22
23 FILE_EXPLORER_CALLBACK_DATA gFileExplorerPrivate = {
24 FILE_EXPLORER_CALLBACK_DATA_SIGNATURE,
25 NULL,
26 NULL,
27 {
28 LibExtractConfig,
29 LibRouteConfig,
30 LibCallback
31 },
32 NULL,
33 &mFsOptionMenu,
34 0
35 };
36
37 HII_VENDOR_DEVICE_PATH *gHiiVendorDevicePath;
38
39 HII_VENDOR_DEVICE_PATH FeHiiVendorDevicePath = {
40 {
41 {
42 HARDWARE_DEVICE_PATH,
43 HW_VENDOR_DP,
44 {
45 (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
46 (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
47 }
48 },
49 //
50 // Will be replace with gEfiCallerIdGuid in code.
51 //
52 { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
53 }
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
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
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
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
276 if (QuestionId >= FILE_OPTION_OFFSET) {
277 LibGetDevicePath (QuestionId);
278 Status = LibUpdateFileExplorer (QuestionId);
279 if (EFI_ERROR (Status)) {
280 return Status;
281 }
282 }
283 }
284
285 return EFI_SUCCESS;
286 }
287
288 /**
289 Create a menu entry by given menu type.
290
291 @retval NULL If failed to create the menu.
292 @return the new menu entry.
293
294 **/
295 MENU_ENTRY *
296 LibCreateMenuEntry (
297 VOID
298 )
299 {
300 MENU_ENTRY *MenuEntry;
301
302 //
303 // Create new menu entry
304 //
305 MenuEntry = AllocateZeroPool (sizeof (MENU_ENTRY));
306 if (MenuEntry == NULL) {
307 return NULL;
308 }
309
310 MenuEntry->VariableContext = AllocateZeroPool (sizeof (FILE_CONTEXT));
311 if (MenuEntry->VariableContext == NULL) {
312 FreePool (MenuEntry);
313 return NULL;
314 }
315
316 MenuEntry->Signature = MENU_ENTRY_SIGNATURE;
317 return MenuEntry;
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 *
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
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
389 if (MenuEntry->HelpString != NULL) {
390 FreePool (MenuEntry->HelpString);
391 }
392
393 FreePool (MenuEntry);
394 }
395
396 /**
397 Free resources allocated in Allocate Rountine.
398
399 @param FreeMenu Menu to be freed
400 **/
401 VOID
402 LibFreeMenu (
403 MENU_OPTION *FreeMenu
404 )
405 {
406 MENU_ENTRY *MenuEntry;
407
408 while (!IsListEmpty (&FreeMenu->Head)) {
409 MenuEntry = CR (
410 FreeMenu->Head.ForwardLink,
411 MENU_ENTRY,
412 Link,
413 MENU_ENTRY_SIGNATURE
414 );
415 RemoveEntryList (&MenuEntry->Link);
416 LibDestroyMenuEntry (MenuEntry);
417 }
418
419 FreeMenu->MenuNumber = 0;
420 }
421
422 /**
423
424 Function opens and returns a file handle to the root directory of a volume.
425
426 @param DeviceHandle A handle for a device
427
428 @return A valid file handle or NULL is returned
429
430 **/
431 EFI_FILE_HANDLE
432 LibOpenRoot (
433 IN EFI_HANDLE DeviceHandle
434 )
435 {
436 EFI_STATUS Status;
437 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
438 EFI_FILE_HANDLE File;
439
440 File = NULL;
441
442 //
443 // File the file system interface to the device
444 //
445 Status = gBS->HandleProtocol (
446 DeviceHandle,
447 &gEfiSimpleFileSystemProtocolGuid,
448 (VOID *)&Volume
449 );
450
451 //
452 // Open the root directory of the volume
453 //
454 if (!EFI_ERROR (Status)) {
455 Status = Volume->OpenVolume (
456 Volume,
457 &File
458 );
459 }
460
461 //
462 // Done
463 //
464 return EFI_ERROR (Status) ? NULL : File;
465 }
466
467 /**
468 This function converts an input device structure to a Unicode string.
469
470 @param DevPath A pointer to the device path structure.
471
472 @return A new allocated Unicode string that represents the device path.
473
474 **/
475 CHAR16 *
476 LibDevicePathToStr (
477 IN EFI_DEVICE_PATH_PROTOCOL *DevPath
478 )
479 {
480 EFI_STATUS Status;
481 CHAR16 *ToText;
482 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
483
484 if (DevPath == NULL) {
485 return NULL;
486 }
487
488 Status = gBS->LocateProtocol (
489 &gEfiDevicePathToTextProtocolGuid,
490 NULL,
491 (VOID **)&DevPathToText
492 );
493 ASSERT_EFI_ERROR (Status);
494 ToText = DevPathToText->ConvertDevicePathToText (
495 DevPath,
496 FALSE,
497 TRUE
498 );
499 ASSERT (ToText != NULL);
500
501 return ToText;
502 }
503
504 /**
505 Duplicate a string.
506
507 @param Src The source.
508
509 @return A new string which is duplicated copy of the source.
510 @retval NULL If there is not enough memory.
511
512 **/
513 CHAR16 *
514 LibStrDuplicate (
515 IN CHAR16 *Src
516 )
517 {
518 CHAR16 *Dest;
519 UINTN Size;
520
521 Size = StrSize (Src);
522 Dest = AllocateZeroPool (Size);
523 ASSERT (Dest != NULL);
524 if (Dest != NULL) {
525 CopyMem (Dest, Src, Size);
526 }
527
528 return Dest;
529 }
530
531 /**
532
533 Function gets the file information from an open file descriptor, and stores it
534 in a buffer allocated from pool.
535
536 @param FHand File Handle.
537 @param InfoType Info type need to get.
538
539 @retval A pointer to a buffer with file information or NULL is returned
540
541 **/
542 VOID *
543 LibFileInfo (
544 IN EFI_FILE_HANDLE FHand,
545 IN EFI_GUID *InfoType
546 )
547 {
548 EFI_STATUS Status;
549 EFI_FILE_INFO *Buffer;
550 UINTN BufferSize;
551
552 Buffer = NULL;
553 BufferSize = 0;
554
555 Status = FHand->GetInfo (
556 FHand,
557 InfoType,
558 &BufferSize,
559 Buffer
560 );
561 if (Status == EFI_BUFFER_TOO_SMALL) {
562 Buffer = AllocatePool (BufferSize);
563 ASSERT (Buffer != NULL);
564 }
565
566 Status = FHand->GetInfo (
567 FHand,
568 InfoType,
569 &BufferSize,
570 Buffer
571 );
572
573 return Buffer;
574 }
575
576 /**
577
578 Get file type base on the file name.
579 Just cut the file name, from the ".". eg ".efi"
580
581 @param FileName File need to be checked.
582
583 @retval the file type string.
584
585 **/
586 CHAR16 *
587 LibGetTypeFromName (
588 IN CHAR16 *FileName
589 )
590 {
591 UINTN Index;
592
593 Index = StrLen (FileName) - 1;
594 while ((FileName[Index] != L'.') && (Index != 0)) {
595 Index--;
596 }
597
598 return Index == 0 ? NULL : &FileName[Index];
599 }
600
601 /**
602 Converts the unicode character of the string from uppercase to lowercase.
603 This is a internal function.
604
605 @param ConfigString String to be converted
606
607 **/
608 VOID
609 LibToLowerString (
610 IN CHAR16 *String
611 )
612 {
613 CHAR16 *TmpStr;
614
615 for (TmpStr = String; *TmpStr != L'\0'; TmpStr++) {
616 if ((*TmpStr >= L'A') && (*TmpStr <= L'Z')) {
617 *TmpStr = (CHAR16)(*TmpStr - L'A' + L'a');
618 }
619 }
620 }
621
622 /**
623
624 Check whether current FileName point to a valid
625 Efi Image File.
626
627 @param FileName File need to be checked.
628
629 @retval TRUE Is Efi Image
630 @retval FALSE Not a valid Efi Image
631
632 **/
633 BOOLEAN
634 LibIsSupportedFileType (
635 IN UINT16 *FileName
636 )
637 {
638 CHAR16 *InputFileType;
639 CHAR16 *TmpStr;
640 BOOLEAN IsSupported;
641
642 if (gFileExplorerPrivate.FileType == NULL) {
643 return TRUE;
644 }
645
646 InputFileType = LibGetTypeFromName (FileName);
647 //
648 // If the file not has *.* style, always return TRUE.
649 //
650 if (InputFileType == NULL) {
651 return TRUE;
652 }
653
654 TmpStr = AllocateCopyPool (StrSize (InputFileType), InputFileType);
655 ASSERT (TmpStr != NULL);
656 LibToLowerString (TmpStr);
657
658 IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE);
659
660 FreePool (TmpStr);
661 return IsSupported;
662 }
663
664 /**
665
666 Append file name to existing file name.
667
668 @param Str1 The existing file name
669 @param Str2 The file name to be appended
670
671 @return Allocate a new string to hold the appended result.
672 Caller is responsible to free the returned string.
673
674 **/
675 CHAR16 *
676 LibAppendFileName (
677 IN CHAR16 *Str1,
678 IN CHAR16 *Str2
679 )
680 {
681 UINTN Size1;
682 UINTN Size2;
683 UINTN MaxLen;
684 CHAR16 *Str;
685 CHAR16 *TmpStr;
686 CHAR16 *Ptr;
687 CHAR16 *LastSlash;
688
689 Size1 = StrSize (Str1);
690 Size2 = StrSize (Str2);
691
692 //
693 // Check overflow
694 //
695 if (((MAX_UINTN - Size1) < Size2) || ((MAX_UINTN - Size1 - Size2) < sizeof (CHAR16))) {
696 return NULL;
697 }
698
699 MaxLen = (Size1 + Size2 + sizeof (CHAR16))/ sizeof (CHAR16);
700 Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
701 ASSERT (Str != NULL);
702
703 TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
704 ASSERT (TmpStr != NULL);
705
706 StrCpyS (Str, MaxLen, Str1);
707 if (!((*Str == '\\') && (*(Str + 1) == 0))) {
708 StrCatS (Str, MaxLen, L"\\");
709 }
710
711 StrCatS (Str, MaxLen, Str2);
712
713 Ptr = Str;
714 LastSlash = Str;
715 while (*Ptr != 0) {
716 if ((*Ptr == '\\') && (*(Ptr + 1) == '.') && (*(Ptr + 2) == '.') && (*(Ptr + 3) == L'\\')) {
717 //
718 // Convert "\Name\..\" to "\"
719 // DO NOT convert the .. if it is at the end of the string. This will
720 // break the .. behavior in changing directories.
721 //
722
723 //
724 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
725 // that overlap.
726 //
727 StrCpyS (TmpStr, MaxLen, Ptr + 3);
728 StrCpyS (LastSlash, MaxLen - ((UINTN)LastSlash - (UINTN)Str) / sizeof (CHAR16), TmpStr);
729 Ptr = LastSlash;
730 } else if ((*Ptr == '\\') && (*(Ptr + 1) == '.') && (*(Ptr + 2) == '\\')) {
731 //
732 // Convert a "\.\" to a "\"
733 //
734
735 //
736 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
737 // that overlap.
738 //
739 StrCpyS (TmpStr, MaxLen, Ptr + 2);
740 StrCpyS (Ptr, MaxLen - ((UINTN)Ptr - (UINTN)Str) / sizeof (CHAR16), TmpStr);
741 Ptr = LastSlash;
742 } else if (*Ptr == '\\') {
743 LastSlash = Ptr;
744 }
745
746 Ptr++;
747 }
748
749 FreePool (TmpStr);
750
751 return Str;
752 }
753
754 /**
755 This function build the FsOptionMenu list which records all
756 available file system in the system. They includes all instances
757 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM.
758
759
760 @retval EFI_SUCCESS Success find the file system
761 @retval EFI_OUT_OF_RESOURCES Can not create menu entry
762
763 **/
764 EFI_STATUS
765 LibFindFileSystem (
766 VOID
767 )
768 {
769 UINTN NoSimpleFsHandles;
770 EFI_HANDLE *SimpleFsHandle;
771 UINT16 *VolumeLabel;
772 UINTN Index;
773 EFI_STATUS Status;
774 MENU_ENTRY *MenuEntry;
775 FILE_CONTEXT *FileContext;
776 UINTN OptionNumber;
777 EFI_FILE_SYSTEM_VOLUME_LABEL *Info;
778
779 NoSimpleFsHandles = 0;
780 OptionNumber = 0;
781
782 //
783 // Locate Handles that support Simple File System protocol
784 //
785 Status = gBS->LocateHandleBuffer (
786 ByProtocol,
787 &gEfiSimpleFileSystemProtocolGuid,
788 NULL,
789 &NoSimpleFsHandles,
790 &SimpleFsHandle
791 );
792 if (!EFI_ERROR (Status)) {
793 //
794 // Find all the instances of the File System prototocol
795 //
796 for (Index = 0; Index < NoSimpleFsHandles; Index++) {
797 //
798 // Allocate pool for this load option
799 //
800 MenuEntry = LibCreateMenuEntry ();
801 if (NULL == MenuEntry) {
802 FreePool (SimpleFsHandle);
803 return EFI_OUT_OF_RESOURCES;
804 }
805
806 FileContext = (FILE_CONTEXT *)MenuEntry->VariableContext;
807 FileContext->DeviceHandle = SimpleFsHandle[Index];
808 FileContext->FileHandle = LibOpenRoot (FileContext->DeviceHandle);
809 if (FileContext->FileHandle == NULL) {
810 LibDestroyMenuEntry (MenuEntry);
811 continue;
812 }
813
814 MenuEntry->HelpString = LibDevicePathToStr (DevicePathFromHandle (FileContext->DeviceHandle));
815 FileContext->FileName = LibStrDuplicate (L"\\");
816 FileContext->DevicePath = FileDevicePath (FileContext->DeviceHandle, FileContext->FileName);
817 FileContext->IsDir = TRUE;
818 FileContext->IsRoot = TRUE;
819
820 //
821 // Get current file system's Volume Label
822 //
823 Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *)LibFileInfo (FileContext->FileHandle, &gEfiFileSystemVolumeLabelInfoIdGuid);
824 if (Info == NULL) {
825 VolumeLabel = L"NO FILE SYSTEM INFO";
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
853 OptionNumber++;
854 InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);
855 }
856 }
857
858 if (NoSimpleFsHandles != 0) {
859 FreePool (SimpleFsHandle);
860 }
861
862 gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
863
864 return EFI_SUCCESS;
865 }
866
867 /**
868 Find the file handle from the input menu info.
869
870 @param MenuEntry Input Menu info.
871 @param RetFileHandle Return the file handle for the input device path.
872
873 @retval EFI_SUCESS Find the file handle success.
874 @retval Other Find the file handle failure.
875 **/
876 EFI_STATUS
877 LibGetFileHandleFromMenu (
878 IN MENU_ENTRY *MenuEntry,
879 OUT EFI_FILE_HANDLE *RetFileHandle
880 )
881 {
882 EFI_FILE_HANDLE Dir;
883 EFI_FILE_HANDLE NewDir;
884 FILE_CONTEXT *FileContext;
885 EFI_STATUS Status;
886
887 FileContext = (FILE_CONTEXT *)MenuEntry->VariableContext;
888 Dir = FileContext->FileHandle;
889
890 //
891 // Open current directory to get files from it
892 //
893 Status = Dir->Open (
894 Dir,
895 &NewDir,
896 FileContext->FileName,
897 EFI_FILE_READ_ONLY,
898 0
899 );
900 if (EFI_ERROR (Status)) {
901 return Status;
902 }
903
904 if (!FileContext->IsRoot) {
905 Dir->Close (Dir);
906 }
907
908 *RetFileHandle = NewDir;
909
910 return EFI_SUCCESS;
911 }
912
913 /**
914 Find the file handle from the input device path info.
915
916 @param RootDirectory Device path info.
917 @param RetFileHandle Return the file handle for the input device path.
918 @param ParentFileName Parent file name.
919 @param DeviceHandle Driver handle for this partition.
920
921 @retval EFI_SUCESS Find the file handle success.
922 @retval Other Find the file handle failure.
923 **/
924 EFI_STATUS
925 LibGetFileHandleFromDevicePath (
926 IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
927 OUT EFI_FILE_HANDLE *RetFileHandle,
928 OUT UINT16 **ParentFileName,
929 OUT EFI_HANDLE *DeviceHandle
930 )
931 {
932 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
933 EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
934 EFI_STATUS Status;
935 EFI_HANDLE Handle;
936 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
937 EFI_FILE_HANDLE FileHandle;
938 EFI_FILE_HANDLE LastHandle;
939 CHAR16 *TempPath;
940
941 *ParentFileName = NULL;
942
943 //
944 // Attempt to access the file via a file system interface
945 //
946 DevicePathNode = RootDirectory;
947 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);
948 if (EFI_ERROR (Status)) {
949 return Status;
950 }
951
952 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Volume);
953 if (EFI_ERROR (Status)) {
954 return Status;
955 }
956
957 //
958 // Open the Volume to get the File System handle
959 //
960 Status = Volume->OpenVolume (Volume, &FileHandle);
961 if (EFI_ERROR (Status)) {
962 return Status;
963 }
964
965 *DeviceHandle = Handle;
966
967 if (IsDevicePathEnd (DevicePathNode)) {
968 *ParentFileName = AllocateCopyPool (StrSize (L"\\"), L"\\");
969 *RetFileHandle = FileHandle;
970 return EFI_SUCCESS;
971 }
972
973 //
974 // Duplicate the device path to avoid the access to unaligned device path node.
975 // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
976 // nodes, It assures the fields in device path nodes are 2 byte aligned.
977 //
978 TempDevicePathNode = DuplicateDevicePath (DevicePathNode);
979 if (TempDevicePathNode == NULL) {
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 {
998 Status = EFI_UNSUPPORTED;
999 goto Done;
1000 }
1001
1002 LastHandle = FileHandle;
1003 FileHandle = NULL;
1004
1005 Status = LastHandle->Open (
1006 LastHandle,
1007 &FileHandle,
1008 ((FILEPATH_DEVICE_PATH *)DevicePathNode)->PathName,
1009 EFI_FILE_MODE_READ,
1010 0
1011 );
1012 if (*ParentFileName == NULL) {
1013 *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *)DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *)DevicePathNode)->PathName);
1014 } else {
1015 TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *)DevicePathNode)->PathName);
1016 if (TempPath == NULL) {
1017 LastHandle->Close (LastHandle);
1018 Status = EFI_OUT_OF_RESOURCES;
1019 goto Done;
1020 }
1021
1022 FreePool (*ParentFileName);
1023 *ParentFileName = TempPath;
1024 }
1025
1026 //
1027 // Close the previous node
1028 //
1029 LastHandle->Close (LastHandle);
1030
1031 DevicePathNode = NextDevicePathNode (DevicePathNode);
1032 }
1033
1034 if (EFI_ERROR (Status)) {
1035 goto Done;
1036 }
1037
1038 *RetFileHandle = FileHandle;
1039
1040 Status = EFI_SUCCESS;
1041
1042 Done:
1043 if (TempDevicePathNode != NULL) {
1044 FreePool (TempDevicePathNode);
1045 }
1046
1047 if ((FileHandle != NULL) && (EFI_ERROR (Status))) {
1048 FileHandle->Close (FileHandle);
1049 }
1050
1051 return Status;
1052 }
1053
1054 /**
1055 Create a new file or folder in current directory.
1056
1057 @param FileName Point to the fileNmae or folder name.
1058 @param CreateFile CreateFile== TRUE means create a new file.
1059 CreateFile== FALSE means create a new Folder.
1060
1061 **/
1062 EFI_STATUS
1063 LibCreateNewFile (
1064 IN CHAR16 *FileName,
1065 IN BOOLEAN CreateFile
1066 )
1067 {
1068 EFI_FILE_HANDLE FileHandle;
1069 EFI_FILE_HANDLE NewHandle;
1070 EFI_HANDLE DeviceHandle;
1071 EFI_STATUS Status;
1072 CHAR16 *ParentName;
1073 CHAR16 *FullFileName;
1074
1075 NewHandle = NULL;
1076 FullFileName = NULL;
1077
1078 LibGetFileHandleFromDevicePath (gFileExplorerPrivate.RetDevicePath, &FileHandle, &ParentName, &DeviceHandle);
1079 FullFileName = LibAppendFileName (ParentName, FileName);
1080 if (FullFileName == NULL) {
1081 return EFI_OUT_OF_RESOURCES;
1082 }
1083
1084 if (CreateFile) {
1085 Status = FileHandle->Open (
1086 FileHandle,
1087 &NewHandle,
1088 FullFileName,
1089 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
1090 0
1091 );
1092 if (EFI_ERROR (Status)) {
1093 FileHandle->Close (FileHandle);
1094 return Status;
1095 }
1096 } else {
1097 Status = FileHandle->Open (
1098 FileHandle,
1099 &NewHandle,
1100 FullFileName,
1101 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
1102 EFI_FILE_DIRECTORY
1103 );
1104 if (EFI_ERROR (Status)) {
1105 FileHandle->Close (FileHandle);
1106 return Status;
1107 }
1108 }
1109
1110 FileHandle->Close (FileHandle);
1111
1112 //
1113 // Return the DevicePath of the new created file or folder.
1114 //
1115 gFileExplorerPrivate.RetDevicePath = FileDevicePath (DeviceHandle, FullFileName);
1116
1117 return EFI_SUCCESS;
1118 }
1119
1120 /**
1121 Find files under current directory.
1122
1123 All files and sub-directories in current directory
1124 will be stored in DirectoryMenu for future use.
1125
1126 @param FileHandle Parent file handle.
1127 @param FileName Parent file name.
1128 @param DeviceHandle Driver handle for this partition.
1129
1130 @retval EFI_SUCCESS Get files from current dir successfully.
1131 @return Other value if can't get files from current dir.
1132
1133 **/
1134 EFI_STATUS
1135 LibFindFiles (
1136 IN EFI_FILE_HANDLE FileHandle,
1137 IN UINT16 *FileName,
1138 IN EFI_HANDLE DeviceHandle
1139 )
1140 {
1141 EFI_FILE_INFO *DirInfo;
1142 UINTN BufferSize;
1143 UINTN DirBufferSize;
1144 MENU_ENTRY *NewMenuEntry;
1145 FILE_CONTEXT *NewFileContext;
1146 UINTN Pass;
1147 EFI_STATUS Status;
1148 UINTN OptionNumber;
1149
1150 OptionNumber = 0;
1151
1152 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
1153 DirInfo = AllocateZeroPool (DirBufferSize);
1154 if (DirInfo == NULL) {
1155 return EFI_OUT_OF_RESOURCES;
1156 }
1157
1158 //
1159 // Get all files in current directory
1160 // Pass 1 to get Directories
1161 // Pass 2 to get files that are EFI images
1162 //
1163 Status = EFI_SUCCESS;
1164 for (Pass = 1; Pass <= 2; Pass++) {
1165 FileHandle->SetPosition (FileHandle, 0);
1166 for ( ; ;) {
1167 BufferSize = DirBufferSize;
1168 Status = FileHandle->Read (FileHandle, &BufferSize, DirInfo);
1169 if (EFI_ERROR (Status) || (BufferSize == 0)) {
1170 Status = EFI_SUCCESS;
1171 break;
1172 }
1173
1174 if ((((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0) && (Pass == 2)) ||
1175 (((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) && (Pass == 1))
1176 )
1177 {
1178 //
1179 // Pass 1 is for Directories
1180 // Pass 2 is for file names
1181 //
1182 continue;
1183 }
1184
1185 if (!(((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0) || LibIsSupportedFileType (DirInfo->FileName))) {
1186 //
1187 // Slip file unless it is a directory entry or a .EFI file
1188 //
1189 continue;
1190 }
1191
1192 NewMenuEntry = LibCreateMenuEntry ();
1193 if (NULL == NewMenuEntry) {
1194 Status = EFI_OUT_OF_RESOURCES;
1195 goto Done;
1196 }
1197
1198 NewFileContext = (FILE_CONTEXT *)NewMenuEntry->VariableContext;
1199 NewFileContext->DeviceHandle = DeviceHandle;
1200 NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName);
1201 if (NewFileContext->FileName == NULL) {
1202 LibDestroyMenuEntry (NewMenuEntry);
1203 Status = EFI_OUT_OF_RESOURCES;
1204 goto Done;
1205 }
1206
1207 NewFileContext->FileHandle = FileHandle;
1208 NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName);
1209 NewMenuEntry->HelpString = NULL;
1210 NewFileContext->IsDir = (BOOLEAN)((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
1211
1212 if (NewFileContext->IsDir) {
1213 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
1214 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
1215 UnicodeSPrint (
1216 NewMenuEntry->DisplayString,
1217 BufferSize,
1218 L"<%s>",
1219 DirInfo->FileName
1220 );
1221 } else {
1222 NewMenuEntry->DisplayString = LibStrDuplicate (DirInfo->FileName);
1223 }
1224
1225 NewMenuEntry->DisplayStringToken = HiiSetString (
1226 gFileExplorerPrivate.FeHiiHandle,
1227 0,
1228 NewMenuEntry->DisplayString,
1229 NULL
1230 );
1231
1232 NewFileContext->IsRoot = FALSE;
1233
1234 OptionNumber++;
1235 InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &NewMenuEntry->Link);
1236 }
1237 }
1238
1239 gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
1240
1241 Done:
1242
1243 FreePool (DirInfo);
1244
1245 return Status;
1246 }
1247
1248 /**
1249 Refresh the global UpdateData structure.
1250
1251 **/
1252 VOID
1253 LibRefreshUpdateData (
1254 VOID
1255 )
1256 {
1257 //
1258 // Free current updated date
1259 //
1260 if (mLibStartOpCodeHandle != NULL) {
1261 HiiFreeOpCodeHandle (mLibStartOpCodeHandle);
1262 }
1263
1264 if (mLibEndOpCodeHandle != NULL) {
1265 HiiFreeOpCodeHandle (mLibEndOpCodeHandle);
1266 }
1267
1268 //
1269 // Create new OpCode Handle
1270 //
1271 mLibStartOpCodeHandle = HiiAllocateOpCodeHandle ();
1272 mLibEndOpCodeHandle = HiiAllocateOpCodeHandle ();
1273
1274 //
1275 // Create Hii Extend Label OpCode as the start opcode
1276 //
1277 mLibStartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
1278 mLibStartOpCodeHandle,
1279 &gEfiIfrTianoGuid,
1280 NULL,
1281 sizeof (EFI_IFR_GUID_LABEL)
1282 );
1283 mLibStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1284
1285 mLibStartLabel->Number = FORM_FILE_EXPLORER_ID;
1286
1287 //
1288 // Create Hii Extend Label OpCode as the start opcode
1289 //
1290 mLibEndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
1291 mLibEndOpCodeHandle,
1292 &gEfiIfrTianoGuid,
1293 NULL,
1294 sizeof (EFI_IFR_GUID_LABEL)
1295 );
1296 mLibEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1297
1298 mLibEndLabel->Number = LABEL_END;
1299 }
1300
1301 /**
1302
1303 Update the File Explore page.
1304
1305 **/
1306 VOID
1307 LibUpdateFileExplorePage (
1308 VOID
1309 )
1310 {
1311 UINTN Index;
1312 MENU_ENTRY *NewMenuEntry;
1313 FILE_CONTEXT *NewFileContext;
1314 MENU_OPTION *MenuOption;
1315 BOOLEAN CreateNewFile;
1316
1317 NewMenuEntry = NULL;
1318 NewFileContext = NULL;
1319 CreateNewFile = FALSE;
1320
1321 LibRefreshUpdateData ();
1322 MenuOption = gFileExplorerPrivate.FsOptionMenu;
1323
1324 mQuestionIdUpdate += QUESTION_ID_UPDATE_STEP;
1325
1326 for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
1327 NewMenuEntry = LibGetMenuEntry (MenuOption, Index);
1328 NewFileContext = (FILE_CONTEXT *)NewMenuEntry->VariableContext;
1329
1330 if (!NewFileContext->IsRoot && !CreateNewFile) {
1331 HiiCreateGotoOpCode (
1332 mLibStartOpCodeHandle,
1333 FORM_ADD_NEW_FILE_ID,
1334 STRING_TOKEN (STR_NEW_FILE),
1335 STRING_TOKEN (STR_NEW_FILE_HELP),
1336 EFI_IFR_FLAG_CALLBACK,
1337 (UINT16)(mNewFileQuestionId++)
1338 );
1339 HiiCreateGotoOpCode (
1340 mLibStartOpCodeHandle,
1341 FORM_ADD_NEW_FOLDER_ID,
1342 STRING_TOKEN (STR_NEW_FOLDER),
1343 STRING_TOKEN (STR_NEW_FOLDER_HELP),
1344 EFI_IFR_FLAG_CALLBACK,
1345 (UINT16)(mNewFolderQuestionId++)
1346 );
1347 HiiCreateTextOpCode (
1348 mLibStartOpCodeHandle,
1349 STRING_TOKEN (STR_NULL_STRING),
1350 STRING_TOKEN (STR_NULL_STRING),
1351 0
1352 );
1353 CreateNewFile = TRUE;
1354 }
1355
1356 if (!NewFileContext->IsDir) {
1357 //
1358 // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile.
1359 //
1360 HiiCreateActionOpCode (
1361 mLibStartOpCodeHandle,
1362 (UINT16)(FILE_OPTION_OFFSET + Index + mQuestionIdUpdate),
1363 NewMenuEntry->DisplayStringToken,
1364 STRING_TOKEN (STR_NULL_STRING),
1365 EFI_IFR_FLAG_CALLBACK,
1366 0
1367 );
1368 } else {
1369 //
1370 // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState.
1371 //
1372 HiiCreateGotoOpCode (
1373 mLibStartOpCodeHandle,
1374 FORM_FILE_EXPLORER_ID,
1375 NewMenuEntry->DisplayStringToken,
1376 STRING_TOKEN (STR_NULL_STRING),
1377 EFI_IFR_FLAG_CALLBACK,
1378 (UINT16)(FILE_OPTION_OFFSET + Index + mQuestionIdUpdate)
1379 );
1380 }
1381 }
1382
1383 HiiUpdateForm (
1384 gFileExplorerPrivate.FeHiiHandle,
1385 &FileExplorerGuid,
1386 FORM_FILE_EXPLORER_ID,
1387 mLibStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
1388 mLibEndOpCodeHandle // LABEL_END
1389 );
1390 }
1391
1392 /**
1393 Update the file explower page with the refershed file system.
1394
1395 @param KeyValue Key value to identify the type of data to expect.
1396
1397 @retval EFI_SUCCESS Update the file explorer form success.
1398 @retval other errors Error occur when parse one directory.
1399
1400 **/
1401 EFI_STATUS
1402 LibUpdateFileExplorer (
1403 IN UINT16 KeyValue
1404 )
1405 {
1406 UINT16 FileOptionMask;
1407 MENU_ENTRY *NewMenuEntry;
1408 FILE_CONTEXT *NewFileContext;
1409 EFI_STATUS Status;
1410 EFI_FILE_HANDLE FileHandle;
1411
1412 Status = EFI_SUCCESS;
1413 FileOptionMask = (UINT16)(FILE_OPTION_MASK & KeyValue) - mQuestionIdUpdate;
1414 NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
1415 NewFileContext = (FILE_CONTEXT *)NewMenuEntry->VariableContext;
1416
1417 if (NewFileContext->IsDir) {
1418 RemoveEntryList (&NewMenuEntry->Link);
1419 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1420 Status = LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle);
1421 if (!EFI_ERROR (Status)) {
1422 Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle);
1423 if (!EFI_ERROR (Status)) {
1424 LibUpdateFileExplorePage ();
1425 } else {
1426 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1427 }
1428 }
1429
1430 LibDestroyMenuEntry (NewMenuEntry);
1431 }
1432
1433 return Status;
1434 }
1435
1436 /**
1437 Get the device path info saved in the menu structure.
1438
1439 @param KeyValue Key value to identify the type of data to expect.
1440
1441 **/
1442 VOID
1443 LibGetDevicePath (
1444 IN UINT16 KeyValue
1445 )
1446 {
1447 UINT16 FileOptionMask;
1448 MENU_ENTRY *NewMenuEntry;
1449 FILE_CONTEXT *NewFileContext;
1450
1451 FileOptionMask = (UINT16)(FILE_OPTION_MASK & KeyValue) - mQuestionIdUpdate;
1452
1453 NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
1454
1455 NewFileContext = (FILE_CONTEXT *)NewMenuEntry->VariableContext;
1456
1457 if (gFileExplorerPrivate.RetDevicePath != NULL) {
1458 FreePool (gFileExplorerPrivate.RetDevicePath);
1459 }
1460
1461 gFileExplorerPrivate.RetDevicePath = DuplicateDevicePath (NewFileContext->DevicePath);
1462 }
1463
1464 /**
1465 Choose a file in the specified directory.
1466
1467 If user input NULL for the RootDirectory, will choose file in the system.
1468
1469 If user input *File != NULL, function will return the allocate device path
1470 info for the choosed file, caller has to free the memory after use it.
1471
1472 @param RootDirectory Pointer to the root directory.
1473 @param FileType The file type need to choose.
1474 @param ChooseHandler Function pointer to the extra task need to do
1475 after choose one file.
1476 @param File Return the device path for the last time chosed file.
1477
1478 @retval EFI_SUCESS Choose file success.
1479 @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL
1480 One of them must not NULL.
1481 @retval Other errors Choose file failed.
1482 **/
1483 EFI_STATUS
1484 EFIAPI
1485 ChooseFile (
1486 IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
1487 IN CHAR16 *FileType OPTIONAL,
1488 IN CHOOSE_HANDLER ChooseHandler OPTIONAL,
1489 OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL
1490 )
1491 {
1492 EFI_FILE_HANDLE FileHandle;
1493 EFI_STATUS Status;
1494 UINT16 *FileName;
1495 EFI_HANDLE DeviceHandle;
1496
1497 if ((ChooseHandler == NULL) && (File == NULL)) {
1498 return EFI_INVALID_PARAMETER;
1499 }
1500
1501 mQuestionIdUpdate = 0;
1502 FileName = NULL;
1503
1504 gFileExplorerPrivate.RetDevicePath = NULL;
1505 gFileExplorerPrivate.ChooseHandler = ChooseHandler;
1506 if (FileType != NULL) {
1507 gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType);
1508 ASSERT (gFileExplorerPrivate.FileType != NULL);
1509 LibToLowerString (gFileExplorerPrivate.FileType);
1510 } else {
1511 gFileExplorerPrivate.FileType = NULL;
1512 }
1513
1514 if (RootDirectory == NULL) {
1515 Status = LibFindFileSystem ();
1516 } else {
1517 Status = LibGetFileHandleFromDevicePath (RootDirectory, &FileHandle, &FileName, &DeviceHandle);
1518 if (EFI_ERROR (Status)) {
1519 goto Done;
1520 }
1521
1522 Status = LibFindFiles (FileHandle, FileName, DeviceHandle);
1523 }
1524
1525 if (EFI_ERROR (Status)) {
1526 goto Done;
1527 }
1528
1529 LibUpdateFileExplorePage ();
1530
1531 gFileExplorerPrivate.FormBrowser2->SendForm (
1532 gFileExplorerPrivate.FormBrowser2,
1533 &gFileExplorerPrivate.FeHiiHandle,
1534 1,
1535 &FileExplorerGuid,
1536 0,
1537 NULL,
1538 NULL
1539 );
1540
1541 Done:
1542 if ((Status == EFI_SUCCESS) && (File != NULL)) {
1543 *File = gFileExplorerPrivate.RetDevicePath;
1544 } else if (gFileExplorerPrivate.RetDevicePath != NULL) {
1545 FreePool (gFileExplorerPrivate.RetDevicePath);
1546 }
1547
1548 if (gFileExplorerPrivate.FileType != NULL) {
1549 FreePool (gFileExplorerPrivate.FileType);
1550 }
1551
1552 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1553
1554 if (FileName != NULL) {
1555 FreePool (FileName);
1556 }
1557
1558 return Status;
1559 }
1560
1561 /**
1562
1563 Install Boot Manager Menu driver.
1564
1565 @param ImageHandle The image handle.
1566 @param SystemTable The system table.
1567
1568 @retval EFI_SUCEESS Install File explorer library success.
1569
1570 **/
1571 EFI_STATUS
1572 EFIAPI
1573 FileExplorerLibConstructor (
1574 IN EFI_HANDLE ImageHandle,
1575 IN EFI_SYSTEM_TABLE *SystemTable
1576 )
1577 {
1578 EFI_STATUS Status;
1579
1580 gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH *)DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL *)&FeHiiVendorDevicePath);
1581 ASSERT (gHiiVendorDevicePath != NULL);
1582 CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid);
1583
1584 //
1585 // Install Device Path Protocol and Config Access protocol to driver handle
1586 //
1587 Status = gBS->InstallMultipleProtocolInterfaces (
1588 &gFileExplorerPrivate.FeDriverHandle,
1589 &gEfiDevicePathProtocolGuid,
1590 gHiiVendorDevicePath,
1591 &gEfiHiiConfigAccessProtocolGuid,
1592 &gFileExplorerPrivate.FeConfigAccess,
1593 NULL
1594 );
1595 if (Status == EFI_ALREADY_STARTED) {
1596 return EFI_SUCCESS;
1597 }
1598
1599 if (EFI_ERROR (Status)) {
1600 return Status;
1601 }
1602
1603 //
1604 // Post our File Explorer VFR binary to the HII database.
1605 //
1606 gFileExplorerPrivate.FeHiiHandle = HiiAddPackages (
1607 &FileExplorerGuid,
1608 gFileExplorerPrivate.FeDriverHandle,
1609 FileExplorerVfrBin,
1610 FileExplorerLibStrings,
1611 NULL
1612 );
1613 ASSERT (gFileExplorerPrivate.FeHiiHandle != NULL);
1614
1615 //
1616 // Locate Formbrowser2 protocol
1617 //
1618 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **)&gFileExplorerPrivate.FormBrowser2);
1619 ASSERT_EFI_ERROR (Status);
1620
1621 InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head);
1622
1623 return EFI_SUCCESS;
1624 }
1625
1626 /**
1627 Unloads the application and its installed protocol.
1628
1629 @param[in] ImageHandle Handle that identifies the image to be unloaded.
1630 @param[in] SystemTable The system table.
1631
1632 @retval EFI_SUCCESS The image has been unloaded.
1633 **/
1634 EFI_STATUS
1635 EFIAPI
1636 FileExplorerLibDestructor (
1637 IN EFI_HANDLE ImageHandle,
1638 IN EFI_SYSTEM_TABLE *SystemTable
1639 )
1640 {
1641 EFI_STATUS Status;
1642
1643 ASSERT (gHiiVendorDevicePath != NULL);
1644
1645 if (gFileExplorerPrivate.FeDriverHandle != NULL) {
1646 Status = gBS->UninstallMultipleProtocolInterfaces (
1647 gFileExplorerPrivate.FeDriverHandle,
1648 &gEfiDevicePathProtocolGuid,
1649 gHiiVendorDevicePath,
1650 &gEfiHiiConfigAccessProtocolGuid,
1651 &gFileExplorerPrivate.FeConfigAccess,
1652 NULL
1653 );
1654 ASSERT_EFI_ERROR (Status);
1655
1656 HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle);
1657 gFileExplorerPrivate.FeDriverHandle = NULL;
1658 }
1659
1660 FreePool (gHiiVendorDevicePath);
1661
1662 return EFI_SUCCESS;
1663 }