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