]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/FileExplorerLib/FileExplorer.c
13a214b06af9fdc262fababe32abd614a0c4ed6c
[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
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
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 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 *
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 *
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 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
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
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 *
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 *
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 *
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*
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
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
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 *
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
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 VolumeLabel = Info->VolumeLabel;
825 if (*VolumeLabel == 0x0000) {
826 VolumeLabel = L"NO VOLUME LABEL";
827 }
828 }
829 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
830 ASSERT (MenuEntry->DisplayString != NULL);
831 UnicodeSPrint (
832 MenuEntry->DisplayString,
833 MAX_CHAR,
834 L"%s, [%s]",
835 VolumeLabel,
836 MenuEntry->HelpString
837 );
838 MenuEntry->DisplayStringToken = HiiSetString (
839 gFileExplorerPrivate.FeHiiHandle,
840 0,
841 MenuEntry->DisplayString,
842 NULL
843 );
844
845 if (Info != NULL)
846 FreePool (Info);
847
848 OptionNumber++;
849 InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);
850 }
851 }
852
853 if (NoSimpleFsHandles != 0) {
854 FreePool (SimpleFsHandle);
855 }
856
857 gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
858
859 return EFI_SUCCESS;
860 }
861
862 /**
863 Find the file handle from the input menu info.
864
865 @param MenuEntry Input Menu info.
866 @param RetFileHandle Return the file handle for the input device path.
867
868 @retval EFI_SUCESS Find the file handle success.
869 @retval Other Find the file handle failure.
870 **/
871 EFI_STATUS
872 LibGetFileHandleFromMenu (
873 IN MENU_ENTRY *MenuEntry,
874 OUT EFI_FILE_HANDLE *RetFileHandle
875 )
876 {
877 EFI_FILE_HANDLE Dir;
878 EFI_FILE_HANDLE NewDir;
879 FILE_CONTEXT *FileContext;
880 EFI_STATUS Status;
881
882 FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
883 Dir = FileContext->FileHandle;
884
885 //
886 // Open current directory to get files from it
887 //
888 Status = Dir->Open (
889 Dir,
890 &NewDir,
891 FileContext->FileName,
892 EFI_FILE_READ_ONLY,
893 0
894 );
895 if (EFI_ERROR (Status)) {
896 return Status;
897 }
898
899 if (!FileContext->IsRoot) {
900 Dir->Close (Dir);
901 }
902
903 *RetFileHandle = NewDir;
904
905 return EFI_SUCCESS;
906 }
907
908 /**
909 Find the file handle from the input device path info.
910
911 @param RootDirectory Device path info.
912 @param RetFileHandle Return the file handle for the input device path.
913 @param ParentFileName Parent file name.
914 @param DeviceHandle Driver handle for this partition.
915
916 @retval EFI_SUCESS Find the file handle success.
917 @retval Other Find the file handle failure.
918 **/
919 EFI_STATUS
920 LibGetFileHandleFromDevicePath (
921 IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
922 OUT EFI_FILE_HANDLE *RetFileHandle,
923 OUT UINT16 **ParentFileName,
924 OUT EFI_HANDLE *DeviceHandle
925 )
926 {
927 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
928 EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
929 EFI_STATUS Status;
930 EFI_HANDLE Handle;
931 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
932 EFI_FILE_HANDLE FileHandle;
933 EFI_FILE_HANDLE LastHandle;
934 CHAR16 *TempPath;
935
936 *ParentFileName = NULL;
937
938 //
939 // Attempt to access the file via a file system interface
940 //
941 DevicePathNode = RootDirectory;
942 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);
943 if (EFI_ERROR (Status)) {
944 return Status;
945 }
946
947 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);
948 if (EFI_ERROR (Status)) {
949 return Status;
950 }
951
952 //
953 // Open the Volume to get the File System handle
954 //
955 Status = Volume->OpenVolume (Volume, &FileHandle);
956 if (EFI_ERROR (Status)) {
957 return Status;
958 }
959
960 *DeviceHandle = Handle;
961
962 if (IsDevicePathEnd(DevicePathNode)) {
963 *ParentFileName = AllocateCopyPool (StrSize (L"\\"), L"\\");
964 *RetFileHandle = FileHandle;
965 return EFI_SUCCESS;
966 }
967
968 //
969 // Duplicate the device path to avoid the access to unaligned device path node.
970 // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
971 // nodes, It assures the fields in device path nodes are 2 byte aligned.
972 //
973 TempDevicePathNode = DuplicateDevicePath (DevicePathNode);
974 if (TempDevicePathNode == NULL) {
975
976 //
977 // Setting Status to an EFI_ERROR value will cause the rest of
978 // the file system support below to be skipped.
979 //
980 Status = EFI_OUT_OF_RESOURCES;
981 goto Done;
982 }
983
984 //
985 // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
986 // directory information and filename can be seperate. The goal is to inch
987 // our way down each device path node and close the previous node
988 //
989 DevicePathNode = TempDevicePathNode;
990 while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) {
991 if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH ||
992 DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) {
993 Status = EFI_UNSUPPORTED;
994 goto Done;
995 }
996
997 LastHandle = FileHandle;
998 FileHandle = NULL;
999
1000 Status = LastHandle->Open (
1001 LastHandle,
1002 &FileHandle,
1003 ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName,
1004 EFI_FILE_MODE_READ,
1005 0
1006 );
1007 if (*ParentFileName == NULL) {
1008 *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);
1009 } else {
1010 TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);
1011 if (TempPath == NULL) {
1012 LastHandle->Close (LastHandle);
1013 Status = EFI_OUT_OF_RESOURCES;
1014 goto Done;
1015 }
1016 FreePool (*ParentFileName);
1017 *ParentFileName = TempPath;
1018 }
1019
1020 //
1021 // Close the previous node
1022 //
1023 LastHandle->Close (LastHandle);
1024
1025 DevicePathNode = NextDevicePathNode (DevicePathNode);
1026 }
1027
1028 if (EFI_ERROR (Status)) {
1029 goto Done;
1030 }
1031
1032 *RetFileHandle = FileHandle;
1033
1034 Status = EFI_SUCCESS;
1035
1036 Done:
1037 if (TempDevicePathNode != NULL) {
1038 FreePool (TempDevicePathNode);
1039 }
1040
1041 if ((FileHandle != NULL) && (EFI_ERROR (Status))) {
1042 FileHandle->Close (FileHandle);
1043 }
1044
1045 return Status;
1046 }
1047
1048 /**
1049 Create a new file or folder in current directory.
1050
1051 @param FileName Point to the fileNmae or folder name.
1052 @param CreateFile CreateFile== TRUE means create a new file.
1053 CreateFile== FALSE means create a new Folder.
1054
1055 **/
1056 EFI_STATUS
1057 LibCreateNewFile (
1058 IN CHAR16 *FileName,
1059 IN BOOLEAN CreateFile
1060 )
1061 {
1062 EFI_FILE_HANDLE FileHandle;
1063 EFI_FILE_HANDLE NewHandle;
1064 EFI_HANDLE DeviceHandle;
1065 EFI_STATUS Status;
1066 CHAR16 *ParentName;
1067 CHAR16 *FullFileName;
1068
1069 NewHandle = NULL;
1070 FullFileName = NULL;
1071
1072 LibGetFileHandleFromDevicePath(gFileExplorerPrivate.RetDevicePath, &FileHandle, &ParentName, &DeviceHandle);
1073 FullFileName = LibAppendFileName (ParentName, FileName);
1074 if (FullFileName == NULL) {
1075 return EFI_OUT_OF_RESOURCES;
1076 }
1077 if (CreateFile) {
1078 Status = FileHandle->Open(
1079 FileHandle,
1080 &NewHandle,
1081 FullFileName,
1082 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
1083 0
1084 );
1085 if (EFI_ERROR (Status)) {
1086 FileHandle->Close (FileHandle);
1087 return Status;
1088 }
1089 } else {
1090 Status = FileHandle->Open(
1091 FileHandle,
1092 &NewHandle,
1093 FullFileName,
1094 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
1095 EFI_FILE_DIRECTORY
1096 );
1097 if (EFI_ERROR (Status)) {
1098 FileHandle->Close (FileHandle);
1099 return Status;
1100 }
1101 }
1102
1103 FileHandle->Close (FileHandle);
1104
1105 //
1106 // Return the DevicePath of the new created file or folder.
1107 //
1108 gFileExplorerPrivate.RetDevicePath = FileDevicePath (DeviceHandle, FullFileName);
1109
1110 return EFI_SUCCESS;
1111
1112 }
1113
1114 /**
1115 Find files under current directory.
1116
1117 All files and sub-directories in current directory
1118 will be stored in DirectoryMenu for future use.
1119
1120 @param FileHandle Parent file handle.
1121 @param FileName Parent file name.
1122 @param DeviceHandle Driver handle for this partition.
1123
1124 @retval EFI_SUCCESS Get files from current dir successfully.
1125 @return Other value if can't get files from current dir.
1126
1127 **/
1128 EFI_STATUS
1129 LibFindFiles (
1130 IN EFI_FILE_HANDLE FileHandle,
1131 IN UINT16 *FileName,
1132 IN EFI_HANDLE DeviceHandle
1133 )
1134 {
1135 EFI_FILE_INFO *DirInfo;
1136 UINTN BufferSize;
1137 UINTN DirBufferSize;
1138 MENU_ENTRY *NewMenuEntry;
1139 FILE_CONTEXT *NewFileContext;
1140 UINTN Pass;
1141 EFI_STATUS Status;
1142 UINTN OptionNumber;
1143
1144 OptionNumber = 0;
1145
1146 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
1147 DirInfo = AllocateZeroPool (DirBufferSize);
1148 if (DirInfo == NULL) {
1149 return EFI_OUT_OF_RESOURCES;
1150 }
1151
1152 //
1153 // Get all files in current directory
1154 // Pass 1 to get Directories
1155 // Pass 2 to get files that are EFI images
1156 //
1157 Status = EFI_SUCCESS;
1158 for (Pass = 1; Pass <= 2; Pass++) {
1159 FileHandle->SetPosition (FileHandle, 0);
1160 for (;;) {
1161 BufferSize = DirBufferSize;
1162 Status = FileHandle->Read (FileHandle, &BufferSize, DirInfo);
1163 if (EFI_ERROR (Status) || BufferSize == 0) {
1164 Status = EFI_SUCCESS;
1165 break;
1166 }
1167
1168 if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
1169 ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
1170 ) {
1171 //
1172 // Pass 1 is for Directories
1173 // Pass 2 is for file names
1174 //
1175 continue;
1176 }
1177
1178 if (!((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 || LibIsSupportedFileType (DirInfo->FileName))) {
1179 //
1180 // Slip file unless it is a directory entry or a .EFI file
1181 //
1182 continue;
1183 }
1184
1185 NewMenuEntry = LibCreateMenuEntry ();
1186 if (NULL == NewMenuEntry) {
1187 Status = EFI_OUT_OF_RESOURCES;
1188 goto Done;
1189 }
1190
1191 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1192 NewFileContext->DeviceHandle = DeviceHandle;
1193 NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName);
1194 if (NewFileContext->FileName == NULL) {
1195 LibDestroyMenuEntry (NewMenuEntry);
1196 Status = EFI_OUT_OF_RESOURCES;
1197 goto Done;
1198 }
1199 NewFileContext->FileHandle = FileHandle;
1200 NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName);
1201 NewMenuEntry->HelpString = NULL;
1202 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
1203
1204 if (NewFileContext->IsDir) {
1205 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
1206 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
1207 UnicodeSPrint (
1208 NewMenuEntry->DisplayString,
1209 BufferSize,
1210 L"<%s>",
1211 DirInfo->FileName
1212 );
1213 } else {
1214 NewMenuEntry->DisplayString = LibStrDuplicate (DirInfo->FileName);
1215 }
1216
1217 NewMenuEntry->DisplayStringToken = HiiSetString (
1218 gFileExplorerPrivate.FeHiiHandle,
1219 0,
1220 NewMenuEntry->DisplayString,
1221 NULL
1222 );
1223
1224 NewFileContext->IsRoot = FALSE;
1225
1226 OptionNumber++;
1227 InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &NewMenuEntry->Link);
1228 }
1229 }
1230
1231 gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
1232
1233 Done:
1234
1235 FreePool (DirInfo);
1236
1237 return Status;
1238 }
1239
1240 /**
1241 Refresh the global UpdateData structure.
1242
1243 **/
1244 VOID
1245 LibRefreshUpdateData (
1246 VOID
1247 )
1248 {
1249 //
1250 // Free current updated date
1251 //
1252 if (mLibStartOpCodeHandle != NULL) {
1253 HiiFreeOpCodeHandle (mLibStartOpCodeHandle);
1254 }
1255 if (mLibEndOpCodeHandle != NULL) {
1256 HiiFreeOpCodeHandle (mLibEndOpCodeHandle);
1257 }
1258
1259 //
1260 // Create new OpCode Handle
1261 //
1262 mLibStartOpCodeHandle = HiiAllocateOpCodeHandle ();
1263 mLibEndOpCodeHandle = HiiAllocateOpCodeHandle ();
1264
1265 //
1266 // Create Hii Extend Label OpCode as the start opcode
1267 //
1268 mLibStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
1269 mLibStartOpCodeHandle,
1270 &gEfiIfrTianoGuid,
1271 NULL,
1272 sizeof (EFI_IFR_GUID_LABEL)
1273 );
1274 mLibStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1275
1276 mLibStartLabel->Number = FORM_FILE_EXPLORER_ID;
1277
1278 //
1279 // Create Hii Extend Label OpCode as the start opcode
1280 //
1281 mLibEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
1282 mLibEndOpCodeHandle,
1283 &gEfiIfrTianoGuid,
1284 NULL,
1285 sizeof (EFI_IFR_GUID_LABEL)
1286 );
1287 mLibEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1288
1289 mLibEndLabel->Number = LABEL_END;
1290 }
1291
1292 /**
1293
1294 Update the File Explore page.
1295
1296 **/
1297 VOID
1298 LibUpdateFileExplorePage (
1299 VOID
1300 )
1301 {
1302 UINTN Index;
1303 MENU_ENTRY *NewMenuEntry;
1304 FILE_CONTEXT *NewFileContext;
1305 MENU_OPTION *MenuOption;
1306 BOOLEAN CreateNewFile;
1307
1308 NewMenuEntry = NULL;
1309 NewFileContext = NULL;
1310 CreateNewFile = FALSE;
1311
1312 LibRefreshUpdateData ();
1313 MenuOption = gFileExplorerPrivate.FsOptionMenu;
1314
1315 mQuestionIdUpdate += QUESTION_ID_UPDATE_STEP;
1316
1317 for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
1318 NewMenuEntry = LibGetMenuEntry (MenuOption, Index);
1319 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1320
1321 if (!NewFileContext->IsRoot && !CreateNewFile) {
1322 HiiCreateGotoOpCode (
1323 mLibStartOpCodeHandle,
1324 FORM_ADD_NEW_FILE_ID,
1325 STRING_TOKEN (STR_NEW_FILE),
1326 STRING_TOKEN (STR_NEW_FILE_HELP),
1327 EFI_IFR_FLAG_CALLBACK,
1328 (UINT16) (mNewFileQuestionId++)
1329 );
1330 HiiCreateGotoOpCode (
1331 mLibStartOpCodeHandle,
1332 FORM_ADD_NEW_FOLDER_ID,
1333 STRING_TOKEN (STR_NEW_FOLDER),
1334 STRING_TOKEN (STR_NEW_FOLDER_HELP),
1335 EFI_IFR_FLAG_CALLBACK,
1336 (UINT16) (mNewFolderQuestionId++)
1337 );
1338 HiiCreateTextOpCode(
1339 mLibStartOpCodeHandle,
1340 STRING_TOKEN (STR_NULL_STRING),
1341 STRING_TOKEN (STR_NULL_STRING),
1342 0
1343 );
1344 CreateNewFile = TRUE;
1345 }
1346
1347 if (!NewFileContext->IsDir) {
1348 //
1349 // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile.
1350 //
1351 HiiCreateActionOpCode (
1352 mLibStartOpCodeHandle,
1353 (UINT16) (FILE_OPTION_OFFSET + Index + mQuestionIdUpdate),
1354 NewMenuEntry->DisplayStringToken,
1355 STRING_TOKEN (STR_NULL_STRING),
1356 EFI_IFR_FLAG_CALLBACK,
1357 0
1358 );
1359 } else {
1360 //
1361 // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState.
1362 //
1363 HiiCreateGotoOpCode (
1364 mLibStartOpCodeHandle,
1365 FORM_FILE_EXPLORER_ID,
1366 NewMenuEntry->DisplayStringToken,
1367 STRING_TOKEN (STR_NULL_STRING),
1368 EFI_IFR_FLAG_CALLBACK,
1369 (UINT16) (FILE_OPTION_OFFSET + Index + mQuestionIdUpdate)
1370 );
1371 }
1372 }
1373
1374 HiiUpdateForm (
1375 gFileExplorerPrivate.FeHiiHandle,
1376 &FileExplorerGuid,
1377 FORM_FILE_EXPLORER_ID,
1378 mLibStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
1379 mLibEndOpCodeHandle // LABEL_END
1380 );
1381 }
1382
1383 /**
1384 Update the file explower page with the refershed file system.
1385
1386 @param KeyValue Key value to identify the type of data to expect.
1387
1388 @retval EFI_SUCCESS Update the file explorer form success.
1389 @retval other errors Error occur when parse one directory.
1390
1391 **/
1392 EFI_STATUS
1393 LibUpdateFileExplorer (
1394 IN UINT16 KeyValue
1395 )
1396 {
1397 UINT16 FileOptionMask;
1398 MENU_ENTRY *NewMenuEntry;
1399 FILE_CONTEXT *NewFileContext;
1400 EFI_STATUS Status;
1401 EFI_FILE_HANDLE FileHandle;
1402
1403 Status = EFI_SUCCESS;
1404 FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue) - mQuestionIdUpdate;
1405 NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
1406 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1407
1408 if (NewFileContext->IsDir) {
1409 RemoveEntryList (&NewMenuEntry->Link);
1410 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1411 LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle);
1412 Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle);
1413 if (!EFI_ERROR (Status)) {
1414 LibUpdateFileExplorePage ();
1415 } else {
1416 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1417 }
1418 LibDestroyMenuEntry (NewMenuEntry);
1419 }
1420
1421 return Status;
1422 }
1423
1424 /**
1425 Get the device path info saved in the menu structure.
1426
1427 @param KeyValue Key value to identify the type of data to expect.
1428
1429 **/
1430 VOID
1431 LibGetDevicePath (
1432 IN UINT16 KeyValue
1433 )
1434 {
1435 UINT16 FileOptionMask;
1436 MENU_ENTRY *NewMenuEntry;
1437 FILE_CONTEXT *NewFileContext;
1438
1439 FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue) - mQuestionIdUpdate;
1440
1441 NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
1442
1443 NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
1444
1445 if (gFileExplorerPrivate.RetDevicePath != NULL) {
1446 FreePool (gFileExplorerPrivate.RetDevicePath);
1447 }
1448 gFileExplorerPrivate.RetDevicePath = DuplicateDevicePath (NewFileContext->DevicePath);
1449 }
1450
1451 /**
1452 Choose a file in the specified directory.
1453
1454 If user input NULL for the RootDirectory, will choose file in the system.
1455
1456 If user input *File != NULL, function will return the allocate device path
1457 info for the choosed file, caller has to free the memory after use it.
1458
1459 @param RootDirectory Pointer to the root directory.
1460 @param FileType The file type need to choose.
1461 @param ChooseHandler Function pointer to the extra task need to do
1462 after choose one file.
1463 @param File Return the device path for the last time chosed file.
1464
1465 @retval EFI_SUCESS Choose file success.
1466 @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL
1467 One of them must not NULL.
1468 @retval Other errors Choose file failed.
1469 **/
1470 EFI_STATUS
1471 EFIAPI
1472 ChooseFile (
1473 IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
1474 IN CHAR16 *FileType, OPTIONAL
1475 IN CHOOSE_HANDLER ChooseHandler, OPTIONAL
1476 OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL
1477 )
1478 {
1479 EFI_FILE_HANDLE FileHandle;
1480 EFI_STATUS Status;
1481 UINT16 *FileName;
1482 EFI_HANDLE DeviceHandle;
1483
1484 if ((ChooseHandler == NULL) && (File == NULL)) {
1485 return EFI_INVALID_PARAMETER;
1486 }
1487
1488 mQuestionIdUpdate = 0;
1489 FileName = NULL;
1490
1491 gFileExplorerPrivate.RetDevicePath = NULL;
1492 gFileExplorerPrivate.ChooseHandler = ChooseHandler;
1493 if (FileType != NULL) {
1494 gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType);
1495 ASSERT(gFileExplorerPrivate.FileType != NULL);
1496 LibToLowerString(gFileExplorerPrivate.FileType);
1497 } else {
1498 gFileExplorerPrivate.FileType = NULL;
1499 }
1500
1501 if (RootDirectory == NULL) {
1502 Status = LibFindFileSystem();
1503 } else {
1504 Status = LibGetFileHandleFromDevicePath(RootDirectory, &FileHandle, &FileName, &DeviceHandle);
1505 if (EFI_ERROR (Status)) {
1506 goto Done;
1507 }
1508
1509 Status = LibFindFiles (FileHandle, FileName, DeviceHandle);
1510 }
1511 if (EFI_ERROR (Status)) {
1512 goto Done;
1513 }
1514
1515 LibUpdateFileExplorePage();
1516
1517 gFileExplorerPrivate.FormBrowser2->SendForm (
1518 gFileExplorerPrivate.FormBrowser2,
1519 &gFileExplorerPrivate.FeHiiHandle,
1520 1,
1521 &FileExplorerGuid,
1522 0,
1523 NULL,
1524 NULL
1525 );
1526
1527 Done:
1528 if ((Status == EFI_SUCCESS) && (File != NULL)) {
1529 *File = gFileExplorerPrivate.RetDevicePath;
1530 } else if (gFileExplorerPrivate.RetDevicePath != NULL) {
1531 FreePool (gFileExplorerPrivate.RetDevicePath);
1532 }
1533
1534 if (gFileExplorerPrivate.FileType != NULL) {
1535 FreePool (gFileExplorerPrivate.FileType);
1536 }
1537
1538 LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
1539
1540 if (FileName != NULL) {
1541 FreePool (FileName);
1542 }
1543
1544 return Status;
1545 }
1546
1547 /**
1548
1549 Install Boot Manager Menu driver.
1550
1551 @param ImageHandle The image handle.
1552 @param SystemTable The system table.
1553
1554 @retval EFI_SUCEESS Install File explorer library success.
1555
1556 **/
1557 EFI_STATUS
1558 EFIAPI
1559 FileExplorerLibConstructor (
1560 IN EFI_HANDLE ImageHandle,
1561 IN EFI_SYSTEM_TABLE *SystemTable
1562 )
1563 {
1564 EFI_STATUS Status;
1565
1566 gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath);
1567 ASSERT (gHiiVendorDevicePath != NULL);
1568 CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid);
1569
1570 //
1571 // Install Device Path Protocol and Config Access protocol to driver handle
1572 //
1573 Status = gBS->InstallMultipleProtocolInterfaces (
1574 &gFileExplorerPrivate.FeDriverHandle,
1575 &gEfiDevicePathProtocolGuid,
1576 gHiiVendorDevicePath,
1577 &gEfiHiiConfigAccessProtocolGuid,
1578 &gFileExplorerPrivate.FeConfigAccess,
1579 NULL
1580 );
1581 if (Status == EFI_ALREADY_STARTED) {
1582 return EFI_SUCCESS;
1583 }
1584 if (EFI_ERROR (Status)) {
1585 return Status;
1586 }
1587
1588 //
1589 // Post our File Explorer VFR binary to the HII database.
1590 //
1591 gFileExplorerPrivate.FeHiiHandle = HiiAddPackages (
1592 &FileExplorerGuid,
1593 gFileExplorerPrivate.FeDriverHandle,
1594 FileExplorerVfrBin,
1595 FileExplorerLibStrings,
1596 NULL
1597 );
1598 ASSERT (gFileExplorerPrivate.FeHiiHandle != NULL);
1599
1600 //
1601 // Locate Formbrowser2 protocol
1602 //
1603 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFileExplorerPrivate.FormBrowser2);
1604 ASSERT_EFI_ERROR (Status);
1605
1606 InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head);
1607
1608 return EFI_SUCCESS;
1609 }
1610
1611 /**
1612 Unloads the application and its installed protocol.
1613
1614 @param[in] ImageHandle Handle that identifies the image to be unloaded.
1615 @param[in] SystemTable The system table.
1616
1617 @retval EFI_SUCCESS The image has been unloaded.
1618 **/
1619 EFI_STATUS
1620 EFIAPI
1621 FileExplorerLibDestructor (
1622 IN EFI_HANDLE ImageHandle,
1623 IN EFI_SYSTEM_TABLE *SystemTable
1624 )
1625 {
1626 EFI_STATUS Status;
1627
1628 ASSERT (gHiiVendorDevicePath != NULL);
1629
1630 if (gFileExplorerPrivate.FeDriverHandle != NULL) {
1631 Status = gBS->UninstallMultipleProtocolInterfaces (
1632 gFileExplorerPrivate.FeDriverHandle,
1633 &gEfiDevicePathProtocolGuid,
1634 gHiiVendorDevicePath,
1635 &gEfiHiiConfigAccessProtocolGuid,
1636 &gFileExplorerPrivate.FeConfigAccess,
1637 NULL
1638 );
1639 ASSERT_EFI_ERROR (Status);
1640
1641 HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle);
1642 gFileExplorerPrivate.FeDriverHandle = NULL;
1643 }
1644
1645 FreePool (gHiiVendorDevicePath);
1646
1647 return EFI_SUCCESS;
1648 }
1649