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