- Timestamp:
- Oct 27, 2010 3:20:21 PM (14 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/ExtPackManagerImpl.cpp
r33487 r33521 22 22 #include "ExtPackManagerImpl.h" 23 23 24 #include <iprt/ctype.h> 24 25 #include <iprt/dir.h> 26 #include <iprt/env.h> 25 27 #include <iprt/file.h> 26 28 #include <iprt/ldr.h> 27 29 #include <iprt/param.h> 28 30 #include <iprt/path.h> 31 #include <iprt/pipe.h> 32 #include <iprt/process.h> 33 #include <iprt/string.h> 29 34 30 35 #include <VBox/com/array.h> 36 #include <VBox/com/ErrorInfo.h> 31 37 #include <VBox/log.h> 32 38 #include "AutoCaller.h" 39 40 41 /******************************************************************************* 42 * Defined Constants And Macros * 43 *******************************************************************************/ 44 /** @name VBOX_EXTPACK_HELPER_NAME 45 * The name of the utility program we employ to install and uninstall the 46 * extension packs. This is a set-uid-to-root binary on unixy platforms, which 47 * is why it has to be a separate program. 48 */ 49 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) 50 # define VBOX_EXTPACK_HELPER_NAME "VBoxExtPackHelper.exe" 51 #else 52 # define VBOX_EXTPACK_HELPER_NAME "VBoxExtPackHelper" 53 #endif 33 54 34 55 … … 220 241 } 221 242 243 /** 244 * Refreshes the extension pack state. 245 * 246 * This is called by the manager so that the on disk changes are picked up. 247 * 248 * @returns S_OK or COM error status with error information. 249 * @param pfCanDelete Optional can-delete-this-object output indicator. 250 */ 251 HRESULT ExtPack::refresh(bool *pfCanDelete) 252 { 253 if (pfCanDelete) 254 *pfCanDelete = false; 255 return S_OK; 256 } 257 222 258 223 259 … … 358 394 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS); 359 395 360 hrc = VBOX_E_OBJECT_NOT_FOUND; 361 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin(); 362 it != m->llInstalledExtPacks.end(); 363 it++) 364 { 365 ExtPack::Data *pExtPackData = (*it)->m; 366 if ( pExtPackData 367 && pExtPackData->strName.compare(strName) == 0) 368 { 369 (*it).queryInterfaceTo(a_pExtPack); 370 hrc = S_OK; 371 break; 372 } 373 } 396 ComPtr<ExtPack> ptrExtPack = findExtPack(strName.c_str()); 397 if (!ptrExtPack.isNull()) 398 ptrExtPack.queryInterfaceTo(a_pExtPack); 399 else 400 hrc = VBOX_E_OBJECT_NOT_FOUND; 374 401 } 375 402 … … 383 410 Utf8Str strTarball(a_bstrTarball); 384 411 412 AutoCaller autoCaller(this); 413 HRESULT hrc = autoCaller.rc(); 414 if (SUCCEEDED(hrc)) 415 { 416 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); 417 418 /* 419 * Check that the file exists and that we can access it. 420 */ 421 if (RTFileExists(strTarball.c_str())) 422 { 423 RTFILE hFile; 424 int vrc = RTFileOpen(&hFile, strTarball.c_str(), RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN); 425 if (RT_SUCCESS(vrc)) 426 { 427 RTFSOBJINFO ObjInfo; 428 vrc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING); 429 if ( RT_SUCCESS(vrc) 430 && RTFS_IS_FILE(ObjInfo.Attr.fMode)) 431 { 432 /* 433 * Derive the name of the extension pack from the file 434 * name. 435 * 436 * RESTRICTION: The name can only contain english alphabet 437 * charactes, decimal digits and space. 438 * Impose a max length of 64 chars. 439 */ 440 char *pszName = RTStrDup(RTPathFilename(strTarball.c_str())); 441 if (pszName) 442 { 443 char *pszEnd = pszName; 444 while (RT_C_IS_ALNUM(*pszEnd) || *pszEnd == ' ') 445 pszEnd++; 446 if ( pszEnd == pszName 447 || pszEnd - pszName <= 64) 448 { 449 *pszEnd = '\0'; 450 451 /* 452 * Refresh the data we have on the extension pack 453 * as it may be made stale by direct meddling or 454 * some other user. 455 */ 456 ExtPack *pExtPack; 457 hrc = refreshExtPack(pszName, false /*a_fUnsuableIsError*/, &pExtPack); 458 if (SUCCEEDED(hrc) && !pExtPack) 459 { 460 /* 461 * Run the set-uid-to-root binary that performs the actual 462 * installation. Then create an object for the packet (we 463 * do this even on failure, to be on the safe side). 464 */ 465 char szTarballFd[64]; 466 RTStrPrintf(szTarballFd, sizeof(szTarballFd), "0x%RX64", 467 (uint64_t)RTFileToNative(hFile)); 468 469 hrc = runSetUidToRootHelper("install", 470 "--basepath", m->strBasePath.c_str(), 471 "--name", pszName, 472 "--tarball", strTarball.c_str(), 473 "--tarball-fd", &szTarballFd[0], 474 NULL); 475 if (SUCCEEDED(hrc)) 476 { 477 hrc = refreshExtPack(pszName, true /*a_fUnsuableIsError*/, &pExtPack); 478 if (SUCCEEDED(hrc)) 479 LogRel(("ExtPackManager: Successfully installed extension pack '%s'.\n", pszName)); 480 } 481 else 482 { 483 ErrorInfoKeeper Eik; 484 refreshExtPack(pszName, false /*a_fUnsuableIsError*/, NULL); 485 } 486 } 487 else if (SUCCEEDED(hrc)) 488 hrc = setError(E_FAIL, 489 tr("Extension pack '%s' is already installed." 490 " In case of a reinstallation, please uninstall it first"), 491 pszName); 492 } 493 else 494 hrc = setError(E_FAIL, tr("Malformed '%s' file name"), strTarball.c_str()); 495 } 496 else 497 hrc = E_OUTOFMEMORY; 498 } 499 else if (RT_SUCCESS(vrc)) 500 hrc = setError(E_FAIL, tr("'%s' is not a regular file"), strTarball.c_str()); 501 else 502 hrc = setError(E_FAIL, tr("Failed to query info on '%s' (%Rrc)"), strTarball.c_str(), vrc); 503 RTFileClose(hFile); 504 } 505 else 506 hrc = setError(E_FAIL, tr("Failed to open '%s' (%Rrc)"), strTarball.c_str(), vrc); 507 } 508 else if (RTPathExists(strTarball.c_str())) 509 hrc = setError(E_FAIL, tr("'%s' is not a regular file"), strTarball.c_str()); 510 else 511 hrc = setError(E_FAIL, tr("File '%s' was inaccessible or not found"), strTarball.c_str()); 512 } 513 514 return hrc; 515 } 516 517 STDMETHODIMP ExtPackManager::Uninstall(IN_BSTR a_bstrName, BOOL a_fForcedRemoval) 518 { 519 CheckComArgNotNull(a_bstrName); 520 Utf8Str strName(a_bstrName); 521 522 AutoCaller autoCaller(this); 523 HRESULT hrc = autoCaller.rc(); 524 if (SUCCEEDED(hrc)) 525 { 526 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); 527 528 /* 529 * Refresh the data we have on the extension pack as it may be made 530 * stale by direct meddling or some other user. 531 */ 532 ExtPack *pExtPack; 533 hrc = refreshExtPack(strName.c_str(), false /*a_fUnsuableIsError*/, &pExtPack); 534 if (SUCCEEDED(hrc)) 535 { 536 if (!pExtPack) 537 { 538 LogRel(("ExtPackManager: Extension pack '%s' is not installed, so nothing to uninstall.\n", strName.c_str())); 539 hrc = S_OK; /* nothing to uninstall */ 540 } 541 else 542 { 543 /* 544 * Run the set-uid-to-root binary that performs the 545 * uninstallation. Then refresh the object. 546 * 547 * This refresh is theorically subject to races, but it's of 548 * the don't-do-that variety. 549 */ 550 hrc = runSetUidToRootHelper("uninstall", 551 "--basepath", m->strBasePath.c_str(), 552 "--name", strName.c_str(), 553 NULL); 554 if (SUCCEEDED(hrc)) 555 { 556 hrc = refreshExtPack(strName.c_str(), false /*a_fUnsuableIsError*/, &pExtPack); 557 if (SUCCEEDED(hrc)) 558 { 559 if (!pExtPack) 560 LogRel(("ExtPackManager: Successfully uninstalled extension pack '%s'.\n", strName.c_str())); 561 else 562 hrc = setError(E_UNEXPECTED, 563 tr("Uninstall extension pack '%s' failed under mysterious circumstances"), 564 strName.c_str()); 565 } 566 } 567 else 568 { 569 ErrorInfoKeeper Eik; 570 refreshExtPack(strName.c_str(), false /*a_fUnsuableIsError*/, NULL); 571 } 572 573 } 574 } 575 } 576 577 return hrc; 578 } 579 580 581 /** 582 * Runs the helper program that does the privileged operations. 583 * 584 * @returns S_OK or a failure status with error information set. 585 * @param a_pszCommand The command to execute. 586 * @param ... The argument strings that goes along with the 587 * command. Maximum is about 16. Terminated by a 588 * NULL. 589 */ 590 HRESULT ExtPackManager::runSetUidToRootHelper(const char *a_pszCommand, ...) 591 { 385 592 /* 386 * Check that the file exists and that we can access it. 593 * Calculate the path to the helper program. 594 */ 595 char szExecName[RTPATH_MAX]; 596 int vrc = RTPathAppPrivateArch(szExecName, sizeof(szExecName)); 597 AssertLogRelRCReturn(vrc, E_UNEXPECTED); 598 599 vrc = RTPathAppend(szExecName, sizeof(szExecName), VBOX_EXTPACK_HELPER_NAME); 600 AssertLogRelRCReturn(vrc, E_UNEXPECTED); 601 602 /* 603 * Convert the variable argument list to a RTProcCreate argument vector. 604 */ 605 const char *apszArgs[20]; 606 unsigned cArgs = 0; 607 apszArgs[cArgs++] = &szExecName[0]; 608 apszArgs[cArgs++] = a_pszCommand; 609 610 va_list va; 611 va_start(va, a_pszCommand); 612 const char *pszLastArg; 613 LogRel(("ExtPack: Executing '%s'", szExecName)); 614 do 615 { 616 LogRel((" '%s'", apszArgs[cArgs - 1])); 617 AssertReturn(cArgs < RT_ELEMENTS(apszArgs) - 1, E_UNEXPECTED); 618 pszLastArg = va_arg(va, const char *); 619 apszArgs[cArgs++] = pszLastArg; 620 } while (pszLastArg != NULL); 621 LogRel(("\n")); 622 va_end(va); 623 apszArgs[cArgs] = NULL; 624 625 /* 626 * Create a PIPE which we attach to stderr so that we can read the error 627 * message on failure and report it back to the caller. 628 */ 629 RTPIPE hPipeR; 630 RTHANDLE hStdErrPipe; 631 hStdErrPipe.enmType = RTHANDLETYPE_PIPE; 632 vrc = RTPipeCreate(&hPipeR, &hStdErrPipe.u.hPipe, RTPIPE_C_INHERIT_WRITE); 633 AssertLogRelRCReturn(vrc, E_UNEXPECTED); 634 635 /* 636 * Spawn the process. 387 637 */ 388 638 HRESULT hrc; 389 if (RTFileExists(strTarball.c_str())) 390 { 391 RTFILE hFile; 392 int vrc = RTFileOpen(&hFile, strTarball.c_str(), RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN); 393 if (RT_SUCCESS(vrc)) 639 RTPROCESS hProcess; 640 vrc = RTProcCreateEx(szExecName, 641 apszArgs, 642 RTENV_DEFAULT, 643 0 /*fFlags*/, 644 NULL /*phStdIn*/, 645 NULL /*phStdOut*/, 646 &hStdErrPipe, 647 NULL /*pszAsUser*/, 648 NULL /*pszPassword*/, 649 &hProcess); 650 if (RT_SUCCESS(vrc)) 651 { 652 vrc = RTPipeClose(hStdErrPipe.u.hPipe); 653 hStdErrPipe.u.hPipe = NIL_RTPIPE; 654 655 /* 656 * Read the pipe output until the process completes. 657 */ 658 RTPROCSTATUS ProcStatus = { -42, RTPROCEXITREASON_ABEND }; 659 size_t cbStdErrBuf = 0; 660 size_t offStdErrBuf = 0; 661 char *pszStdErrBuf = NULL; 662 do 394 663 { 395 664 /* 396 * . 665 * Service the pipe. Block waiting for output or the pipe breaking 666 * when the process terminates. 397 667 */ 398 399 400 RTFileClose(hFile); 668 if (hPipeR != NIL_RTPIPE) 669 { 670 char achBuf[16]; //1024 671 size_t cbRead; 672 vrc = RTPipeReadBlocking(hPipeR, achBuf, sizeof(achBuf), &cbRead); 673 if (RT_SUCCESS(vrc)) 674 { 675 /* grow the buffer? */ 676 size_t cbBufReq = offStdErrBuf + cbRead + 1; 677 if ( cbBufReq > cbStdErrBuf 678 && cbBufReq < _256K) 679 { 680 size_t cbNew = RT_ALIGN_Z(cbBufReq, 16); // 1024 681 void *pvNew = RTMemRealloc(pszStdErrBuf, cbNew); 682 if (pvNew) 683 { 684 pszStdErrBuf = (char *)pvNew; 685 cbStdErrBuf = cbNew; 686 } 687 } 688 689 /* append if we've got room. */ 690 if (cbBufReq <= cbStdErrBuf) 691 { 692 memcpy(&pszStdErrBuf[offStdErrBuf], achBuf, cbRead); 693 offStdErrBuf = offStdErrBuf + cbRead; 694 pszStdErrBuf[offStdErrBuf] = '\0'; 695 } 696 } 697 else 698 { 699 AssertLogRelMsg(vrc == VERR_BROKEN_PIPE, ("%Rrc\n", vrc)); 700 RTPipeClose(hPipeR); 701 hPipeR = NIL_RTPIPE; 702 } 703 } 704 705 /* 706 * Service the process. Block if we have no pipe. 707 */ 708 if (hProcess != NIL_RTPROCESS) 709 { 710 vrc = RTProcWait(hProcess, 711 hPipeR == NIL_RTPIPE ? RTPROCWAIT_FLAGS_BLOCK : RTPROCWAIT_FLAGS_NOBLOCK, 712 &ProcStatus); 713 if (RT_SUCCESS(vrc)) 714 hProcess = NIL_RTPROCESS; 715 else 716 AssertLogRelMsgStmt(vrc != VERR_PROCESS_RUNNING, ("%Rrc\n", vrc), hProcess = NIL_RTPROCESS); 717 } 718 } while ( hPipeR != NIL_RTPIPE 719 || hProcess != NIL_RTPROCESS); 720 721 /* 722 * Compose the status code and, on failure, error message. 723 */ 724 LogRel(("ExtPack: enmReason=%d iStatus=%d stderr='%s'\n", 725 ProcStatus.enmReason, ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : "")); 726 727 if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL 728 && ProcStatus.iStatus == 0 729 && offStdErrBuf == 0) 730 hrc = S_OK; 731 else if (ProcStatus.enmReason == RTPROCEXITREASON_NORMAL) 732 { 733 AssertMsg(ProcStatus.iStatus != 0, ("%s\n", pszStdErrBuf)); 734 hrc = setError(E_UNEXPECTED, tr("The installer failed with exit code %d: %s"), 735 ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : ""); 736 } 737 else if (ProcStatus.enmReason == RTPROCEXITREASON_SIGNAL) 738 hrc = setError(E_UNEXPECTED, tr("The installer was killed by signal #d (stderr: %s)"), 739 ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : ""); 740 else if (ProcStatus.enmReason == RTPROCEXITREASON_ABEND) 741 hrc = setError(E_UNEXPECTED, tr("The installer aborted abnormally (stderr: %s)"), 742 offStdErrBuf ? pszStdErrBuf : ""); 743 else 744 hrc = setError(E_UNEXPECTED, tr("internal error: enmReason=%d iStatus=%d stderr='%s'"), 745 ProcStatus.enmReason, ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : ""); 746 747 RTMemFree(pszStdErrBuf); 748 } 749 else 750 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to launch the helper application '%s' (%Rrc)"), szExecName, vrc); 751 752 RTPipeClose(hPipeR); 753 RTPipeClose(hStdErrPipe.u.hPipe); 754 755 return hrc; 756 } 757 758 /** 759 * Finds an installed extension pack. 760 * 761 * @returns Pointer to the extension pack if found, NULL if not. (No reference 762 * counting problem here since the caller must be holding the lock.) 763 * @param a_pszName The name of the extension pack. 764 */ 765 ExtPack *ExtPackManager::findExtPack(const char *a_pszName) 766 { 767 size_t cchName = strlen(a_pszName); 768 769 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin(); 770 it != m->llInstalledExtPacks.end(); 771 it++) 772 { 773 ExtPack::Data *pExtPackData = (*it)->m; 774 if ( pExtPackData 775 && pExtPackData->strName.length() == cchName 776 && pExtPackData->strName.compare(a_pszName, iprt::MiniString::CaseInsensitive) == 0) 777 return (*it); 778 } 779 return NULL; 780 } 781 782 /** 783 * Removes an installed extension pack from the internal list. 784 * 785 * The package is expected to exist! 786 * 787 * @param a_pszName The name of the extension pack. 788 */ 789 void ExtPackManager::removeExtPack(const char *a_pszName) 790 { 791 size_t cchName = strlen(a_pszName); 792 793 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin(); 794 it != m->llInstalledExtPacks.end(); 795 it++) 796 { 797 ExtPack::Data *pExtPackData = (*it)->m; 798 if ( pExtPackData 799 && pExtPackData->strName.length() == cchName 800 && pExtPackData->strName.compare(a_pszName, iprt::MiniString::CaseInsensitive) == 0) 801 { 802 m->llInstalledExtPacks.erase(it); 803 return; 804 } 805 } 806 AssertMsgFailed(("%s\n", a_pszName)); 807 } 808 809 /** 810 * Refreshes the specified extension pack. 811 * 812 * This may remove the extension pack from the list, so any non-smart pointers 813 * to the extension pack object may become invalid. 814 * 815 * @returns S_OK and *ppExtPack on success, COM status code and error message 816 * on failure. 817 * @param a_pszName The extension to update.. 818 * @param a_fUnsuableIsError If @c true, report an unusable extension pack 819 * as an error. 820 * @param a_ppExtPack Where to store the pointer to the extension 821 * pack of it is still around after the refresh. 822 * This is optional. 823 */ 824 HRESULT ExtPackManager::refreshExtPack(const char *a_pszName, bool a_fUnsuableIsError, ExtPack **a_ppExtPack) 825 { 826 HRESULT hrc; 827 ExtPack *pExtPack = findExtPack(a_pszName); 828 if (pExtPack) 829 { 830 /* 831 * Refresh existing object. 832 */ 833 bool fCanDelete; 834 hrc = pExtPack->refresh(&fCanDelete); 835 if (SUCCEEDED(hrc)) 836 { 837 if (fCanDelete) 838 { 839 removeExtPack(a_pszName); 840 pExtPack = NULL; 841 } 842 } 843 } 844 else 845 { 846 /* 847 * Does the dir exist? Make some special effort to deal with case 848 * sensitivie file systems (a_pszName is case insensitive). 849 */ 850 char szDir[RTPATH_MAX]; 851 int vrc = RTPathJoin(szDir, sizeof(szDir), m->strBasePath.c_str(), a_pszName); 852 AssertLogRelRCReturn(vrc, E_FAIL); 853 854 RTDIRENTRYEX Entry; 855 RTFSOBJINFO ObjInfo; 856 vrc = RTPathQueryInfoEx(szDir, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); 857 bool fExists = RT_SUCCESS(vrc) && RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode); 858 if (!fExists) 859 { 860 PRTDIR pDir; 861 vrc = RTDirOpen(&pDir, m->strBasePath.c_str()); 862 if (RT_SUCCESS(vrc)) 863 { 864 for (;;) 865 { 866 vrc = RTDirReadEx(pDir, &Entry, NULL /*pcbDirEntry*/, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); 867 if (RT_FAILURE(vrc)) 868 { 869 AssertLogRelMsg(vrc == VERR_NO_MORE_FILES, ("%Rrc\n", vrc)); 870 break; 871 } 872 if ( RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode) 873 && !RTStrICmp(Entry.szName, a_pszName)) 874 { 875 /* 876 * The installed extension pack has a uses different case. 877 * Update the name and directory variables. 878 */ 879 vrc = RTPathJoin(szDir, sizeof(szDir), m->strBasePath.c_str(), Entry.szName); /* not really necessary */ 880 AssertLogRelRCReturnStmt(vrc, E_UNEXPECTED, RTDirClose(pDir)); 881 a_pszName = Entry.szName; 882 fExists = true; 883 break; 884 } 885 } 886 RTDirClose(pDir); 887 } 888 } 889 if (fExists) 890 { 891 /* 892 * We've got something, create a new extension pack object for it. 893 */ 894 ComObjPtr<ExtPack> NewExtPack; 895 hrc = NewExtPack.createObject(); 896 if (SUCCEEDED(hrc)) 897 hrc = NewExtPack->init(a_pszName, m->strBasePath.c_str()); 898 if (SUCCEEDED(hrc)) 899 { 900 m->llInstalledExtPacks.push_back(NewExtPack); 901 if (NewExtPack->m->fUsable) 902 LogRel(("ExtPackManager: Found extension pack '%s'.\n", a_pszName)); 903 else 904 LogRel(("ExtPackManager: Found bad extension pack '%s': %s\n", 905 a_pszName, NewExtPack->m->strWhyUnusable.c_str() )); 906 pExtPack = NewExtPack; 907 } 401 908 } 402 909 else 403 hrc = setError(E_FAIL, tr("Failed to open '%s' (%Rrc)"), strTarball.c_str(), vrc); 404 } 405 else if (RTPathExists(strTarball.c_str())) 406 hrc = setError(E_FAIL, tr("'%s' is not a regular file"), strTarball.c_str()); 407 else 408 hrc = setError(E_FAIL, tr("File '%s' was inaccessible or not found"), strTarball.c_str()); 409 return hrc; 410 } 411 412 STDMETHODIMP ExtPackManager::Uninstall(IN_BSTR a_bstrName, BOOL a_fForcedRemoval) 413 { 414 NOREF(a_bstrName); NOREF(a_fForcedRemoval); 415 return E_NOTIMPL; 910 hrc = S_OK; 911 } 912 913 /* 914 * Report error if not usable, if that is desired. 915 */ 916 if ( SUCCEEDED(hrc) 917 && pExtPack 918 && a_fUnsuableIsError 919 && !pExtPack->m->fUsable) 920 hrc = setError(E_FAIL, "%s", pExtPack->m->strWhyUnusable.c_str()); 921 922 if (a_ppExtPack) 923 *a_ppExtPack = pExtPack; 924 return hrc; 416 925 } 417 926 … … 430 939 } 431 940 941 432 942 /* vi: set tabstop=4 shiftwidth=4 expandtab: */ -
trunk/src/VBox/Main/include/ExtPackManagerImpl.h
r33474 r33521 63 63 * @{ */ 64 64 void *getCallbackTable(); 65 HRESULT refresh(bool *pfCanDelete); 65 66 /** @} */ 66 67 … … 109 110 /** @name Internal interfaces used by other Main classes. 110 111 * @{ */ 111 int callAllConfigHooks(IConsole *a_pConsole, PVM a_pVM);112 int callAllNewMachineHooks(IMachine *a_pMachine);112 int callAllConfigHooks(IConsole *a_pConsole, PVM a_pVM); 113 int callAllNewMachineHooks(IMachine *a_pMachine); 113 114 /** @} */ 115 116 private: 117 HRESULT runSetUidToRootHelper(const char *a_pszCommand, ...); 118 ExtPack *findExtPack(const char *a_pszName); 119 void removeExtPack(const char *a_pszName); 120 HRESULT refreshExtPack(const char *a_pszName, bool a_fUnsuableIsError, ExtPack **a_ppExtPack); 114 121 115 122 private:
Note:
See TracChangeset
for help on using the changeset viewer.