VirtualBox

Changeset 32866 in vbox


Ignore:
Timestamp:
Oct 1, 2010 2:41:42 PM (14 years ago)
Author:
vboxsync
Message:

Guest Copy/VBoxManage+Main: Added very first bits (not enabled by default yet, untested).

Location:
trunk/src/VBox
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/Makefile.kmk

    r32719 r32866  
    5656        $(if $(VBOX_WITH_AHCI), VBOX_WITH_AHCI) \
    5757        $(if $(VBOX_WITH_ALSA), VBOX_WITH_ALSA) \
     58        $(if $(VBOX_WITH_COPYTOGUEST),VBOX_WITH_COPYTOGUEST) \
    5859        $(if $(VBOX_WITH_E1000),VBOX_WITH_E1000) \
    5960        $(if $(VBOX_WITH_GUEST_CONTROL),VBOX_WITH_GUEST_CONTROL) \
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r32854 r32866  
    6464/** Set by the signal handler. */
    6565static volatile bool    g_fExecCanceled = false;
     66static volatile bool    g_fCopyCanceled = false;
    6667
    6768#endif /* VBOX_ONLY_DOCS */
     
    7778                 "                            [--flags <flags>] [--timeout <msec>]\n"
    7879                 "                            [--verbose] [--wait-for exit,stdout,stderr||]\n"
     80#ifdef VBOX_WITH_COPYTOGUEST
     81                 "\n"
     82                 "                            copyto <vmname>|<uuid>\n"
     83                 "                            <source on host> <destination on guest>\n"
     84                 "                            [--recursive] [--verbose] [--flags <flags>]\n"
     85#endif
    7986                 "\n");
    8087}
     
    8996 * unnecessary here.
    9097 */
    91 static void execProcessSignalHandler(int iSignal)
     98static void ctrlExecProcessSignalHandler(int iSignal)
    9299{
    93100    NOREF(iSignal);
     
    95102}
    96103
    97 static const char *getStatus(ULONG uStatus)
     104static const char *ctrlExecGetStatus(ULONG uStatus)
    98105{
    99106    switch (uStatus)
     
    120127}
    121128
    122 static int handleExecProgram(HandlerArg *a)
     129static int handleCtrlExecProgram(HandlerArg *a)
    123130{
    124131    /*
     
    379386                if (fCancelable)
    380387                {
    381                     signal(SIGINT,   execProcessSignalHandler);
     388                    signal(SIGINT,   ctrlExecProcessSignalHandler);
    382389            #ifdef SIGBREAK
    383                     signal(SIGBREAK, execProcessSignalHandler);
     390                    signal(SIGBREAK, ctrlExecProcessSignalHandler);
    384391            #endif
    385392                }
     
    518525                        rc = guest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &uRetStatus);
    519526                        if (SUCCEEDED(rc))
    520                             RTPrintf("Exit code=%u (Status=%u [%s], Flags=%u)\n",
    521                                     uRetExitCode, uRetStatus, getStatus(uRetStatus), uRetFlags);
     527                            RTPrintf("Exit code=%u (Status=%u [%s], Flags=%u)\n", uRetExitCode, uRetStatus, ctrlExecGetStatus(uRetStatus), uRetFlags);
    522528                    }
    523529                }
     
    533539    return SUCCEEDED(rc) ? 0 : 1;
    534540}
     541
     542#ifdef VBOX_WITH_COPYTOGUEST
     543/**
     544 * Signal handler that sets g_fCopyCanceled.
     545 *
     546 * This can be executed on any thread in the process, on Windows it may even be
     547 * a thread dedicated to delivering this signal.  Do not doing anything
     548 * unnecessary here.
     549 */
     550static void ctrlCopySignalHandler(int iSignal)
     551{
     552    NOREF(iSignal);
     553    ASMAtomicWriteBool(&g_fCopyCanceled, true);
     554}
     555
     556static int handleCtrlCopyTo(HandlerArg *a)
     557{
     558    /*
     559     * Check the syntax.  We can deduce the correct syntax from the number of
     560     * arguments.
     561     */
     562    if (a->argc < 3) /* At least the source + destination should be present :-). */
     563        return errorSyntax(USAGE_GUESTCONTROL, "Incorrect parameters");
     564
     565    Utf8Str Utf8Source(a->argv[1]);
     566    Utf8Str Utf8Dest(a->argv[2]);
     567    uint32_t uFlags = 0;
     568    bool fVerbose = false;
     569    bool fCopyRecursive = false;
     570
     571    /* Iterate through all possible commands (if available). */
     572    bool usageOK = true;
     573    for (int i = 2; usageOK && i < a->argc; i++)
     574    {
     575        if (!strcmp(a->argv[i], "--flags"))
     576        {
     577            if (i + 1 >= a->argc)
     578                usageOK = false;
     579            else
     580            {
     581                /* Nothing to do here yet. */
     582                ++i;
     583            }
     584        }
     585        else if (   !strcmp(a->argv[i], "--recursive")
     586                 || !strcmp(a->argv[i], "--r"))
     587        {
     588            uFlags |= CopyFileFlag_Recursive;
     589        }
     590        else if (   !strcmp(a->argv[i], "--update")
     591                 || !strcmp(a->argv[i], "--u"))
     592        {
     593            uFlags |= CopyFileFlag_Update;
     594        }
     595        else if (   !strcmp(a->argv[i], "--follow")
     596                 || !strcmp(a->argv[i], "--f"))
     597        {
     598            uFlags |= CopyFileFlag_FollowLinks;
     599        }
     600        /** @todo Add force flag for overwriting existing stuff. */
     601        else if (!strcmp(a->argv[i], "--verbose"))
     602            fVerbose = true;
     603        else
     604            return errorSyntax(USAGE_GUESTCONTROL,
     605                               "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
     606    }
     607
     608    if (!usageOK)
     609        return errorSyntax(USAGE_GUESTCONTROL, "Incorrect parameters");
     610
     611    if (Utf8Source.isEmpty())
     612        return errorSyntax(USAGE_GUESTCONTROL,
     613                           "No source specified!");
     614
     615    if (Utf8Dest.isEmpty())
     616        return errorSyntax(USAGE_GUESTCONTROL,
     617                           "No destination specified!");
     618
     619    /* lookup VM. */
     620    ComPtr<IMachine> machine;
     621    /* assume it's an UUID */
     622    HRESULT rc = a->virtualBox->GetMachine(Bstr(a->argv[0]).raw(),
     623                                           machine.asOutParam());
     624    if (FAILED(rc) || !machine)
     625    {
     626        /* must be a name */
     627        CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
     628                                               machine.asOutParam()));
     629    }
     630
     631    if (machine)
     632    {
     633        do
     634        {
     635            /* open an existing session for VM */
     636            CHECK_ERROR_BREAK(machine, LockMachine(a->session, LockType_Shared));
     637            // @todo r=dj assert that it's an existing session
     638
     639            /* get the mutable session machine */
     640            a->session->COMGETTER(Machine)(machine.asOutParam());
     641
     642            /* get the associated console */
     643            ComPtr<IConsole> console;
     644            CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
     645
     646            ComPtr<IGuest> guest;
     647            CHECK_ERROR_BREAK(console, COMGETTER(Guest)(guest.asOutParam()));
     648
     649            ComPtr<IProgress> progress;
     650            ULONG uPID = 0;
     651
     652            if (fVerbose)
     653            {
     654                if (fCopyRecursive)
     655                    RTPrintf("Recursively copying \"%s\" to \"%s\" ...\n", Utf8Source, Utf8Dest);
     656                else
     657                    RTPrintf("Copying \"%s\" to \"%s\" ...\n", Utf8Source, Utf8Dest);
     658            }
     659
     660            /* Do the copy. */
     661            rc = guest->CopyToGuest(Bstr(Utf8Source).raw(), Bstr(Utf8Dest).raw(),
     662                                    uFlags, progress.asOutParam());
     663            if (FAILED(rc))
     664            {
     665                /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way
     666                 * because it contains more accurate info about what went wrong. */
     667                ErrorInfo info(guest, COM_IIDOF(IGuest));
     668                if (info.isFullAvailable())
     669                {
     670                    if (rc == VBOX_E_IPRT_ERROR)
     671                        RTMsgError("%ls.", info.getText().raw());
     672                    else
     673                        RTMsgError("%ls (%Rhrc).", info.getText().raw(), info.getResultCode());
     674                }
     675                break;
     676            }
     677            else
     678            {
     679                /* setup signal handling if cancelable */
     680                ASSERT(progress);
     681                bool fCanceledAlready = false;
     682                BOOL fCancelable;
     683                HRESULT hrc = progress->COMGETTER(Cancelable)(&fCancelable);
     684                if (FAILED(hrc))
     685                    fCancelable = FALSE;
     686                if (fCancelable)
     687                {
     688                    signal(SIGINT,   ctrlCopySignalHandler);
     689            #ifdef SIGBREAK
     690                    signal(SIGBREAK, ctrlCopySignalHandler);
     691            #endif
     692                }
     693
     694                /* Wait for process to exit ... */
     695                BOOL fCompleted = FALSE;
     696                BOOL fCanceled = FALSE;
     697                while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted))))
     698                {
     699                    /* Process async cancelation */
     700                    if (g_fCopyCanceled && !fCanceledAlready)
     701                    {
     702                        hrc = progress->Cancel();
     703                        if (SUCCEEDED(hrc))
     704                            fCanceledAlready = TRUE;
     705                        else
     706                            g_fCopyCanceled = false;
     707                    }
     708
     709                    /* Progress canceled by Main API? */
     710                    if (   SUCCEEDED(progress->COMGETTER(Canceled(&fCanceled)))
     711                        && fCanceled)
     712                    {
     713                        break;
     714                    }
     715                }
     716
     717                /* Undo signal handling */
     718                if (fCancelable)
     719                {
     720                    signal(SIGINT,   SIG_DFL);
     721            #ifdef SIGBREAK
     722                    signal(SIGBREAK, SIG_DFL);
     723            #endif
     724                }
     725
     726                if (fCanceled)
     727                {
     728                    if (fVerbose)
     729                        RTPrintf("Copy operation canceled!\n");
     730                }
     731                else if (   fCompleted
     732                         && SUCCEEDED(rc))
     733                {
     734                    LONG iRc = false;
     735                    CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&iRc), rc);
     736                    if (FAILED(iRc))
     737                    {
     738                        com::ProgressErrorInfo info(progress);
     739                        if (   info.isFullAvailable()
     740                            || info.isBasicAvailable())
     741                        {
     742                            /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way
     743                             * because it contains more accurate info about what went wrong. */
     744                            if (info.getResultCode() == VBOX_E_IPRT_ERROR)
     745                                RTMsgError("%ls.", info.getText().raw());
     746                            else
     747                            {
     748                                RTMsgError("Copy operation error details:");
     749                                GluePrintErrorInfo(info);
     750                            }
     751                        }
     752                        else
     753                        {
     754                            if (RT_FAILURE(rc))
     755                                RTMsgError("Error while looking up error code, rc=%Rrc", rc);
     756                            else
     757                                com::GluePrintRCMessage(iRc);
     758                        }
     759                    }
     760                    else if (fVerbose)
     761                    {
     762                        RTPrintf("Copy operation successful!\n");
     763                    }
     764                }
     765                else
     766                {
     767                    if (fVerbose)
     768                        RTPrintf("Copy operation aborted!\n");
     769                }
     770            }
     771            a->session->UnlockMachine();
     772        } while (0);
     773    }
     774    return SUCCEEDED(rc) ? 0 : 1;
     775}
     776#endif
    535777
    536778/**
     
    552794    if (   strcmp(a->argv[0], "exec") == 0
    553795        || strcmp(a->argv[0], "execute") == 0)
    554         return handleExecProgram(&arg);
     796    {
     797        return handleCtrlExecProgram(&arg);
     798    }
     799#ifdef VBOX_WITH_COPYTOGUEST
     800    else if (   strcmp(a->argv[0], "copyto")  == 0
     801             || strcmp(a->argv[0], "copy_to") == 0)
     802    {
     803        return handleCtrlCopyTo(&arg);
     804    }
     805#endif
    555806
    556807    /* default: */
  • trunk/src/VBox/Main/GuestImpl.cpp

    r32855 r32866  
    3333#endif
    3434#include <iprt/cpp/utils.h>
     35#include <iprt/dir.h>
    3536#include <iprt/getopt.h>
     37#include <iprt/list.h>
     38#include <iprt/path.h>
    3639#include <VBox/pgm.h>
    3740
     
    15391542}
    15401543
     1544#ifdef VBOX_WITH_COPYTOGUEST
     1545int Guest::directoryEntryAppend(const char *pszPath, PRTLISTNODE pList)
     1546{
     1547    using namespace guestControl;
     1548
     1549    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
     1550    AssertPtrReturn(pList, VERR_INVALID_POINTER);
     1551
     1552    LogFlowFunc(("Appending to pList=%p: %s\n", pList, pszPath));
     1553
     1554    DirEntry *pNode = (DirEntry*)RTMemAlloc(sizeof(DirEntry));
     1555    if (pNode == NULL)
     1556        return VERR_NO_MEMORY;
     1557
     1558    if (RT_SUCCESS(RTStrAAppend(&pNode->pszPath, pszPath)))
     1559    {
     1560        pNode->Node.pPrev = NULL;
     1561        pNode->Node.pNext = NULL;
     1562        RTListAppend(pList, &pNode->Node);
     1563        return VINF_SUCCESS;
     1564    }
     1565    return VERR_NO_MEMORY;
     1566}
     1567
     1568int Guest::directoryRead(const char *pszDirectory, const char *pszFilter,
     1569                         ULONG uFlags, ULONG *pcObjects, PRTLISTNODE pList)
     1570{
     1571    using namespace guestControl;
     1572
     1573    AssertPtrReturn(pszDirectory, VERR_INVALID_POINTER);
     1574    /* Filter is optional. */
     1575    AssertPtrReturn(pcObjects, VERR_INVALID_POINTER);
     1576    AssertPtrReturn(pList, VERR_INVALID_POINTER);
     1577
     1578    LogFlowFunc(("Reading directory: %s, filter: %s\n",
     1579                 pszDirectory, pszFilter ? pszFilter : "<None>"));
     1580
     1581    char *pszDirWithFilter = NULL;
     1582    PRTDIR pDir;
     1583    int rc = RTStrAAppend(&pszDirWithFilter, pszDirectory);
     1584    if (RT_SUCCESS(rc))
     1585    {
     1586        if (pszFilter)
     1587        {
     1588            RTStrAAppend(&pszDirWithFilter, pszDirectory);
     1589            rc = RTDirOpenFiltered(&pDir, pszDirectory, RTDIRFILTER_WINNT);
     1590        }
     1591        else
     1592            rc = RTDirOpen(&pDir, pszDirectory);
     1593    }
     1594
     1595    if (RT_SUCCESS(rc))
     1596    {
     1597        rc = directoryEntryAppend(pszDirectory, pList);
     1598        if (RT_SUCCESS(rc))
     1599        {
     1600            *pcObjects = *pcObjects + 1;
     1601            for (;;)
     1602            {
     1603                RTDIRENTRY DirEntry;
     1604                rc = RTDirRead(pDir, &DirEntry, NULL);
     1605                if (RT_FAILURE(rc))
     1606                    break;
     1607                switch (DirEntry.enmType)
     1608                {
     1609                    case RTDIRENTRYTYPE_DIRECTORY:
     1610                        if (uFlags & CopyFileFlag_Recursive)
     1611                            rc = directoryRead(DirEntry.szName, pszFilter,
     1612                                               uFlags, pcObjects, pList);
     1613                        break;
     1614
     1615                    case RTDIRENTRYTYPE_FILE:
     1616                    {
     1617                        char *pszFile;
     1618                        if (RTStrAPrintf(&pszFile, "%s/%s",
     1619                                         pszDirectory, DirEntry.szName))
     1620                        {
     1621                            rc = directoryEntryAppend(pszFile, pList);
     1622                            if (RT_SUCCESS(rc))
     1623                                *pcObjects = *pcObjects + 1;
     1624                            RTStrFree(pszFile);
     1625                        }
     1626                        break;
     1627                    }
     1628
     1629                    case RTDIRENTRYTYPE_SYMLINK:
     1630                        if (   (uFlags & CopyFileFlag_Recursive)
     1631                            && (uFlags & CopyFileFlag_FollowLinks))
     1632                        {
     1633                            rc = directoryRead(DirEntry.szName, pszFilter,
     1634                                               uFlags, pcObjects, pList);
     1635                        }
     1636                        break;
     1637
     1638                    default:
     1639                        break;
     1640                }
     1641                if (RT_FAILURE(rc))
     1642                    break;
     1643            }
     1644        }
     1645        RTDirClose(pDir);
     1646    }
     1647    if (pszDirWithFilter)
     1648        RTStrFree(pszDirWithFilter);
     1649    return rc;
     1650}
     1651#endif
     1652
     1653STDMETHODIMP Guest::CopyToGuest(IN_BSTR aSource, IN_BSTR aDest, ULONG aFlags,
     1654                                IProgress **aProgress)
     1655{
     1656#ifndef VBOX_WITH_GUEST_CONTROL
     1657    ReturnComNotImplemented();
     1658#else  /* VBOX_WITH_GUEST_CONTROL */
     1659#ifndef VBOX_WITH_COPYTOGUEST
     1660    ReturnComNotImplemented();
     1661#else
     1662    using namespace guestControl;
     1663
     1664    CheckComArgStrNotEmptyOrNull(aSource);
     1665    CheckComArgStrNotEmptyOrNull(aDest);
     1666    CheckComArgOutPointerValid(aProgress);
     1667
     1668    AutoCaller autoCaller(this);
     1669    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1670
     1671    /* Validate flags. */
     1672    if (aFlags)
     1673    {
     1674        if (   !(aFlags & CopyFileFlag_Recursive)
     1675            && !(aFlags & CopyFileFlag_Update)
     1676            && !(aFlags & CopyFileFlag_FollowLinks))
     1677            return E_INVALIDARG;
     1678    }
     1679
     1680    HRESULT rc = S_OK;
     1681
     1682    try
     1683    {
     1684        char szSourceAbs[RTPATH_MAX];
     1685        Utf8Str Utf8Dest(aDest);
     1686
     1687        int vrc = RTPathAbs(Utf8Str(aSource).c_str(),
     1688                            szSourceAbs, sizeof(szSourceAbs));
     1689        if (RT_SUCCESS(vrc))
     1690        {
     1691            LogRel(("Copying \"%s\" to guest into \"%s\" ...\n",
     1692                    szSourceAbs, Utf8Dest.c_str()));
     1693        }
     1694        else
     1695            rc = setError(VBOX_E_IPRT_ERROR,
     1696                          tr("Could not determine absolute path! rc=%Rrc"), vrc);
     1697
     1698        ULONG cObjectsToCopy = 0;
     1699        RTLISTNODE listEntries;
     1700        if (SUCCEEDED(rc))
     1701        {
     1702            /*
     1703             * Count objects to copy.
     1704             * This is needed for have multi operation progress object.
     1705             * Examples:
     1706             *     D:\ -> D:\*
     1707             *     E:\asdf\qwer\ -> E:\asdf\qwer\*
     1708             *     C:\temp.txt
     1709             *     C:\Foo\bar\*.txt
     1710             *     /home/foo/bar/movie.avi
     1711             */
     1712            char *pszFileName = RTPathFilename(szSourceAbs);
     1713            RTListInit(&listEntries);
     1714
     1715            vrc = directoryRead(szSourceAbs, pszFileName /* Filter */,
     1716                                    aFlags, &cObjectsToCopy, &listEntries);
     1717            if (RT_FAILURE(vrc))
     1718                rc = setError(VBOX_E_IPRT_ERROR,
     1719                              tr("Could not open source directory! rc=%Rrc"), vrc);
     1720        }
     1721
     1722        if (SUCCEEDED(rc))
     1723        {
     1724            /*
     1725             * Create progress object.  Note that this is a multi operation
     1726             * object to perform an operation per the following steps:
     1727             * - Operation 1 (0): Create/start process.
     1728             * - Operation 2 (1): Wait for process to exit.
     1729             * If this progress completed successfully (S_OK), the process
     1730             * started and exited normally. In any other case an error/exception
     1731             * occured.
     1732             */
     1733            ComObjPtr <Progress> progress;
     1734            rc = progress.createObject();
     1735            if (SUCCEEDED(rc))
     1736            {
     1737                rc = progress->init(static_cast<IGuest*>(this),
     1738                                    Bstr(tr("Executing process")).raw(),
     1739                                    TRUE,
     1740                                    cObjectsToCopy,                             /* Number of operations. */
     1741                                    Bstr(tr("Starting process ...")).raw());    /* Description of first stage. */
     1742            }
     1743            if (FAILED(rc)) return rc;
     1744        }
     1745
     1746        /* Destroy list. */
     1747        DirEntry *pNode = RTListNodeGetFirst(&listEntries, DirEntry, Node);
     1748        while (pNode)
     1749        {
     1750            DirEntry *pNext = RTListNodeGetNext(&pNode->Node, DirEntry, Node);
     1751            bool fLast = RTListNodeIsLast(&listEntries, &pNode->Node);
     1752
     1753            if (pNode->pszPath)
     1754                RTStrFree(pNode->pszPath);
     1755            RTListNodeRemove(&pNode->Node);
     1756            RTMemFree(pNode);
     1757
     1758            if (fLast)
     1759                break;
     1760
     1761            pNode = pNext;
     1762        }
     1763    }
     1764
     1765#if 0
     1766
     1767        /*
     1768         * Prepare process execution.
     1769         */
     1770        int vrc = VINF_SUCCESS;
     1771        Utf8Str Utf8Command(aCommand);
     1772
     1773        /* Adjust timeout */
     1774        if (aTimeoutMS == 0)
     1775            aTimeoutMS = UINT32_MAX;
     1776
     1777        /* Prepare arguments. */
     1778        char **papszArgv = NULL;
     1779        uint32_t uNumArgs = 0;
     1780        if (aArguments > 0)
     1781        {
     1782            com::SafeArray<IN_BSTR> args(ComSafeArrayInArg(aArguments));
     1783            uNumArgs = args.size();
     1784            papszArgv = (char**)RTMemAlloc(sizeof(char*) * (uNumArgs + 1));
     1785            AssertReturn(papszArgv, E_OUTOFMEMORY);
     1786            for (unsigned i = 0; RT_SUCCESS(vrc) && i < uNumArgs; i++)
     1787                vrc = RTUtf16ToUtf8(args[i], &papszArgv[i]);
     1788            papszArgv[uNumArgs] = NULL;
     1789        }
     1790
     1791        Utf8Str Utf8UserName(aUserName);
     1792        Utf8Str Utf8Password(aPassword);
     1793        if (RT_SUCCESS(vrc))
     1794        {
     1795            uint32_t uContextID = 0;
     1796
     1797            char *pszArgs = NULL;
     1798            if (uNumArgs > 0)
     1799                vrc = RTGetOptArgvToString(&pszArgs, papszArgv, 0);
     1800            if (RT_SUCCESS(vrc))
     1801            {
     1802                uint32_t cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
     1803
     1804                /* Prepare environment. */
     1805                void *pvEnv = NULL;
     1806                uint32_t uNumEnv = 0;
     1807                uint32_t cbEnv = 0;
     1808                if (aEnvironment > 0)
     1809                {
     1810                    com::SafeArray<IN_BSTR> env(ComSafeArrayInArg(aEnvironment));
     1811
     1812                    for (unsigned i = 0; i < env.size(); i++)
     1813                    {
     1814                        vrc = prepareExecuteEnv(Utf8Str(env[i]).c_str(), &pvEnv, &cbEnv, &uNumEnv);
     1815                        if (RT_FAILURE(vrc))
     1816                            break;
     1817                    }
     1818                }
     1819
     1820                LogRel(("Executing guest process \"%s\" as user \"%s\" ...\n",
     1821                        Utf8Command.c_str(), Utf8UserName.c_str()));
     1822
     1823                if (RT_SUCCESS(vrc))
     1824                {
     1825                    PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
     1826                    AssertReturn(pData, VBOX_E_IPRT_ERROR);
     1827                    RT_ZERO(*pData);
     1828                    uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START,
     1829                                                        pData, sizeof(CALLBACKDATAEXECSTATUS), progress);
     1830                    Assert(uContextID > 0);
     1831
     1832                    VBOXHGCMSVCPARM paParms[15];
     1833                    int i = 0;
     1834                    paParms[i++].setUInt32(uContextID);
     1835                    paParms[i++].setPointer((void*)Utf8Command.c_str(), (uint32_t)Utf8Command.length() + 1);
     1836                    paParms[i++].setUInt32(aFlags);
     1837                    paParms[i++].setUInt32(uNumArgs);
     1838                    paParms[i++].setPointer((void*)pszArgs, cbArgs);
     1839                    paParms[i++].setUInt32(uNumEnv);
     1840                    paParms[i++].setUInt32(cbEnv);
     1841                    paParms[i++].setPointer((void*)pvEnv, cbEnv);
     1842                    paParms[i++].setPointer((void*)Utf8UserName.c_str(), (uint32_t)Utf8UserName.length() + 1);
     1843                    paParms[i++].setPointer((void*)Utf8Password.c_str(), (uint32_t)Utf8Password.length() + 1);
     1844                    paParms[i++].setUInt32(aTimeoutMS);
     1845
     1846                    VMMDev *vmmDev;
     1847                    {
     1848                        /* Make sure mParent is valid, so set the read lock while using.
     1849                         * Do not keep this lock while doing the actual call, because in the meanwhile
     1850                         * another thread could request a write lock which would be a bad idea ... */
     1851                        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     1852
     1853                        /* Forward the information to the VMM device. */
     1854                        AssertPtr(mParent);
     1855                        vmmDev = mParent->getVMMDev();
     1856                    }
     1857
     1858                    if (vmmDev)
     1859                    {
     1860                        LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
     1861                        vrc = vmmDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_CMD,
     1862                                                   i, paParms);
     1863                    }
     1864                    else
     1865                        vrc = VERR_INVALID_VM_HANDLE;
     1866                    RTMemFree(pvEnv);
     1867                }
     1868                RTStrFree(pszArgs);
     1869            }
     1870            if (RT_SUCCESS(vrc))
     1871            {
     1872                LogFlowFunc(("Waiting for HGCM callback (timeout=%ldms) ...\n", aTimeoutMS));
     1873
     1874                /*
     1875                 * Wait for the HGCM low level callback until the process
     1876                 * has been started (or something went wrong). This is necessary to
     1877                 * get the PID.
     1878                 */
     1879                CallbackMapIter it = getCtrlCallbackContextByID(uContextID);
     1880                BOOL fCanceled = FALSE;
     1881                if (it != mCallbackMap.end())
     1882                {
     1883                    ComAssert(!it->second.pProgress.isNull());
     1884
     1885                    /*
     1886                     * Wait for the first stage (=0) to complete (that is starting the process).
     1887                     */
     1888                    PCALLBACKDATAEXECSTATUS pData = NULL;
     1889                    rc = it->second.pProgress->WaitForOperationCompletion(0, aTimeoutMS);
     1890                    if (SUCCEEDED(rc))
     1891                    {
     1892                        /* Was the operation canceled by one of the parties? */
     1893                        rc = it->second.pProgress->COMGETTER(Canceled)(&fCanceled);
     1894                        if (FAILED(rc)) throw rc;
     1895
     1896                        if (!fCanceled)
     1897                        {
     1898                            AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     1899
     1900                            pData = (PCALLBACKDATAEXECSTATUS)it->second.pvData;
     1901                            Assert(it->second.cbData == sizeof(CALLBACKDATAEXECSTATUS));
     1902                            AssertPtr(pData);
     1903
     1904                            /* Did we get some status? */
     1905                            switch (pData->u32Status)
     1906                            {
     1907                                case PROC_STS_STARTED:
     1908                                    /* Process is (still) running; get PID. */
     1909                                    *aPID = pData->u32PID;
     1910                                    break;
     1911
     1912                                /* In any other case the process either already
     1913                                 * terminated or something else went wrong, so no PID ... */
     1914                                case PROC_STS_TEN: /* Terminated normally. */
     1915                                case PROC_STS_TEA: /* Terminated abnormally. */
     1916                                case PROC_STS_TES: /* Terminated through signal. */
     1917                                case PROC_STS_TOK:
     1918                                case PROC_STS_TOA:
     1919                                case PROC_STS_DWN:
     1920                                    /*
     1921                                     * Process (already) ended, but we want to get the
     1922                                     * PID anyway to retrieve the output in a later call.
     1923                                     */
     1924                                    *aPID = pData->u32PID;
     1925                                    break;
     1926
     1927                                case PROC_STS_ERROR:
     1928                                    vrc = pData->u32Flags; /* u32Flags member contains IPRT error code. */
     1929                                    break;
     1930
     1931                                case PROC_STS_UNDEFINED:
     1932                                    vrc = VERR_TIMEOUT;    /* Operation did not complete within time. */
     1933                                    break;
     1934
     1935                                default:
     1936                                    vrc = VERR_INVALID_PARAMETER; /* Unknown status, should never happen! */
     1937                                    break;
     1938                            }
     1939                        }
     1940                        else /* Operation was canceled. */
     1941                            vrc = VERR_CANCELLED;
     1942                    }
     1943                    else /* Operation did not complete within time. */
     1944                        vrc = VERR_TIMEOUT;
     1945
     1946                    /*
     1947                     * Do *not* remove the callback yet - we might wait with the IProgress object on something
     1948                     * else (like end of process) ...
     1949                     */
     1950                    if (RT_FAILURE(vrc))
     1951                    {
     1952                        if (vrc == VERR_FILE_NOT_FOUND) /* This is the most likely error. */
     1953                            rc = setError(VBOX_E_IPRT_ERROR,
     1954                                          tr("The file '%s' was not found on guest"), Utf8Command.c_str());
     1955                        else if (vrc == VERR_PATH_NOT_FOUND)
     1956                            rc = setError(VBOX_E_IPRT_ERROR,
     1957                                          tr("The path to file '%s' was not found on guest"), Utf8Command.c_str());
     1958                        else if (vrc == VERR_BAD_EXE_FORMAT)
     1959                            rc = setError(VBOX_E_IPRT_ERROR,
     1960                                          tr("The file '%s' is not an executable format on guest"), Utf8Command.c_str());
     1961                        else if (vrc == VERR_AUTHENTICATION_FAILURE)
     1962                            rc = setError(VBOX_E_IPRT_ERROR,
     1963                                          tr("The specified user '%s' was not able to logon on guest"), Utf8UserName.c_str());
     1964                        else if (vrc == VERR_TIMEOUT)
     1965                            rc = setError(VBOX_E_IPRT_ERROR,
     1966                                          tr("The guest did not respond within time (%ums)"), aTimeoutMS);
     1967                        else if (vrc == VERR_CANCELLED)
     1968                            rc = setError(VBOX_E_IPRT_ERROR,
     1969                                          tr("The execution operation was canceled"));
     1970                        else if (vrc == VERR_PERMISSION_DENIED)
     1971                            rc = setError(VBOX_E_IPRT_ERROR,
     1972                                          tr("Invalid user/password credentials"));
     1973                        else
     1974                        {
     1975                            if (pData && pData->u32Status == PROC_STS_ERROR)
     1976                                rc = setError(VBOX_E_IPRT_ERROR,
     1977                                              tr("Process could not be started: %Rrc"), pData->u32Flags);
     1978                            else
     1979                                rc = setError(E_UNEXPECTED,
     1980                                              tr("The service call failed with error %Rrc"), vrc);
     1981                        }
     1982                    }
     1983                    else /* Execution went fine. */
     1984                    {
     1985                        /* Return the progress to the caller. */
     1986                        progress.queryInterfaceTo(aProgress);
     1987                    }
     1988                }
     1989                else /* Callback context not found; should never happen! */
     1990                    AssertMsg(it != mCallbackMap.end(), ("Callback context with ID %u not found!", uContextID));
     1991            }
     1992            else /* HGCM related error codes .*/
     1993            {
     1994                if (vrc == VERR_INVALID_VM_HANDLE)
     1995                    rc = setError(VBOX_E_VM_ERROR,
     1996                                  tr("VMM device is not available (is the VM running?)"));
     1997                else if (vrc == VERR_TIMEOUT)
     1998                    rc = setError(VBOX_E_VM_ERROR,
     1999                                  tr("The guest execution service is not ready"));
     2000                else if (vrc == VERR_HGCM_SERVICE_NOT_FOUND)
     2001                    rc = setError(VBOX_E_VM_ERROR,
     2002                                  tr("The guest execution service is not available"));
     2003                else /* HGCM call went wrong. */
     2004                    rc = setError(E_UNEXPECTED,
     2005                                  tr("The HGCM call failed with error %Rrc"), vrc);
     2006            }
     2007
     2008            for (unsigned i = 0; i < uNumArgs; i++)
     2009                RTMemFree(papszArgv[i]);
     2010            RTMemFree(papszArgv);
     2011        }
     2012
     2013        if (RT_FAILURE(vrc))
     2014            LogRel(("Executing guest process \"%s\" as user \"%s\" failed with %Rrc\n",
     2015                    Utf8Command.c_str(), Utf8UserName.c_str(), vrc));
     2016#endif
     2017    catch (std::bad_alloc &)
     2018    {
     2019        rc = E_OUTOFMEMORY;
     2020    }
     2021    return rc;
     2022#endif /* VBOX_WITH_COPYTOGUEST */
     2023#endif /* VBOX_WITH_GUEST_CONTROL */
     2024}
     2025
    15412026// public methods only for internal purposes
    15422027/////////////////////////////////////////////////////////////////////////////
  • trunk/src/VBox/Main/Makefile.kmk

    r32728 r32866  
    5858        $(if $(VBOX_WITH_RAW_MODE),VBOX_WITH_RAW_MODE,) \
    5959        $(if $(VBOX_WITH_NETFLT),VBOX_WITH_NETFLT,) \
     60        $(if $(VBOX_WITH_COPYTOGUEST),VBOX_WITH_COPYTOGUEST,) \
    6061        $(if $(VBOX_WITH_CROGL),VBOX_WITH_CROGL,) \
    6162        $(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r32852 r32866  
    77197719  </enum>
    77207720
     7721  <enum
     7722    name="CopyFileFlag"
     7723    uuid="23f79fdf-738a-493d-b80b-42d607c9b916"
     7724  >
     7725    <desc>
     7726      Host/Guest copy flags.
     7727    </desc>
     7728
     7729    <const name="None"        value="0">
     7730      <desc>No flag set.</desc>
     7731    </const>
     7732
     7733    <const name="Recursive"   value="2">
     7734      <desc>Copy directories recursively.</desc>
     7735    </const>
     7736
     7737    <const name="Update"      value="4">
     7738      <desc>Copy only when the source file is newer than the destination file or when the destination file is missing.</desc>
     7739    </const>
     7740
     7741    <const name="FollowLinks" value="4">
     7742      <desc>Follow symbolic links.</desc>
     7743    </const>
     7744  </enum>
     7745
    77217746  <interface
    77227747     name="IGuest" extends="$unknown"
    7723      uuid="cd80e5b8-faef-4be3-8d0e-d68fee10708d"
     7748     uuid="6e3113ac-ed90-4864-8c2c-942c8022324d"
    77247749     wsmap="managed"
    77257750     >
     
    80078032          The current process status.
    80088033        </desc>
     8034      </param>
     8035    </method>
     8036
     8037    <method name="copyToGuest">
     8038      <desc>
     8039        Copies files/directories from host to the guest.
     8040
     8041        <result name="VBOX_E_IPRT_ERROR">
     8042          Error while copying.
     8043        </result>
     8044
     8045      </desc>
     8046      <param name="source" type="wstring" dir="in">
     8047        <desc>
     8048          Foo.
     8049        </desc>
     8050      </param>
     8051      <param name="dest" type="wstring" dir="in">
     8052        <desc>
     8053          Bar.
     8054        </desc>
     8055      </param>
     8056      <param name="flags" type="unsigned long" dir="in">
     8057        <desc>
     8058          Copy flags.
     8059        </desc>
     8060      </param>
     8061      <param name="progress" type="IProgress" dir="return">
     8062        <desc>Progress object to track the operation completion.</desc>
    80098063      </param>
    80108064    </method>
  • trunk/src/VBox/Main/include/GuestImpl.h

    r32086 r32866  
    2020
    2121#include "VirtualBoxBase.h"
     22#include <iprt/list.h>
    2223#include <VBox/ostypes.h>
    2324
     
    99100    STDMETHOD(GetProcessOutput)(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData));
    100101    STDMETHOD(GetProcessStatus)(ULONG aPID, ULONG *aExitCode, ULONG *aFlags, ULONG *aStatus);
     102    STDMETHOD(CopyToGuest)(IN_BSTR aSource, IN_BSTR aDest, ULONG aFlags, IProgress **aProgress);
    101103    STDMETHOD(InternalGetStatistics)(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
    102104                                     ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon, ULONG *aMemShared, ULONG *aMemCache,
     
    148150    typedef std::map< uint32_t, GuestProcess >::iterator GuestProcessMapIter;
    149151    typedef std::map< uint32_t, GuestProcess >::const_iterator GuestProcessMapIterConst;
     152
     153#ifdef VBOX_WITH_COPYTOGUEST
     154    /*
     155     *
     156     */
     157    struct DirEntry
     158    {
     159        char       *pszPath;
     160        RTLISTNODE  Node;
     161    };
     162
     163    int directoryEntryAppend(const char *pszPath, PRTLISTNODE pList);
     164    int directoryRead(const char *pszDirectory, const char *pszFilter, ULONG uFlags, ULONG *pcObjects, PRTLISTNODE pList);
     165#endif
    150166
    151167    int prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnv);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette