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