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