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