VirtualBox

Changeset 42810 in vbox


Ignore:
Timestamp:
Aug 14, 2012 2:45:11 PM (13 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
80054
Message:

Guest Control 2.0: Update.

Location:
trunk/src/VBox
Files:
5 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r42808 r42810  
    807807            }
    808808
    809 #ifdef DEBUG
    810             if (fVerbose)
    811                 RTPrintf("rc=%Rrc, waitResult=%ld\n", rc, waitResult);
    812 #endif
    813809            switch (waitResult)
    814810            {
     
    838834                    fCompleted = true;
    839835                    break;
    840                case ProcessWaitResult_Any:
    841                    fReadStdOut = fReadStdErr = true;
    842                    break;
     836                case ProcessWaitResult_WaitFlagNotSupported:
     837                {
     838                    /* The guest does not support waiting for stdout/err, so
     839                     * yield to reduce the CPU load due to busy waiting. */
     840                    RTThreadYield(); /* Optional, don't check rc. */
     841
     842                    /* Try both, stdout + stderr. */
     843                    fReadStdOut = fReadStdErr = true;
     844                    break;
     845                }
    843846                default:
    844847                    /* Ignore all other results, let the timeout expire */;
  • trunk/src/VBox/Main/Makefile.kmk

    r42551 r42810  
    639639ifdef VBOX_WITH_GUEST_CONTROL
    640640VBoxC_SOURCES += \
     641        src-client/GuestSessionImplTasks.cpp \
    641642        src-client/GuestCtrlPrivate.cpp \
    642643        src-client/GuestCtrlImplTasks.cpp \
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r42806 r42810  
    90359035  <enum
    90369036    name="ProcessWaitResult"
    9037     uuid="24a4d49f-a7c1-44b0-b01f-5686a316466b"
     9037    uuid="40719cbe-f192-4fe9-a231-6697b3c8e2b4"
    90389038    >
    90399039    <desc>
     
    90889088      <desc>Data on stderr became available for reading.</desc>
    90899089    </const>
    9090     <const name="Any"                     value="9">
     9090    <const name="WaitFlagNotSupported"    value="9">
    90919091      <desc>
    90929092        A waiting flag specified in the <link to="IProcess::waitFor"/> call
  • trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp

    r42787 r42810  
    12831283                        || (fWaitFlags & ProcessWaitForFlag_StdErr))
    12841284                    {
    1285                         /* Use _Any because we don't know what to tell the caller. */
    1286                         waitRes.mResult = ProcessWaitResult_Any;
     1285                        /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */
     1286                        waitRes.mResult = ProcessWaitResult_WaitFlagNotSupported;
    12871287                    }
    12881288                }
     
    13841384        vrc = waitFor(ProcessWaitForFlag_Start, uTimeoutMS, waitRes);
    13851385        if (   RT_FAILURE(vrc)
    1386             || (    waitRes.mResult == ProcessWaitResult_Start
    1387                 &&  waitRes.mResult == ProcessWaitResult_Any
    1388                )
    1389            )
     1386            || waitRes.mResult == ProcessWaitResult_Start)
    13901387        {
    13911388            if (RT_SUCCESS(vrc))
    13921389                vrc = waitRes.mRC;
    13931390        }
     1391        /** @todo More error handling needed. */
    13941392    }
    13951393
  • trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp

    r42808 r42810  
    6363    BaseFinalRelease();
    6464    LogFlowThisFuncLeave();
    65 }
    66 
    67 // session task classes
    68 /////////////////////////////////////////////////////////////////////////////
    69 
    70 GuestSessionTask::GuestSessionTask(GuestSession *pSession)
    71 {
    72     mSession = pSession;
    73 }
    74 
    75 GuestSessionTask::~GuestSessionTask(void)
    76 {
    77 }
    78 
    79 int GuestSessionTask::setProgress(ULONG uPercent)
    80 {
    81     if (mProgress.isNull()) /* Progress is optional. */
    82         return VINF_SUCCESS;
    83 
    84     BOOL fCanceled;
    85     if (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
    86         && fCanceled)
    87         return VERR_CANCELLED;
    88     BOOL fCompleted;
    89     if (   SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))
    90         && !fCompleted)
    91         return VINF_SUCCESS;
    92     HRESULT hr = mProgress->SetCurrentOperationProgress(uPercent);
    93     if (FAILED(hr))
    94         return VERR_COM_UNEXPECTED;
    95 
    96     return VINF_SUCCESS;
    97 }
    98 
    99 int GuestSessionTask::setProgressSuccess(void)
    100 {
    101     if (mProgress.isNull()) /* Progress is optional. */
    102         return VINF_SUCCESS;
    103 
    104     BOOL fCanceled;
    105     BOOL fCompleted;
    106     if (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
    107         && !fCanceled
    108         && SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))
    109         && !fCompleted)
    110     {
    111         HRESULT hr = mProgress->notifyComplete(S_OK);
    112         if (FAILED(hr))
    113             return VERR_COM_UNEXPECTED; /** @todo Find a better rc. */
    114     }
    115 
    116     return VINF_SUCCESS;
    117 }
    118 
    119 HRESULT GuestSessionTask::setProgressErrorMsg(HRESULT hr, const Utf8Str &strMsg)
    120 {
    121     if (mProgress.isNull()) /* Progress is optional. */
    122         return hr; /* Return original rc. */
    123 
    124     BOOL fCanceled;
    125     BOOL fCompleted;
    126     if (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
    127         && !fCanceled
    128         && SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))
    129         && !fCompleted)
    130     {
    131         HRESULT hr2 = mProgress->notifyComplete(hr,
    132                                                COM_IIDOF(IGuestSession),
    133                                                GuestSession::getStaticComponentName(),
    134                                                strMsg.c_str());
    135         if (FAILED(hr2))
    136             return hr2;
    137     }
    138     return hr; /* Return original rc. */
    139 }
    140 
    141 SessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession,
    142                                      const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)
    143                                      : mSource(strSource),
    144                                        mDest(strDest),
    145                                        mSourceFile(NULL),
    146                                        mSourceOffset(0),
    147                                        mSourceSize(0),
    148                                        GuestSessionTask(pSession)
    149 {
    150     mCopyFileFlags = uFlags;
    151 }
    152 
    153 /** @todo Merge this and the above call and let the above call do the open/close file handling so that the
    154  *        inner code only has to deal with file handles. No time now ... */
    155 SessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession,
    156                                      PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize,
    157                                      const Utf8Str &strDest, uint32_t uFlags)
    158                                      : GuestSessionTask(pSession)
    159 {
    160     mSourceFile    = pSourceFile;
    161     mSourceOffset  = cbSourceOffset;
    162     mSourceSize    = cbSourceSize;
    163     mDest          = strDest;
    164     mCopyFileFlags = uFlags;
    165 }
    166 
    167 SessionTaskCopyTo::~SessionTaskCopyTo(void)
    168 {
    169 
    170 }
    171 
    172 int SessionTaskCopyTo::Run(void)
    173 {
    174     LogFlowThisFuncEnter();
    175 
    176     ComObjPtr<GuestSession> pSession = mSession;
    177     Assert(!pSession.isNull());
    178 
    179     AutoCaller autoCaller(pSession);
    180     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    181 
    182     if (mCopyFileFlags)
    183     {
    184         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    185                             Utf8StrFmt(GuestSession::tr("Copy flags (%#x) not implemented yet"),
    186                             mCopyFileFlags));
    187         return VERR_INVALID_PARAMETER;
    188     }
    189 
    190     int rc;
    191 
    192     RTFILE fileLocal;
    193     PRTFILE pFile = &fileLocal;
    194 
    195     if (!mSourceFile)
    196     {
    197         /* Does our source file exist? */
    198         if (!RTFileExists(mSource.c_str()))
    199         {
    200             rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    201                                      Utf8StrFmt(GuestSession::tr("Source file \"%s\" does not exist or is not a file"),
    202                                                 mSource.c_str()));
    203         }
    204         else
    205         {
    206             rc = RTFileOpen(pFile, mSource.c_str(),
    207                             RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
    208             if (RT_FAILURE(rc))
    209             {
    210                 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    211                                          Utf8StrFmt(GuestSession::tr("Could not open source file \"%s\" for reading: %Rrc"),
    212                                                     mSource.c_str(), rc));
    213             }
    214             else
    215             {
    216                 rc = RTFileGetSize(*pFile, &mSourceSize);
    217                 if (RT_FAILURE(rc))
    218                 {
    219                     setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    220                                         Utf8StrFmt(GuestSession::tr("Could not query file size of \"%s\": %Rrc"),
    221                                                    mSource.c_str(), rc));
    222                 }
    223             }
    224         }
    225     }
    226     else
    227     {
    228         pFile = mSourceFile;
    229         /* Size + offset are optional. */
    230     }
    231 
    232     GuestProcessStartupInfo procInfo;
    233     procInfo.mName    = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to the guest to \"%s\" (%RU64 bytes)"),
    234                                    mSource.c_str(), mDest.c_str(), mSourceSize);
    235     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_CAT);
    236     procInfo.mFlags   = ProcessCreateFlag_Hidden;
    237 
    238     /* Set arguments.*/
    239     procInfo.mArguments.push_back(Utf8StrFmt("--output=%s", mDest.c_str())); /** @todo Do we need path conversion? */
    240 
    241     /* Startup process. */
    242     ComObjPtr<GuestProcess> pProcess;
    243     rc = pSession->processCreateExInteral(procInfo, pProcess);
    244     if (RT_SUCCESS(rc))
    245         rc = pProcess->startProcess();
    246     if (RT_FAILURE(rc))
    247     {
    248         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    249                             Utf8StrFmt(GuestSession::tr("Unable to start guest process: %Rrc"), rc));
    250     }
    251     else
    252     {
    253         GuestProcessWaitResult waitRes;
    254         BYTE byBuf[_64K];
    255 
    256         BOOL fCanceled = FALSE;
    257         uint64_t cbWrittenTotal = 0;
    258         uint64_t cbToRead = mSourceSize;
    259 
    260         for (;;)
    261         {
    262             rc = pProcess->waitFor(ProcessWaitForFlag_StdIn,
    263                                    30 * 1000 /* Timeout */, waitRes);
    264             if (   RT_FAILURE(rc)
    265                 || (   waitRes.mResult != ProcessWaitResult_StdIn
    266                     && waitRes.mResult != ProcessWaitResult_Any))
    267             {
    268                 break;
    269             }
    270 
    271             size_t cbRead = 0;
    272             if (mSourceSize) /* If we have nothing to write, take a shortcut. */
    273             {
    274                 /** @todo Not very efficient, but works for now. */
    275                 rc = RTFileSeek(*pFile, mSourceOffset + cbWrittenTotal,
    276                                 RTFILE_SEEK_BEGIN, NULL /* poffActual */);
    277                 if (RT_SUCCESS(rc))
    278                 {
    279                     rc = RTFileRead(*pFile, (uint8_t*)byBuf,
    280                                     RT_MIN(cbToRead, sizeof(byBuf)), &cbRead);
    281                     /*
    282                      * Some other error occured? There might be a chance that RTFileRead
    283                      * could not resolve/map the native error code to an IPRT code, so just
    284                      * print a generic error.
    285                      */
    286                     if (RT_FAILURE(rc))
    287                     {
    288                         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    289                                             Utf8StrFmt(GuestSession::tr("Could not read from file \"%s\" (%Rrc)"),
    290                                                        mSource.c_str(), rc));
    291                         break;
    292                     }
    293                 }
    294                 else
    295                 {
    296                     setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    297                                         Utf8StrFmt(GuestSession::tr("Seeking file \"%s\" offset %RU64 failed: %Rrc"),
    298                                                    mSource.c_str(), cbWrittenTotal, rc));
    299                     break;
    300                 }
    301             }
    302 
    303             uint32_t fFlags = ProcessInputFlag_None;
    304 
    305             /* Did we reach the end of the content we want to transfer (last chunk)? */
    306             if (   (cbRead < sizeof(byBuf))
    307                 /* Did we reach the last block which is exactly _64K? */
    308                 || (cbToRead - cbRead == 0)
    309                 /* ... or does the user want to cancel? */
    310                 || (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
    311                     && fCanceled)
    312                )
    313             {
    314                 fFlags |= ProcessInputFlag_EndOfFile;
    315             }
    316 
    317             uint32_t cbWritten;
    318             Assert(sizeof(byBuf) >= cbRead);
    319             rc = pProcess->writeData(0 /* StdIn */, fFlags,
    320                                      byBuf, cbRead,
    321                                      30 * 1000 /* Timeout */, &cbWritten);
    322             if (RT_FAILURE(rc))
    323             {
    324                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    325                                     Utf8StrFmt(GuestSession::tr("Writing to file \"%s\" (offset %RU64) failed: %Rrc"),
    326                                                mDest.c_str(), cbWrittenTotal, rc));
    327                 break;
    328             }
    329 
    330             LogFlowThisFunc(("cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n",
    331                              cbWritten, cbToRead - cbWritten, cbWrittenTotal + cbWritten, mSourceSize));
    332 
    333             /* Only subtract bytes reported written by the guest. */
    334             Assert(cbToRead >= cbWritten);
    335             cbToRead -= cbWritten;
    336 
    337             /* Update total bytes written to the guest. */
    338             cbWrittenTotal += cbWritten;
    339             Assert(cbWrittenTotal <= mSourceSize);
    340 
    341             /* Did the user cancel the operation above? */
    342             if (fCanceled)
    343                 break;
    344 
    345             /* Update the progress.
    346              * Watch out for division by zero. */
    347             mSourceSize > 0
    348                 ? rc = setProgress((ULONG)(cbWrittenTotal * 100 / mSourceSize))
    349                 : rc = setProgress(100);
    350             if (RT_FAILURE(rc))
    351                 break;
    352 
    353             /* End of file reached? */
    354             if (!cbToRead)
    355                 break;
    356         } /* for */
    357 
    358         if (   !fCanceled
    359             || RT_SUCCESS(rc))
    360         {
    361             /*
    362              * Even if we succeeded until here make sure to check whether we really transfered
    363              * everything.
    364              */
    365             if (   mSourceSize > 0
    366                 && cbWrittenTotal == 0)
    367             {
    368                 /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
    369                  * to the destination -> access denied. */
    370                 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    371                                          Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""),
    372                                                     mSource.c_str(), mDest.c_str()));
    373             }
    374             else if (cbWrittenTotal < mSourceSize)
    375             {
    376                 /* If we did not copy all let the user know. */
    377                 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    378                                          Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RU64 bytes transfered)"),
    379                                                     mSource.c_str(), cbWrittenTotal, mSourceSize));
    380             }
    381             else
    382             {
    383                 rc = pProcess->waitFor(ProcessWaitForFlag_Terminate,
    384                                        30 * 1000 /* Timeout */, waitRes);
    385                 if (   RT_FAILURE(rc)
    386                     || waitRes.mResult != ProcessWaitResult_Terminate)
    387                 {
    388                     if (RT_FAILURE(rc))
    389                         rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    390                                                  Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed: %Rrc"),
    391                                                             mSource.c_str(), rc));
    392                     else
    393                         rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    394                                                  Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed with wait result %ld"),
    395                                                             mSource.c_str(), waitRes.mResult));
    396                 }
    397 
    398                 if (RT_SUCCESS(rc))
    399                 {
    400                     ProcessStatus_T procStatus;
    401                     LONG exitCode;
    402                     if (   (   SUCCEEDED(pProcess->COMGETTER(Status(&procStatus)))
    403                             && procStatus != ProcessStatus_TerminatedNormally)
    404                         || (   SUCCEEDED(pProcess->COMGETTER(ExitCode(&exitCode)))
    405                             && exitCode != 0)
    406                        )
    407                     {
    408                         rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    409                                                  Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %ld"),
    410                                                             mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */
    411                     }
    412                 }
    413 
    414                 if (RT_SUCCESS(rc))
    415                     rc = setProgressSuccess();
    416             }
    417         }
    418 
    419         pProcess->close();
    420     } /* processCreateExInteral */
    421 
    422     if (!mSourceFile) /* Only close locally opened files. */
    423         RTFileClose(*pFile);
    424 
    425     LogFlowFuncLeaveRC(rc);
    426     return rc;
    427 }
    428 
    429 int SessionTaskCopyTo::RunAsync(const Utf8Str &strDesc, ComObjPtr<Progress> &pProgress)
    430 {
    431     LogFlowThisFunc(("strDesc=%s, strSource=%s, strDest=%s, mCopyFileFlags=%x\n",
    432                      strDesc.c_str(), mSource.c_str(), mDest.c_str(), mCopyFileFlags));
    433 
    434     mDesc = strDesc;
    435     mProgress = pProgress;
    436 
    437     int rc = RTThreadCreate(NULL, SessionTaskCopyTo::taskThread, this,
    438                             0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    439                             "gctlCpyTo");
    440     LogFlowFuncLeaveRC(rc);
    441     return rc;
    442 }
    443 
    444 /* static */
    445 int SessionTaskCopyTo::taskThread(RTTHREAD Thread, void *pvUser)
    446 {
    447     std::auto_ptr<SessionTaskCopyTo> task(static_cast<SessionTaskCopyTo*>(pvUser));
    448     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
    449 
    450     LogFlowFunc(("pTask=%p\n", task.get()));
    451     return task->Run();
    452 }
    453 
    454 SessionTaskCopyFrom::SessionTaskCopyFrom(GuestSession *pSession,
    455                                          const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)
    456                                          : GuestSessionTask(pSession)
    457 {
    458     mSource = strSource;
    459     mDest   = strDest;
    460     mFlags  = uFlags;
    461 }
    462 
    463 SessionTaskCopyFrom::~SessionTaskCopyFrom(void)
    464 {
    465 
    466 }
    467 
    468 int SessionTaskCopyFrom::Run(void)
    469 {
    470     LogFlowThisFuncEnter();
    471 
    472     ComObjPtr<GuestSession> pSession = mSession;
    473     Assert(!pSession.isNull());
    474 
    475     AutoCaller autoCaller(pSession);
    476     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    477 
    478     /*
    479      * Note: There will be races between querying file size + reading the guest file's
    480      *       content because we currently *do not* lock down the guest file when doing the
    481      *       actual operations.
    482      ** @todo Implement guest file locking!
    483      */
    484     GuestFsObjData objData;
    485     int rc = pSession->fileQueryInfoInternal(Utf8Str(mSource), objData);
    486     if (RT_FAILURE(rc))
    487     {
    488         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    489                             Utf8StrFmt(GuestSession::tr("Querying guest file information for \"%s\" failed: %Rrc"),
    490                             mSource.c_str(), rc));
    491     }
    492     else if (objData.mType != FsObjType_File) /* Only single files are supported at the moment. */
    493     {
    494         rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    495                                  Utf8StrFmt(GuestSession::tr("Object \"%s\" on the guest is not a file"), mSource.c_str()));
    496     }
    497 
    498     if (RT_SUCCESS(rc))
    499     {
    500         RTFILE fileDest;
    501         rc = RTFileOpen(&fileDest, mDest.c_str(),
    502                         RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */
    503         if (RT_FAILURE(rc))
    504         {
    505             setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    506                                 Utf8StrFmt(GuestSession::tr("Error opening destination file \"%s\": %Rrc"),
    507                                            mDest.c_str(), rc));
    508         }
    509         else
    510         {
    511             GuestProcessStartupInfo procInfo;
    512             procInfo.mName    = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"),
    513                                                             mSource.c_str(), mDest.c_str(), objData.mObjectSize);
    514             procInfo.mCommand   = Utf8Str(VBOXSERVICE_TOOL_CAT);
    515             procInfo.mFlags     = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
    516 
    517             /* Set arguments.*/
    518             procInfo.mArguments.push_back(mSource); /* Which file to output? */
    519 
    520             /* Startup process. */
    521             ComObjPtr<GuestProcess> pProcess;
    522             rc = pSession->processCreateExInteral(procInfo, pProcess);
    523             if (RT_SUCCESS(rc))
    524                 rc = pProcess->startProcess();
    525             if (RT_FAILURE(rc))
    526             {
    527                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    528                                     Utf8StrFmt(GuestSession::tr("Unable to start guest process for copying data from guest to host: %Rrc"), rc));
    529             }
    530             else
    531             {
    532                 GuestProcessWaitResult waitRes;
    533                 BYTE byBuf[_64K];
    534 
    535                 BOOL fCanceled = FALSE;
    536                 uint64_t cbWrittenTotal = 0;
    537                 uint64_t cbToRead = objData.mObjectSize;
    538 
    539                 for (;;)
    540                 {
    541                     rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
    542                                            30 * 1000 /* Timeout */, waitRes);
    543                     if (   waitRes.mResult == ProcessWaitResult_StdOut
    544                         || waitRes.mResult == ProcessWaitResult_Any)
    545                     {
    546                         size_t cbRead;
    547                         rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
    548                                                 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
    549                                                 &cbRead);
    550                         if (RT_FAILURE(rc))
    551                         {
    552                             setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    553                                                 Utf8StrFmt(GuestSession::tr("Reading from file \"%s\" (offset %RU64) failed: %Rrc"),
    554                                                 mSource.c_str(), cbWrittenTotal, rc));
    555                             break;
    556                         }
    557 
    558                         if (cbRead)
    559                         {
    560                             rc = RTFileWrite(fileDest, byBuf, cbRead, NULL /* No partial writes */);
    561                             if (RT_FAILURE(rc))
    562                             {
    563                                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    564                                                     Utf8StrFmt(GuestSession::tr("Error writing to file \"%s\" (%RU64 bytes left): %Rrc"),
    565                                                     mDest.c_str(), cbToRead, rc));
    566                                 break;
    567                             }
    568 
    569                             /* Only subtract bytes reported written by the guest. */
    570                             Assert(cbToRead >= cbRead);
    571                             cbToRead -= cbRead;
    572 
    573                             /* Update total bytes written to the guest. */
    574                             cbWrittenTotal += cbRead;
    575                             Assert(cbWrittenTotal <= (uint64_t)objData.mObjectSize);
    576 
    577                             /* Did the user cancel the operation above? */
    578                             if (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
    579                                 && fCanceled)
    580                                 break;
    581 
    582                             rc = setProgress((ULONG)(cbWrittenTotal / ((uint64_t)objData.mObjectSize / 100.0)));
    583                             if (RT_FAILURE(rc))
    584                                 break;
    585                         }
    586                     }
    587                     else if (   RT_FAILURE(rc)
    588                              || waitRes.mResult == ProcessWaitResult_Terminate
    589                              || waitRes.mResult == ProcessWaitResult_Error
    590                              || waitRes.mResult == ProcessWaitResult_Timeout)
    591                     {
    592                         if (RT_FAILURE(waitRes.mRC))
    593                             rc = waitRes.mRC;
    594                         break;
    595                     }
    596                 } /* for */
    597 
    598                 LogFlowThisFunc(("rc=%Rrc, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n",
    599                                  rc, cbWrittenTotal, objData.mObjectSize, cbToRead));
    600 
    601                 if (   !fCanceled
    602                     || RT_SUCCESS(rc))
    603                 {
    604                     /*
    605                      * Even if we succeeded until here make sure to check whether we really transfered
    606                      * everything.
    607                      */
    608                     if (   objData.mObjectSize > 0
    609                         && cbWrittenTotal == 0)
    610                     {
    611                         /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
    612                          * to the destination -> access denied. */
    613                         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    614                                             Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""),
    615                                             mSource.c_str(), mDest.c_str()));
    616                         rc = VERR_GENERAL_FAILURE; /* Fudge. */
    617                     }
    618                     else if (cbWrittenTotal < (uint64_t)objData.mObjectSize)
    619                     {
    620                         /* If we did not copy all let the user know. */
    621                         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    622                                             Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RI64 bytes transfered)"),
    623                                             mSource.c_str(), cbWrittenTotal, objData.mObjectSize));
    624                         rc = VERR_GENERAL_FAILURE; /* Fudge. */
    625                     }
    626                     else
    627                     {
    628                         ProcessStatus_T procStatus;
    629                         LONG exitCode;
    630                         if (   (   SUCCEEDED(pProcess->COMGETTER(Status(&procStatus)))
    631                                 && procStatus != ProcessStatus_TerminatedNormally)
    632                             || (   SUCCEEDED(pProcess->COMGETTER(ExitCode(&exitCode)))
    633                                 && exitCode != 0)
    634                            )
    635                         {
    636                             setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    637                                                 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %d"),
    638                                                 mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */
    639                             rc = VERR_GENERAL_FAILURE; /* Fudge. */
    640                         }
    641                         else /* Yay, success! */
    642                             rc = setProgressSuccess();
    643                     }
    644                 }
    645 
    646                 pProcess->close();
    647             }
    648 
    649             RTFileClose(fileDest);
    650         }
    651     }
    652 
    653     LogFlowFuncLeaveRC(rc);
    654     return rc;
    655 }
    656 
    657 int SessionTaskCopyFrom::RunAsync(const Utf8Str &strDesc, ComObjPtr<Progress> &pProgress)
    658 {
    659     LogFlowThisFunc(("strDesc=%s, strSource=%s, strDest=%s, uFlags=%x\n",
    660                      strDesc.c_str(), mSource.c_str(), mDest.c_str(), mFlags));
    661 
    662     mDesc = strDesc;
    663     mProgress = pProgress;
    664 
    665     int rc = RTThreadCreate(NULL, SessionTaskCopyFrom::taskThread, this,
    666                             0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    667                             "gctlCpyFrom");
    668     LogFlowFuncLeaveRC(rc);
    669     return rc;
    670 }
    671 
    672 /* static */
    673 int SessionTaskCopyFrom::taskThread(RTTHREAD Thread, void *pvUser)
    674 {
    675     std::auto_ptr<SessionTaskCopyFrom> task(static_cast<SessionTaskCopyFrom*>(pvUser));
    676     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
    677 
    678     LogFlowFunc(("pTask=%p\n", task.get()));
    679     return task->Run();
    680 }
    681 
    682 SessionTaskUpdateAdditions::SessionTaskUpdateAdditions(GuestSession *pSession,
    683                                                        const Utf8Str &strSource, uint32_t uFlags)
    684                                                        : GuestSessionTask(pSession)
    685 {
    686     mSource = strSource;
    687     mFlags  = uFlags;
    688 }
    689 
    690 SessionTaskUpdateAdditions::~SessionTaskUpdateAdditions(void)
    691 {
    692 
    693 }
    694 
    695 int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO,
    696                                                 Utf8Str const &strFileSource, const Utf8Str &strFileDest,
    697                                                 bool fOptional, uint32_t *pcbSize)
    698 {
    699     AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    700     AssertPtrReturn(pISO, VERR_INVALID_POINTER);
    701     /* pcbSize is optional. */
    702 
    703     uint32_t cbOffset;
    704     size_t cbSize;
    705 
    706     int rc = RTIsoFsGetFileInfo(pISO, strFileSource.c_str(), &cbOffset, &cbSize);
    707     if (RT_FAILURE(rc))
    708     {
    709         if (fOptional)
    710             return VINF_SUCCESS;
    711 
    712         return rc;
    713     }
    714 
    715     Assert(cbOffset);
    716     Assert(cbSize);
    717     rc = RTFileSeek(pISO->file, cbOffset, RTFILE_SEEK_BEGIN, NULL);
    718 
    719     /* Copy over the Guest Additions file to the guest. */
    720     if (RT_SUCCESS(rc))
    721     {
    722         LogRel(("Copying Guest Additions installer file \"%s\" to \"%s\" on guest ...\n",
    723                 strFileSource.c_str(), strFileDest.c_str()));
    724 
    725         if (RT_SUCCESS(rc))
    726         {
    727             SessionTaskCopyTo *pTask = new SessionTaskCopyTo(pSession /* GuestSession */,
    728                                                              &pISO->file, cbOffset, cbSize,
    729                                                              strFileDest, CopyFileFlag_None);
    730             AssertPtrReturn(pTask, VERR_NO_MEMORY);
    731 
    732             ComObjPtr<Progress> pProgressCopyTo;
    733             rc = pSession->startTaskAsync(Utf8StrFmt(GuestSession::tr("Copying Guest Additions installer file \"%s\" to \"%s\" on guest"),
    734                                                      mSource.c_str(), strFileDest.c_str()),
    735                                           pTask, pProgressCopyTo);
    736             if (RT_SUCCESS(rc))
    737             {
    738                 BOOL fCanceled = FALSE;
    739                 HRESULT hr = pProgressCopyTo->WaitForCompletion(-1);
    740                 if (   SUCCEEDED(pProgressCopyTo->COMGETTER(Canceled)(&fCanceled))
    741                     && fCanceled)
    742                 {
    743                     rc = VERR_GENERAL_FAILURE; /* Fudge. */
    744                 }
    745                 else if (FAILED(hr))
    746                 {
    747                     Assert(FAILED(hr));
    748                     rc = VERR_GENERAL_FAILURE; /* Fudge. */
    749                 }
    750             }
    751         }
    752     }
    753 
    754     /** @todo Note: Since there is no file locking involved at the moment, there can be modifications
    755      *              between finished copying, the verification and the actual execution. */
    756 
    757     /* Determine where the installer image ended up and if it has the correct size. */
    758     if (RT_SUCCESS(rc))
    759     {
    760         LogRel(("Verifying Guest Additions installer file \"%s\" ...\n", strFileDest.c_str()));
    761 
    762         GuestFsObjData objData;
    763         int64_t cbSizeOnGuest;
    764         rc = pSession->fileQuerySizeInternal(strFileDest, &cbSizeOnGuest);
    765 #ifdef VBOX_SERVICE_ENVARG_BUG
    766         if (RT_FAILURE(rc))
    767         {
    768             /* Ugly hack: Because older Guest Additions have problems with environment variable
    769                           expansion in parameters we have to check an alternative location on Windows.
    770                           So check for "%TEMP%\" being "C:\\Windows\\system32\\EMP" actually. */
    771             if (strFileDest.startsWith("%TEMP%\\", RTCString::CaseSensitive))
    772             {
    773                 Utf8Str strFileDestBug = "C:\\Windows\\system32\\EMP" + strFileDest.substr(sizeof("%TEMP%\\") - sizeof(char));
    774                 rc = pSession->fileQuerySizeInternal(strFileDestBug, &cbSizeOnGuest);
    775             }
    776         }
    777 #endif
    778         if (   RT_SUCCESS(rc)
    779             && cbSize == (uint64_t)cbSizeOnGuest)
    780         {
    781             LogRel(("Guest Additions installer file \"%s\" successfully verified\n",
    782                     strFileDest.c_str()));
    783         }
    784         else
    785         {
    786             if (RT_SUCCESS(rc)) /* Size does not match. */
    787                 rc = VERR_BROKEN_PIPE; /** @todo FInd a better error. */
    788         }
    789 
    790         if (RT_SUCCESS(rc))
    791         {
    792             if (pcbSize)
    793                 *pcbSize = cbSizeOnGuest;
    794         }
    795     }
    796 
    797     return rc;
    798 }
    799 
    800 int SessionTaskUpdateAdditions::runFile(GuestSession *pSession, GuestProcessStartupInfo &procInfo)
    801 {
    802     AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    803 
    804 #ifdef VBOX_SERVICE_ENVARG_BUG
    805     GuestFsObjData objData;
    806     int rc = pSession->fileQueryInfoInternal(procInfo.mCommand, objData);
    807     if (RT_FAILURE(rc))
    808         procInfo.mCommand = "C:\\Windows\\system32\\EMP" + procInfo.mCommand.substr(sizeof("%TEMP%\\") - sizeof(char));
    809 #endif
    810 
    811     ComObjPtr<GuestProcess> pProcess;
    812     rc = pSession->processCreateExInteral(procInfo, pProcess);
    813     if (RT_SUCCESS(rc))
    814         rc = pProcess->startProcess();
    815 
    816     if (RT_SUCCESS(rc))
    817     {
    818         LogRel(("Running %s ...\n", procInfo.mName.c_str()));
    819 
    820         GuestProcessWaitResult waitRes;
    821         rc = pProcess->waitFor(ProcessWaitForFlag_Terminate,
    822                                10 * 60 * 1000 /* 10 mins Timeout */, waitRes);
    823         if (waitRes.mResult == ProcessWaitResult_Terminate)
    824         {
    825             ProcessStatus_T procStatus;
    826             LONG exitCode;
    827             if (   (   SUCCEEDED(pProcess->COMGETTER(Status(&procStatus)))
    828                     && procStatus != ProcessStatus_TerminatedNormally)
    829                 || (   SUCCEEDED(pProcess->COMGETTER(ExitCode(&exitCode)))
    830                     && exitCode != 0)
    831                )
    832             {
    833                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    834                                     Utf8StrFmt(GuestSession::tr("Running %s failed with status %ld, exit code %ld"),
    835                                                procInfo.mName.c_str(), procStatus, exitCode));
    836                 rc = VERR_GENERAL_FAILURE; /* Fudge. */
    837             }
    838             else /* Yay, success! */
    839             {
    840                 LogRel(("%s successfully completed\n", procInfo.mName.c_str()));
    841             }
    842         }
    843         else
    844         {
    845             if (RT_FAILURE(rc))
    846                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    847                                     Utf8StrFmt(GuestSession::tr("Error while waiting running %s: %Rrc"),
    848                                                procInfo.mName.c_str(), rc));
    849             else
    850             {
    851                 setProgressErrorMsg(VBOX_E_IPRT_ERROR, pProcess->errorMsg());
    852                 rc = VERR_GENERAL_FAILURE; /* Fudge. */
    853             }
    854         }
    855     }
    856 
    857     if (!pProcess.isNull())
    858         pProcess->close();
    859 
    860     return rc;
    861 }
    862 
    863 int SessionTaskUpdateAdditions::Run(void)
    864 {
    865     LogFlowThisFuncEnter();
    866 
    867     ComObjPtr<GuestSession> pSession = mSession;
    868     Assert(!pSession.isNull());
    869 
    870     AutoCaller autoCaller(pSession);
    871     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    872 
    873     int rc = setProgress(10);
    874     if (RT_FAILURE(rc))
    875         return rc;
    876 
    877     HRESULT hr = S_OK;
    878 
    879     LogRel(("Automatic update of Guest Additions started, using \"%s\"\n", mSource.c_str()));
    880 
    881     /*
    882      * Determine guest OS type and the required installer image.
    883      * At the moment only Windows guests are supported.
    884      */
    885     Utf8Str strInstallerImage;
    886 
    887     ComObjPtr<Guest> pGuest(mSession->getParent());
    888     Bstr osTypeId;
    889     if (   SUCCEEDED(pGuest->COMGETTER(OSTypeId(osTypeId.asOutParam())))
    890         && !osTypeId.isEmpty())
    891     {
    892         Utf8Str osTypeIdUtf8(osTypeId); /* Needed for .contains(). */
    893         if (   osTypeIdUtf8.contains("Microsoft", Utf8Str::CaseInsensitive)
    894             || osTypeIdUtf8.contains("Windows", Utf8Str::CaseInsensitive))
    895         {
    896             if (osTypeIdUtf8.contains("64", Utf8Str::CaseInsensitive))
    897                 strInstallerImage = "VBOXWINDOWSADDITIONS_AMD64.EXE";
    898             else
    899                 strInstallerImage = "VBOXWINDOWSADDITIONS_X86.EXE";
    900             /* Since the installers are located in the root directory,
    901              * no further path processing needs to be done (yet). */
    902         }
    903         else /* Everything else is not supported (yet). */
    904         {
    905             hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    906                                      Utf8StrFmt(GuestSession::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"),
    907                                      osTypeIdUtf8.c_str()));
    908             rc = VERR_GENERAL_FAILURE; /* Fudge. */
    909         }
    910     }
    911     else
    912     {
    913         hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    914                                  Utf8StrFmt(GuestSession::tr("Could not detected guest OS type/version, please update manually")));
    915         rc = VERR_GENERAL_FAILURE; /* Fudge. */
    916     }
    917 
    918     RTISOFSFILE iso;
    919     if (RT_SUCCESS(rc))
    920     {
    921         Assert(!strInstallerImage.isEmpty());
    922 
    923         /*
    924          * Try to open the .ISO file and locate the specified installer.
    925          */
    926         rc = RTIsoFsOpen(&iso, mSource.c_str());
    927         if (RT_FAILURE(rc))
    928         {
    929             hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    930                                      Utf8StrFmt(GuestSession::tr("Unable to open Guest Additions .ISO file \"%s\": %Rrc"),
    931                                      mSource.c_str(), rc));
    932         }
    933         else
    934         {
    935             rc = setProgress(5);
    936 
    937             /** @todo Add support for non-Windows as well! */
    938             Utf8Str strInstallerDest = "%TEMP%\\VBoxWindowsAdditions.exe";
    939             bool fInstallCertificates = false;
    940 
    941             if (RT_SUCCESS(rc))
    942             {
    943                 /*
    944                  * Copy over main installer to the guest.
    945                  */
    946                 rc = copyFileToGuest(pSession, &iso, strInstallerImage, strInstallerDest,
    947                                      false /* File is not optional */, NULL /* cbSize */);
    948                 if (RT_SUCCESS(rc))
    949                     rc = setProgress(20);
    950 
    951                 /*
    952                  * Install needed certificates for the WHQL crap.
    953                  ** @todo Only for Windows!
    954                  */
    955                 if (RT_SUCCESS(rc))
    956                 {
    957                     rc = copyFileToGuest(pSession, &iso, "CERT/ORACLE_VBOX.CER", "%TEMP%\\oracle-vbox.cer",
    958                                          true /* File is optional */, NULL /* cbSize */);
    959                     if (RT_SUCCESS(rc))
    960                     {
    961                         rc = setProgress(30);
    962                         if (RT_SUCCESS(rc))
    963                         {
    964                             rc = copyFileToGuest(pSession, &iso, "CERT/VBOXCERTUTIL.EXE", "%TEMP%\\VBoxCertUtil.exe",
    965                                                  true /* File is optional */, NULL /* cbSize */);
    966                             if (RT_SUCCESS(rc))
    967                             {
    968                                 fInstallCertificates = true;
    969                                 rc = setProgress(40);
    970                             }
    971                             else
    972                                 hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    973                                                          Utf8StrFmt(GuestSession::tr("Error while copying certificate installation tool to the guest: %Rrc"), rc));
    974                         }
    975                     }
    976                     else
    977                         hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    978                                                  Utf8StrFmt(GuestSession::tr("Error while copying certificate to the guest: %Rrc"), rc));
    979                 }
    980             }
    981 
    982             /*
    983              * Run VBoxCertUtil.exe to install the Oracle certificate.
    984              */
    985             if (   RT_SUCCESS(rc)
    986                 && fInstallCertificates)
    987             {
    988                 LogRel(("Installing certificates on the guest ...\n"));
    989 
    990                 GuestProcessStartupInfo procInfo;
    991                 procInfo.mName    = Utf8StrFmt(GuestSession::tr("VirtualBox Guest Additions Certificate Utility"));
    992                 procInfo.mCommand = Utf8Str("%TEMP%\\VBoxCertUtil.exe");
    993                 procInfo.mFlags   = ProcessCreateFlag_Hidden;
    994 
    995                 /* Construct arguments. */
    996                 /** @todo Remove hardcoded paths. */
    997                 procInfo.mArguments.push_back(Utf8Str("add-trusted-publisher"));
    998                 /* Ugly hack: Because older Guest Additions have problems with environment variable
    999                           expansion in parameters we have to check an alternative location on Windows.
    1000                           So check for "%TEMP%\VBoxWindowsAdditions.exe" in a screwed up way. */
    1001 #ifdef VBOX_SERVICE_ENVARG_BUG
    1002                 GuestFsObjData objData;
    1003                 rc = pSession->fileQueryInfoInternal("%TEMP%\\oracle-vbox.cer", objData);
    1004                 if (RT_SUCCESS(rc))
    1005 #endif
    1006                     procInfo.mArguments.push_back(Utf8Str("%TEMP%\\oracle-vbox.cer"));
    1007 #ifdef VBOX_SERVICE_ENVARG_BUG
    1008                 else
    1009                     procInfo.mArguments.push_back(Utf8Str("C:\\Windows\\system32\\EMPoracle-vbox.cer"));
    1010 #endif
    1011                 /* Overwrite rc in any case. */
    1012                 rc = runFile(pSession, procInfo);
    1013             }
    1014 
    1015             if (RT_SUCCESS(rc))
    1016                 rc = setProgress(60);
    1017 
    1018             if (RT_SUCCESS(rc))
    1019             {
    1020                 LogRel(("Updating Guest Additions ...\n"));
    1021 
    1022                 GuestProcessStartupInfo procInfo;
    1023                 procInfo.mName    = Utf8StrFmt(GuestSession::tr("VirtualBox Guest Additions Setup"));
    1024                 procInfo.mCommand = Utf8Str(strInstallerDest);
    1025                 procInfo.mFlags   = ProcessCreateFlag_Hidden;
    1026                 /* If the caller does not want to wait for out guest update process to end,
    1027                  * complete the progress object now so that the caller can do other work. */
    1028                 if (mFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly)
    1029                     procInfo.mFlags |= ProcessCreateFlag_WaitForProcessStartOnly;
    1030 
    1031                 /* Construct arguments. */
    1032                 procInfo.mArguments.push_back(Utf8Str("/S")); /* We want to install in silent mode. */
    1033                 procInfo.mArguments.push_back(Utf8Str("/l")); /* ... and logging enabled. */
    1034                 /* Don't quit VBoxService during upgrade because it still is used for this
    1035                  * piece of code we're in right now (that is, here!) ... */
    1036                 procInfo.mArguments.push_back(Utf8Str("/no_vboxservice_exit"));
    1037                 /* Tell the installer to report its current installation status
    1038                  * using a running VBoxTray instance via balloon messages in the
    1039                  * Windows taskbar. */
    1040                 procInfo.mArguments.push_back(Utf8Str("/post_installstatus"));
    1041 
    1042                 rc = runFile(pSession, procInfo);
    1043                 if (RT_SUCCESS(rc))
    1044                     hr = setProgressSuccess();
    1045             }
    1046             RTIsoFsClose(&iso);
    1047         }
    1048     }
    1049 
    1050     LogFlowFuncLeaveRC(rc);
    1051     return rc;
    1052 }
    1053 
    1054 int SessionTaskUpdateAdditions::RunAsync(const Utf8Str &strDesc, ComObjPtr<Progress> &pProgress)
    1055 {
    1056     LogFlowThisFunc(("strDesc=%s, strSource=%s, uFlags=%x\n",
    1057                      strDesc.c_str(), mSource.c_str(), mFlags));
    1058 
    1059     mDesc = strDesc;
    1060     mProgress = pProgress;
    1061 
    1062     int rc = RTThreadCreate(NULL, SessionTaskUpdateAdditions::taskThread, this,
    1063                             0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    1064                             "gctlUpGA");
    1065     LogFlowFuncLeaveRC(rc);
    1066     return rc;
    1067 }
    1068 
    1069 /* static */
    1070 int SessionTaskUpdateAdditions::taskThread(RTTHREAD Thread, void *pvUser)
    1071 {
    1072     std::auto_ptr<SessionTaskUpdateAdditions> task(static_cast<SessionTaskUpdateAdditions*>(pvUser));
    1073     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
    1074 
    1075     LogFlowFunc(("pTask=%p\n", task.get()));
    1076     return task->Run();
    107765}
    107866
  • trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp

    r42808 r42810  
    3434#include <iprt/file.h> /* For CopyTo/From. */
    3535
    36 #include <VBox/com/array.h>
    37 #include <VBox/version.h>
    38 
    3936
    4037/*
     
    4542 */
    4643#define VBOX_SERVICE_ENVARG_BUG
    47 
    48 // constructor / destructor
    49 /////////////////////////////////////////////////////////////////////////////
    50 
    51 DEFINE_EMPTY_CTOR_DTOR(GuestSession)
    52 
    53 HRESULT GuestSession::FinalConstruct(void)
    54 {
    55     LogFlowThisFunc(("\n"));
    56     return BaseFinalConstruct();
    57 }
    58 
    59 void GuestSession::FinalRelease(void)
    60 {
    61     LogFlowThisFuncEnter();
    62     uninit();
    63     BaseFinalRelease();
    64     LogFlowThisFuncLeave();
    65 }
    6644
    6745// session task classes
     
    264242            if (   RT_FAILURE(rc)
    265243                || (   waitRes.mResult != ProcessWaitResult_StdIn
    266                     && waitRes.mResult != ProcessWaitResult_Any))
     244                    && waitRes.mResult != ProcessWaitResult_WaitFlagNotSupported))
    267245            {
    268246                break;
    269247            }
     248
     249            /* If the guest does not support waiting for stdin, we now yield in
     250             * order to reduce the CPU load due to busy waiting. */
     251            if (waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported)
     252                RTThreadYield(); /* Optional, don't check rc. */
    270253
    271254            size_t cbRead = 0;
     
    542525                                           30 * 1000 /* Timeout */, waitRes);
    543526                    if (   waitRes.mResult == ProcessWaitResult_StdOut
    544                         || waitRes.mResult == ProcessWaitResult_Any)
     527                        || waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported)
    545528                    {
     529                        /* If the guest does not support waiting for stdin, we now yield in
     530                         * order to reduce the CPU load due to busy waiting. */
     531                        if (waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported)
     532                            RTThreadYield(); /* Optional, don't check rc. */
     533
    546534                        size_t cbRead;
    547535                        rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
     
    10771065}
    10781066
    1079 // public initializer/uninitializer for internal purposes only
    1080 /////////////////////////////////////////////////////////////////////////////
    1081 
    1082 int GuestSession::init(Guest *aGuest, ULONG aSessionID,
    1083                        Utf8Str aUser, Utf8Str aPassword, Utf8Str aDomain, Utf8Str aName)
    1084 {
    1085     LogFlowThisFuncEnter();
    1086 
    1087     AssertPtrReturn(aGuest, VERR_INVALID_POINTER);
    1088 
    1089     /* Enclose the state transition NotReady->InInit->Ready. */
    1090     AutoInitSpan autoInitSpan(this);
    1091     AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
    1092 
    1093     mData.mTimeout = 30 * 60 * 1000; /* Session timeout is 30 mins by default. */
    1094     mData.mParent = aGuest;
    1095     mData.mId = aSessionID;
    1096 
    1097     mData.mCredentials.mUser = aUser;
    1098     mData.mCredentials.mPassword = aPassword;
    1099     mData.mCredentials.mDomain = aDomain;
    1100     mData.mName = aName;
    1101 
    1102     /* Confirm a successful initialization when it's the case. */
    1103     autoInitSpan.setSucceeded();
    1104 
    1105     LogFlowFuncLeaveRC(VINF_SUCCESS);
    1106     return VINF_SUCCESS;
    1107 }
    1108 
    1109 /**
    1110  * Uninitializes the instance.
    1111  * Called from FinalRelease().
    1112  */
    1113 void GuestSession::uninit(void)
    1114 {
    1115     LogFlowThisFuncEnter();
    1116 
    1117     /* Enclose the state transition Ready->InUninit->NotReady. */
    1118     AutoUninitSpan autoUninitSpan(this);
    1119     if (autoUninitSpan.uninitDone())
    1120         return;
    1121 
    1122 #ifdef VBOX_WITH_GUEST_CONTROL
    1123     for (SessionDirectories::iterator itDirs = mData.mDirectories.begin();
    1124          itDirs != mData.mDirectories.end(); ++itDirs)
    1125     {
    1126         (*itDirs)->uninit();
    1127         (*itDirs).setNull();
    1128     }
    1129     mData.mDirectories.clear();
    1130 
    1131     for (SessionFiles::iterator itFiles = mData.mFiles.begin();
    1132          itFiles != mData.mFiles.end(); ++itFiles)
    1133     {
    1134         (*itFiles)->uninit();
    1135         (*itFiles).setNull();
    1136     }
    1137     mData.mFiles.clear();
    1138 
    1139     for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
    1140          itProcs != mData.mProcesses.end(); ++itProcs)
    1141     {
    1142         itProcs->second->close();
    1143     }
    1144 
    1145     for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
    1146          itProcs != mData.mProcesses.end(); ++itProcs)
    1147     {
    1148         itProcs->second->uninit();
    1149         itProcs->second.setNull();
    1150     }
    1151     mData.mProcesses.clear();
    1152 
    1153     mData.mParent->sessionClose(this);
    1154 
    1155     LogFlowThisFuncLeave();
    1156 #endif
    1157 }
    1158 
    1159 // implementation of public getters/setters for attributes
    1160 /////////////////////////////////////////////////////////////////////////////
    1161 
    1162 STDMETHODIMP GuestSession::COMGETTER(User)(BSTR *aUser)
    1163 {
    1164 #ifndef VBOX_WITH_GUEST_CONTROL
    1165     ReturnComNotImplemented();
    1166 #else
    1167     LogFlowThisFuncEnter();
    1168 
    1169     CheckComArgOutPointerValid(aUser);
    1170 
    1171     AutoCaller autoCaller(this);
    1172     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1173 
    1174     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1175 
    1176     mData.mCredentials.mUser.cloneTo(aUser);
    1177 
    1178     LogFlowFuncLeaveRC(S_OK);
    1179     return S_OK;
    1180 #endif /* VBOX_WITH_GUEST_CONTROL */
    1181 }
    1182 
    1183 STDMETHODIMP GuestSession::COMGETTER(Domain)(BSTR *aDomain)
    1184 {
    1185 #ifndef VBOX_WITH_GUEST_CONTROL
    1186     ReturnComNotImplemented();
    1187 #else
    1188     LogFlowThisFuncEnter();
    1189 
    1190     CheckComArgOutPointerValid(aDomain);
    1191 
    1192     AutoCaller autoCaller(this);
    1193     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1194 
    1195     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1196 
    1197     mData.mCredentials.mDomain.cloneTo(aDomain);
    1198 
    1199     LogFlowFuncLeaveRC(S_OK);
    1200     return S_OK;
    1201 #endif /* VBOX_WITH_GUEST_CONTROL */
    1202 }
    1203 
    1204 STDMETHODIMP GuestSession::COMGETTER(Name)(BSTR *aName)
    1205 {
    1206 #ifndef VBOX_WITH_GUEST_CONTROL
    1207     ReturnComNotImplemented();
    1208 #else
    1209     LogFlowThisFuncEnter();
    1210 
    1211     CheckComArgOutPointerValid(aName);
    1212 
    1213     AutoCaller autoCaller(this);
    1214     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1215 
    1216     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1217 
    1218     mData.mName.cloneTo(aName);
    1219 
    1220     LogFlowFuncLeaveRC(S_OK);
    1221     return S_OK;
    1222 #endif /* VBOX_WITH_GUEST_CONTROL */
    1223 }
    1224 
    1225 STDMETHODIMP GuestSession::COMGETTER(Id)(ULONG *aId)
    1226 {
    1227 #ifndef VBOX_WITH_GUEST_CONTROL
    1228     ReturnComNotImplemented();
    1229 #else
    1230     LogFlowThisFuncEnter();
    1231 
    1232     CheckComArgOutPointerValid(aId);
    1233 
    1234     AutoCaller autoCaller(this);
    1235     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1236 
    1237     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1238 
    1239     *aId = mData.mId;
    1240 
    1241     LogFlowFuncLeaveRC(S_OK);
    1242     return S_OK;
    1243 #endif /* VBOX_WITH_GUEST_CONTROL */
    1244 }
    1245 
    1246 STDMETHODIMP GuestSession::COMGETTER(Timeout)(ULONG *aTimeout)
    1247 {
    1248 #ifndef VBOX_WITH_GUEST_CONTROL
    1249     ReturnComNotImplemented();
    1250 #else
    1251     LogFlowThisFuncEnter();
    1252 
    1253     CheckComArgOutPointerValid(aTimeout);
    1254 
    1255     AutoCaller autoCaller(this);
    1256     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1257 
    1258     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1259 
    1260     *aTimeout = mData.mTimeout;
    1261 
    1262     LogFlowFuncLeaveRC(S_OK);
    1263     return S_OK;
    1264 #endif /* VBOX_WITH_GUEST_CONTROL */
    1265 }
    1266 
    1267 STDMETHODIMP GuestSession::COMSETTER(Timeout)(ULONG aTimeout)
    1268 {
    1269 #ifndef VBOX_WITH_GUEST_CONTROL
    1270     ReturnComNotImplemented();
    1271 #else
    1272     LogFlowThisFuncEnter();
    1273 
    1274     AutoCaller autoCaller(this);
    1275     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1276 
    1277     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1278 
    1279     mData.mTimeout = aTimeout;
    1280 
    1281     LogFlowFuncLeaveRC(S_OK);
    1282     return S_OK;
    1283 #endif /* VBOX_WITH_GUEST_CONTROL */
    1284 }
    1285 
    1286 STDMETHODIMP GuestSession::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnvironment))
    1287 {
    1288 #ifndef VBOX_WITH_GUEST_CONTROL
    1289     ReturnComNotImplemented();
    1290 #else
    1291     LogFlowThisFuncEnter();
    1292 
    1293     CheckComArgOutSafeArrayPointerValid(aEnvironment);
    1294 
    1295     AutoCaller autoCaller(this);
    1296     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1297 
    1298     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1299 
    1300     size_t cEnvVars = mData.mEnvironment.Size();
    1301     LogFlowThisFunc(("%s cEnvVars=%RU32\n", mData.mName.c_str(), cEnvVars));
    1302     com::SafeArray<BSTR> environment(cEnvVars);
    1303 
    1304     for (size_t i = 0; i < cEnvVars; i++)
    1305     {
    1306         Bstr strEnv(mData.mEnvironment.Get(i));
    1307         strEnv.cloneTo(&environment[i]);
    1308     }
    1309     environment.detachTo(ComSafeArrayOutArg(aEnvironment));
    1310 
    1311     LogFlowFuncLeaveRC(S_OK);
    1312     return S_OK;
    1313 #endif /* VBOX_WITH_GUEST_CONTROL */
    1314 }
    1315 
    1316 STDMETHODIMP GuestSession::COMSETTER(Environment)(ComSafeArrayIn(IN_BSTR, aValues))
    1317 {
    1318 #ifndef VBOX_WITH_GUEST_CONTROL
    1319     ReturnComNotImplemented();
    1320 #else
    1321     LogFlowThisFuncEnter();
    1322 
    1323     AutoCaller autoCaller(this);
    1324     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1325 
    1326     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1327 
    1328     com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aValues));
    1329 
    1330     int rc = VINF_SUCCESS;
    1331     for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)
    1332     {
    1333         Utf8Str strEnv(environment[i]);
    1334         if (!strEnv.isEmpty()) /* Silently skip empty entries. */
    1335             rc = mData.mEnvironment.Set(strEnv);
    1336     }
    1337 
    1338     HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
    1339     LogFlowFuncLeaveRC(hr);
    1340     return hr;
    1341 #endif /* VBOX_WITH_GUEST_CONTROL */
    1342 }
    1343 
    1344 STDMETHODIMP GuestSession::COMGETTER(Processes)(ComSafeArrayOut(IGuestProcess *, aProcesses))
    1345 {
    1346 #ifndef VBOX_WITH_GUEST_CONTROL
    1347     ReturnComNotImplemented();
    1348 #else
    1349     LogFlowThisFuncEnter();
    1350 
    1351     CheckComArgOutSafeArrayPointerValid(aProcesses);
    1352 
    1353     AutoCaller autoCaller(this);
    1354     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1355 
    1356     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1357 
    1358     SafeIfaceArray<IGuestProcess> collection(mData.mProcesses);
    1359     collection.detachTo(ComSafeArrayOutArg(aProcesses));
    1360 
    1361     LogFlowFuncLeaveRC(S_OK);
    1362     return S_OK;
    1363 #endif /* VBOX_WITH_GUEST_CONTROL */
    1364 }
    1365 
    1366 STDMETHODIMP GuestSession::COMGETTER(Directories)(ComSafeArrayOut(IGuestDirectory *, aDirectories))
    1367 {
    1368 #ifndef VBOX_WITH_GUEST_CONTROL
    1369     ReturnComNotImplemented();
    1370 #else
    1371     LogFlowThisFuncEnter();
    1372 
    1373     CheckComArgOutSafeArrayPointerValid(aDirectories);
    1374 
    1375     AutoCaller autoCaller(this);
    1376     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1377 
    1378     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1379 
    1380     SafeIfaceArray<IGuestDirectory> collection(mData.mDirectories);
    1381     collection.detachTo(ComSafeArrayOutArg(aDirectories));
    1382 
    1383     LogFlowFuncLeaveRC(S_OK);
    1384     return S_OK;
    1385 #endif /* VBOX_WITH_GUEST_CONTROL */
    1386 }
    1387 
    1388 STDMETHODIMP GuestSession::COMGETTER(Files)(ComSafeArrayOut(IGuestFile *, aFiles))
    1389 {
    1390 #ifndef VBOX_WITH_GUEST_CONTROL
    1391     ReturnComNotImplemented();
    1392 #else
    1393     LogFlowThisFuncEnter();
    1394 
    1395     CheckComArgOutSafeArrayPointerValid(aFiles);
    1396 
    1397     AutoCaller autoCaller(this);
    1398     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1399 
    1400     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1401 
    1402     SafeIfaceArray<IGuestFile> collection(mData.mFiles);
    1403     collection.detachTo(ComSafeArrayOutArg(aFiles));
    1404 
    1405     LogFlowFuncLeaveRC(S_OK);
    1406     return S_OK;
    1407 #endif /* VBOX_WITH_GUEST_CONTROL */
    1408 }
    1409 
    1410 // private methods
    1411 /////////////////////////////////////////////////////////////////////////////
    1412 
    1413 int GuestSession::directoryClose(ComObjPtr<GuestDirectory> pDirectory)
    1414 {
    1415     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1416 
    1417     for (SessionDirectories::iterator itDirs = mData.mDirectories.begin();
    1418          itDirs != mData.mDirectories.end(); ++itDirs)
    1419     {
    1420         if (pDirectory == (*itDirs))
    1421         {
    1422             mData.mDirectories.erase(itDirs);
    1423             return VINF_SUCCESS;
    1424         }
    1425     }
    1426 
    1427     return VERR_NOT_FOUND;
    1428 }
    1429 
    1430 int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags)
    1431 {
    1432     LogFlowThisFunc(("strPath=%s, uMode=%x, uFlags=%x\n",
    1433                      strPath.c_str(), uMode, uFlags));
    1434 
    1435     GuestProcessStartupInfo procInfo;
    1436     procInfo.mName      = Utf8StrFmt(tr("Creating directory \"%s\"", strPath.c_str()));
    1437     procInfo.mCommand   = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
    1438     procInfo.mFlags     = ProcessCreateFlag_Hidden;
    1439 
    1440     int rc = VINF_SUCCESS;
    1441 
    1442     /* Construct arguments. */
    1443     if (uFlags & DirectoryCreateFlag_Parents)
    1444         procInfo.mArguments.push_back(Utf8Str("--parents")); /* We also want to create the parent directories. */
    1445     if (uMode)
    1446     {
    1447         procInfo.mArguments.push_back(Utf8Str("--mode")); /* Set the creation mode. */
    1448 
    1449         char szMode[16];
    1450         if (RTStrPrintf(szMode, sizeof(szMode), "%o", uMode))
    1451         {
    1452             procInfo.mArguments.push_back(Utf8Str(szMode));
    1453         }
    1454         else
    1455             rc = VERR_INVALID_PARAMETER;
    1456     }
    1457     procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
    1458 
    1459     ComObjPtr<GuestProcess> pProcess;
    1460     rc = processCreateExInteral(procInfo, pProcess);
    1461     if (RT_SUCCESS(rc))
    1462         rc = pProcess->startProcess();
    1463     if (RT_SUCCESS(rc))
    1464     {
    1465         GuestProcessWaitResult waitRes;
    1466         rc = pProcess->waitFor(ProcessWaitForFlag_Terminate, 30 * 1000 /* Timeout */, waitRes);
    1467         if (RT_SUCCESS(rc))
    1468         {
    1469             ProcessStatus_T procStatus;
    1470             HRESULT hr = pProcess->COMGETTER(Status)(&procStatus);
    1471             ComAssertComRC(hr);
    1472             if (procStatus == ProcessStatus_TerminatedNormally)
    1473             {
    1474                 LONG lExitCode;
    1475                 pProcess->COMGETTER(ExitCode)(&lExitCode);
    1476                 if (lExitCode != 0)
    1477                     return VERR_CANT_CREATE;
    1478             }
    1479             else
    1480                 rc = VERR_BROKEN_PIPE; /** @todo Find a better rc. */
    1481         }
    1482     }
    1483 
    1484     LogFlowFuncLeaveRC(rc);
    1485     return rc;
    1486 }
    1487 
    1488 int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
    1489 {
    1490     LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
    1491 
    1492     int rc = fsQueryInfoInternal(strPath, objData);
    1493     if (RT_SUCCESS(rc))
    1494     {
    1495         rc = objData.mType == FsObjType_Directory
    1496            ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
    1497     }
    1498 
    1499     LogFlowFuncLeaveRC(rc);
    1500     return rc;
    1501 }
    1502 
    1503 int GuestSession::objectCreateTempInternal(Utf8Str strTemplate,
    1504                                            Utf8Str strPath,
    1505                                            bool fDirectory,
    1506                                            Utf8Str &strName, int *prc)
    1507 {
    1508     GuestProcessStartupInfo procInfo;
    1509     GuestProcessStream      streamOut;
    1510     ComObjPtr<GuestProcess> pProcess;
    1511     int rc = VINF_SUCCESS;
    1512 
    1513     if (fDirectory)
    1514         procInfo.mName    = Utf8StrFmt(tr("Creating temporary directory from template \"%s\"",
    1515                                    strTemplate.c_str()));
    1516     else
    1517         procInfo.mName    = Utf8StrFmt(tr("Creating temporary file from template \"%s\"",
    1518                                    strTemplate.c_str()));
    1519     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
    1520     procInfo.mFlags   =   ProcessCreateFlag_Hidden
    1521                         | ProcessCreateFlag_WaitForStdOut;
    1522     /* Construct arguments. */
    1523     procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
    1524     if (fDirectory)
    1525         procInfo.mArguments.push_back(Utf8Str("-d"));
    1526     if (strPath.length())  /* Otherwise use /tmp or equivalent. */
    1527     {
    1528         procInfo.mArguments.push_back(Utf8Str("-t"));
    1529         procInfo.mArguments.push_back(strPath);
    1530     }
    1531     procInfo.mArguments.push_back(strTemplate);
    1532 
    1533     rc = processCreateExInteral(procInfo, pProcess);
    1534     if (RT_SUCCESS(rc))
    1535     {
    1536         GuestProcessWaitResult waitRes;
    1537         BYTE byBuf[_64K];
    1538         size_t cbRead;
    1539 
    1540         for (;;)
    1541         {
    1542             rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
    1543                                    30 * 1000 /* Timeout */, waitRes);
    1544             if (   RT_FAILURE(rc)
    1545                 || waitRes.mResult == ProcessWaitResult_Terminate
    1546                 || waitRes.mResult == ProcessWaitResult_Error
    1547                 || waitRes.mResult == ProcessWaitResult_Timeout)
    1548             {
    1549                 break;
    1550             }
    1551 
    1552             rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
    1553                                     30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
    1554                                     &cbRead);
    1555             if (RT_FAILURE(rc))
    1556                 break;
    1557 
    1558             if (cbRead)
    1559             {
    1560                 rc = streamOut.AddData(byBuf, cbRead);
    1561                 if (RT_FAILURE(rc))
    1562                     break;
    1563             }
    1564         }
    1565 
    1566         LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",
    1567                          rc, cbRead, streamOut.GetSize()));
    1568     }
    1569     else
    1570         LogThisFunc(("Error while starting temporary object creation tool on guest: %Rrc\n", rc));
    1571     if (RT_FAILURE(rc))
    1572         LogThisFunc(("Error while running temporary object creation tool: %Rrc\n", rc));
    1573     else if (!streamOut.GetSize())
    1574     {
    1575         LogThisFunc(("No return code after creating temporary object\n"));
    1576         rc = VERR_NO_DATA;
    1577     }
    1578     if (RT_SUCCESS(rc))
    1579     {
    1580         const char *pcszName;
    1581         int64_t i64rc;
    1582         GuestProcessStreamBlock streamBlock;
    1583         rc = streamOut.ParseBlock(streamBlock);
    1584         if (RT_SUCCESS(rc))
    1585         {
    1586             pcszName = streamBlock.GetString("name");
    1587             if (pcszName)
    1588                 strName = pcszName;
    1589             else
    1590             {
    1591                 LogThisFunc(("No name returned after creating temporary object\n"));
    1592                 rc = VERR_NO_DATA;
    1593             }
    1594             if (RT_FAILURE(rc = streamBlock.GetInt64Ex("rc", &i64rc)))
    1595                 LogThisFunc(("No return code after creating temporary object\n"));
    1596         }
    1597         if (   RT_SUCCESS(rc)
    1598             && (   i64rc == VERR_INVALID_PARAMETER
    1599                 || i64rc == VERR_NOT_SUPPORTED))
    1600             rc = (int)i64rc;
    1601         if (RT_SUCCESS(rc))
    1602             *prc = (int)i64rc;
    1603     }
    1604     else
    1605         LogThisFunc(("Error while getting return code from creating temporary object: %Rrc\n", rc));
    1606     return rc;
    1607 }
    1608 
    1609 int GuestSession::directoryOpenInternal(const Utf8Str &strPath, const Utf8Str &strFilter,
    1610                                         uint32_t uFlags, ComObjPtr<GuestDirectory> &pDirectory)
    1611 {
    1612     LogFlowThisFunc(("strPath=%s, strPath=%s, uFlags=%x\n",
    1613                      strPath.c_str(), strFilter.c_str(), uFlags));
    1614 
    1615     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1616 
    1617     /* Create the directory object. */
    1618     HRESULT hr = pDirectory.createObject();
    1619     if (FAILED(hr))
    1620         return VERR_COM_UNEXPECTED;
    1621 
    1622     int rc = pDirectory->init(this /* Parent */,
    1623                               strPath, strFilter, uFlags);
    1624     if (RT_FAILURE(rc))
    1625         return rc;
    1626 
    1627     /* Add the created directory to our vector. */
    1628     mData.mDirectories.push_back(pDirectory);
    1629 
    1630     LogFlowFunc(("Added new directory \"%s\" (Session: %RU32)\n",
    1631                  strPath.c_str(), mData.mId));
    1632 
    1633     LogFlowFuncLeaveRC(rc);
    1634     return rc;
    1635 }
    1636 
    1637 int GuestSession::dispatchToProcess(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData)
    1638 {
    1639     LogFlowFuncEnter();
    1640 
    1641     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1642 
    1643     uint32_t uProcessID = VBOX_GUESTCTRL_CONTEXTID_GET_PROCESS(uContextID);
    1644 #ifdef DEBUG
    1645     LogFlowFunc(("uProcessID=%RU32 (%RU32 total)\n",
    1646                  uProcessID, mData.mProcesses.size()));
    1647 #endif
    1648     int rc;
    1649     SessionProcesses::const_iterator itProc
    1650         = mData.mProcesses.find(uProcessID);
    1651     if (itProc != mData.mProcesses.end())
    1652     {
    1653         ComObjPtr<GuestProcess> pProcess(itProc->second);
    1654         Assert(!pProcess.isNull());
    1655 
    1656         alock.release();
    1657         rc = pProcess->callbackDispatcher(uContextID, uFunction, pvData, cbData);
    1658     }
    1659     else
    1660         rc = VERR_NOT_FOUND;
    1661 
    1662     LogFlowFuncLeaveRC(rc);
    1663     return rc;
    1664 }
    1665 
    1666 int GuestSession::fileClose(ComObjPtr<GuestFile> pFile)
    1667 {
    1668     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1669 
    1670     for (SessionFiles::iterator itFiles = mData.mFiles.begin();
    1671          itFiles != mData.mFiles.end(); ++itFiles)
    1672     {
    1673         if (pFile == (*itFiles))
    1674         {
    1675             mData.mFiles.erase(itFiles);
    1676             return VINF_SUCCESS;
    1677         }
    1678     }
    1679 
    1680     return VERR_NOT_FOUND;
    1681 }
    1682 
    1683 /**
    1684  * Implementation of FileRemove().  Can throw an exception due to the use of
    1685  * Utf8Str, Utf8StrFmt and std::vector near the beginning (and others?).  The
    1686  * caller should catch this.  On success, *prc will be set to the return code
    1687  * of the delete operation to distinguish between API and command failure.
    1688  */
    1689 int GuestSession::fileRemoveInternal(Utf8Str strPath, int *prc)
    1690 {
    1691     GuestProcessStartupInfo procInfo;
    1692     GuestProcessStream      streamOut;
    1693     int rc = VINF_SUCCESS;
    1694 
    1695     AssertPtrReturn(prc, VERR_INVALID_POINTER);
    1696     procInfo.mName    = Utf8StrFmt(tr("Removing file \"%s\"",
    1697                                    strPath.c_str()));
    1698     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM);
    1699     procInfo.mFlags   =   ProcessCreateFlag_Hidden
    1700                         | ProcessCreateFlag_WaitForStdOut;
    1701     /* Construct arguments. */
    1702     procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
    1703     procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
    1704 
    1705     ComObjPtr<GuestProcess> pProcess;
    1706     rc = processCreateExInteral(procInfo, pProcess);
    1707     if (RT_SUCCESS(rc))
    1708         rc = pProcess->startProcess();
    1709     if (RT_SUCCESS(rc))
    1710     {
    1711         GuestProcessWaitResult waitRes;
    1712         BYTE byBuf[_64K];
    1713         size_t cbRead;
    1714 
    1715         for (;;)
    1716         {
    1717             rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
    1718                                    30 * 1000 /* Timeout */, waitRes);
    1719             if (   RT_FAILURE(rc)
    1720                 || waitRes.mResult == ProcessWaitResult_Terminate
    1721                 || waitRes.mResult == ProcessWaitResult_Error
    1722                 || waitRes.mResult == ProcessWaitResult_Timeout)
    1723             {
    1724                 break;
    1725             }
    1726 
    1727             rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
    1728                                     30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
    1729                                     &cbRead);
    1730             if (RT_FAILURE(rc))
    1731                 break;
    1732 
    1733             if (cbRead)
    1734             {
    1735                 rc = streamOut.AddData(byBuf, cbRead);
    1736                 if (RT_FAILURE(rc))
    1737                     break;
    1738             }
    1739         }
    1740 
    1741         LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",
    1742                          rc, cbRead, streamOut.GetSize()));
    1743     }
    1744     else
    1745         LogThisFunc(("Error starting delete tool on guest: %Rrc\n", rc));
    1746     if (RT_FAILURE(rc))
    1747         LogThisFunc(("Error running delete tool on guest: %Rrc\n", rc));
    1748     else if (!streamOut.GetSize())
    1749     {
    1750         LogThisFunc(("No return code after deleting file"));
    1751         rc = VERR_NO_DATA;
    1752     }
    1753     if (RT_SUCCESS(rc))
    1754     {
    1755         GuestProcessStreamBlock streamBlock;
    1756         int64_t i64rc;
    1757         rc = streamOut.ParseBlock(streamBlock);
    1758         streamBlock.GetString("fname");
    1759         rc = streamBlock.GetInt64Ex("rc", &i64rc);
    1760         if (RT_SUCCESS(rc))
    1761             *prc = (int)i64rc;
    1762     }
    1763     else
    1764         Log(("Error getting return code from deleting file: %Rrc\n", rc));
    1765     return rc;
    1766 }
    1767 
    1768 int GuestSession::fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition,
    1769                                    uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile)
    1770 {
    1771     LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, iOffset=%RI64\n",
    1772                      strPath.c_str(), strOpenMode.c_str(), strDisposition.c_str(), uCreationMode, iOffset));
    1773 
    1774     /* Create the directory object. */
    1775     HRESULT hr = pFile.createObject();
    1776     if (FAILED(hr))
    1777         return VERR_COM_UNEXPECTED;
    1778 
    1779     /* Note: There will be a race between creating and getting/initing the directory
    1780              object here. */
    1781     int rc = pFile->init(this /* Parent */,
    1782                          strPath, strOpenMode, strDisposition, uCreationMode, iOffset);
    1783     if (RT_FAILURE(rc))
    1784         return rc;
    1785 
    1786     /* Add the created directory to our vector. */
    1787     mData.mFiles.push_back(pFile);
    1788 
    1789     LogFlowFunc(("Added new file \"%s\" (Session: %RU32\n",
    1790                  strPath.c_str(), mData.mId));
    1791 
    1792     LogFlowFuncLeaveRC(rc);
    1793     return rc;
    1794 }
    1795 
    1796 int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
    1797 {
    1798     LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
    1799 
    1800     int rc = fsQueryInfoInternal(strPath, objData);
    1801     if (RT_SUCCESS(rc))
    1802     {
    1803         rc = objData.mType == FsObjType_File
    1804            ? VINF_SUCCESS : VERR_NOT_A_FILE;
    1805     }
    1806 
    1807     LogFlowFuncLeaveRC(rc);
    1808     return rc;
    1809 }
    1810 
    1811 int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize)
    1812 {
    1813     AssertPtrReturn(pllSize, VERR_INVALID_POINTER);
    1814 
    1815     GuestFsObjData objData;
    1816     int rc = fileQueryInfoInternal(strPath, objData);
    1817     if (RT_SUCCESS(rc))
    1818     {
    1819         if (objData.mType == FsObjType_File)
    1820             *pllSize = objData.mObjectSize;
    1821         else
    1822             rc = VERR_NOT_A_FILE;
    1823     }
    1824 
    1825     return rc;
    1826 }
    1827 
    1828 int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
    1829 {
    1830     LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
    1831 
    1832     GuestProcessStartupInfo procInfo;
    1833     procInfo.mName    = Utf8StrFmt(tr("Querying info for \"%s\""), strPath.c_str());
    1834     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT);
    1835     procInfo.mFlags   = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
    1836 
    1837     /* Construct arguments. */
    1838     procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
    1839     procInfo.mArguments.push_back(strPath);
    1840 
    1841     GuestProcessStream streamOut;
    1842 
    1843     ComObjPtr<GuestProcess> pProcess;
    1844     int rc = processCreateExInteral(procInfo, pProcess);
    1845     if (RT_SUCCESS(rc))
    1846         rc = pProcess->startProcess();
    1847     if (RT_SUCCESS(rc))
    1848     {
    1849         GuestProcessWaitResult waitRes;
    1850         BYTE byBuf[_64K];
    1851         size_t cbRead = 0;
    1852 
    1853         /** @todo Merge with GuestDirectory::read. */
    1854         for (;;)
    1855         {
    1856             rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
    1857                                    30 * 1000 /* Timeout */, waitRes);
    1858             if (   RT_FAILURE(rc)
    1859                 || waitRes.mResult == ProcessWaitResult_Terminate
    1860                 || waitRes.mResult == ProcessWaitResult_Error
    1861                 || waitRes.mResult == ProcessWaitResult_Timeout)
    1862             {
    1863                 break;
    1864             }
    1865 
    1866             rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
    1867                                     30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
    1868                                     &cbRead);
    1869             if (RT_FAILURE(rc))
    1870                 break;
    1871 
    1872             if (cbRead)
    1873             {
    1874                 rc = streamOut.AddData(byBuf, cbRead);
    1875                 if (RT_FAILURE(rc))
    1876                     break;
    1877             }
    1878         }
    1879 
    1880         LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n",
    1881                          rc, cbRead, streamOut.GetSize()));
    1882     }
    1883 
    1884     if (RT_SUCCESS(rc))
    1885     {
    1886         GuestProcessStreamBlock streamBlock;
    1887         rc = streamOut.ParseBlock(streamBlock);
    1888         if (RT_SUCCESS(rc))
    1889         {
    1890             rc = objData.FromStat(streamBlock);
    1891         }
    1892         else
    1893             AssertMsgFailed(("Parsing stream block failed: %Rrc\n", rc));
    1894     }
    1895 
    1896     LogFlowFuncLeaveRC(rc);
    1897     return rc;
    1898 }
    1899 
    1900 const GuestCredentials& GuestSession::getCredentials(void)
    1901 {
    1902     return mData.mCredentials;
    1903 }
    1904 
    1905 const GuestEnvironment& GuestSession::getEnvironment(void)
    1906 {
    1907     return mData.mEnvironment;
    1908 }
    1909 
    1910 Utf8Str GuestSession::getName(void)
    1911 {
    1912     return mData.mName;
    1913 }
    1914 
    1915 int GuestSession::processClose(ComObjPtr<GuestProcess> pProcess)
    1916 {
    1917     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1918 
    1919     for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
    1920          itProcs != mData.mProcesses.end(); ++itProcs)
    1921     {
    1922         if (pProcess == itProcs->second)
    1923         {
    1924             LogFlowFunc(("Removing process (Session: %RU32) with process ID=%RU32, guest PID=%RU32 (now total %ld processes)\n",
    1925                          mData.mId, itProcs->second->getProcessID(), itProcs->second->getPID(), mData.mProcesses.size() - 1));
    1926 
    1927             mData.mProcesses.erase(itProcs);
    1928             return VINF_SUCCESS;
    1929         }
    1930     }
    1931 
    1932     return VERR_NOT_FOUND;
    1933 }
    1934 
    1935 /**
    1936  * Creates but does *not* start the process yet. See GuestProcess::startProcess() or
    1937  * GuestProcess::startProcessAsync() for that.
    1938  *
    1939  * @return  IPRT status code.
    1940  * @param   procInfo
    1941  * @param   pProcess
    1942  */
    1943 int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
    1944 {
    1945     LogFlowFunc(("mCmd=%s, mFlags=%x, mTimeoutMS=%RU32\n",
    1946                  procInfo.mCommand.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
    1947 #ifdef DEBUG
    1948     if (procInfo.mArguments.size())
    1949     {
    1950         LogFlowFunc(("Arguments:"));
    1951         ProcessArguments::const_iterator it = procInfo.mArguments.begin();
    1952         while (it != procInfo.mArguments.end())
    1953         {
    1954             LogFlow((" %s", (*it).c_str()));
    1955             it++;
    1956         }
    1957         LogFlow(("\n"));
    1958     }
    1959 #endif
    1960 
    1961     /* Validate flags. */
    1962     if (procInfo.mFlags)
    1963     {
    1964         if (   !(procInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
    1965             && !(procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
    1966             && !(procInfo.mFlags & ProcessCreateFlag_Hidden)
    1967             && !(procInfo.mFlags & ProcessCreateFlag_NoProfile)
    1968             && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
    1969             && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdErr))
    1970         {
    1971             return VERR_INVALID_PARAMETER;
    1972         }
    1973     }
    1974 
    1975     /* Adjust timeout. If set to 0, we define
    1976      * an infinite timeout. */
    1977     if (procInfo.mTimeoutMS == 0)
    1978         procInfo.mTimeoutMS = UINT32_MAX;
    1979 
    1980     /** @tood Implement process priority + affinity. */
    1981 
    1982     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1983 
    1984     int rc = VERR_MAX_PROCS_REACHED;
    1985     if (mData.mProcesses.size() >= VBOX_GUESTCTRL_MAX_PROCESSES)
    1986         return rc;
    1987 
    1988     /* Create a new (host-based) process ID and assign it. */
    1989     uint32_t uNewProcessID = 0;
    1990     ULONG uTries = 0;
    1991 
    1992     for (;;)
    1993     {
    1994         /* Is the context ID already used? */
    1995         if (!processExists(uNewProcessID, NULL /* pProgress */))
    1996         {
    1997             /* Callback with context ID was not found. This means
    1998              * we can use this context ID for our new callback we want
    1999              * to add below. */
    2000             rc = VINF_SUCCESS;
    2001             break;
    2002         }
    2003         uNewProcessID++;
    2004         if (uNewProcessID == VBOX_GUESTCTRL_MAX_PROCESSES)
    2005             uNewProcessID = 0;
    2006 
    2007         if (++uTries == UINT32_MAX)
    2008             break; /* Don't try too hard. */
    2009     }
    2010 
    2011     if (RT_FAILURE(rc))
    2012         return rc;
    2013 
    2014     /* Create the process object. */
    2015     HRESULT hr = pProcess.createObject();
    2016     if (FAILED(hr))
    2017         return VERR_COM_UNEXPECTED;
    2018 
    2019     rc = pProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,
    2020                         uNewProcessID, procInfo);
    2021     if (RT_FAILURE(rc))
    2022         return rc;
    2023 
    2024     /* Add the created process to our map. */
    2025     mData.mProcesses[uNewProcessID] = pProcess;
    2026 
    2027     LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes)\n",
    2028                  mData.mId, uNewProcessID, mData.mProcesses.size()));
    2029 
    2030     return rc;
    2031 }
    2032 
    2033 inline bool GuestSession::processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess)
    2034 {
    2035     SessionProcesses::const_iterator it = mData.mProcesses.find(uProcessID);
    2036     if (it != mData.mProcesses.end())
    2037     {
    2038         if (pProcess)
    2039             *pProcess = it->second;
    2040         return true;
    2041     }
    2042     return false;
    2043 }
    2044 
    2045 inline int GuestSession::processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess)
    2046 {
    2047     AssertReturn(uPID, false);
    2048     /* pProcess is optional. */
    2049 
    2050     SessionProcesses::iterator it = mData.mProcesses.begin();
    2051     for (; it != mData.mProcesses.end(); it++)
    2052     {
    2053         ComObjPtr<GuestProcess> pCurProc = it->second;
    2054         AutoCaller procCaller(pCurProc);
    2055         if (procCaller.rc())
    2056             return VERR_COM_INVALID_OBJECT_STATE;
    2057 
    2058         if (it->second->getPID() == uPID)
    2059         {
    2060             if (pProcess)
    2061                 *pProcess = pCurProc;
    2062             return VINF_SUCCESS;
    2063         }
    2064     }
    2065 
    2066     return VERR_NOT_FOUND;
    2067 }
    2068 
    2069 int GuestSession::startTaskAsync(const Utf8Str &strTaskDesc,
    2070                                  GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress)
    2071 {
    2072     LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask));
    2073 
    2074     AssertPtrReturn(pTask, VERR_INVALID_POINTER);
    2075 
    2076     /* Create the progress object. */
    2077     HRESULT hr = pProgress.createObject();
    2078     if (FAILED(hr))
    2079         return VERR_COM_UNEXPECTED;
    2080 
    2081     hr = pProgress->init(static_cast<IGuestSession*>(this),
    2082                          Bstr(strTaskDesc).raw(),
    2083                          TRUE /* aCancelable */);
    2084     if (FAILED(hr))
    2085         return VERR_COM_UNEXPECTED;
    2086 
    2087     /* Initialize our worker task. */
    2088     std::auto_ptr<GuestSessionTask> task(pTask);
    2089 
    2090     int rc = task->RunAsync(strTaskDesc, pProgress);
    2091     if (RT_FAILURE(rc))
    2092         return rc;
    2093 
    2094     /* Don't destruct on success. */
    2095     task.release();
    2096 
    2097     LogFlowFuncLeaveRC(rc);
    2098     return rc;
    2099 }
    2100 
    2101 /**
    2102  * Queries/collects information prior to establishing a guest session.
    2103  * This is necessary to know which guest control protocol version to use,
    2104  * among other things (later).
    2105  *
    2106  * @return  IPRT status code.
    2107  */
    2108 int GuestSession::queryInfo(void)
    2109 {
    2110 #if 1
    2111     /* Since the new functions were not implemented yet, force Main to use protocol ver 1. */
    2112     mData.mProtocolVersion = 1;
    2113 #else
    2114     /*
    2115      * Try querying the guest control protocol version running on the guest.
    2116      * This is done using the Guest Additions version
    2117      */
    2118     ComObjPtr<Guest> pGuest = mData.mParent;
    2119     Assert(!pGuest.isNull());
    2120 
    2121     uint32_t uVerAdditions = pGuest->getAdditionsVersion();
    2122     mData.mProtocolVersion = (   VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions) >= 4
    2123                               && VBOX_FULL_VERSION_GET_MINOR(uVerAdditions) >= 2) /** @todo What's about v5.0 ? */
    2124                            ? 2  /* Guest control 2.0. */
    2125                            : 1; /* Legacy guest control (VBox < 4.2). */
    2126     /* Build revision is ignored. */
    2127 
    2128     /* Tell the user but don't bitch too often. */
    2129     static short s_gctrlLegacyWarning = 0;
    2130     if (s_gctrlLegacyWarning++ < 3) /** @todo Find a bit nicer text. */
    2131         LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"),
    2132                 VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions), mData.mProtocolVersion));
    2133 #endif
    2134     return VINF_SUCCESS;
    2135 }
    2136 
    2137 // implementation of public methods
    2138 /////////////////////////////////////////////////////////////////////////////
    2139 
    2140 STDMETHODIMP GuestSession::Close(void)
    2141 {
    2142 #ifndef VBOX_WITH_GUEST_CONTROL
    2143     ReturnComNotImplemented();
    2144 #else
    2145     LogFlowThisFuncEnter();
    2146 
    2147     uninit();
    2148 
    2149     LogFlowFuncLeaveRC(S_OK);
    2150     return S_OK;
    2151 #endif /* VBOX_WITH_GUEST_CONTROL */
    2152 }
    2153 
    2154 STDMETHODIMP GuestSession::CopyFrom(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
    2155 {
    2156 #ifndef VBOX_WITH_GUEST_CONTROL
    2157     ReturnComNotImplemented();
    2158 #else
    2159     CheckComArgStrNotEmptyOrNull(aSource);
    2160     CheckComArgStrNotEmptyOrNull(aDest);
    2161     CheckComArgOutPointerValid(aProgress);
    2162 
    2163     LogFlowThisFuncEnter();
    2164 
    2165     if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
    2166         return setError(E_INVALIDARG, tr("No source specified"));
    2167     if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
    2168         return setError(E_INVALIDARG, tr("No destination specified"));
    2169 
    2170     AutoCaller autoCaller(this);
    2171     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2172 
    2173     uint32_t fFlags = CopyFileFlag_None;
    2174     if (aFlags)
    2175     {
    2176         com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
    2177         for (size_t i = 0; i < flags.size(); i++)
    2178             fFlags |= flags[i];
    2179     }
    2180 
    2181     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2182 
    2183     HRESULT hr = S_OK;
    2184 
    2185     ComObjPtr<Progress> pProgress;
    2186     SessionTaskCopyFrom *pTask = new SessionTaskCopyFrom(this /* GuestSession */,
    2187                                                          Utf8Str(aSource), Utf8Str(aDest), fFlags);
    2188     AssertPtrReturn(pTask, VERR_NO_MEMORY);
    2189     int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from guest to \"%ls\" on the host"), aSource, aDest),
    2190                             pTask, pProgress);
    2191     if (RT_SUCCESS(rc))
    2192     {
    2193         /* Return progress to the caller. */
    2194         hr = pProgress.queryInterfaceTo(aProgress);
    2195     }
    2196     else
    2197         hr = setError(VBOX_E_IPRT_ERROR,
    2198                       tr("Starting task for copying file \"%ls\" from guest to \"%ls\" on the host failed: %Rrc"), rc);
    2199     return hr;
    2200 #endif /* VBOX_WITH_GUEST_CONTROL */
    2201 }
    2202 
    2203 STDMETHODIMP GuestSession::CopyTo(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
    2204 {
    2205 #ifndef VBOX_WITH_GUEST_CONTROL
    2206     ReturnComNotImplemented();
    2207 #else
    2208     CheckComArgStrNotEmptyOrNull(aSource);
    2209     CheckComArgStrNotEmptyOrNull(aDest);
    2210     CheckComArgOutPointerValid(aProgress);
    2211 
    2212     LogFlowThisFuncEnter();
    2213 
    2214     if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
    2215         return setError(E_INVALIDARG, tr("No source specified"));
    2216     if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
    2217         return setError(E_INVALIDARG, tr("No destination specified"));
    2218 
    2219     AutoCaller autoCaller(this);
    2220     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2221 
    2222     uint32_t fFlags = CopyFileFlag_None;
    2223     if (aFlags)
    2224     {
    2225         com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
    2226         for (size_t i = 0; i < flags.size(); i++)
    2227             fFlags |= flags[i];
    2228     }
    2229 
    2230     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2231 
    2232     HRESULT hr = S_OK;
    2233 
    2234     ComObjPtr<Progress> pProgress;
    2235     SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this /* GuestSession */,
    2236                                                      Utf8Str(aSource), Utf8Str(aDest), fFlags);
    2237     AssertPtrReturn(pTask, VERR_NO_MEMORY);
    2238     int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from host to \"%ls\" on the guest"), aSource, aDest),
    2239                             pTask, pProgress);
    2240     if (RT_SUCCESS(rc))
    2241     {
    2242         /* Return progress to the caller. */
    2243         hr = pProgress.queryInterfaceTo(aProgress);
    2244     }
    2245     else
    2246         hr = setError(VBOX_E_IPRT_ERROR,
    2247                       tr("Starting task for copying file \"%ls\" from host to \"%ls\" on the guest failed: %Rrc"), rc);
    2248    return hr;
    2249 #endif /* VBOX_WITH_GUEST_CONTROL */
    2250 }
    2251 
    2252 STDMETHODIMP GuestSession::DirectoryCreate(IN_BSTR aPath, ULONG aMode,
    2253                                            ComSafeArrayIn(DirectoryCreateFlag_T, aFlags))
    2254 {
    2255 #ifndef VBOX_WITH_GUEST_CONTROL
    2256     ReturnComNotImplemented();
    2257 #else
    2258     LogFlowThisFuncEnter();
    2259 
    2260     if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
    2261         return setError(E_INVALIDARG, tr("No directory to create specified"));
    2262 
    2263     AutoCaller autoCaller(this);
    2264     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2265 
    2266     uint32_t fFlags = DirectoryCreateFlag_None;
    2267     if (aFlags)
    2268     {
    2269         com::SafeArray<DirectoryCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
    2270         for (size_t i = 0; i < flags.size(); i++)
    2271             fFlags |= flags[i];
    2272 
    2273         if (fFlags)
    2274         {
    2275             if (!(fFlags & DirectoryCreateFlag_Parents))
    2276                 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), fFlags);
    2277         }
    2278     }
    2279 
    2280     HRESULT hr = S_OK;
    2281 
    2282     ComObjPtr <GuestDirectory> pDirectory;
    2283     int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags);
    2284     if (RT_FAILURE(rc))
    2285     {
    2286         switch (rc)
    2287         {
    2288             case VERR_INVALID_PARAMETER:
    2289                hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));
    2290                break;
    2291 
    2292             case VERR_BROKEN_PIPE:
    2293                hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Unexpectedly aborted"));
    2294                break;
    2295 
    2296             case VERR_CANT_CREATE:
    2297                hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory"));
    2298                break;
    2299 
    2300             default:
    2301                hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
    2302                break;
    2303         }
    2304     }
    2305 
    2306     return hr;
    2307 #endif /* VBOX_WITH_GUEST_CONTROL */
    2308 }
    2309 
    2310 STDMETHODIMP GuestSession::DirectoryCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, BSTR *aDirectory)
    2311 {
    2312 #ifndef VBOX_WITH_GUEST_CONTROL
    2313     ReturnComNotImplemented();
    2314 #else
    2315     LogFlowThisFuncEnter();
    2316 
    2317     if (RT_UNLIKELY((aTemplate) == NULL || *(aTemplate) == '\0'))
    2318         return setError(E_INVALIDARG, tr("No file to remove specified"));
    2319 
    2320     AutoCaller autoCaller(this);
    2321     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2322 
    2323     int rc = VINF_SUCCESS;
    2324 
    2325     try  /* Can this be done without exceptions? */
    2326     {
    2327         Utf8Str strName;
    2328         if (RT_FAILURE(objectCreateTempInternal(Utf8Str(aTemplate),
    2329                                                 Utf8Str(aPath),
    2330                                                 true, strName, &rc)))
    2331             return E_FAIL;
    2332         HRESULT hrc =   rc == VERR_INVALID_PARAMETER ? E_INVALIDARG
    2333                       : rc == VERR_NOT_SUPPORTED ? VBOX_E_NOT_SUPPORTED
    2334                       : RT_FAILURE(rc) ? VBOX_E_IPRT_ERROR
    2335                       : S_OK;
    2336         if (FAILED(hrc))
    2337             return setError(hrc, tr("Temporary directory creation failed: %Rrc"),
    2338                             rc);
    2339         strName.cloneTo(aDirectory);
    2340         return S_OK;
    2341     }
    2342     catch (...)
    2343     {
    2344         return E_OUTOFMEMORY;
    2345     }
    2346 #endif /* VBOX_WITH_GUEST_CONTROL */
    2347 }
    2348 
    2349 STDMETHODIMP GuestSession::DirectoryExists(IN_BSTR aPath, BOOL *aExists)
    2350 {
    2351 #ifndef VBOX_WITH_GUEST_CONTROL
    2352     ReturnComNotImplemented();
    2353 #else
    2354     LogFlowThisFuncEnter();
    2355 
    2356     if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
    2357         return setError(E_INVALIDARG, tr("No directory to check existence for specified"));
    2358     CheckComArgOutPointerValid(aExists);
    2359 
    2360     AutoCaller autoCaller(this);
    2361     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2362 
    2363     HRESULT hr = S_OK;
    2364 
    2365     GuestFsObjData objData;
    2366     int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
    2367     if (RT_SUCCESS(rc))
    2368     {
    2369         *aExists = objData.mType == FsObjType_Directory;
    2370     }
    2371     else
    2372     {
    2373         switch (rc)
    2374         {
    2375             /** @todo Add more errors here! */
    2376 
    2377             default:
    2378                hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence failed: %Rrc"), rc);
    2379                break;
    2380         }
    2381     }
    2382 
    2383     return hr;
    2384 #endif /* VBOX_WITH_GUEST_CONTROL */
    2385 }
    2386 
    2387 STDMETHODIMP GuestSession::DirectoryOpen(IN_BSTR aPath, IN_BSTR aFilter, ComSafeArrayIn(DirectoryOpenFlag_T, aFlags), IGuestDirectory **aDirectory)
    2388 {
    2389 #ifndef VBOX_WITH_GUEST_CONTROL
    2390     ReturnComNotImplemented();
    2391 #else
    2392     LogFlowThisFuncEnter();
    2393 
    2394     if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
    2395         return setError(E_INVALIDARG, tr("No directory to open specified"));
    2396     if (RT_UNLIKELY((aFilter) != NULL && *(aFilter) != '\0'))
    2397         return setError(E_INVALIDARG, tr("Directory filters not implemented yet"));
    2398 
    2399     CheckComArgOutPointerValid(aDirectory);
    2400 
    2401     AutoCaller autoCaller(this);
    2402     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2403 
    2404     uint32_t fFlags = DirectoryOpenFlag_None;
    2405     if (aFlags)
    2406     {
    2407         com::SafeArray<DirectoryOpenFlag_T> flags(ComSafeArrayInArg(aFlags));
    2408         for (size_t i = 0; i < flags.size(); i++)
    2409             fFlags |= flags[i];
    2410 
    2411         if (fFlags)
    2412             return setError(E_INVALIDARG, tr("Open flags (%#x) not implemented yet"), fFlags);
    2413     }
    2414 
    2415     HRESULT hr = S_OK;
    2416 
    2417     ComObjPtr <GuestDirectory> pDirectory;
    2418     int rc = directoryOpenInternal(Utf8Str(aPath), Utf8Str(aFilter), fFlags, pDirectory);
    2419     if (RT_SUCCESS(rc))
    2420     {
    2421         if (aDirectory)
    2422         {
    2423             /* Return directory object to the caller. */
    2424             hr = pDirectory.queryInterfaceTo(aDirectory);
    2425         }
    2426         else
    2427         {
    2428             rc = directoryClose(pDirectory);
    2429             if (RT_FAILURE(rc))
    2430                 hr = setError(VBOX_E_IPRT_ERROR, tr("Unable to close directory object, rc=%Rrc"), rc);
    2431         }
    2432     }
    2433     else
    2434     {
    2435         switch (rc)
    2436         {
    2437             case VERR_INVALID_PARAMETER:
    2438                hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Invalid parameters given"));
    2439                break;
    2440 
    2441             case VERR_BROKEN_PIPE:
    2442                hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Unexpectedly aborted"));
    2443                break;
    2444 
    2445             default:
    2446                hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: %Rrc"), rc);
    2447                break;
    2448         }
    2449     }
    2450 
    2451     return hr;
    2452 #endif /* VBOX_WITH_GUEST_CONTROL */
    2453 }
    2454 
    2455 STDMETHODIMP GuestSession::DirectoryQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
    2456 {
    2457 #ifndef VBOX_WITH_GUEST_CONTROL
    2458     ReturnComNotImplemented();
    2459 #else
    2460     LogFlowThisFuncEnter();
    2461 
    2462     if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
    2463         return setError(E_INVALIDARG, tr("No directory to query information for specified"));
    2464     CheckComArgOutPointerValid(aInfo);
    2465 
    2466     AutoCaller autoCaller(this);
    2467     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2468 
    2469     HRESULT hr = S_OK;
    2470 
    2471     GuestFsObjData objData;
    2472     int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData);
    2473     if (RT_SUCCESS(rc))
    2474     {
    2475         if (objData.mType == FsObjType_Directory)
    2476         {
    2477             ComObjPtr<GuestFsObjInfo> pFsObjInfo;
    2478             hr = pFsObjInfo.createObject();
    2479             if (FAILED(hr))
    2480                 return VERR_COM_UNEXPECTED;
    2481 
    2482             rc = pFsObjInfo->init(objData);
    2483             if (RT_SUCCESS(rc))
    2484                 hr = pFsObjInfo.queryInterfaceTo(aInfo);
    2485         }
    2486     }
    2487 
    2488     if (RT_FAILURE(rc))
    2489     {
    2490         switch (rc)
    2491         {
    2492             /** @todo Add more errors here! */
    2493 
    2494             case VERR_NOT_A_DIRECTORY:
    2495                 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a directory"));
    2496                 break;
    2497 
    2498             default:
    2499                 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information failed: %Rrc"), rc);
    2500                 break;
    2501         }
    2502     }
    2503 
    2504     return hr;
    2505 #endif /* VBOX_WITH_GUEST_CONTROL */
    2506 }
    2507 
    2508 STDMETHODIMP GuestSession::DirectoryRemove(IN_BSTR aPath)
    2509 {
    2510 #ifndef VBOX_WITH_GUEST_CONTROL
    2511     ReturnComNotImplemented();
    2512 #else
    2513     LogFlowThisFuncEnter();
    2514 
    2515     AutoCaller autoCaller(this);
    2516     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2517 
    2518     ReturnComNotImplemented();
    2519 #endif /* VBOX_WITH_GUEST_CONTROL */
    2520 }
    2521 
    2522 STDMETHODIMP GuestSession::DirectoryRemoveRecursive(IN_BSTR aPath, ComSafeArrayIn(DirectoryRemoveRecFlag_T, aFlags), IProgress **aProgress)
    2523 {
    2524 #ifndef VBOX_WITH_GUEST_CONTROL
    2525     ReturnComNotImplemented();
    2526 #else
    2527     LogFlowThisFuncEnter();
    2528 
    2529     AutoCaller autoCaller(this);
    2530     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2531 
    2532     ReturnComNotImplemented();
    2533 #endif /* VBOX_WITH_GUEST_CONTROL */
    2534 }
    2535 
    2536 STDMETHODIMP GuestSession::DirectoryRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
    2537 {
    2538 #ifndef VBOX_WITH_GUEST_CONTROL
    2539     ReturnComNotImplemented();
    2540 #else
    2541     LogFlowThisFuncEnter();
    2542 
    2543     AutoCaller autoCaller(this);
    2544     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2545 
    2546     ReturnComNotImplemented();
    2547 #endif /* VBOX_WITH_GUEST_CONTROL */
    2548 }
    2549 
    2550 STDMETHODIMP GuestSession::DirectorySetACL(IN_BSTR aPath, IN_BSTR aACL)
    2551 {
    2552 #ifndef VBOX_WITH_GUEST_CONTROL
    2553     ReturnComNotImplemented();
    2554 #else
    2555     LogFlowThisFuncEnter();
    2556 
    2557     AutoCaller autoCaller(this);
    2558     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2559 
    2560     ReturnComNotImplemented();
    2561 #endif /* VBOX_WITH_GUEST_CONTROL */
    2562 }
    2563 
    2564 STDMETHODIMP GuestSession::EnvironmentClear(void)
    2565 {
    2566 #ifndef VBOX_WITH_GUEST_CONTROL
    2567     ReturnComNotImplemented();
    2568 #else
    2569     LogFlowThisFuncEnter();
    2570 
    2571     AutoCaller autoCaller(this);
    2572     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2573 
    2574     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2575 
    2576     mData.mEnvironment.Clear();
    2577 
    2578     LogFlowFuncLeaveRC(S_OK);
    2579     return S_OK;
    2580 #endif /* VBOX_WITH_GUEST_CONTROL */
    2581 }
    2582 
    2583 STDMETHODIMP GuestSession::EnvironmentGet(IN_BSTR aName, BSTR *aValue)
    2584 {
    2585 #ifndef VBOX_WITH_GUEST_CONTROL
    2586     ReturnComNotImplemented();
    2587 #else
    2588     LogFlowThisFuncEnter();
    2589 
    2590     if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
    2591         return setError(E_INVALIDARG, tr("No value name specified"));
    2592 
    2593     CheckComArgOutPointerValid(aValue);
    2594 
    2595     AutoCaller autoCaller(this);
    2596     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2597 
    2598     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2599 
    2600     Bstr strValue(mData.mEnvironment.Get(Utf8Str(aName)));
    2601     strValue.cloneTo(aValue);
    2602 
    2603     LogFlowFuncLeaveRC(S_OK);
    2604     return S_OK;
    2605 #endif /* VBOX_WITH_GUEST_CONTROL */
    2606 }
    2607 
    2608 STDMETHODIMP GuestSession::EnvironmentSet(IN_BSTR aName, IN_BSTR aValue)
    2609 {
    2610 #ifndef VBOX_WITH_GUEST_CONTROL
    2611     ReturnComNotImplemented();
    2612 #else
    2613     LogFlowThisFuncEnter();
    2614 
    2615     if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
    2616         return setError(E_INVALIDARG, tr("No value name specified"));
    2617 
    2618     AutoCaller autoCaller(this);
    2619     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2620 
    2621     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2622 
    2623     int rc = mData.mEnvironment.Set(Utf8Str(aName), Utf8Str(aValue));
    2624 
    2625     HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
    2626     LogFlowFuncLeaveRC(hr);
    2627     return hr;
    2628 #endif /* VBOX_WITH_GUEST_CONTROL */
    2629 }
    2630 
    2631 STDMETHODIMP GuestSession::EnvironmentUnset(IN_BSTR aName)
    2632 {
    2633 #ifndef VBOX_WITH_GUEST_CONTROL
    2634     ReturnComNotImplemented();
    2635 #else
    2636     LogFlowThisFuncEnter();
    2637 
    2638     AutoCaller autoCaller(this);
    2639     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2640 
    2641     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2642 
    2643     mData.mEnvironment.Unset(Utf8Str(aName));
    2644 
    2645     LogFlowFuncLeaveRC(S_OK);
    2646     return S_OK;
    2647 #endif /* VBOX_WITH_GUEST_CONTROL */
    2648 }
    2649 
    2650 STDMETHODIMP GuestSession::FileCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, IGuestFile **aFile)
    2651 {
    2652 #ifndef VBOX_WITH_GUEST_CONTROL
    2653     ReturnComNotImplemented();
    2654 #else
    2655     LogFlowThisFuncEnter();
    2656 
    2657     AutoCaller autoCaller(this);
    2658     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2659 
    2660     ReturnComNotImplemented();
    2661 #endif /* VBOX_WITH_GUEST_CONTROL */
    2662 }
    2663 
    2664 STDMETHODIMP GuestSession::FileExists(IN_BSTR aPath, BOOL *aExists)
    2665 {
    2666 #ifndef VBOX_WITH_GUEST_CONTROL
    2667     ReturnComNotImplemented();
    2668 #else
    2669     LogFlowThisFuncEnter();
    2670 
    2671     if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
    2672         return setError(E_INVALIDARG, tr("No file to check existence for specified"));
    2673     CheckComArgOutPointerValid(aExists);
    2674 
    2675     AutoCaller autoCaller(this);
    2676     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2677 
    2678     HRESULT hr = S_OK;
    2679 
    2680     GuestFsObjData objData;
    2681     int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
    2682     if (RT_SUCCESS(rc))
    2683     {
    2684         *aExists = objData.mType == FsObjType_File;
    2685     }
    2686     else
    2687     {
    2688         switch (rc)
    2689         {
    2690             /** @todo Add more errors here! */
    2691 
    2692             default:
    2693                hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file existence failed: %Rrc"), rc);
    2694                break;
    2695         }
    2696     }
    2697 
    2698     return hr;
    2699 #endif /* VBOX_WITH_GUEST_CONTROL */
    2700 }
    2701 
    2702 STDMETHODIMP GuestSession::FileRemove(IN_BSTR aPath)
    2703 {
    2704 #ifndef VBOX_WITH_GUEST_CONTROL
    2705     ReturnComNotImplemented();
    2706 #else
    2707     LogFlowThisFuncEnter();
    2708 
    2709     if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
    2710         return setError(E_INVALIDARG, tr("No file to remove specified"));
    2711 
    2712     AutoCaller autoCaller(this);
    2713     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2714 
    2715     try  /* Can this be done without exceptions? */
    2716     {
    2717         int rc2;
    2718         int rc = fileRemoveInternal(Utf8Str(aPath), &rc2);
    2719         if (RT_FAILURE((rc)))
    2720             return setError(E_FAIL,
    2721                             tr("Internal error deleting file: %Rrc"), rc);
    2722         else if (RT_FAILURE((rc2)))
    2723             return setError(VBOX_E_IPRT_ERROR,
    2724                             tr("File deletion on guest returned: %Rrc"), rc2);
    2725     }
    2726     catch (...)
    2727     {
    2728         return E_OUTOFMEMORY;
    2729     }
    2730     return S_OK;
    2731 #endif /* VBOX_WITH_GUEST_CONTROL */
    2732 }
    2733 
    2734 STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile)
    2735 {
    2736 #ifndef VBOX_WITH_GUEST_CONTROL
    2737     ReturnComNotImplemented();
    2738 #else
    2739     LogFlowThisFuncEnter();
    2740 
    2741     if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
    2742         return setError(E_INVALIDARG, tr("No file to open specified"));
    2743     if (RT_UNLIKELY((aOpenMode) == NULL || *(aOpenMode) == '\0'))
    2744         return setError(E_INVALIDARG, tr("No open mode specified"));
    2745     if (RT_UNLIKELY((aDisposition) == NULL || *(aDisposition) == '\0'))
    2746         return setError(E_INVALIDARG, tr("No disposition mode specified"));
    2747 
    2748     CheckComArgOutPointerValid(aFile);
    2749 
    2750     AutoCaller autoCaller(this);
    2751     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2752 
    2753     /** @todo Validate open mode. */
    2754     /** @todo Validate disposition mode. */
    2755 
    2756     /** @todo Validate creation mode. */
    2757     uint32_t uCreationMode = 0;
    2758 
    2759     HRESULT hr = S_OK;
    2760 
    2761     ComObjPtr <GuestFile> pFile;
    2762     int rc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition),
    2763                               aCreationMode, aOffset, pFile);
    2764     if (RT_SUCCESS(rc))
    2765     {
    2766         /* Return directory object to the caller. */
    2767         hr = pFile.queryInterfaceTo(aFile);
    2768     }
    2769     else
    2770     {
    2771         switch (rc)
    2772         {
    2773             /** @todo Add more error info! */
    2774 
    2775             default:
    2776                hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
    2777                break;
    2778         }
    2779     }
    2780 
    2781     return hr;
    2782 #endif /* VBOX_WITH_GUEST_CONTROL */
    2783 }
    2784 
    2785 STDMETHODIMP GuestSession::FileQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
    2786 {
    2787 #ifndef VBOX_WITH_GUEST_CONTROL
    2788     ReturnComNotImplemented();
    2789 #else
    2790     LogFlowThisFuncEnter();
    2791 
    2792     if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
    2793         return setError(E_INVALIDARG, tr("No file to query information for specified"));
    2794     CheckComArgOutPointerValid(aInfo);
    2795 
    2796     AutoCaller autoCaller(this);
    2797     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2798 
    2799     HRESULT hr = S_OK;
    2800 
    2801     GuestFsObjData objData;
    2802     int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
    2803     if (RT_SUCCESS(rc))
    2804     {
    2805         ComObjPtr<GuestFsObjInfo> pFsObjInfo;
    2806         hr = pFsObjInfo.createObject();
    2807         if (FAILED(hr))
    2808             return VERR_COM_UNEXPECTED;
    2809 
    2810         rc = pFsObjInfo->init(objData);
    2811         if (RT_SUCCESS(rc))
    2812             hr = pFsObjInfo.queryInterfaceTo(aInfo);
    2813     }
    2814 
    2815     if (RT_FAILURE(rc))
    2816     {
    2817         switch (rc)
    2818         {
    2819             /** @todo Add more errors here! */
    2820 
    2821             case VERR_NOT_A_FILE:
    2822                 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a file"));
    2823                 break;
    2824 
    2825             default:
    2826                hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), rc);
    2827                break;
    2828         }
    2829     }
    2830 
    2831     return hr;
    2832 #endif /* VBOX_WITH_GUEST_CONTROL */
    2833 }
    2834 
    2835 STDMETHODIMP GuestSession::FileQuerySize(IN_BSTR aPath, LONG64 *aSize)
    2836 {
    2837 #ifndef VBOX_WITH_GUEST_CONTROL
    2838     ReturnComNotImplemented();
    2839 #else
    2840     LogFlowThisFuncEnter();
    2841 
    2842     if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
    2843         return setError(E_INVALIDARG, tr("No file to query size for specified"));
    2844     CheckComArgOutPointerValid(aSize);
    2845 
    2846     AutoCaller autoCaller(this);
    2847     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2848 
    2849     HRESULT hr = S_OK;
    2850 
    2851     int64_t llSize;
    2852     int rc = fileQuerySizeInternal(Utf8Str(aPath), &llSize);
    2853     if (RT_SUCCESS(rc))
    2854     {
    2855         *aSize = llSize;
    2856     }
    2857     else
    2858     {
    2859         switch (rc)
    2860         {
    2861             /** @todo Add more errors here! */
    2862 
    2863             default:
    2864                hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), rc);
    2865                break;
    2866         }
    2867     }
    2868 
    2869     return hr;
    2870 #endif /* VBOX_WITH_GUEST_CONTROL */
    2871 }
    2872 
    2873 STDMETHODIMP GuestSession::FileRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
    2874 {
    2875 #ifndef VBOX_WITH_GUEST_CONTROL
    2876     ReturnComNotImplemented();
    2877 #else
    2878     LogFlowThisFuncEnter();
    2879 
    2880     AutoCaller autoCaller(this);
    2881     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2882 
    2883     ReturnComNotImplemented();
    2884 #endif /* VBOX_WITH_GUEST_CONTROL */
    2885 }
    2886 
    2887 STDMETHODIMP GuestSession::FileSetACL(IN_BSTR aPath, IN_BSTR aACL)
    2888 {
    2889 #ifndef VBOX_WITH_GUEST_CONTROL
    2890     ReturnComNotImplemented();
    2891 #else
    2892     LogFlowThisFuncEnter();
    2893 
    2894     AutoCaller autoCaller(this);
    2895     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2896 
    2897     ReturnComNotImplemented();
    2898 #endif /* VBOX_WITH_GUEST_CONTROL */
    2899 }
    2900 
    2901 STDMETHODIMP GuestSession::ProcessCreate(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
    2902                                          ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS, IGuestProcess **aProcess)
    2903 {
    2904 #ifndef VBOX_WITH_GUEST_CONTROL
    2905     ReturnComNotImplemented();
    2906 #else
    2907     LogFlowThisFuncEnter();
    2908 
    2909     com::SafeArray<LONG> affinity;
    2910 
    2911     HRESULT hr = ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
    2912                                  ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);
    2913     return hr;
    2914 #endif /* VBOX_WITH_GUEST_CONTROL */
    2915 }
    2916 
    2917 STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
    2918                                            ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS,
    2919                                            ProcessPriority_T aPriority, ComSafeArrayIn(LONG, aAffinity),
    2920                                            IGuestProcess **aProcess)
    2921 {
    2922 #ifndef VBOX_WITH_GUEST_CONTROL
    2923     ReturnComNotImplemented();
    2924 #else
    2925     LogFlowThisFuncEnter();
    2926 
    2927     if (RT_UNLIKELY((aCommand) == NULL || *(aCommand) == '\0'))
    2928         return setError(E_INVALIDARG, tr("No command to execute specified"));
    2929     CheckComArgOutPointerValid(aProcess);
    2930 
    2931     AutoCaller autoCaller(this);
    2932     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2933 
    2934     GuestProcessStartupInfo procInfo;
    2935     procInfo.mCommand = Utf8Str(aCommand);
    2936 
    2937     if (aArguments)
    2938     {
    2939         com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
    2940         for (size_t i = 0; i < arguments.size(); i++)
    2941             procInfo.mArguments.push_back(Utf8Str(arguments[i]));
    2942     }
    2943 
    2944     int rc = VINF_SUCCESS;
    2945 
    2946     /*
    2947      * Create the process environment:
    2948      * - Apply the session environment in a first step, and
    2949      * - Apply environment variables specified by this call to
    2950      *   have the chance of overwriting/deleting session entries.
    2951      */
    2952     procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
    2953 
    2954     if (aEnvironment)
    2955     {
    2956         com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aEnvironment));
    2957         for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)
    2958             rc = procInfo.mEnvironment.Set(Utf8Str(environment[i]));
    2959     }
    2960 
    2961     HRESULT hr = S_OK;
    2962 
    2963     if (RT_SUCCESS(rc))
    2964     {
    2965         if (aFlags)
    2966         {
    2967             com::SafeArray<ProcessCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
    2968             for (size_t i = 0; i < flags.size(); i++)
    2969                 procInfo.mFlags |= flags[i];
    2970         }
    2971 
    2972         procInfo.mTimeoutMS = aTimeoutMS;
    2973 
    2974         if (aAffinity)
    2975         {
    2976             com::SafeArray<LONG> affinity(ComSafeArrayInArg(aAffinity));
    2977             for (size_t i = 0; i < affinity.size(); i++)
    2978                 procInfo.mAffinity[i] = affinity[i]; /** @todo Really necessary? Later. */
    2979         }
    2980 
    2981         procInfo.mPriority = aPriority;
    2982 
    2983         ComObjPtr<GuestProcess> pProcess;
    2984         rc = processCreateExInteral(procInfo, pProcess);
    2985         if (RT_SUCCESS(rc))
    2986         {
    2987             /* Return guest session to the caller. */
    2988             HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
    2989             if (FAILED(hr2))
    2990                 rc = VERR_COM_OBJECT_NOT_FOUND;
    2991 
    2992             if (RT_SUCCESS(rc))
    2993                 rc = pProcess->startProcessAsync();
    2994         }
    2995     }
    2996 
    2997     if (RT_FAILURE(rc))
    2998     {
    2999         switch (rc)
    3000         {
    3001             case VERR_MAX_PROCS_REACHED:
    3002                 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest processes per session (%ld) reached"),
    3003                               VBOX_GUESTCTRL_MAX_PROCESSES);
    3004                 break;
    3005 
    3006             /** @todo Add more errors here. */
    3007 
    3008             default:
    3009                 hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
    3010                 break;
    3011         }
    3012     }
    3013 
    3014     LogFlowFuncLeaveRC(rc);
    3015     return hr;
    3016 #endif /* VBOX_WITH_GUEST_CONTROL */
    3017 }
    3018 
    3019 STDMETHODIMP GuestSession::ProcessGet(ULONG aPID, IGuestProcess **aProcess)
    3020 {
    3021 #ifndef VBOX_WITH_GUEST_CONTROL
    3022     ReturnComNotImplemented();
    3023 #else
    3024     LogFlowThisFunc(("aPID=%RU32\n", aPID));
    3025 
    3026     CheckComArgOutPointerValid(aProcess);
    3027     if (aPID == 0)
    3028         return setError(E_INVALIDARG, tr("No valid process ID (PID) specified"));
    3029 
    3030     AutoCaller autoCaller(this);
    3031     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3032 
    3033     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3034 
    3035     HRESULT hr = S_OK;
    3036 
    3037     ComObjPtr<GuestProcess> pProcess;
    3038     int rc = processGetByPID(aPID, &pProcess);
    3039     if (RT_FAILURE(rc))
    3040         hr = setError(E_INVALIDARG, tr("No process with PID %RU32 found"), aPID);
    3041 
    3042     /* This will set (*aProcess) to NULL if pProgress is NULL. */
    3043     HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
    3044     if (SUCCEEDED(hr))
    3045         hr = hr2;
    3046 
    3047     LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", *aProcess, hr));
    3048     return hr;
    3049 #endif /* VBOX_WITH_GUEST_CONTROL */
    3050 }
    3051 
    3052 STDMETHODIMP GuestSession::SymlinkCreate(IN_BSTR aSource, IN_BSTR aTarget, SymlinkType_T aType)
    3053 {
    3054 #ifndef VBOX_WITH_GUEST_CONTROL
    3055     ReturnComNotImplemented();
    3056 #else
    3057     LogFlowThisFuncEnter();
    3058 
    3059     AutoCaller autoCaller(this);
    3060     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3061 
    3062     ReturnComNotImplemented();
    3063 #endif /* VBOX_WITH_GUEST_CONTROL */
    3064 }
    3065 
    3066 STDMETHODIMP GuestSession::SymlinkExists(IN_BSTR aSymlink, BOOL *aExists)
    3067 {
    3068 #ifndef VBOX_WITH_GUEST_CONTROL
    3069     ReturnComNotImplemented();
    3070 #else
    3071     LogFlowThisFuncEnter();
    3072 
    3073     AutoCaller autoCaller(this);
    3074     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3075 
    3076     ReturnComNotImplemented();
    3077 #endif /* VBOX_WITH_GUEST_CONTROL */
    3078 }
    3079 
    3080 STDMETHODIMP GuestSession::SymlinkRead(IN_BSTR aSymlink, ComSafeArrayIn(SymlinkReadFlag_T, aFlags), BSTR *aTarget)
    3081 {
    3082 #ifndef VBOX_WITH_GUEST_CONTROL
    3083     ReturnComNotImplemented();
    3084 #else
    3085     LogFlowThisFuncEnter();
    3086 
    3087     AutoCaller autoCaller(this);
    3088     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3089 
    3090     ReturnComNotImplemented();
    3091 #endif /* VBOX_WITH_GUEST_CONTROL */
    3092 }
    3093 
    3094 STDMETHODIMP GuestSession::SymlinkRemoveDirectory(IN_BSTR aPath)
    3095 {
    3096 #ifndef VBOX_WITH_GUEST_CONTROL
    3097     ReturnComNotImplemented();
    3098 #else
    3099     LogFlowThisFuncEnter();
    3100 
    3101     AutoCaller autoCaller(this);
    3102     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3103 
    3104     ReturnComNotImplemented();
    3105 #endif /* VBOX_WITH_GUEST_CONTROL */
    3106 }
    3107 
    3108 STDMETHODIMP GuestSession::SymlinkRemoveFile(IN_BSTR aFile)
    3109 {
    3110 #ifndef VBOX_WITH_GUEST_CONTROL
    3111     ReturnComNotImplemented();
    3112 #else
    3113     LogFlowThisFuncEnter();
    3114 
    3115     AutoCaller autoCaller(this);
    3116     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3117 
    3118     ReturnComNotImplemented();
    3119 #endif /* VBOX_WITH_GUEST_CONTROL */
    3120 }
    3121 
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