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