VirtualBox

Changeset 43162 in vbox


Ignore:
Timestamp:
Sep 4, 2012 1:53:59 PM (12 years ago)
Author:
vboxsync
Message:

Main/Guest Control 2.0: Cleanup, separated guest error handling.

Location:
trunk/src/VBox/Main
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r43065 r43162  
    90319031      <desc>
    90329032        The waiting operation timed out. This also will happen
    9033         when no event has been occured matching the specified the
    9034         current waiting flags in the <link to="IProcess::waitFor"/> call.
     9033        when no event has been occured matching the
     9034        current waiting flags in a <link to="IProcess::waitFor"/> call.
    90359035      </desc>
    90369036    </const>
  • trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h

    r43061 r43162  
    7171
    7272/**
    73  * Generic class for a all guest control callbacks/events.
     73 * Base class for a all guest control callbacks/events.
    7474 */
    7575class GuestCtrlEvent
     
    121121{
    122122public:
     123
    123124    GuestCtrlCallback(void);
    124125
     
    165166typedef std::map < uint32_t, GuestCtrlCallback* > GuestCtrlCallbacks;
    166167
    167 struct GuestProcessWaitResult
    168 {
    169     GuestProcessWaitResult(void)
    170         : mResult(ProcessWaitResult_None),
    171           mRC(VINF_SUCCESS) { }
    172 
    173     /** The wait result when returning from the wait call. */
     168
     169/*
     170 * Class representing a guest control process waiting
     171 * event.
     172 */
     173class GuestProcessWaitEvent : public GuestCtrlEvent
     174{
     175public:
     176
     177    GuestProcessWaitEvent(void);
     178
     179    GuestProcessWaitEvent(uint32_t uWaitFlags);
     180
     181    virtual ~GuestProcessWaitEvent(void);
     182
     183public:
     184
     185    void Destroy(void);
     186
     187    int Init(uint32_t uWaitFlags);
     188
     189    uint32_t GetWaitFlags(void) { return ASMAtomicReadU32(&mFlags); }
     190
     191    ProcessWaitResult_T GetWaitResult(void) { return mResult; }
     192
     193    int GetWaitRc(void) { return mRC; }
     194
     195    int Signal(ProcessWaitResult_T enmResult, int rc = VINF_SUCCESS);
     196
     197protected:
     198
     199    /** The waiting flag(s). The specifies what to
     200     *  wait for. See ProcessWaitFlag_T. */
     201    uint32_t                    mFlags;
     202    /** Structure containing the overall result. */
    174203    ProcessWaitResult_T         mResult;
    175     /** Optional rc to this result. */
    176     int                         mRC;
    177 };
    178 
    179 
    180 /*
    181  * Class representing a guest control process event.
    182  */
    183 class GuestProcessEvent : public GuestCtrlEvent
    184 {
    185 public:
    186     GuestProcessEvent(void);
    187 
    188     GuestProcessEvent(uint32_t uWaitFlags);
    189 
    190     virtual ~GuestProcessEvent(void);
    191 
    192 public:
    193 
    194     void Destroy(void);
    195 
    196     int Init(uint32_t uWaitFlags);
    197 
    198     uint32_t GetWaitFlags(void) { return ASMAtomicReadU32(&mWaitFlags); }
    199 
    200     GuestProcessWaitResult GetResult(void) { return mWaitResult; }
    201 
    202     int Signal(ProcessWaitResult_T enmResult, int rc = VINF_SUCCESS);
    203 
    204 protected:
    205 
    206     /** The waiting flag(s). The specifies what to
    207      *  wait for. */
    208     uint32_t                    mWaitFlags;
    209     /** Structure containing the overall result. */
    210     GuestProcessWaitResult      mWaitResult;
    211204};
    212205
  • trunk/src/VBox/Main/include/GuestDirectoryImpl.h

    r42897 r43162  
    2121
    2222#include "VirtualBoxBase.h"
    23 #include "GuestCtrlImplPrivate.h"
     23#include "GuestProcessImpl.h"
    2424
    25 class GuestProcess;
    2625class GuestSession;
    2726
     
    4544    DECLARE_EMPTY_CTOR_DTOR(GuestDirectory)
    4645
    47     int     init(GuestSession *aSession, const Utf8Str &strPath, const Utf8Str &strFilter = "", uint32_t uFlags = 0);
     46    int     init(GuestSession *aSession, const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags);
    4847    void    uninit(void);
    4948    HRESULT FinalConstruct(void);
     
    6867    /** @name Private internal methods.
    6968     * @{ */
    70     int parseData(GuestProcessStreamBlock &streamBlock);
    7169    /** @}  */
    7270
     
    7775        Utf8Str                    mFilter;
    7876        uint32_t                   mFlags;
    79         /** The stdout stream object which contains all
    80          *  read out data for parsing. Must be persisent
    81          *  between several read() calls. */
    82         GuestProcessStream         mStream;
    83         /** The guest process which is responsible for
    84          *  getting the stdout stream. */
    85         GuestProcess              *mProcess;
     77        GuestProcessTool           mProcessTool;
    8678    } mData;
    8779};
  • trunk/src/VBox/Main/include/GuestFileImpl.h

    r42897 r43162  
    4646    DECLARE_EMPTY_CTOR_DTOR(GuestFile)
    4747
    48     int     init(GuestSession *pSession, const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition, uint32_t uCreationMode, int64_t iOffset);
     48    int     init(GuestSession *pSession, const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition, uint32_t uCreationMode, int64_t iOffset, int *pGuestRc);
    4949    void    uninit(void);
    5050    HRESULT FinalConstruct(void);
  • trunk/src/VBox/Main/include/GuestProcessImpl.h

    r42897 r43162  
    7575    inline bool callbackExists(uint32_t uContextID);
    7676    inline int checkPID(uint32_t uPID);
    77     Utf8Str errorMsg(void) { return mData.mErrorMsg; }
     77    static Utf8Str guestErrorToString(int guestRc);
    7878    bool isReady(void);
    7979    ULONG getProcessID(void) { return mData.mProcessID; }
    80     int rc(void) { return mData.mRC; }
    81     int readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead);
    82     int startProcess(void);
     80    int readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc);
     81    static HRESULT setErrorExternal(VirtualBoxBase *pInterface, int guestRc);
     82    int startProcess(int *pGuestRc);
    8383    int startProcessAsync(void);
    8484    int terminateProcess(void);
    85     int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &guestResult);
    86     int waitForStart(uint32_t uTimeoutMS);
    87     int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten);
     85    int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc);
     86    int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc);
    8887    /** @}  */
    8988
     
    101100    int prepareExecuteEnv(const char *pszEnv, void **ppvList, ULONG *pcbList, ULONG *pcEnvVars);
    102101    int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms);
    103     int setErrorInternal(int rc, const Utf8Str &strMessage);
    104     HRESULT setErrorExternal(void);
    105     int signalWaiters(ProcessWaitResult_T enmWaitResult);
     102    int setProcessStatus(ProcessStatus_T procStatus, int procRc);
     103    int signalWaiters(ProcessWaitResult_T enmWaitResult, int rc = VINF_SUCCESS);
    106104    static DECLCALLBACK(int) startProcessThread(RTTHREAD Thread, void *pvUser);
    107105    /** @}  */
     
    130128        /** The current process status. */
    131129        ProcessStatus_T          mStatus;
    132         /** The overall rc of the process execution. */
    133130        int                      mRC;
    134         /** The overall error message of the
    135          *  process execution. */
    136         Utf8Str                  mErrorMsg;
    137131        /** The next upcoming context ID. */
    138132        ULONG                    mNextContextID;
     
    144138        /** The actual process event for doing the waits.
    145139         *  At the moment we only support one wait a time. */
    146         GuestProcessEvent       *mWaitEvent;
     140        GuestProcessWaitEvent   *mWaitEvent;
    147141    } mData;
     142};
     143
     144/**
     145 * Guest process tool flags.
     146 */
     147/** No flags specified. */
     148#define GUESTPROCESSTOOL_FLAG_NONE            0
     149/** Run until next stream block from stdout has been
     150 *  read in completely, then return.
     151 */
     152#define GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK    RT_BIT(0)
     153
     154/**
     155 * Internal class for handling a VBoxService tool ("vbox_ls", vbox_stat", ...).
     156 */
     157class GuestProcessTool
     158{
     159public:
     160
     161    GuestProcessTool(void);
     162
     163    virtual ~GuestProcessTool(void);
     164
     165public:
     166
     167    int Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo, bool fAsync, int *pGuestRc);
     168
     169    GuestProcessStream &GetStdOut(void) { return mStdOut; }
     170
     171    GuestProcessStream &GetStdErr(void) { return mStdErr; }
     172
     173    int Wait(uint32_t fFlags, int *pGuestRc);
     174
     175    int WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBlock, int *pGuestRc);
     176
     177    int GetCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock);
     178
     179    bool IsRunning(void);
     180
     181    int TerminatedOk(LONG *pExitCode);
     182
     183    void Terminate(void);
     184
     185protected:
     186
     187    GuestSession               *pSession;
     188    ComObjPtr<GuestProcess>     pProcess;
     189    GuestProcessStartupInfo     mStartupInfo;
     190    GuestProcessStream          mStdOut;
     191    GuestProcessStream          mStdErr;
    148192};
    149193
  • trunk/src/VBox/Main/include/GuestSessionImpl.h

    r43002 r43162  
    297297     * @{ */
    298298    int                     directoryRemoveFromList(GuestDirectory *pDirectory);
    299     int                     directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags);
    300     int                     objectCreateTempInternal(Utf8Str strTemplate,
    301                                                      Utf8Str strPath,
    302                                                      bool fDirectory,
    303                                                      Utf8Str &strName,
    304                                                      int *prc);
     299    int                     directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, int *pGuestRc);
     300    int                     objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath, bool fDirectory, const Utf8Str &strName, int *pGuestRc);
    305301    int                     directoryOpenInternal(const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags, ComObjPtr<GuestDirectory> &pDirectory);
    306     int                     directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData);
     302    int                     directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc);
    307303    int                     dispatchToProcess(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData);
    308304    int                     fileRemoveFromList(GuestFile *pFile);
    309     int                     fileRemoveInternal(Utf8Str strPath, int *prc);
     305    int                     fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc);
    310306    int                     fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition,
    311                                              uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile);
    312     int                     fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData);
    313     int                     fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize);
    314     int                     fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData);
     307                                             uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile, int *pGuestRc);
     308    int                     fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc);
     309    int                     fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc);
     310    int                     fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc);
    315311    const GuestCredentials &getCredentials(void);
    316312    const GuestEnvironment &getEnvironment(void);
  • trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp

    r42897 r43162  
    102102int GuestCtrlEvent::Wait(ULONG uTimeoutMS)
    103103{
    104     LogFlowFuncEnter();
     104    LogFlowThisFuncEnter();
    105105
    106106    AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
     
    304304///////////////////////////////////////////////////////////////////////////////
    305305
    306 GuestProcessEvent::GuestProcessEvent(void)
    307     : mWaitFlags(0)
    308 {
    309 }
    310 
    311 GuestProcessEvent::GuestProcessEvent(uint32_t uWaitFlags)
    312     : mWaitFlags(uWaitFlags)
     306GuestProcessWaitEvent::GuestProcessWaitEvent(void)
     307    : mFlags(0),
     308      mResult(ProcessWaitResult_None)
     309{
     310}
     311
     312GuestProcessWaitEvent::GuestProcessWaitEvent(uint32_t uWaitFlags)
     313    : mFlags(uWaitFlags)
    313314{
    314315    int rc = GuestCtrlEvent::Init();
     
    316317}
    317318
    318 GuestProcessEvent::~GuestProcessEvent(void)
     319GuestProcessWaitEvent::~GuestProcessWaitEvent(void)
    319320{
    320321    Destroy();
    321322}
    322323
    323 void GuestProcessEvent::Destroy(void)
     324void GuestProcessWaitEvent::Destroy(void)
    324325{
    325326    GuestCtrlEvent::Destroy();
    326327
    327     mWaitFlags = ProcessWaitForFlag_None;
    328 }
    329 
    330 int GuestProcessEvent::Signal(ProcessWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/)
    331 {
    332     mWaitResult.mRC = rc;
    333     mWaitResult.mResult = enmResult;
     328    mFlags = ProcessWaitForFlag_None;
     329}
     330
     331int GuestProcessWaitEvent::Signal(ProcessWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/)
     332{
     333    mResult = enmResult;
    334334
    335335    return GuestCtrlEvent::Signal(rc);
  • trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp

    r42897 r43162  
    6060
    6161int GuestDirectory::init(GuestSession *aSession,
    62                          const Utf8Str &strPath, const Utf8Str &strFilter /*= ""*/, uint32_t uFlags /*= 0*/)
     62                         const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags)
    6363{
    6464    LogFlowThisFunc(("strPath=%s, strFilter=%s, uFlags=%x\n",
     
    7878    procInfo.mName      = Utf8StrFmt(tr("Reading directory \"%s\"", strPath.c_str()));
    7979    procInfo.mCommand   = Utf8Str(VBOXSERVICE_TOOL_LS);
    80     procInfo.mTimeoutMS = 0; /* No timeout. */
    81     procInfo.mFlags     = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
     80    procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */
     81    procInfo.mFlags     = ProcessCreateFlag_WaitForStdOut;
    8282
    8383    procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
     
    9494     * Start the process asynchronously and keep it around so that we can use
    9595     * it later in subsequent read() calls.
     96     * Note: No guest rc available because operation is asynchronous.
    9697     */
    97     ComObjPtr<GuestProcess> pProcess;
    98     int rc = mData.mSession->processCreateExInteral(procInfo, pProcess);
     98    int rc = mData.mProcessTool.Init(mData.mSession, procInfo,
     99                                     true /* Async */, NULL /* Guest rc */);
    99100    if (RT_SUCCESS(rc))
    100         rc = pProcess->startProcessAsync();
    101 
    102     LogFlowThisFunc(("rc=%Rrc\n", rc));
    103 
    104     if (RT_SUCCESS(rc))
    105     {
    106         mData.mProcess = pProcess;
    107 
     101    {
    108102        /* Confirm a successful initialization when it's the case. */
    109103        autoInitSpan.setSucceeded();
     
    169163/////////////////////////////////////////////////////////////////////////////
    170164
    171 int GuestDirectory::parseData(GuestProcessStreamBlock &streamBlock)
    172 {
    173     LogFlowThisFunc(("cbStream=%RU32\n", mData.mStream.GetSize()));
    174 
    175     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    176 
    177     int rc;
    178     do
    179     {
    180         /* Try parsing the data to see if the current block is complete. */
    181         rc = mData.mStream.ParseBlock(streamBlock);
    182         if (streamBlock.GetCount())
    183             break;
    184 
    185     } while (RT_SUCCESS(rc));
    186 
    187     LogFlowFuncLeaveRC(rc);
    188     return rc;
    189 }
    190 
    191165// implementation of public methods
    192166/////////////////////////////////////////////////////////////////////////////
     
    204178    AssertPtr(mData.mSession);
    205179    int rc = mData.mSession->directoryRemoveFromList(this);
    206     if (mData.mProcess)
    207     {
    208         int rc2 = mData.mSession->processRemoveFromList(mData.mProcess);
    209         if (RT_SUCCESS(rc))
    210             rc = rc2;
    211     }
     180
     181    mData.mProcessTool.Terminate();
    212182
    213183    /*
     
    233203    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    234204
    235     ComObjPtr<GuestProcess> pProcess = mData.mProcess;
    236     Assert(!pProcess.isNull());
    237 
    238     GuestProcessStreamBlock streamBlock;
    239     GuestFsObjData objData;
    240 
    241     int rc = parseData(streamBlock);
    242     if (   RT_FAILURE(rc)
    243         || streamBlock.IsEmpty()) /* More data needed. */
    244     {
    245         rc = pProcess->waitForStart(30 * 1000 /* 30s timeout */);
     205    GuestProcessStreamBlock curBlock;
     206    int guestRc;
     207
     208    int rc = mData.mProcessTool.WaitEx(GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK,
     209                                       &curBlock, &guestRc);
     210
     211    /*
     212     * Note: The guest process can still be around to serve the next
     213     *       upcoming stream block next time.
     214     */
     215    if (   RT_SUCCESS(rc)
     216        && !mData.mProcessTool.IsRunning())
     217    {
     218        rc = mData.mProcessTool.TerminatedOk(NULL /* Exit code */);
     219        if (rc == VERR_NOT_EQUAL)
     220            rc = VERR_ACCESS_DENIED;
    246221    }
    247222
    248223    if (RT_SUCCESS(rc))
    249224    {
    250         BYTE byBuf[_64K];
    251         size_t cbRead = 0;
    252 
    253         /** @todo Merge with GuestSession::queryFileInfoInternal. */
    254         for (;RT_SUCCESS(rc);)
     225        if (curBlock.GetCount()) /* Did we get content? */
    255226        {
    256             GuestProcessWaitResult waitRes;
    257             rc = pProcess->waitFor(  ProcessWaitForFlag_Terminate
    258                                    | ProcessWaitForFlag_StdOut,
    259                                    30 * 1000 /* Timeout */, waitRes);
    260             if (   RT_FAILURE(rc)
    261                 || waitRes.mResult == ProcessWaitResult_Terminate
    262                 || waitRes.mResult == ProcessWaitResult_Error
    263                 || waitRes.mResult == ProcessWaitResult_Timeout)
    264             {
    265                 if (RT_FAILURE(waitRes.mRC))
    266                     rc = waitRes.mRC;
    267                 break;
    268             }
    269 
    270             rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
    271                                     30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
    272                                     &cbRead);
    273             if (RT_FAILURE(rc))
    274                 break;
    275 
    276             if (cbRead)
    277             {
    278                 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    279 
    280                 rc = mData.mStream.AddData(byBuf, cbRead);
    281                 if (RT_FAILURE(rc))
    282                     break;
    283 
    284                 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n",
    285                                  rc, cbRead, mData.mStream.GetSize()));
    286 
    287                 rc = parseData(streamBlock);
    288                 if (RT_SUCCESS(rc))
    289                 {
    290                     /* Parsing the current stream block succeeded so
    291                      * we don't need more at the moment. */
    292                     break;
    293                 }
    294             }
    295         }
    296 
    297         LogFlowThisFunc(("Reading done with rc=%Rrc, cbRead=%RU64, cbStream=%RU32\n",
    298                          rc, cbRead, mData.mStream.GetSize()));
    299 
    300         if (RT_SUCCESS(rc))
    301         {
    302             rc = parseData(streamBlock);
    303             if (rc == VERR_NO_DATA) /* Since this is the last parsing call, this is ok. */
    304                 rc = VINF_SUCCESS;
    305         }
    306 
    307         /*
    308          * Note: The guest process can still be around to serve the next
    309          *       upcoming stream block next time.
    310          */
    311         if (RT_SUCCESS(rc))
    312         {
    313             /** @todo Move into common function. */
    314             ProcessStatus_T procStatus = ProcessStatus_Undefined;
    315             LONG exitCode = 0;
    316 
    317             HRESULT hr2 = pProcess->COMGETTER(Status(&procStatus));
    318             ComAssertComRC(hr2);
    319             hr2 = pProcess->COMGETTER(ExitCode(&exitCode));
    320             ComAssertComRC(hr2);
    321 
    322             if (   (   procStatus != ProcessStatus_Started
    323                     && procStatus != ProcessStatus_Paused
    324                     && procStatus != ProcessStatus_Terminating
    325                    )
    326                 && exitCode != 0)
    327             {
    328                 rc = VERR_ACCESS_DENIED;
    329             }
    330         }
    331     }
    332 
    333     if (RT_SUCCESS(rc))
    334     {
    335         if (streamBlock.GetCount()) /* Did we get content? */
    336         {
    337             rc = objData.FromLs(streamBlock);
     227            GuestFsObjData objData;
     228            rc = objData.FromLs(curBlock);
    338229            if (RT_FAILURE(rc))
    339230                rc = VERR_PATH_NOT_FOUND;
     
    372263        switch (rc)
    373264        {
     265            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     266                hr = GuestProcess::setErrorExternal(this, guestRc);
     267                break;
     268
    374269            case VERR_ACCESS_DENIED:
    375270                hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Unable to read / access denied"),
     
    383278
    384279            case VERR_NO_MORE_FILES:
     280                /* See SDK reference. */
    385281                hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""),
    386282                              mData.mName.c_str());
  • trunk/src/VBox/Main/src-client/GuestFileImpl.cpp

    r42897 r43162  
    6161int GuestFile::init(GuestSession *pSession, const Utf8Str &strPath,
    6262                    const Utf8Str &strOpenMode, const Utf8Str &strDisposition, uint32_t uCreationMode,
    63                     int64_t iOffset)
     63                    int64_t iOffset, int *pGuestRc)
    6464{
    6565    /* Enclose the state transition NotReady->InInit->Ready. */
     
    7676
    7777    /** @todo Validate parameters! */
     78    /** @todo Implement guest side file handling! */
    7879
    7980    /* Confirm a successful initialization when it's the case. */
  • trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp

    r43062 r43162  
    426426        AssertPtr(pCallback);
    427427#ifdef DEBUG
    428         LogFlowThisFunc(("pCallback=%p\n", pCallback));
     428        LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",
     429                         pCallback, uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID)));
    429430#endif
    430431    }
     
    497498inline int GuestProcess::callbackRemove(uint32_t uContextID)
    498499{
     500    LogFlowThisFunc(("Removing callback (Session: %RU32, Process: %RU32, Count=%RU32) CID=%RU32\n",
     501                     VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID),
     502                     VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID),
     503                     VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID),
     504                     uContextID));
     505
    499506    GuestCtrlCallbacks::iterator it =
    500507        mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));
     
    545552}
    546553
     554/* static */
     555Utf8Str GuestProcess::guestErrorToString(int guestRc)
     556{
     557    Utf8Str strError;
     558
     559    /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
     560    switch (guestRc)
     561    {
     562        case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
     563            strError += Utf8StrFmt(tr("The specified file was not found on guest"));
     564            break;
     565
     566        case VERR_INVALID_VM_HANDLE:
     567            strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)"));
     568            break;
     569
     570        case VERR_HGCM_SERVICE_NOT_FOUND:
     571            strError += Utf8StrFmt(tr("The guest execution service is not available"));
     572            break;
     573
     574        case VERR_PATH_NOT_FOUND:
     575            strError += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
     576            break;
     577
     578        case VERR_BAD_EXE_FORMAT:
     579            strError += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
     580            break;
     581
     582        case VERR_AUTHENTICATION_FAILURE:
     583            strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
     584            break;
     585
     586        case VERR_INVALID_NAME:
     587            strError += Utf8StrFmt(tr("The specified file is an invalid name"));
     588            break;
     589
     590        case VERR_TIMEOUT:
     591            strError += Utf8StrFmt(tr("The guest did not respond within time"));
     592            break;
     593
     594        case VERR_CANCELLED:
     595            strError += Utf8StrFmt(tr("The execution operation was canceled"));
     596            break;
     597
     598        case VERR_PERMISSION_DENIED:
     599            strError += Utf8StrFmt(tr("Invalid user/password credentials"));
     600            break;
     601
     602        case VERR_MAX_PROCS_REACHED:
     603            strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
     604            break;
     605
     606        case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */
     607            strError += Utf8StrFmt(tr("Unable to retrieving requested information"));
     608            break;
     609
     610        case VERR_NOT_FOUND:
     611            strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)"));
     612            break;
     613
     614        default:
     615            strError += Utf8StrFmt(tr("%Rrc"), guestRc);
     616            break;
     617    }
     618
     619    return strError;
     620}
     621
    547622inline bool GuestProcess::isAlive(void)
    548623{
     
    649724        return vrc;
    650725
    651     BOOL fSignal = FALSE;
     726    ProcessStatus_T procStatus = ProcessStatus_Undefined;
     727    int procRc = VINF_SUCCESS;
     728
     729    bool fSignalWaiters = false;
    652730    ProcessWaitResult_T waitRes;
     731
    653732    uint32_t uWaitFlags = mData.mWaitEvent
    654733                        ? mData.mWaitEvent->GetWaitFlags() : 0;
    655734    switch (pData->u32Status)
    656735    {
    657        case PROC_STS_STARTED:
    658         {
    659             fSignal = (uWaitFlags & ProcessWaitForFlag_Start);
     736        case PROC_STS_STARTED:
     737        {
     738            fSignalWaiters = (uWaitFlags & ProcessWaitForFlag_Start);
    660739            /* If the caller only wants to wait until the process has been started,
    661740             * notify in any case. */
    662741            if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
    663                 fSignal = true;
     742                fSignalWaiters = true;
    664743            waitRes = ProcessWaitResult_Start;
    665744
    666             mData.mStatus = ProcessStatus_Started;
    667             mData.mPID = pData->u32PID;
     745            procStatus = ProcessStatus_Started;
     746            mData.mPID = pData->u32PID; /* Set the process PID. */
    668747            break;
    669748        }
     
    671750        case PROC_STS_TEN:
    672751        {
    673             fSignal = TRUE; /* Signal in any case. */
     752            fSignalWaiters = true; /* Signal in any case. */
    674753            waitRes = ProcessWaitResult_Terminate;
    675754
    676             mData.mStatus = ProcessStatus_TerminatedNormally;
     755            procStatus = ProcessStatus_TerminatedNormally;
    677756            mData.mExitCode = pData->u32Flags; /* Contains the exit code. */
    678757            break;
     
    681760        case PROC_STS_TES:
    682761        {
    683             fSignal = TRUE; /* Signal in any case. */
     762            fSignalWaiters = true; /* Signal in any case. */
    684763            waitRes = ProcessWaitResult_Terminate;
    685764
    686             mData.mStatus = ProcessStatus_TerminatedSignal;
     765            procStatus = ProcessStatus_TerminatedSignal;
    687766            mData.mExitCode = pData->u32Flags; /* Contains the signal. */
    688767            break;
     
    691770        case PROC_STS_TEA:
    692771        {
    693             fSignal = TRUE; /* Signal in any case. */
     772            fSignalWaiters = true; /* Signal in any case. */
    694773            waitRes = ProcessWaitResult_Terminate;
    695774
    696             mData.mStatus = ProcessStatus_TerminatedAbnormally;
     775            procStatus = ProcessStatus_TerminatedAbnormally;
    697776            break;
    698777        }
     
    700779        case PROC_STS_TOK:
    701780        {
    702             fSignal = TRUE; /* Signal in any case. */
     781            fSignalWaiters = true; /* Signal in any case. */
    703782            waitRes = ProcessWaitResult_Timeout;
    704783
    705             mData.mStatus = ProcessStatus_TimedOutKilled;
     784            procStatus = ProcessStatus_TimedOutKilled;
    706785            break;
    707786        }
     
    709788        case PROC_STS_TOA:
    710789        {
    711             fSignal = TRUE; /* Signal in any case. */
     790            fSignalWaiters = true; /* Signal in any case. */
    712791            waitRes = ProcessWaitResult_Timeout;
    713792
    714             mData.mStatus = ProcessStatus_TimedOutAbnormally;
     793            procStatus = ProcessStatus_TimedOutAbnormally;
    715794            break;
    716795        }
     
    718797        case PROC_STS_DWN:
    719798        {
    720             fSignal = TRUE; /* Signal in any case. */
     799            fSignalWaiters = true; /* Signal in any case. */
    721800            /* Do we need to report termination? */
    722801            if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
     
    725804                waitRes = ProcessWaitResult_Terminate;
    726805
    727             mData.mStatus = ProcessStatus_Down;
     806            procStatus = ProcessStatus_Down;
    728807            break;
    729808        }
     
    731810        case PROC_STS_ERROR:
    732811        {
    733             fSignal = TRUE; /* Signal in any case. */
     812            fSignalWaiters = true; /* Signal in any case. */
    734813            waitRes = ProcessWaitResult_Error;
    735814
    736             mData.mStatus = ProcessStatus_Error;
    737 
    738             Utf8Str strError = Utf8StrFmt(tr("Guest process \"%s\" could not be started: "), mData.mProcess.mCommand.c_str());
    739 
    740             /* Note: It's not required that the process has been started before. */
    741             if (mData.mPID)
    742             {
    743                 strError += Utf8StrFmt(tr("Error vrc=%Rrc occured (PID %RU32)"), vrc, mData.mPID);
    744             }
    745             else
    746             {
    747                 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
    748                 switch (pData->u32Flags) /* pData->u32Flags contains the IPRT error code from guest side. */
    749                 {
    750                     case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
    751                         strError += Utf8StrFmt(tr("The specified file was not found on guest"));
    752                         break;
    753 
    754                     case VERR_PATH_NOT_FOUND:
    755                         strError += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
    756                         break;
    757 
    758                     case VERR_BAD_EXE_FORMAT:
    759                         strError += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
    760                         break;
    761 
    762                     case VERR_AUTHENTICATION_FAILURE:
    763                         strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
    764                         break;
    765 
    766                     case VERR_INVALID_NAME:
    767                         strError += Utf8StrFmt(tr("The specified file is an invalid name"));
    768                         break;
    769 
    770                     case VERR_TIMEOUT:
    771                         strError += Utf8StrFmt(tr("The guest did not respond within time"));
    772                         break;
    773 
    774                     case VERR_CANCELLED:
    775                         strError += Utf8StrFmt(tr("The execution operation was canceled"));
    776                         break;
    777 
    778                     case VERR_PERMISSION_DENIED:
    779                         strError += Utf8StrFmt(tr("Invalid user/password credentials"));
    780                         break;
    781 
    782                     case VERR_MAX_PROCS_REACHED:
    783                         strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
    784                         break;
    785 
    786                     default:
    787                         strError += Utf8StrFmt(tr("Reported error %Rrc"), pData->u32Flags);
    788                         break;
    789                 }
    790             }
    791 
    792             vrc = setErrorInternal(pData->u32Flags, strError);
    793             AssertRC(vrc);
     815            procRc = pData->u32Flags; /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
     816            procStatus = ProcessStatus_Error;
    794817            break;
    795818        }
     
    799822        {
    800823            /* Silently skip this request. */
    801             fSignal = TRUE; /* Signal in any case. */
     824            fSignalWaiters = true; /* Signal in any case. */
    802825            waitRes = ProcessWaitResult_Status;
    803826
    804             mData.mStatus = ProcessStatus_Undefined;
    805             break;
    806         }
    807     }
    808 
    809     LogFlowThisFunc(("Got vrc=%Rrc, waitResult=%d\n", vrc, waitRes));
     827            procStatus = ProcessStatus_Undefined;
     828            break;
     829        }
     830    }
     831
     832    LogFlowThisFunc(("Got rc=%Rrc, waitRes=%d, procSts=%ld, procRc=%Rrc, fSignalWaiters=%RTbool\n",
     833                     vrc, waitRes, procStatus, procRc, fSignalWaiters));
     834
     835    /* Set the process status. */
     836    int rc2 = setProcessStatus(procStatus, procRc);
     837    if (RT_SUCCESS(vrc))
     838        vrc = rc2;
    810839
    811840    /*
     
    813842     */
    814843    if (pCallback)
    815         vrc = pCallback->Signal();
    816 
    817     if (fSignal)
    818     {
    819         int rc2 = signalWaiters(waitRes);
     844        vrc = pCallback->Signal(procRc);
     845
     846    if (fSignalWaiters)
     847    {
     848        rc2 = signalWaiters(waitRes, procRc);
    820849        if (RT_SUCCESS(vrc))
    821850            vrc = rc2;
     
    885914
    886915int GuestProcess::readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS,
    887                            void *pvData, size_t cbData, size_t *pcbRead)
    888 {
    889     LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32\n",
    890                      mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData));
     916                           void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc)
     917{
     918    LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32, pGuestRc=%p\n",
     919                     mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData, pGuestRc));
    891920    AssertReturn(uSize, VERR_INVALID_PARAMETER);
    892921    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     
    900929        if (pcbRead)
    901930            *pcbRead = 0;
     931        if (pGuestRc)
     932            *pGuestRc = VINF_SUCCESS;
    902933        return VINF_SUCCESS; /* Nothing to read anymore. */
    903934    }
    904935
     936    int vrc = VINF_SUCCESS;
     937
     938    GuestCtrlCallback *pCallbackRead;
     939    try
     940    {
     941        pCallbackRead = new GuestCtrlCallback();
     942        AssertPtr(pCallbackRead);
     943    }
     944    catch(std::bad_alloc &)
     945    {
     946        vrc = VERR_NO_MEMORY;
     947    }
     948
     949    /* Create callback and add it to the map. */
    905950    uint32_t uContextID = 0;
    906     GuestCtrlCallback *pCallbackRead = new GuestCtrlCallback();
    907     if (!pCallbackRead)
    908         return VERR_NO_MEMORY;
    909 
    910     /* Create callback and add it to the map. */
    911     int vrc = pCallbackRead->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT);
    912951    if (RT_SUCCESS(vrc))
    913         vrc = callbackAdd(pCallbackRead, &uContextID);
     952    {
     953        vrc = pCallbackRead->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT);
     954        if (RT_SUCCESS(vrc))
     955            vrc = callbackAdd(pCallbackRead, &uContextID);
     956    }
    914957
    915958    alock.release(); /* Drop the write lock again. */
     
    938981        if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
    939982        {
    940             vrc = pCallbackRead->GetResultCode();
    941             LogFlowThisFunc(("Callback returned vrc=%Rrc, cbData=%RU32\n", vrc, pCallbackRead->GetDataSize()));
    942 
    943             if (RT_SUCCESS(vrc))
     983            int guestRc = pCallbackRead->GetResultCode();
     984            LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackRead->GetDataSize()));
     985
     986            if (RT_SUCCESS(guestRc))
    944987            {
    945988                Assert(pCallbackRead->GetDataSize() == sizeof(CALLBACKDATAEXECOUT));
     
    9591002                    *pcbRead = cbRead;
    9601003            }
    961         }
    962         else
    963             vrc = VERR_TIMEOUT;
     1004            else
     1005                vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
     1006
     1007            if (pGuestRc)
     1008                *pGuestRc = guestRc;
     1009        }
    9641010    }
    9651011
     
    9911037    if (RT_FAILURE(vrc))
    9921038    {
    993         int rc2;
    994         if (vrc == VERR_INVALID_VM_HANDLE)
    995             rc2 = setErrorInternal(vrc, tr("VMM device is not available (is the VM running?)"));
    996         else if (vrc == VERR_NOT_FOUND)
    997             rc2 = setErrorInternal(vrc, tr("The guest execution service is not ready (yet)"));
    998         else if (vrc == VERR_HGCM_SERVICE_NOT_FOUND)
    999             rc2 = setErrorInternal(vrc, tr("The guest execution service is not available"));
    1000         else
    1001             rc2 = setErrorInternal(vrc, Utf8StrFmt(tr("The HGCM call failed with error %Rrc"), vrc));
     1039        int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
    10021040        AssertRC(rc2);
    10031041    }
     
    10081046
    10091047/* Does not do locking; caller is responsible for that! */
    1010 int GuestProcess::setErrorInternal(int vrc, const Utf8Str &strMessage)
    1011 {
    1012     LogFlowThisFunc(("vrc=%Rrc, strMsg=%s\n", vrc, strMessage.c_str()));
    1013 
    1014     Assert(RT_FAILURE(vrc));
    1015     Assert(!strMessage.isEmpty());
     1048int GuestProcess::setProcessStatus(ProcessStatus_T procStatus, int procRc)
     1049{
     1050    LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, procRc=%Rrc\n",
     1051                     mData.mStatus, procStatus, procRc));
    10161052
    10171053#ifdef DEBUG
    1018     /* Do not allow overwriting an already set error. If this happens
    1019      * this means we forgot some error checking/locking somewhere. */
    1020     Assert(RT_SUCCESS(mData.mRC));
    1021     Assert(mData.mErrorMsg.isEmpty());
     1054    if (procStatus == ProcessStatus_Error)
     1055    {
     1056        AssertMsg(RT_FAILURE(procRc), ("Guest rc must be an error (%Rrc)\n", procRc));
     1057        /* Do not allow overwriting an already set error. If this happens
     1058         * this means we forgot some error checking/locking somewhere. */
     1059        AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
     1060    }
     1061    else
     1062        AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc));
    10221063#endif
    10231064
    1024     mData.mStatus = ProcessStatus_Error;
    1025     mData.mRC = vrc;
    1026     mData.mErrorMsg = strMessage;
    1027 
    1028     int rc2 = signalWaiters(ProcessWaitResult_Error);
    1029     LogFlowFuncLeaveRC(rc2);
    1030     return rc2;
    1031 }
    1032 
    1033 HRESULT GuestProcess::setErrorExternal(void)
    1034 {
    1035     return RT_SUCCESS(mData.mRC)
    1036            ? S_OK : setError(VBOX_E_IPRT_ERROR, "%s", mData.mErrorMsg.c_str());
    1037 }
    1038 
    1039 int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult)
    1040 {
    1041     LogFlowThisFunc(("enmWaitResult=%d, mWaitCount=%RU32, mWaitEvent=%p\n",
    1042                  enmWaitResult, mData.mWaitCount, mData.mWaitEvent));
     1065    mData.mStatus = procStatus;
     1066    mData.mRC     = procRc;
     1067
     1068    return VINF_SUCCESS;
     1069}
     1070
     1071/* static */
     1072HRESULT GuestProcess::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
     1073{
     1074    AssertPtr(pInterface);
     1075    AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
     1076
     1077    return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc).c_str());
     1078}
     1079
     1080int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */)
     1081{
     1082    LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",
     1083                     enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));
    10431084
    10441085    /* Note: No write locking here -- already done in the caller. */
     
    10461087    int vrc = VINF_SUCCESS;
    10471088    if (mData.mWaitEvent)
    1048         vrc = mData.mWaitEvent->Signal(enmWaitResult);
     1089        vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);
    10491090    LogFlowFuncLeaveRC(vrc);
    10501091    return vrc;
    10511092}
    10521093
    1053 int GuestProcess::startProcess(void)
     1094int GuestProcess::startProcess(int *pGuestRc)
    10541095{
    10551096    LogFlowThisFunc(("aCmd=%s, aTimeoutMS=%RU32, fFlags=%x\n",
     
    10601101    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    10611102
    1062     int vrc;
     1103    int vrc = VINF_SUCCESS;
    10631104    uint32_t uContextID = 0;
    1064     GuestCtrlCallback *pCallbackStart = new GuestCtrlCallback();
    1065     if (!pCallbackStart)
    1066         return VERR_NO_MEMORY;
    1067 
    1068     mData.mStatus = ProcessStatus_Starting;
    1069 
    1070     /* Create callback and add it to the map. */
    1071     vrc = pCallbackStart->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START);
     1105
     1106    GuestCtrlCallback *pCallbackStart;
     1107    try
     1108    {
     1109        pCallbackStart = new GuestCtrlCallback();
     1110        AssertPtr(pCallbackStart);
     1111    }
     1112    catch(std::bad_alloc &)
     1113    {
     1114        vrc = VERR_NO_MEMORY;
     1115    }
     1116
    10721117    if (RT_SUCCESS(vrc))
    1073         vrc = callbackAdd(pCallbackStart, &uContextID);
     1118    {
     1119        mData.mStatus = ProcessStatus_Starting;
     1120
     1121        /* Create callback and add it to the map. */
     1122        vrc = pCallbackStart->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START);
     1123        if (RT_SUCCESS(vrc))
     1124            vrc = callbackAdd(pCallbackStart, &uContextID);
     1125    }
    10741126
    10751127    if (RT_SUCCESS(vrc))
     
    11751227            if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
    11761228            {
    1177                 vrc = pCallbackStart->GetResultCode();
    1178                 LogFlowThisFunc(("Callback returned vrc=%Rrc\n", vrc));
     1229                int guestRc = pCallbackStart->GetResultCode();
     1230                if (pGuestRc)
     1231                    *pGuestRc = guestRc;
     1232                LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
    11791233            }
    11801234            else
     
    12401294    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    12411295
    1242     int vrc = pProcess->startProcess();
    1243     if (RT_FAILURE(vrc))
    1244     {
    1245         /** @todo What now? */
    1246     }
     1296    int vrc = pProcess->startProcess(NULL /* Guest rc, ignored */);
     1297    /* Nothing to do here anymore. */
    12471298
    12481299    LogFlowFuncLeaveRC(vrc);
     
    12631314}
    12641315
    1265 int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &waitRes)
     1316int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc)
    12661317{
    12671318    LogFlowThisFuncEnter();
     
    12691320    AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
    12701321
    1271     LogFlowThisFunc(("fWaitFlags=%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p\n",
    1272                      fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent));
     1322    LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
     1323                     fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));
    12731324
    12741325    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    12751326
    1276     ProcessStatus_T curStatus = mData.mStatus;
    1277 
    12781327    /* Did some error occur before? Then skip waiting and return. */
    1279     if (curStatus == ProcessStatus_Error)
    1280     {
    1281         waitRes.mResult = ProcessWaitResult_Error;
    1282         return VINF_SUCCESS;
    1283     }
    1284 
    1285     waitRes.mResult = ProcessWaitResult_None;
    1286     waitRes.mRC = VINF_SUCCESS;
    1287 
     1328    if (mData.mStatus == ProcessStatus_Error)
     1329    {
     1330        waitResult = ProcessWaitResult_Error;
     1331        AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest process indicated an error\n", mData.mRC));
     1332        if (pGuestRc)
     1333            *pGuestRc = mData.mRC; /* Return last set error. */
     1334        return VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
     1335    }
     1336
     1337    waitResult = ProcessWaitResult_None;
    12881338    if (   (fWaitFlags & ProcessWaitForFlag_Terminate)
    12891339        || (fWaitFlags & ProcessWaitForFlag_StdIn)
     
    12971347            case ProcessStatus_TerminatedAbnormally:
    12981348            case ProcessStatus_Down:
    1299                 waitRes.mResult = ProcessWaitResult_Terminate;
    1300                 waitRes.mRC = mData.mRC;
     1349                waitResult = ProcessWaitResult_Terminate;
    13011350                break;
    13021351
    13031352            case ProcessStatus_TimedOutKilled:
    13041353            case ProcessStatus_TimedOutAbnormally:
    1305                 waitRes.mResult = ProcessWaitResult_Timeout;
    1306                 waitRes.mRC = mData.mRC;
     1354                waitResult = ProcessWaitResult_Timeout;
    13071355                break;
    13081356
    13091357            case ProcessStatus_Error:
    1310                 waitRes.mResult = ProcessWaitResult_Error;
    1311                 waitRes.mRC = mData.mRC;
     1358                /* Handled above. */
    13121359                break;
    13131360
    13141361            case ProcessStatus_Started:
    13151362            {
    1316                 /* Filter out waits which are *not* supported using
    1317                  * older guest control Guest Additions. */
    1318                 if (mData.mParent->getProtocolVersion() < 2)
    1319                 {
    1320                     /* We don't support waiting for stdin, out + err,
    1321                      * just skip waiting then. */
    1322                     if (   (fWaitFlags & ProcessWaitForFlag_StdIn)
    1323                         || (fWaitFlags & ProcessWaitForFlag_StdOut)
    1324                         || (fWaitFlags & ProcessWaitForFlag_StdErr))
    1325                     {
    1326                         /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */
    1327                         waitRes.mResult = ProcessWaitResult_WaitFlagNotSupported;
    1328                     }
    1329                 }
    1330 
    13311363                /*
    13321364                 * If ProcessCreateFlag_WaitForProcessStartOnly was specified on process creation the
     
    13351367                 */
    13361368                if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
    1337                     waitRes.mResult = ProcessWaitResult_Start;
     1369                    waitResult = ProcessWaitResult_Start;
    13381370                break;
    13391371            }
     
    13601392            case ProcessStatus_TerminatedAbnormally:
    13611393            case ProcessStatus_Down:
    1362                 waitRes.mResult = ProcessWaitResult_Start;
     1394                waitResult = ProcessWaitResult_Start;
    13631395                break;
    13641396
    13651397            case ProcessStatus_Error:
    1366                 waitRes.mResult = ProcessWaitResult_Error;
    1367                 waitRes.mRC = mData.mRC;
     1398                waitResult = ProcessWaitResult_Error;
    13681399                break;
    13691400
    13701401            case ProcessStatus_TimedOutKilled:
    13711402            case ProcessStatus_TimedOutAbnormally:
    1372                 waitRes.mResult = ProcessWaitResult_Timeout;
    1373                 waitRes.mRC = mData.mRC;
     1403                waitResult = ProcessWaitResult_Timeout;
    13741404                break;
    13751405
     
    13851415    }
    13861416
    1387     LogFlowThisFunc(("waitResult=%ld, waitRC=%Rrc\n", waitRes.mResult, waitRes.mRC));
    1388 
    1389     /* No waiting needed? Return immediately. */
    1390     if (waitRes.mResult != ProcessWaitResult_None)
    1391         return VINF_SUCCESS;
     1417    /* Filter out waits which are *not* supported using
     1418     * older guest control Guest Additions. */
     1419    if (mData.mParent->getProtocolVersion() < 2)
     1420    {
     1421        if (   waitResult == ProcessWaitResult_None
     1422            /* We don't support waiting for stdin, out + err,
     1423             * just skip waiting then. */
     1424            && (   (fWaitFlags & ProcessWaitForFlag_StdIn)
     1425                || (fWaitFlags & ProcessWaitForFlag_StdOut)
     1426                || (fWaitFlags & ProcessWaitForFlag_StdErr)
     1427               )
     1428           )
     1429        {
     1430            /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */
     1431            waitResult = ProcessWaitResult_WaitFlagNotSupported;
     1432        }
     1433    }
     1434
     1435    LogFlowThisFunc(("procStatus=%ld, procRc=%Rrc, waitResult=%ld\n",
     1436                     mData.mStatus, mData.mRC, waitResult));
     1437
     1438    /* No waiting needed? Return immediately using the last set error. */
     1439    if (waitResult != ProcessWaitResult_None)
     1440    {
     1441        if (pGuestRc)
     1442            *pGuestRc = mData.mRC; /* Return last set error (if any). */
     1443        return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
     1444    }
    13921445
    13931446    if (mData.mWaitCount > 0)
     
    13951448    mData.mWaitCount++;
    13961449
    1397     Assert(mData.mWaitEvent == NULL);
    1398     mData.mWaitEvent = new GuestProcessEvent(fWaitFlags);
    1399     AssertPtrReturn(mData.mWaitEvent, VERR_NO_MEMORY);
    1400 
    1401     alock.release(); /* Release lock before waiting. */
    1402 
    1403     int vrc = mData.mWaitEvent->Wait(uTimeoutMS);
     1450    int vrc = VINF_SUCCESS;
     1451    try
     1452    {
     1453        Assert(mData.mWaitEvent == NULL);
     1454        mData.mWaitEvent = new GuestProcessWaitEvent(fWaitFlags);
     1455    }
     1456    catch(std::bad_alloc &)
     1457    {
     1458        vrc = VERR_NO_MEMORY;
     1459    }
     1460
    14041461    if (RT_SUCCESS(vrc))
    14051462    {
    1406         waitRes = mData.mWaitEvent->GetResult();
    1407     }
    1408     else if (vrc == VERR_TIMEOUT)
    1409     {
    1410         waitRes.mRC = VINF_SUCCESS;
    1411         waitRes.mResult = ProcessWaitResult_Timeout;
    1412 
    1413         vrc = VINF_SUCCESS;
    1414     }
    1415 
    1416     alock.acquire(); /* Get the lock again. */
    1417 
    1418     /* Note: The caller always is responsible of deleting the
    1419      *       stuff it created before. See close() for more information. */
    1420     delete mData.mWaitEvent;
    1421     mData.mWaitEvent = NULL;
    1422 
     1463        GuestProcessWaitEvent *pEvent = mData.mWaitEvent;
     1464        AssertPtr(pEvent);
     1465
     1466        alock.release(); /* Release lock before waiting. */
     1467
     1468        vrc = pEvent->Wait(uTimeoutMS);
     1469        if (RT_SUCCESS(vrc))
     1470        {
     1471            waitResult = pEvent->GetWaitResult();
     1472            int waitRc = pEvent->GetWaitRc();
     1473
     1474            LogFlowThisFunc(("Waiting event returned rc=%Rrc\n", waitRc));
     1475
     1476            if (pGuestRc)
     1477                *pGuestRc = waitRc;
     1478
     1479            vrc = RT_SUCCESS(waitRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
     1480        }
     1481
     1482        alock.acquire(); /* Get the lock again. */
     1483
     1484        /* Note: The caller always is responsible of deleting the
     1485         *       stuff it created before. See close() for more information. */
     1486        delete mData.mWaitEvent;
     1487        mData.mWaitEvent = NULL;
     1488    }
     1489
     1490    Assert(mData.mWaitCount);
    14231491    mData.mWaitCount--;
    14241492
     
    14271495}
    14281496
    1429 int GuestProcess::waitForStart(uint32_t uTimeoutMS)
    1430 {
    1431     LogFlowThisFunc(("uTimeoutMS=%RU32\n", uTimeoutMS));
     1497int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags,
     1498                            void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc)
     1499{
     1500    LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p, pGuestRc=%p\n",
     1501                     mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten, pGuestRc));
     1502    /* All is optional. There can be 0 byte writes. */
     1503
     1504    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     1505
     1506    if (mData.mStatus != ProcessStatus_Started)
     1507    {
     1508        if (puWritten)
     1509            *puWritten = 0;
     1510        if (pGuestRc)
     1511            *pGuestRc = VINF_SUCCESS;
     1512        return VINF_SUCCESS; /* Not available for writing (anymore). */
     1513    }
    14321514
    14331515    int vrc = VINF_SUCCESS;
    14341516
    1435     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1436     if (mData.mStatus != ProcessStatus_Started)
    1437     {
    1438         alock.release();
    1439 
    1440         GuestProcessWaitResult waitRes;
    1441         vrc = waitFor(ProcessWaitForFlag_Start, uTimeoutMS, waitRes);
    1442         if (   RT_FAILURE(vrc)
    1443             || waitRes.mResult == ProcessWaitResult_Start)
    1444         {
    1445             if (RT_SUCCESS(vrc))
    1446                 vrc = waitRes.mRC;
    1447         }
    1448         /** @todo More error handling needed. */
    1449     }
    1450 
    1451     LogFlowFuncLeaveRC(vrc);
    1452     return vrc;
    1453 }
    1454 
    1455 int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags,
    1456                             void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten)
    1457 {
    1458     LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p\n",
    1459                      mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten));
    1460     /* All is optional. There can be 0 byte writes. */
    1461 
    1462     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1463 
    1464     if (mData.mStatus != ProcessStatus_Started)
    1465         return VINF_SUCCESS; /* Not available for writing (anymore). */
    1466 
     1517    GuestCtrlCallback *pCallbackWrite;
     1518    try
     1519    {
     1520        pCallbackWrite = new GuestCtrlCallback();
     1521        AssertPtr(pCallbackWrite);
     1522    }
     1523    catch(std::bad_alloc &)
     1524    {
     1525        vrc = VERR_NO_MEMORY;
     1526    }
     1527
     1528    /* Create callback and add it to the map. */
    14671529    uint32_t uContextID = 0;
    1468     GuestCtrlCallback *pCallbackWrite = new GuestCtrlCallback();
    1469     if (!pCallbackWrite)
    1470         return VERR_NO_MEMORY;
    1471 
    1472     /* Create callback and add it to the map. */
    1473     int vrc = pCallbackWrite->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS);
    14741530    if (RT_SUCCESS(vrc))
    1475         vrc = callbackAdd(pCallbackWrite, &uContextID);
     1531    {
     1532        vrc = pCallbackWrite->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS);
     1533        if (RT_SUCCESS(vrc))
     1534            vrc = callbackAdd(pCallbackWrite, &uContextID);
     1535    }
    14761536
    14771537    alock.release(); /* Drop the write lock again. */
     
    15011561        if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
    15021562        {
    1503             vrc = pCallbackWrite->GetResultCode();
    1504             LogFlowThisFunc(("Callback returned vrc=%Rrc, cbData=%RU32\n", vrc, pCallbackWrite->GetDataSize()));
    1505 
    1506             if (RT_SUCCESS(vrc))
     1563            int guestRc = pCallbackWrite->GetResultCode();
     1564            LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackWrite->GetDataSize()));
     1565
     1566            if (RT_SUCCESS(guestRc))
    15071567            {
    15081568                Assert(pCallbackWrite->GetDataSize() == sizeof(CALLBACKDATAEXECINSTATUS));
     
    15361596                LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
    15371597
     1598                if (pGuestRc)
     1599                    *pGuestRc = guestRc;
     1600
    15381601                if (puWritten)
    15391602                    *puWritten = cbWritten;
     1603
     1604                if (RT_FAILURE(guestRc))
     1605                    vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
    15401606            }
    15411607        }
    1542         else
    1543             vrc = VERR_TIMEOUT;
    15441608    }
    15451609
     
    15731637    Assert(data.size() >= aToRead);
    15741638
    1575     size_t cbRead;
    1576     int vrc = readData(aHandle, aToRead, aTimeoutMS, data.raw(), aToRead, &cbRead);
     1639    HRESULT hr = S_OK;
     1640
     1641    size_t cbRead; int guestRc;
     1642    int vrc = readData(aHandle, aToRead, aTimeoutMS, data.raw(), aToRead, &cbRead, &guestRc);
    15771643    if (RT_SUCCESS(vrc))
    15781644    {
     
    15811647        data.detachTo(ComSafeArrayOutArg(aData));
    15821648    }
    1583 
    1584     LogFlowThisFunc(("readData returned %Rrc, cbRead=%RU64\n", vrc, cbRead));
    1585 
    1586     /** @todo Do setError() here. */
    1587     HRESULT hr = RT_SUCCESS(vrc) ? S_OK : VBOX_E_IPRT_ERROR;
     1649    else
     1650    {
     1651        switch (vrc)
     1652        {
     1653            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1654                hr = GuestProcess::setErrorExternal(this, guestRc);
     1655                break;
     1656
     1657            default:
     1658                hr = setError(VBOX_E_IPRT_ERROR,
     1659                              tr("Reading from process \"%s\" (PID %RU32) failed: %Rrc"),
     1660                              mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
     1661                break;
     1662        }
     1663    }
     1664
     1665    LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64\n", vrc, cbRead));
     1666
    15881667    LogFlowFuncLeaveRC(vrc);
    1589 
    15901668    return hr;
    15911669#endif /* VBOX_WITH_GUEST_CONTROL */
     
    16571735     * Note: Do not hold any locks here while waiting!
    16581736     */
    1659     HRESULT hr;
    1660 
    1661     GuestProcessWaitResult waitRes;
    1662     int vrc = waitFor(aWaitFlags, aTimeoutMS, waitRes);
     1737    HRESULT hr = S_OK;
     1738
     1739    int guestRc; ProcessWaitResult_T waitResult;
     1740    int vrc = waitFor(aWaitFlags, aTimeoutMS, waitResult, &guestRc);
    16631741    if (RT_SUCCESS(vrc))
    16641742    {
    1665         *aReason = waitRes.mResult;
    1666         hr = setErrorExternal();
     1743        *aReason = waitResult;
    16671744    }
    16681745    else
    16691746    {
    1670         hr = setError(VBOX_E_IPRT_ERROR,
    1671                       tr("Waiting for process \"%s\" (PID %RU32) failed with vrc=%Rrc"),
    1672                       mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
    1673     }
     1747        switch (vrc)
     1748        {
     1749            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1750                hr = GuestProcess::setErrorExternal(this, guestRc);
     1751                break;
     1752
     1753            default:
     1754                hr = setError(VBOX_E_IPRT_ERROR,
     1755                              tr("Waiting for process \"%s\" (PID %RU32) failed: %Rrc"),
     1756                              mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
     1757                break;
     1758        }
     1759    }
     1760
    16741761    LogFlowFuncLeaveRC(vrc);
    16751762    return hr;
     
    17161803    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    17171804
    1718     com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
    1719     int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, (uint32_t*)aWritten);
    1720 
    1721     LogFlowThisFunc(("writeData returned %Rrc, aWritten=%RU32\n", vrc, aWritten));
    1722 
    1723     /** @todo Do setError() here. */
    1724     HRESULT hr = RT_SUCCESS(vrc) ? S_OK : VBOX_E_IPRT_ERROR;
     1805    HRESULT hr = S_OK;
     1806
     1807    com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); int guestRc;
     1808    int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, (uint32_t*)aWritten, &guestRc);
     1809    if (RT_FAILURE(vrc))
     1810    {
     1811        switch (vrc)
     1812        {
     1813            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1814                hr = GuestProcess::setErrorExternal(this, guestRc);
     1815                break;
     1816
     1817            default:
     1818                hr = setError(VBOX_E_IPRT_ERROR,
     1819                              tr("Writing to process \"%s\" (PID %RU32) failed: %Rrc"),
     1820                              mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
     1821                break;
     1822        }
     1823    }
     1824
     1825    LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, aWritten));
     1826
    17251827    LogFlowFuncLeaveRC(vrc);
    1726 
    17271828    return hr;
    17281829#endif /* VBOX_WITH_GUEST_CONTROL */
     
    17541855}
    17551856
     1857///////////////////////////////////////////////////////////////////////////////
     1858
     1859GuestProcessTool::GuestProcessTool(void)
     1860    : pSession(NULL)
     1861{
     1862}
     1863
     1864GuestProcessTool::~GuestProcessTool(void)
     1865{
     1866    Terminate();
     1867}
     1868
     1869int GuestProcessTool::Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo,
     1870                           bool fAsync, int *pGuestRc)
     1871{
     1872    LogFlowThisFunc(("pGuestSession=%p, szCmd=%s, fAsync=%RTbool\n",
     1873                     pGuestSession, startupInfo.mCommand.c_str(), fAsync));
     1874
     1875    AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER);
     1876
     1877    pSession     = pGuestSession;
     1878    mStartupInfo = startupInfo;
     1879
     1880    /* Make sure the process is hidden. */
     1881    mStartupInfo.mFlags |= ProcessCreateFlag_Hidden;
     1882
     1883    int vrc = pSession->processCreateExInteral(mStartupInfo, pProcess);
     1884    if (RT_SUCCESS(vrc))
     1885        vrc = fAsync ? pProcess->startProcessAsync() : pProcess->startProcess(pGuestRc);
     1886
     1887    if (   !fAsync
     1888        && (   pGuestRc
     1889            && RT_FAILURE(*pGuestRc)
     1890           )
     1891       )
     1892    {
     1893        vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
     1894    }
     1895
     1896    LogFlowFuncLeaveRC(vrc);
     1897    return vrc;
     1898}
     1899
     1900int GuestProcessTool::GetCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock)
     1901{
     1902    const GuestProcessStream *pStream = NULL;
     1903    if (uHandle == OUTPUT_HANDLE_ID_STDOUT)
     1904        pStream = &mStdOut;
     1905    else if (uHandle == OUTPUT_HANDLE_ID_STDERR)
     1906        pStream = &mStdErr;
     1907
     1908    if (!pStream)
     1909        return VERR_INVALID_PARAMETER;
     1910
     1911    int vrc;
     1912    do
     1913    {
     1914        /* Try parsing the data to see if the current block is complete. */
     1915        vrc = mStdOut.ParseBlock(strmBlock);
     1916        if (strmBlock.GetCount())
     1917            break;
     1918    } while (RT_SUCCESS(vrc));
     1919
     1920    LogFlowThisFunc(("rc=%Rrc, %RU64 pairs\n",
     1921                      vrc, strmBlock.GetCount()));
     1922    return vrc;
     1923}
     1924
     1925bool GuestProcessTool::IsRunning(void)
     1926{
     1927    AssertReturn(!pProcess.isNull(), true);
     1928
     1929    ProcessStatus_T procStatus = ProcessStatus_Undefined;
     1930    HRESULT hr = pProcess->COMGETTER(Status(&procStatus));
     1931    Assert(SUCCEEDED(hr));
     1932
     1933    if (   procStatus != ProcessStatus_Started
     1934        && procStatus != ProcessStatus_Paused
     1935        && procStatus != ProcessStatus_Terminating)
     1936    {
     1937        return false;
     1938    }
     1939
     1940    return true;
     1941}
     1942
     1943int GuestProcessTool::TerminatedOk(LONG *pExitCode)
     1944{
     1945    Assert(!pProcess.isNull());
     1946    /* pExitCode is optional. */
     1947
     1948    if (!IsRunning())
     1949    {
     1950        LONG exitCode;
     1951        HRESULT hr = pProcess->COMGETTER(ExitCode(&exitCode));
     1952        Assert(SUCCEEDED(hr));
     1953
     1954        if (pExitCode)
     1955            *pExitCode = exitCode;
     1956
     1957        if (exitCode != 0)
     1958            return VERR_NOT_EQUAL; /** @todo Special guest control rc needed! */
     1959        return VINF_SUCCESS;
     1960    }
     1961
     1962    return VERR_INVALID_STATE; /** @todo Special guest control rc needed! */
     1963}
     1964
     1965int GuestProcessTool::Wait(uint32_t fFlags, int *pGuestRc)
     1966{
     1967    return WaitEx(fFlags, NULL /* pStreamBlock */, pGuestRc);
     1968}
     1969
     1970int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBlock, int *pGuestRc)
     1971{
     1972    LogFlowThisFunc(("pSession=%p, pProcess=%p, fFlags=0x%x, pStreamBlock=%p, pGuestRc=%p\n",
     1973                     pSession, pProcess, fFlags, pStreamBlock, pGuestRc));
     1974
     1975    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     1976    Assert(!pProcess.isNull());
     1977    /* Other parameters are optional. */
     1978
     1979    /* Can we parse the next block without waiting? */
     1980    int vrc;
     1981    if (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK)
     1982    {
     1983        AssertPtr(pStreamBlock);
     1984        vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock);
     1985        if (RT_SUCCESS(vrc))
     1986            return vrc;
     1987    }
     1988
     1989    /* Do the waiting. */
     1990    uint32_t fWaitFlags = ProcessWaitForFlag_Terminate;
     1991    if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
     1992        fWaitFlags |= ProcessWaitForFlag_StdOut;
     1993    if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
     1994        fWaitFlags |= ProcessWaitForFlag_StdErr;
     1995
     1996    LogFlowFunc(("waitFlags=0x%x\n", fWaitFlags));
     1997
     1998    /** @todo Decrease timeout. */
     1999    uint32_t uTimeoutMS = mStartupInfo.mTimeoutMS;
     2000
     2001    int guestRc;
     2002    bool fDone = false;
     2003
     2004    BYTE byBuf[_64K];
     2005    size_t cbRead;
     2006
     2007    bool fHandleStdOut = false;
     2008    bool fHandleStdErr = false;
     2009
     2010    ProcessWaitResult_T waitRes;
     2011    do
     2012    {
     2013        vrc = pProcess->waitFor(fWaitFlags,
     2014                                uTimeoutMS, waitRes, &guestRc);
     2015        if (RT_FAILURE(vrc))
     2016            break;
     2017
     2018        switch (waitRes)
     2019        {
     2020            case ProcessWaitResult_StdOut:
     2021                fHandleStdOut = true;
     2022                break;
     2023
     2024            case ProcessWaitResult_StdErr:
     2025                fHandleStdErr = true;
     2026                break;
     2027
     2028            case ProcessWaitResult_WaitFlagNotSupported:
     2029                if (fWaitFlags & ProcessWaitForFlag_StdOut)
     2030                    fHandleStdOut = true;
     2031                if (fWaitFlags & ProcessWaitForFlag_StdErr)
     2032                    fHandleStdErr = true;
     2033                /* Since waiting for stdout / stderr is not supported by the guest,
     2034                 * wait a bit to not hog the CPU too much when polling for data. */
     2035                RTThreadSleep(1); /* Optional, don't check rc. */
     2036                break;
     2037
     2038            case ProcessWaitResult_Error:
     2039            case ProcessWaitResult_Terminate:
     2040                fDone = true;
     2041                break;
     2042
     2043            default:
     2044                AssertMsgFailed(("Unhandled process wait result %ld\n", waitRes));
     2045                fDone = true;
     2046                break;
     2047        }
     2048
     2049        if (fHandleStdOut)
     2050        {
     2051            vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
     2052                                     uTimeoutMS, byBuf, sizeof(byBuf),
     2053                                     &cbRead, &guestRc);
     2054            if (RT_FAILURE(vrc))
     2055                break;
     2056
     2057            if (cbRead)
     2058            {
     2059                LogFlowThisFunc(("Received %RU64 bytes from stdout\n", cbRead));
     2060                vrc = mStdOut.AddData(byBuf, cbRead);
     2061
     2062                if (   RT_SUCCESS(vrc)
     2063                    && (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK))
     2064                {
     2065                    AssertPtr(pStreamBlock);
     2066                    vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock);
     2067                    if (RT_SUCCESS(vrc))
     2068                        fDone = true;
     2069                }
     2070            }
     2071
     2072            fHandleStdOut = false;
     2073        }
     2074
     2075        if (fHandleStdErr)
     2076        {
     2077            vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDERR, sizeof(byBuf),
     2078                                     uTimeoutMS, byBuf, sizeof(byBuf),
     2079                                     &cbRead, &guestRc);
     2080            if (RT_FAILURE(vrc))
     2081                break;
     2082
     2083            if (cbRead)
     2084            {
     2085                LogFlowThisFunc(("Received %RU64 bytes from stderr\n", cbRead));
     2086                vrc = mStdErr.AddData(byBuf, cbRead);
     2087            }
     2088
     2089            fHandleStdErr = false;
     2090        }
     2091
     2092    } while (!fDone && RT_SUCCESS(vrc));
     2093
     2094    LogFlowThisFunc(("Loop ended with rc=%Rrc, guestRc=%Rrc, waitRes=%ld\n",
     2095                     vrc, guestRc, waitRes));
     2096    if (pGuestRc)
     2097        *pGuestRc = guestRc;
     2098
     2099    LogFlowFuncLeaveRC(vrc);
     2100    return vrc;
     2101}
     2102
     2103void GuestProcessTool::Terminate(void)
     2104{
     2105    LogFlowThisFuncEnter();
     2106
     2107    if (!pProcess.isNull())
     2108    {
     2109        Assert(pSession);
     2110        int rc2 = pSession->processRemoveFromList(pProcess);
     2111        AssertRC(rc2);
     2112
     2113        pProcess.setNull();
     2114    }
     2115
     2116    LogFlowThisFuncLeave();
     2117}
     2118
  • trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp

    r42928 r43162  
    426426            Assert(mData.mDirectories.size());
    427427            LogFlowFunc(("Removing directory \"%s\" (Session: %RU32) (now total %ld directories)\n",
    428                          Utf8Str(strName).c_str(), mData.mNumObjects - 1));
     428                         Utf8Str(strName).c_str(), mData.mId, mData.mDirectories.size() - 1));
    429429
    430430            mData.mDirectories.erase(itDirs);
     
    436436}
    437437
    438 int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags)
     438int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, int *pGuestRc)
    439439{
    440440    LogFlowThisFunc(("strPath=%s, uMode=%x, uFlags=%x\n",
     
    442442
    443443    GuestProcessStartupInfo procInfo;
    444     procInfo.mName      = Utf8StrFmt(tr("Creating directory \"%s\"", strPath.c_str()));
    445     procInfo.mCommand   = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
    446     procInfo.mFlags     = ProcessCreateFlag_Hidden;
    447 
    448     int rc = VINF_SUCCESS;
     444    procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
     445    procInfo.mFlags   = ProcessCreateFlag_Hidden;
     446
     447    int vrc = VINF_SUCCESS;
    449448
    450449    /* Construct arguments. */
     
    461460        }
    462461        else
    463             rc = VERR_INVALID_PARAMETER;
     462            vrc = VERR_BUFFER_OVERFLOW;
    464463    }
    465464    procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
    466465
    467     ComObjPtr<GuestProcess> pProcess;
    468     rc = processCreateExInteral(procInfo, pProcess);
    469     if (RT_SUCCESS(rc))
    470         rc = pProcess->startProcess();
    471     if (RT_SUCCESS(rc))
    472     {
    473         GuestProcessWaitResult waitRes;
    474         rc = pProcess->waitFor(ProcessWaitForFlag_Terminate, 30 * 1000 /* Timeout */, waitRes);
    475         if (RT_SUCCESS(rc))
    476         {
    477             ProcessStatus_T procStatus;
    478             HRESULT hr = pProcess->COMGETTER(Status)(&procStatus);
    479             ComAssertComRC(hr);
    480             if (procStatus == ProcessStatus_TerminatedNormally)
    481             {
    482                 LONG lExitCode;
    483                 pProcess->COMGETTER(ExitCode)(&lExitCode);
    484                 if (lExitCode != 0)
    485                     return VERR_CANT_CREATE;
    486             }
    487             else
    488                 rc = VERR_BROKEN_PIPE; /** @todo Find a better rc. */
    489         }
    490     }
    491 
    492     LogFlowFuncLeaveRC(rc);
    493     return rc;
    494 }
    495 
    496 int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
     466    int guestRc;
     467    if (RT_SUCCESS(vrc))
     468    {
     469        GuestProcessTool procTool;
     470        vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
     471        if (RT_SUCCESS(vrc))
     472        {
     473            if (RT_SUCCESS(guestRc))
     474                vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
     475        }
     476
     477        if (RT_SUCCESS(vrc))
     478        {
     479            if (RT_SUCCESS(guestRc))
     480                guestRc = procTool.TerminatedOk(NULL /* Exit code */);
     481        }
     482
     483        if (pGuestRc)
     484            *pGuestRc = guestRc;
     485    }
     486
     487    LogFlowFuncLeaveRC(vrc);
     488    if (RT_FAILURE(vrc))
     489        return vrc;
     490    return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
     491}
     492
     493int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
    497494{
    498495    LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
    499496
    500     int rc = fsQueryInfoInternal(strPath, objData);
    501     if (RT_SUCCESS(rc))
    502     {
    503         rc = objData.mType == FsObjType_Directory
    504            ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
    505     }
    506 
    507     LogFlowFuncLeaveRC(rc);
    508     return rc;
    509 }
    510 
    511 int GuestSession::objectCreateTempInternal(Utf8Str strTemplate,
    512                                            Utf8Str strPath,
    513                                            bool fDirectory,
    514                                            Utf8Str &strName, int *prc)
     497    int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc);
     498    if (RT_SUCCESS(vrc))
     499    {
     500        vrc = objData.mType == FsObjType_Directory
     501            ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
     502    }
     503
     504    LogFlowFuncLeaveRC(vrc);
     505    return vrc;
     506}
     507
     508int GuestSession::objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath,
     509                                           bool fDirectory, const Utf8Str &strName, int *pGuestRc)
    515510{
    516511    GuestProcessStartupInfo procInfo;
    517     GuestProcessStream      streamOut;
    518     ComObjPtr<GuestProcess> pProcess;
    519     int rc = VINF_SUCCESS;
    520 
    521     if (fDirectory)
    522         procInfo.mName    = Utf8StrFmt(tr("Creating temporary directory from template \"%s\"",
    523                                    strTemplate.c_str()));
    524     else
    525         procInfo.mName    = Utf8StrFmt(tr("Creating temporary file from template \"%s\"",
    526                                    strTemplate.c_str()));
    527512    procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
    528     procInfo.mFlags   =   ProcessCreateFlag_Hidden
    529                         | ProcessCreateFlag_WaitForStdOut;
    530     /* Construct arguments. */
     513    procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
    531514    procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
    532515    if (fDirectory)
    533516        procInfo.mArguments.push_back(Utf8Str("-d"));
    534     if (strPath.length())  /* Otherwise use /tmp or equivalent. */
     517    if (strPath.length()) /* Otherwise use /tmp or equivalent. */
    535518    {
    536519        procInfo.mArguments.push_back(Utf8Str("-t"));
     
    539522    procInfo.mArguments.push_back(strTemplate);
    540523
    541     rc = processCreateExInteral(procInfo, pProcess);
    542     if (RT_SUCCESS(rc))
    543         rc = pProcess->startProcess();
    544     if (RT_SUCCESS(rc))
    545     {
    546         GuestProcessWaitResult waitRes;
    547         BYTE byBuf[_64K];
    548         size_t cbRead;
    549 
    550         for (;;)
    551         {
    552             rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
    553                                    30 * 1000 /* Timeout */, waitRes);
    554             if (   RT_FAILURE(rc)
    555                 || waitRes.mResult == ProcessWaitResult_Terminate
    556                 || waitRes.mResult == ProcessWaitResult_Error
    557                 || waitRes.mResult == ProcessWaitResult_Timeout)
    558             {
    559                 break;
    560             }
    561 
    562             rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
    563                                     30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
    564                                     &cbRead);
    565             if (RT_FAILURE(rc))
    566                 break;
    567 
    568             if (cbRead)
    569             {
    570                 rc = streamOut.AddData(byBuf, cbRead);
    571                 if (RT_FAILURE(rc))
    572                     break;
    573             }
    574         }
    575 
    576         LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",
    577                          rc, cbRead, streamOut.GetSize()));
    578     }
    579     else
    580         LogThisFunc(("Error while starting temporary object creation tool on guest: %Rrc\n", rc));
    581     if (RT_FAILURE(rc))
    582         LogThisFunc(("Error while running temporary object creation tool: %Rrc\n", rc));
    583     else if (!streamOut.GetSize())
    584     {
    585         LogThisFunc(("No return code after creating temporary object\n"));
    586         rc = VERR_NO_DATA;
    587     }
    588     if (RT_SUCCESS(rc))
    589     {
    590         const char *pcszName;
    591         int64_t i64rc;
    592         GuestProcessStreamBlock streamBlock;
    593         rc = streamOut.ParseBlock(streamBlock);
    594         if (RT_SUCCESS(rc))
    595         {
    596             pcszName = streamBlock.GetString("name");
    597             if (pcszName)
    598                 strName = pcszName;
    599             else
    600             {
    601                 LogThisFunc(("No name returned after creating temporary object\n"));
    602                 rc = VERR_NO_DATA;
    603             }
    604             if (RT_FAILURE(rc = streamBlock.GetInt64Ex("rc", &i64rc)))
    605                 LogThisFunc(("No return code after creating temporary object\n"));
    606         }
    607         if (   RT_SUCCESS(rc)
    608             && (   i64rc == VERR_INVALID_PARAMETER
    609                 || i64rc == VERR_NOT_SUPPORTED))
    610             rc = (int)i64rc;
    611         if (RT_SUCCESS(rc))
    612             *prc = (int)i64rc;
    613     }
    614     else
    615         LogThisFunc(("Error while getting return code from creating temporary object: %Rrc\n", rc));
    616     return rc;
     524    GuestProcessTool procTool; int guestRc;
     525    int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
     526    if (RT_SUCCESS(vrc))
     527    {
     528        if (RT_SUCCESS(guestRc))
     529            vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
     530    }
     531
     532    if (RT_SUCCESS(vrc))
     533    {
     534        if (RT_SUCCESS(guestRc))
     535            guestRc = procTool.TerminatedOk(NULL /* Exit code */);
     536    }
     537
     538    if (pGuestRc)
     539        *pGuestRc = guestRc;
     540
     541    if (RT_FAILURE(vrc))
     542        return vrc;
     543    return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
    617544}
    618545
     
    630557        return VERR_COM_UNEXPECTED;
    631558
    632     int rc = pDirectory->init(this /* Parent */,
    633                               strPath, strFilter, uFlags);
    634     if (RT_FAILURE(rc))
    635         return rc;
     559    int vrc = pDirectory->init(this /* Parent */,
     560                               strPath, strFilter, uFlags);
     561    if (RT_FAILURE(vrc))
     562        return vrc;
    636563
    637564    /* Add the created directory to our vector. */
     
    641568                 strPath.c_str(), mData.mId));
    642569
    643     LogFlowFuncLeaveRC(rc);
    644     return rc;
     570    LogFlowFuncLeaveRC(vrc);
     571    return vrc;
    645572}
    646573
     
    704631}
    705632
    706 /**
    707  * Implementation of FileRemove().  Can throw an exception due to the use of
    708  * Utf8Str, Utf8StrFmt and std::vector near the beginning (and others?).  The
    709  * caller should catch this.  On success, *prc will be set to the return code
    710  * of the delete operation to distinguish between API and command failure.
    711  */
    712 int GuestSession::fileRemoveInternal(Utf8Str strPath, int *prc)
     633int GuestSession::fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc)
    713634{
    714635    GuestProcessStartupInfo procInfo;
    715636    GuestProcessStream      streamOut;
    716     int rc = VINF_SUCCESS;
    717 
    718     AssertPtrReturn(prc, VERR_INVALID_POINTER);
    719     procInfo.mName    = Utf8StrFmt(tr("Removing file \"%s\"",
    720                                    strPath.c_str()));
     637
    721638    procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM);
    722     procInfo.mFlags   =   ProcessCreateFlag_Hidden
    723                         | ProcessCreateFlag_WaitForStdOut;
    724     /* Construct arguments. */
     639    procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
    725640    procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
    726     procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
    727 
    728     ComObjPtr<GuestProcess> pProcess;
    729     rc = processCreateExInteral(procInfo, pProcess);
    730     if (RT_SUCCESS(rc))
    731         rc = pProcess->startProcess();
    732     if (RT_SUCCESS(rc))
    733     {
    734         GuestProcessWaitResult waitRes;
    735         BYTE byBuf[_64K];
    736         size_t cbRead;
    737 
    738         for (;;)
    739         {
    740             rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
    741                                    30 * 1000 /* Timeout */, waitRes);
    742             if (   RT_FAILURE(rc)
    743                 || waitRes.mResult == ProcessWaitResult_Terminate
    744                 || waitRes.mResult == ProcessWaitResult_Error
    745                 || waitRes.mResult == ProcessWaitResult_Timeout)
    746             {
    747                 break;
    748             }
    749 
    750             rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
    751                                     30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
    752                                     &cbRead);
    753             if (RT_FAILURE(rc))
    754                 break;
    755 
    756             if (cbRead)
    757             {
    758                 rc = streamOut.AddData(byBuf, cbRead);
    759                 if (RT_FAILURE(rc))
    760                     break;
    761             }
    762         }
    763 
    764         LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",
    765                          rc, cbRead, streamOut.GetSize()));
    766     }
    767     else
    768         LogThisFunc(("Error starting delete tool on guest: %Rrc\n", rc));
    769     if (RT_FAILURE(rc))
    770         LogThisFunc(("Error running delete tool on guest: %Rrc\n", rc));
    771     else if (!streamOut.GetSize())
    772     {
    773         LogThisFunc(("No return code after deleting file"));
    774         rc = VERR_NO_DATA;
    775     }
    776     if (RT_SUCCESS(rc))
    777     {
    778         GuestProcessStreamBlock streamBlock;
    779         int64_t i64rc;
    780         rc = streamOut.ParseBlock(streamBlock);
    781         streamBlock.GetString("fname");
    782         rc = streamBlock.GetInt64Ex("rc", &i64rc);
    783         if (RT_SUCCESS(rc))
    784             *prc = (int)i64rc;
    785     }
    786     else
    787         Log(("Error getting return code from deleting file: %Rrc\n", rc));
    788     return rc;
     641    procInfo.mArguments.push_back(strPath); /* The file we want to remove. */
     642
     643    GuestProcessTool procTool; int guestRc;
     644    int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
     645    if (RT_SUCCESS(vrc))
     646        vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
     647
     648    if (RT_SUCCESS(vrc))
     649    {
     650        if (RT_SUCCESS(guestRc))
     651            guestRc = procTool.TerminatedOk(NULL /* Exit code */);
     652    }
     653
     654    if (pGuestRc)
     655        *pGuestRc = guestRc;
     656
     657    if (RT_FAILURE(vrc))
     658        return vrc;
     659    return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
    789660}
    790661
    791662int GuestSession::fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition,
    792                                    uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile)
     663                                   uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile, int *pGuestRc)
    793664{
    794665    LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, iOffset=%RI64\n",
     
    800671        return VERR_COM_UNEXPECTED;
    801672
    802     int rc = pFile->init(this /* Parent */,
    803                          strPath, strOpenMode, strDisposition, uCreationMode, iOffset);
    804     if (RT_FAILURE(rc))
    805         return rc;
     673    int vrc = pFile->init(this /* Parent */,
     674                          strPath, strOpenMode, strDisposition, uCreationMode, iOffset, pGuestRc);
     675    if (RT_FAILURE(vrc))
     676        return vrc;
     677    /** @todo Handle guestRc. */
    806678
    807679    /* Add the created directory to our vector. */
     
    813685                 strPath.c_str(), mData.mId, mData.mProcesses.size(), mData.mNumObjects));
    814686
    815     LogFlowFuncLeaveRC(rc);
    816     return rc;
    817 }
    818 
    819 int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
     687    LogFlowFuncLeaveRC(vrc);
     688    return vrc;
     689}
     690
     691int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
    820692{
    821693    LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
    822694
    823     int rc = fsQueryInfoInternal(strPath, objData);
    824     if (RT_SUCCESS(rc))
    825     {
    826         rc = objData.mType == FsObjType_File
    827            ? VINF_SUCCESS : VERR_NOT_A_FILE;
    828     }
    829 
    830     LogFlowFuncLeaveRC(rc);
    831     return rc;
    832 }
    833 
    834 int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize)
     695    int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc);
     696    if (RT_SUCCESS(vrc))
     697    {
     698        vrc = objData.mType == FsObjType_File
     699            ? VINF_SUCCESS : VERR_NOT_A_FILE;
     700    }
     701
     702    LogFlowFuncLeaveRC(vrc);
     703    return vrc;
     704}
     705
     706int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc)
    835707{
    836708    AssertPtrReturn(pllSize, VERR_INVALID_POINTER);
    837709
    838710    GuestFsObjData objData;
    839     int rc = fileQueryInfoInternal(strPath, objData);
    840     if (RT_SUCCESS(rc))
    841     {
    842         if (objData.mType == FsObjType_File)
    843             *pllSize = objData.mObjectSize;
    844         else
    845             rc = VERR_NOT_A_FILE;
    846     }
    847 
    848     return rc;
    849 }
    850 
    851 int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
     711    int vrc = fileQueryInfoInternal(strPath, objData, pGuestRc);
     712    if (RT_SUCCESS(vrc))
     713        *pllSize = objData.mObjectSize;
     714
     715    return vrc;
     716}
     717
     718int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
    852719{
    853720    LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
     
    855722    /** @todo Merge this with IGuestFile::queryInfo(). */
    856723    GuestProcessStartupInfo procInfo;
    857     procInfo.mName    = Utf8StrFmt(tr("Querying info for \"%s\""), strPath.c_str());
    858724    procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT);
    859     procInfo.mFlags   = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
     725    procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
    860726
    861727    /* Construct arguments. */
     
    863729    procInfo.mArguments.push_back(strPath);
    864730
    865     GuestProcessStream streamOut;
    866 
    867     ComObjPtr<GuestProcess> pProcess;
    868     int rc = processCreateExInteral(procInfo, pProcess);
    869     if (RT_SUCCESS(rc))
    870         rc = pProcess->startProcess();
    871     if (RT_SUCCESS(rc))
    872     {
    873         GuestProcessWaitResult waitRes;
    874         BYTE byBuf[_64K];
    875         size_t cbRead = 0;
    876 
    877         /** @todo Merge with GuestDirectory::read. */
    878         for (;;)
    879         {
    880             rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
    881                                    30 * 1000 /* Timeout */, waitRes);
    882             if (   RT_FAILURE(rc)
    883                 || waitRes.mResult == ProcessWaitResult_Terminate
    884                 || waitRes.mResult == ProcessWaitResult_Error
    885                 || waitRes.mResult == ProcessWaitResult_Timeout)
    886             {
    887                 break;
    888             }
    889 
    890             rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
    891                                     30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
    892                                     &cbRead);
    893             if (RT_FAILURE(rc))
    894                 break;
    895 
    896             if (cbRead)
    897             {
    898                 rc = streamOut.AddData(byBuf, cbRead);
    899                 if (RT_FAILURE(rc))
    900                     break;
    901             }
    902         }
    903 
    904         LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n",
    905                          rc, cbRead, streamOut.GetSize()));
    906     }
    907 
    908     if (RT_SUCCESS(rc))
    909     {
    910         GuestProcessStreamBlock streamBlock;
    911         rc = streamOut.ParseBlock(streamBlock);
    912         if (RT_SUCCESS(rc))
    913         {
    914             rc = objData.FromStat(streamBlock);
    915         }
    916         else
    917             AssertMsgFailed(("Parsing stream block failed: %Rrc\n", rc));
    918     }
    919 
    920     LogFlowFuncLeaveRC(rc);
    921     return rc;
     731    GuestProcessTool procTool; int guestRc;
     732    int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
     733    if (RT_SUCCESS(vrc))
     734        vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
     735    if (RT_SUCCESS(vrc))
     736    {
     737        guestRc = procTool.TerminatedOk(NULL /* Exit code */);
     738        if (RT_SUCCESS(guestRc))
     739        {
     740            GuestProcessStreamBlock curBlock;
     741            vrc = procTool.GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT,  curBlock);
     742            /** @todo Check for more / validate blocks! */
     743            if (RT_SUCCESS(vrc))
     744                vrc = objData.FromStat(curBlock);
     745        }
     746    }
     747
     748    if (pGuestRc)
     749        *pGuestRc = guestRc;
     750
     751    LogFlowFuncLeaveRC(vrc);
     752    if (RT_FAILURE(vrc))
     753        return vrc;
     754    return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
    922755}
    923756
     
    13411174    HRESULT hr = S_OK;
    13421175
    1343     ComObjPtr <GuestDirectory> pDirectory;
    1344     int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags);
     1176    ComObjPtr <GuestDirectory> pDirectory; int guestRc;
     1177    int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags, &guestRc);
    13451178    if (RT_FAILURE(rc))
    13461179    {
    13471180        switch (rc)
    13481181        {
     1182            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1183                hr = GuestProcess::setErrorExternal(this, guestRc);
     1184                break;
     1185
    13491186            case VERR_INVALID_PARAMETER:
    13501187               hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));
     
    13771214
    13781215    if (RT_UNLIKELY((aTemplate) == NULL || *(aTemplate) == '\0'))
    1379         return setError(E_INVALIDARG, tr("No file to remove specified"));
    1380 
    1381     AutoCaller autoCaller(this);
    1382     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1383 
    1384     int rc = VINF_SUCCESS;
    1385 
    1386     try  /* Can this be done without exceptions? */
    1387     {
    1388         Utf8Str strName;
    1389         if (RT_FAILURE(objectCreateTempInternal(Utf8Str(aTemplate),
    1390                                                 Utf8Str(aPath),
    1391                                                 true, strName, &rc)))
    1392             return E_FAIL;
    1393         HRESULT hrc =   rc == VERR_INVALID_PARAMETER ? E_INVALIDARG
    1394                       : rc == VERR_NOT_SUPPORTED ? VBOX_E_NOT_SUPPORTED
    1395                       : RT_FAILURE(rc) ? VBOX_E_IPRT_ERROR
    1396                       : S_OK;
    1397         if (FAILED(hrc))
    1398             return setError(hrc, tr("Temporary directory creation failed: %Rrc"),
    1399                             rc);
     1216        return setError(E_INVALIDARG, tr("No template specified"));
     1217    if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
     1218        return setError(E_INVALIDARG, tr("No directory name specified"));
     1219    CheckComArgOutPointerValid(aDirectory);
     1220
     1221    AutoCaller autoCaller(this);
     1222    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1223
     1224    HRESULT hr = S_OK;
     1225
     1226    Utf8Str strName; int guestRc;
     1227    int rc = objectCreateTempInternal(Utf8Str(aTemplate),
     1228                                      Utf8Str(aPath),
     1229                                      true /* Directory */, strName, &guestRc);
     1230    if (RT_SUCCESS(rc))
     1231    {
    14001232        strName.cloneTo(aDirectory);
    1401         return S_OK;
    1402     }
    1403     catch (...)
    1404     {
    1405         return E_OUTOFMEMORY;
    1406     }
     1233    }
     1234    else
     1235    {
     1236        switch (rc)
     1237        {
     1238            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1239                hr = GuestProcess::setErrorExternal(this, guestRc);
     1240                break;
     1241
     1242            default:
     1243               hr = setError(VBOX_E_IPRT_ERROR, tr("Temporary directory creation \"%s\" with template \"%s\" failed: %Rrc"),
     1244                             Utf8Str(aPath).c_str(), Utf8Str(aTemplate).c_str(), rc);
     1245               break;
     1246        }
     1247    }
     1248
     1249    return hr;
    14071250#endif /* VBOX_WITH_GUEST_CONTROL */
    14081251}
     
    14241267    HRESULT hr = S_OK;
    14251268
    1426     GuestFsObjData objData;
    1427     int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData);
     1269    GuestFsObjData objData; int guestRc;
     1270    int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
    14281271    if (RT_SUCCESS(rc))
    14291272    {
     
    14341277        switch (rc)
    14351278        {
    1436             /** @todo Add more errors here! */
     1279            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1280                hr = GuestProcess::setErrorExternal(this, guestRc);
     1281                break;
    14371282
    14381283            default:
    1439                hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence failed: %Rrc"), rc);
     1284               hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence \"%s\" failed: %Rrc"),
     1285                             Utf8Str(aPath).c_str(), rc);
    14401286               break;
    14411287        }
     
    14561302        return setError(E_INVALIDARG, tr("No directory to open specified"));
    14571303    if (RT_UNLIKELY((aFilter) != NULL && *(aFilter) != '\0'))
    1458         return setError(E_INVALIDARG, tr("Directory filters not implemented yet"));
    1459 
     1304        return setError(E_INVALIDARG, tr("Directory filters are not implemented yet"));
    14601305    CheckComArgOutPointerValid(aDirectory);
    14611306
     
    14801325    if (RT_SUCCESS(rc))
    14811326    {
    1482         if (aDirectory)
    1483         {
    1484             /* Return directory object to the caller. */
    1485             hr = pDirectory.queryInterfaceTo(aDirectory);
    1486         }
    1487         else
    1488         {
    1489             rc = directoryRemoveFromList(pDirectory);
    1490             if (RT_FAILURE(rc))
    1491                 hr = setError(VBOX_E_IPRT_ERROR, tr("Unable to close directory object, rc=%Rrc"), rc);
    1492         }
     1327        /* Return directory object to the caller. */
     1328        hr = pDirectory.queryInterfaceTo(aDirectory);
    14931329    }
    14941330    else
     
    14971333        {
    14981334            case VERR_INVALID_PARAMETER:
    1499                hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Invalid parameters given"));
     1335               hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed; invalid parameters given",
     1336                                                   Utf8Str(aPath).c_str()));
    15001337               break;
    15011338
    1502             case VERR_BROKEN_PIPE:
    1503                hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Unexpectedly aborted"));
    1504                break;
    1505 
    15061339            default:
    1507                hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: %Rrc"), rc);
     1340               hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed: %Rrc"),
     1341                             Utf8Str(aPath).c_str(),rc);
    15081342               break;
    15091343        }
     
    15301364    HRESULT hr = S_OK;
    15311365
    1532     GuestFsObjData objData;
    1533     int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData);
    1534     if (RT_SUCCESS(rc))
     1366    GuestFsObjData objData; int guestRc;
     1367    int vrc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
     1368    if (RT_SUCCESS(vrc))
    15351369    {
    15361370        if (objData.mType == FsObjType_Directory)
     
    15381372            ComObjPtr<GuestFsObjInfo> pFsObjInfo;
    15391373            hr = pFsObjInfo.createObject();
    1540             if (FAILED(hr))
    1541                 return VERR_COM_UNEXPECTED;
    1542 
    1543             rc = pFsObjInfo->init(objData);
    1544             if (RT_SUCCESS(rc))
     1374            if (FAILED(hr)) return hr;
     1375
     1376            vrc = pFsObjInfo->init(objData);
     1377            if (RT_SUCCESS(vrc))
     1378            {
    15451379                hr = pFsObjInfo.queryInterfaceTo(aInfo);
    1546         }
    1547     }
    1548 
    1549     if (RT_FAILURE(rc))
    1550     {
    1551         switch (rc)
    1552         {
    1553             /** @todo Add more errors here! */
     1380                if (FAILED(hr)) return hr;
     1381            }
     1382        }
     1383    }
     1384
     1385    if (RT_FAILURE(vrc))
     1386    {
     1387        switch (vrc)
     1388        {
     1389            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1390                hr = GuestProcess::setErrorExternal(this, guestRc);
     1391                break;
    15541392
    15551393            case VERR_NOT_A_DIRECTORY:
    1556                 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a directory"));
     1394                hr = setError(VBOX_E_IPRT_ERROR, tr("Element \"%s\" exists but is not a directory",
     1395                                                    Utf8Str(aPath).c_str()));
    15571396                break;
    15581397
    15591398            default:
    1560                 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information failed: %Rrc"), rc);
     1399                hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information for \"%s\" failed: %Rrc"),
     1400                              Utf8Str(aPath).c_str(), vrc);
    15611401                break;
    15621402        }
     
    17371577    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    17381578
     1579    GuestFsObjData objData; int guestRc;
     1580    int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
     1581    if (RT_SUCCESS(vrc))
     1582    {
     1583        *aExists = TRUE;
     1584        return S_OK;
     1585    }
     1586
    17391587    HRESULT hr = S_OK;
    17401588
    1741     GuestFsObjData objData;
    1742     int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
    1743     if (RT_SUCCESS(rc))
    1744     {
    1745         *aExists = objData.mType == FsObjType_File;
    1746     }
    1747     else
    1748     {
    1749         switch (rc)
    1750         {
    1751             /** @todo Add more errors here! */
    1752 
    1753             default:
    1754                hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file existence failed: %Rrc"), rc);
    1755                break;
    1756         }
     1589    switch (vrc)
     1590    {
     1591        case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1592            hr = GuestProcess::setErrorExternal(this, guestRc);
     1593            break;
     1594
     1595        case VERR_NOT_A_FILE:
     1596            *aExists = FALSE;
     1597            break;
     1598
     1599        default:
     1600            hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information for \"%s\" failed: %Rrc"),
     1601                          Utf8Str(aPath).c_str(), vrc);
     1602            break;
    17571603    }
    17581604
     
    17741620    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    17751621
    1776     try  /* Can this be done without exceptions? */
    1777     {
    1778         int rc2;
    1779         int rc = fileRemoveInternal(Utf8Str(aPath), &rc2);
    1780         if (RT_FAILURE((rc)))
    1781             return setError(E_FAIL,
    1782                             tr("Internal error deleting file: %Rrc"), rc);
    1783         else if (RT_FAILURE((rc2)))
    1784             return setError(VBOX_E_IPRT_ERROR,
    1785                             tr("File deletion on guest returned: %Rrc"), rc2);
    1786     }
    1787     catch (...)
    1788     {
    1789         return E_OUTOFMEMORY;
    1790     }
    1791     return S_OK;
     1622    HRESULT hr = S_OK;
     1623
     1624    int guestRc;
     1625    int vrc = fileRemoveInternal(Utf8Str(aPath), &guestRc);
     1626    if (RT_FAILURE(vrc))
     1627    {
     1628        switch (vrc)
     1629        {
     1630            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1631                hr = GuestProcess::setErrorExternal(this, guestRc);
     1632                break;
     1633
     1634            default:
     1635                hr = setError(VBOX_E_IPRT_ERROR, tr("Removing file \"%s\" failed: %Rrc"),
     1636                              Utf8Str(aPath).c_str(), vrc);
     1637                break;
     1638        }
     1639    }
     1640
     1641    return hr;
    17921642#endif /* VBOX_WITH_GUEST_CONTROL */
    17931643}
     
    18201670    HRESULT hr = S_OK;
    18211671
    1822     ComObjPtr <GuestFile> pFile;
    1823     int rc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition),
    1824                               aCreationMode, aOffset, pFile);
    1825     if (RT_SUCCESS(rc))
     1672    ComObjPtr <GuestFile> pFile; int guestRc;
     1673    int vrc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition),
     1674                               aCreationMode, aOffset, pFile, &guestRc);
     1675    if (RT_SUCCESS(vrc))
    18261676    {
    18271677        /* Return directory object to the caller. */
     
    18301680    else
    18311681    {
    1832         switch (rc)
    1833         {
    1834             /** @todo Add more error info! */
     1682        switch (vrc)
     1683        {
     1684            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1685                hr = GuestProcess::setErrorExternal(this, guestRc);
     1686                break;
    18351687
    18361688            default:
    1837                hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
    1838                break;
     1689                hr = setError(VBOX_E_IPRT_ERROR, tr("Creating directory \"%s\" failed: %Rrc"),
     1690                              Utf8Str(aPath).c_str(), vrc);
     1691                break;
    18391692        }
    18401693    }
     
    18601713    HRESULT hr = S_OK;
    18611714
    1862     GuestFsObjData objData;
    1863     int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
    1864     if (RT_SUCCESS(rc))
     1715    GuestFsObjData objData; int guestRc;
     1716    int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
     1717    if (RT_SUCCESS(vrc))
    18651718    {
    18661719        ComObjPtr<GuestFsObjInfo> pFsObjInfo;
    18671720        hr = pFsObjInfo.createObject();
    1868         if (FAILED(hr))
    1869             return VERR_COM_UNEXPECTED;
    1870 
    1871         rc = pFsObjInfo->init(objData);
    1872         if (RT_SUCCESS(rc))
     1721        if (FAILED(hr)) return hr;
     1722
     1723        vrc = pFsObjInfo->init(objData);
     1724        if (RT_SUCCESS(vrc))
     1725        {
    18731726            hr = pFsObjInfo.queryInterfaceTo(aInfo);
    1874     }
    1875 
    1876     if (RT_FAILURE(rc))
    1877     {
    1878         switch (rc)
    1879         {
    1880             /** @todo Add more errors here! */
     1727            if (FAILED(hr)) return hr;
     1728        }
     1729    }
     1730
     1731    if (RT_FAILURE(vrc))
     1732    {
     1733        switch (vrc)
     1734        {
     1735            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1736                hr = GuestProcess::setErrorExternal(this, guestRc);
     1737                break;
    18811738
    18821739            case VERR_NOT_A_FILE:
     
    18851742
    18861743            default:
    1887                hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), rc);
     1744               hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), vrc);
    18881745               break;
    18891746        }
     
    19101767    HRESULT hr = S_OK;
    19111768
    1912     int64_t llSize;
    1913     int rc = fileQuerySizeInternal(Utf8Str(aPath), &llSize);
    1914     if (RT_SUCCESS(rc))
     1769    int64_t llSize; int guestRc;
     1770    int vrc = fileQuerySizeInternal(Utf8Str(aPath), &llSize, &guestRc);
     1771    if (RT_SUCCESS(vrc))
    19151772    {
    19161773        *aSize = llSize;
     
    19181775    else
    19191776    {
    1920         switch (rc)
    1921         {
    1922             /** @todo Add more errors here! */
     1777        switch (vrc)
     1778        {
     1779            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1780                hr = GuestProcess::setErrorExternal(this, guestRc);
     1781                break;
    19231782
    19241783            default:
    1925                hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), rc);
     1784               hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), vrc);
    19261785               break;
    19271786        }
     
    19701829    com::SafeArray<LONG> affinity;
    19711830
    1972     HRESULT hr = ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
    1973                                  ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);
    1974     return hr;
     1831    return ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
     1832                           ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);
    19751833#endif /* VBOX_WITH_GUEST_CONTROL */
    19761834}
  • trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp

    r43061 r43162  
    5050 * Update file flags.
    5151 */
    52 #define UPDATEFILE_FLAG_NONE                RT_BIT(0)
     52#define UPDATEFILE_FLAG_NONE                0
    5353/** Copy over the file from host to the
    5454 *  guest. */
    55 #define UPDATEFILE_FLAG_COPY_FROM_ISO       RT_BIT(1)
     55#define UPDATEFILE_FLAG_COPY_FROM_ISO       RT_BIT(0)
    5656/** Execute file on the guest after it has
    5757 *  been successfully transfered. */
     
    251251
    252252    GuestProcessStartupInfo procInfo;
    253     procInfo.mName    = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to the guest to \"%s\" (%RU64 bytes)"),
    254                                    mSource.c_str(), mDest.c_str(), mSourceSize);
    255253    procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_CAT);
    256254    procInfo.mFlags   = ProcessCreateFlag_Hidden;
     
    260258
    261259    /* Startup process. */
    262     ComObjPtr<GuestProcess> pProcess;
     260    ComObjPtr<GuestProcess> pProcess; int guestRc;
    263261    rc = pSession->processCreateExInteral(procInfo, pProcess);
    264262    if (RT_SUCCESS(rc))
    265         rc = pProcess->startProcess();
     263        rc = pProcess->startProcess(&guestRc);
    266264    if (RT_FAILURE(rc))
    267265    {
    268         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    269                             Utf8StrFmt(GuestSession::tr("Unable to start guest process: %Rrc"), rc));
    270     }
    271     else
    272     {
    273         GuestProcessWaitResult waitRes;
     266        switch (rc)
     267        {
     268            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     269                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     270                                    GuestProcess::guestErrorToString(guestRc));
     271                break;
     272
     273            default:
     274                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     275                                    Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
     276                                               mSource.c_str(), rc));
     277                break;
     278        }
     279    }
     280
     281    if (RT_SUCCESS(rc))
     282    {
     283        ProcessWaitResult_T waitRes;
    274284        BYTE byBuf[_64K];
    275285
     
    280290        for (;;)
    281291        {
     292            int guestRc;
    282293            rc = pProcess->waitFor(ProcessWaitForFlag_StdIn,
    283                                    30 * 1000 /* Timeout */, waitRes);
     294                                   30 * 1000 /* Timeout */, waitRes, &guestRc);
    284295            if (   RT_FAILURE(rc)
    285                 || (   waitRes.mResult != ProcessWaitResult_StdIn
    286                     && waitRes.mResult != ProcessWaitResult_WaitFlagNotSupported))
     296                || (   waitRes != ProcessWaitResult_StdIn
     297                    && waitRes != ProcessWaitResult_WaitFlagNotSupported))
    287298            {
    288299                break;
     
    291302            /* If the guest does not support waiting for stdin, we now yield in
    292303             * order to reduce the CPU load due to busy waiting. */
    293             if (waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported)
    294                 RTThreadYield(); /* Optional, don't check rc. */
     304            if (waitRes == ProcessWaitResult_WaitFlagNotSupported)
     305                RTThreadSleep(1); /* Optional, don't check rc. */
    295306
    296307            size_t cbRead = 0;
     
    320331                {
    321332                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    322                                         Utf8StrFmt(GuestSession::tr("Seeking file \"%s\" offset %RU64 failed: %Rrc"),
     333                                        Utf8StrFmt(GuestSession::tr("Seeking file \"%s\" to offset %RU64 failed: %Rrc"),
    323334                                                   mSource.c_str(), cbWrittenTotal, rc));
    324335                    break;
     
    333344                || (cbToRead - cbRead == 0)
    334345                /* ... or does the user want to cancel? */
    335                 || (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
     346                || (   !mProgress.isNull()
     347                    && SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
    336348                    && fCanceled)
    337349               )
    338350            {
     351                LogFlowThisFunc(("Writing last chunk cbRead=%RU64\n", cbRead));
    339352                fFlags |= ProcessInputFlag_EndOfFile;
    340353            }
     
    344357            rc = pProcess->writeData(0 /* StdIn */, fFlags,
    345358                                     byBuf, cbRead,
    346                                      30 * 1000 /* Timeout */, &cbWritten);
     359                                     30 * 1000 /* Timeout */, &cbWritten, &guestRc);
    347360            if (RT_FAILURE(rc))
    348361            {
    349                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    350                                     Utf8StrFmt(GuestSession::tr("Writing to file \"%s\" (offset %RU64) failed: %Rrc"),
    351                                                mDest.c_str(), cbWrittenTotal, rc));
     362                switch (rc)
     363                {
     364                    case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     365                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     366                                            GuestProcess::guestErrorToString(guestRc));
     367                        break;
     368
     369                    default:
     370                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     371                                            Utf8StrFmt(GuestSession::tr("Writing to file \"%s\" (offset %RU64) failed: %Rrc"),
     372                                            mDest.c_str(), cbWrittenTotal, rc));
     373                        break;
     374                }
     375
    352376                break;
    353377            }
    354 
    355             LogFlowThisFunc(("cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n",
    356                              cbWritten, cbToRead - cbWritten, cbWrittenTotal + cbWritten, mSourceSize));
    357378
    358379            /* Only subtract bytes reported written by the guest. */
     
    363384            cbWrittenTotal += cbWritten;
    364385            Assert(cbWrittenTotal <= mSourceSize);
     386
     387            LogFlowThisFunc(("rc=%Rrc, cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n",
     388                             rc, cbWritten, cbToRead, cbWrittenTotal, mSourceSize));
    365389
    366390            /* Did the user cancel the operation above? */
     
    381405        } /* for */
    382406
     407        LogFlowThisFunc(("Copy loop ended with rc=%Rrc\n" ,rc));
     408
    383409        if (   !fCanceled
    384410            || RT_SUCCESS(rc))
     
    393419                /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
    394420                 * to the destination -> access denied. */
    395                 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    396                                          Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""),
    397                                                     mSource.c_str(), mDest.c_str()));
     421                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     422                                    Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""),
     423                                               mSource.c_str(), mDest.c_str()));
     424                rc = VERR_GENERAL_FAILURE; /* Fudge. */
    398425            }
    399426            else if (cbWrittenTotal < mSourceSize)
    400427            {
    401428                /* If we did not copy all let the user know. */
    402                 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    403                                          Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RU64 bytes transfered)"),
    404                                                     mSource.c_str(), cbWrittenTotal, mSourceSize));
     429                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     430                                    Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RU64 bytes transfered)"),
     431                                               mSource.c_str(), cbWrittenTotal, mSourceSize));
     432                rc = VERR_GENERAL_FAILURE; /* Fudge. */
    405433            }
    406434            else
    407435            {
    408436                rc = pProcess->waitFor(ProcessWaitForFlag_Terminate,
    409                                        30 * 1000 /* Timeout */, waitRes);
     437                                       30 * 1000 /* Timeout */, waitRes, &guestRc);
    410438                if (   RT_FAILURE(rc)
    411                     || waitRes.mResult != ProcessWaitResult_Terminate)
     439                    || waitRes != ProcessWaitResult_Terminate)
    412440                {
    413441                    if (RT_FAILURE(rc))
    414                         rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    415                                                  Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed: %Rrc"),
    416                                                             mSource.c_str(), rc));
     442                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     443                                            Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed: %Rrc"),
     444                                                       mSource.c_str(), rc));
    417445                    else
    418                         rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    419                                                  Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed with wait result %ld"),
    420                                                             mSource.c_str(), waitRes.mResult));
     446                    {
     447                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     448                                            Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed with wait result %ld"),
     449                                                       mSource.c_str(), waitRes));
     450                        rc = VERR_GENERAL_FAILURE; /* Fudge. */
     451                    }
    421452                }
    422453
     
    431462                       )
    432463                    {
    433                         rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    434                                                  Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %ld"),
    435                                                             mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */
     464                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     465                                            Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %ld"),
     466                                                       mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */
     467                        rc = VERR_GENERAL_FAILURE; /* Fudge. */
    436468                    }
    437469                }
     
    508540     ** @todo Implement guest file locking!
    509541     */
    510     GuestFsObjData objData;
    511     int rc = pSession->fileQueryInfoInternal(Utf8Str(mSource), objData);
     542    GuestFsObjData objData; int guestRc;
     543    int rc = pSession->fileQueryInfoInternal(Utf8Str(mSource), objData, &guestRc);
    512544    if (RT_FAILURE(rc))
    513545    {
     
    545577
    546578            /* Startup process. */
    547             ComObjPtr<GuestProcess> pProcess;
     579            ComObjPtr<GuestProcess> pProcess; int guestRc;
    548580            rc = pSession->processCreateExInteral(procInfo, pProcess);
    549581            if (RT_SUCCESS(rc))
    550                 rc = pProcess->startProcess();
     582                rc = pProcess->startProcess(&guestRc);
    551583            if (RT_FAILURE(rc))
    552584            {
    553                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    554                                     Utf8StrFmt(GuestSession::tr("Unable to start guest process for copying data from guest to host: %Rrc"), rc));
     585                switch (rc)
     586                {
     587                    case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     588                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     589                                            GuestProcess::guestErrorToString(guestRc));
     590                        break;
     591
     592                    default:
     593                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     594                                            Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
     595                                                       mSource.c_str(), rc));
     596                        break;
     597                }
    555598            }
    556599            else
    557600            {
    558                 GuestProcessWaitResult waitRes;
     601                ProcessWaitResult_T waitRes;
    559602                BYTE byBuf[_64K];
    560603
     
    563606                uint64_t cbToRead = objData.mObjectSize;
    564607
     608                int guestRc;
     609
    565610                for (;;)
    566611                {
    567612                    rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
    568                                            30 * 1000 /* Timeout */, waitRes);
    569                     if (   waitRes.mResult == ProcessWaitResult_StdOut
    570                         || waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported)
     613                                           30 * 1000 /* Timeout */, waitRes, &guestRc);
     614                    if (RT_FAILURE(rc))
     615                    {
     616                        switch (rc)
     617                        {
     618                            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     619                                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     620                                                    GuestProcess::guestErrorToString(guestRc));
     621                                break;
     622
     623                            default:
     624                                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     625                                                    Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
     626                                                               mSource.c_str(), rc));
     627                                break;
     628                        }
     629
     630                        break;
     631                    }
     632
     633                    if (   waitRes == ProcessWaitResult_StdOut
     634                        || waitRes == ProcessWaitResult_WaitFlagNotSupported)
    571635                    {
    572636                        /* If the guest does not support waiting for stdin, we now yield in
    573637                         * order to reduce the CPU load due to busy waiting. */
    574                         if (waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported)
    575                             RTThreadYield(); /* Optional, don't check rc. */
    576 
    577                         size_t cbRead;
     638                        if (waitRes == ProcessWaitResult_WaitFlagNotSupported)
     639                            RTThreadSleep(1); /* Optional, don't check rc. */
     640
     641                        size_t cbRead; int guestRc;
    578642                        rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
    579643                                                30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
    580                                                 &cbRead);
     644                                                &cbRead, &guestRc);
    581645                        if (RT_FAILURE(rc))
    582646                        {
    583                             setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    584                                                 Utf8StrFmt(GuestSession::tr("Reading from file \"%s\" (offset %RU64) failed: %Rrc"),
    585                                                 mSource.c_str(), cbWrittenTotal, rc));
     647                            switch (rc)
     648                            {
     649                                case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     650                                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     651                                                        GuestProcess::guestErrorToString(guestRc));
     652                                    break;
     653
     654                                default:
     655                                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     656                                                        Utf8StrFmt(GuestSession::tr("Reading from file \"%s\" (offset %RU64) failed: %Rrc"),
     657                                                                   mSource.c_str(), cbWrittenTotal, rc));
     658                                    break;
     659                            }
     660
    586661                            break;
    587662                        }
     
    616691                        }
    617692                    }
    618                     else if (   RT_FAILURE(rc)
    619                              || waitRes.mResult == ProcessWaitResult_Terminate
    620                              || waitRes.mResult == ProcessWaitResult_Error
    621                              || waitRes.mResult == ProcessWaitResult_Timeout)
     693                    else
    622694                    {
    623                         if (RT_FAILURE(waitRes.mRC))
    624                             rc = waitRes.mRC;
    625695                        break;
    626696                    }
     697
    627698                } /* for */
    628699
    629                 LogFlowThisFunc(("rc=%Rrc, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n",
    630                                  rc, cbWrittenTotal, objData.mObjectSize, cbToRead));
     700                LogFlowThisFunc(("rc=%Rrc, guestrc=%Rrc, waitRes=%ld, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n",
     701                                 rc, guestRc, waitRes, cbWrittenTotal, objData.mObjectSize, cbToRead));
    631702
    632703                if (   !fCanceled
     
    794865
    795866        GuestFsObjData objData;
    796         int64_t cbSizeOnGuest;
    797         rc = pSession->fileQuerySizeInternal(strFileDest, &cbSizeOnGuest);
     867        int64_t cbSizeOnGuest; int guestRc;
     868        rc = pSession->fileQuerySizeInternal(strFileDest, &cbSizeOnGuest, &guestRc);
    798869        if (   RT_SUCCESS(rc)
    799870            && cbSize == (uint64_t)cbSizeOnGuest)
     
    811882            }
    812883            else
    813                 LogFlowThisFunc(("Error copying Guest Additions installer file \"%s\": %Rrc\n",
    814                                  strFileDest.c_str(), rc));
     884            {
     885                switch (rc)
     886                {
     887                    case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     888                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     889                                            GuestProcess::guestErrorToString(guestRc));
     890                        break;
     891
     892                    default:
     893                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     894                                            Utf8StrFmt(GuestSession::tr("Error while querying size for file \"%s\": %Rrc"),
     895                                                       strFileDest.c_str(), rc));
     896                        break;
     897                }
     898            }
    815899        }
    816900
     
    829913    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    830914
    831     ComObjPtr<GuestProcess> pProcess;
    832     int rc = pSession->processCreateExInteral(procInfo, pProcess);
    833     if (RT_SUCCESS(rc))
    834         rc = pProcess->startProcess();
    835 
    836     if (RT_SUCCESS(rc))
    837     {
    838         LogRel(("Running %s ...\n", procInfo.mName.c_str()));
    839 
    840         GuestProcessWaitResult waitRes;
    841         rc = pProcess->waitFor(ProcessWaitForFlag_Terminate,
    842                                10 * 60 * 1000 /* 10 mins Timeout */, waitRes);
    843         LogFlowThisFunc(("waitFor rc=%Rrc, waitRes=%ld\n", rc, waitRes));
    844         if (waitRes.mResult == ProcessWaitResult_Terminate)
    845         {
    846             ProcessStatus_T procStatus;
    847             LONG exitCode;
    848             if (   (   SUCCEEDED(pProcess->COMGETTER(Status(&procStatus)))
    849                     && procStatus != ProcessStatus_TerminatedNormally)
    850                 || (   SUCCEEDED(pProcess->COMGETTER(ExitCode(&exitCode)))
    851                     && exitCode != 0)
    852                )
    853             {
     915    LogRel(("Running %s ...\n", procInfo.mName.c_str()));
     916
     917    LONG exitCode;
     918    GuestProcessTool procTool; int guestRc;
     919    int vrc = procTool.Init(pSession, procInfo, false /* Async */, &guestRc);
     920    if (RT_SUCCESS(vrc))
     921    {
     922        if (RT_SUCCESS(guestRc))
     923            vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
     924        if (RT_SUCCESS(vrc))
     925            vrc = procTool.TerminatedOk(&exitCode);
     926    }
     927
     928    if (RT_FAILURE(vrc))
     929    {
     930        switch (vrc)
     931        {
     932            case VERR_NOT_EQUAL: /** @todo Special guest control rc needed! */
    854933                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    855                                     Utf8StrFmt(GuestSession::tr("Running %s failed with status %ld, exit code %ld"),
    856                                                procInfo.mName.c_str(), procStatus, exitCode));
    857                 rc = VERR_GENERAL_FAILURE; /* Fudge. */
    858             }
    859             else /* Yay, success! */
    860             {
    861                 LogFlowThisFunc(("%s successfully completed\n", procInfo.mName.c_str()));
    862             }
    863         }
    864         else if (   procInfo.mFlags == ProcessCreateFlag_WaitForProcessStartOnly
    865                  && waitRes.mResult == ProcessWaitResult_Start)
    866         {
    867             LogFlowThisFunc(("%s successfully started\n", procInfo.mName.c_str()));
    868         }
    869         else
    870         {
    871             /** @todo Unify error handling. */
    872             if (RT_FAILURE(rc))
    873             {
     934                                    Utf8StrFmt(GuestSession::tr("Running update file \"%s\" on guest terminated with exit code %ld"),
     935                                               procInfo.mCommand.c_str(), exitCode));
     936                break;
     937
     938            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
    874939                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    875                                     Utf8StrFmt(GuestSession::tr("Error while waiting running %s: %Rrc"),
    876                                                procInfo.mName.c_str(), rc));
    877             }
    878             else
    879             {
    880                 if (pProcess->errorMsg().isEmpty())
    881                 {
    882                     setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    883                                         Utf8StrFmt(GuestSession::tr("Running %s returned unexpectedly with status %ld"),
    884                                                    procInfo.mName.c_str(), waitRes.mResult));
    885                 }
    886                 else
    887                     setProgressErrorMsg(VBOX_E_IPRT_ERROR, pProcess->errorMsg());
    888                 rc = VERR_GENERAL_FAILURE; /* Fudge. */
    889             }
    890         }
    891     }
    892 
    893     if (!pProcess.isNull())
    894         pProcess->uninit();
    895 
    896     return rc;
     940                                    GuestProcess::guestErrorToString(vrc));
     941                break;
     942
     943            default:
     944                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     945                                    Utf8StrFmt(GuestSession::tr("Error while running update file \"%s\" on guest: %Rrc"),
     946                                               procInfo.mCommand.c_str(), vrc));
     947                break;
     948        }
     949    }
     950
     951    return vrc;
    897952}
    898953
     
    10801135                rc = getGuestProperty(pGuest, "/VirtualBox/GuestAdd/Version", strAddsVer);
    10811136                if (   RT_SUCCESS(rc)
    1082                     && RTStrVersionCompare(strAddsVer.c_str(), "4.2") >= 0)
     1137                    && RTStrVersionCompare(strAddsVer.c_str(), "4.2r80329") > 0)
    10831138                {
    10841139                    fUseInstallDir = true;
     
    11071162
    11081163            /* Create the installation directory. */
     1164            int guestRc;
    11091165            rc = pSession->directoryCreateInternal(strUpdateDir,
    1110                                                    755 /* Mode */, DirectoryCreateFlag_Parents);
     1166                                                   755 /* Mode */, DirectoryCreateFlag_Parents, &guestRc);
    11111167            if (RT_FAILURE(rc))
    1112                 hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1113                                          Utf8StrFmt(GuestSession::tr("Error creating installation directory \"%s\" on the guest: %Rrc"),
    1114                                                     strUpdateDir.c_str(), rc));
     1168            {
     1169                switch (rc)
     1170                {
     1171                    case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
     1172                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1173                                            GuestProcess::guestErrorToString(guestRc));
     1174                        break;
     1175
     1176                    default:
     1177                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1178                                            Utf8StrFmt(GuestSession::tr("Error creating installation directory \"%s\" on the guest: %Rrc"),
     1179                                                       strUpdateDir.c_str(), rc));
     1180                        break;
     1181                }
     1182            }
    11151183            if (RT_SUCCESS(rc))
    11161184                rc = setProgress(10);
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