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