Index: trunk/src/VBox/Main/src-client/GuestCtrlIO.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestCtrlIO.cpp	(revision 38212)
+++ trunk/src/VBox/Main/src-client/GuestCtrlIO.cpp	(revision 38235)
@@ -32,6 +32,5 @@
     : m_cbAllocated(0),
       m_cbSize(0),
-      m_cbOffsetBuffer(0),
-      m_cbOffsetParser(0),
+      m_cbOffset(0),
       m_pbBuffer(NULL)
 {
@@ -44,5 +43,12 @@
 }
 
-
+/**
+ * Adds data to the internal parser buffer. Useful if there
+ * are multiple rounds of adding data needed.
+ *
+ * @return  IPRT status code.
+ * @param   pbData              Pointer to data to add.
+ * @param   cbData              Size (in bytes) of data to add.
+ */
 int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData)
 {
@@ -53,8 +59,8 @@
 
     /* Rewind the buffer if it's empty. */
-    size_t     cbInBuf   = m_cbSize - m_cbOffsetBuffer;
+    size_t     cbInBuf   = m_cbSize - m_cbOffset;
     bool const fAddToSet = cbInBuf == 0;
     if (fAddToSet)
-        m_cbSize = m_cbOffsetBuffer = 0;
+        m_cbSize = m_cbOffset = 0;
 
     /* Try and see if we can simply append the data. */
@@ -67,12 +73,12 @@
     {
         /* Move any buffered data to the front. */
-        cbInBuf = m_cbSize - m_cbOffsetBuffer;
+        cbInBuf = m_cbSize - m_cbOffset;
         if (cbInBuf == 0)
-            m_cbSize = m_cbOffsetBuffer = 0;
-        else if (m_cbOffsetBuffer) /* Do we have something to move? */
-        {
-            memmove(m_pbBuffer, &m_pbBuffer[m_cbOffsetBuffer], cbInBuf);
+            m_cbSize = m_cbOffset = 0;
+        else if (m_cbOffset) /* Do we have something to move? */
+        {
+            memmove(m_pbBuffer, &m_pbBuffer[m_cbOffset], cbInBuf);
             m_cbSize = cbInBuf;
-            m_cbOffsetBuffer = 0;
+            m_cbOffset = 0;
         }
 
@@ -108,4 +114,9 @@
 }
 
+/**
+ * Destroys the currently stored stream pairs.
+ *
+ * @return  IPRT status code.
+ */
 void GuestProcessStream::ClearPairs()
 {
@@ -120,5 +131,6 @@
 
 /**
- * Destroys the stored stream pairs.
+ * Destroys the currently stored stream pairs and the internal
+ * data buffer.
  */
 void GuestProcessStream::Destroy()
@@ -127,7 +139,21 @@
 
     if (m_pbBuffer)
+    {
         RTMemFree(m_pbBuffer);
-}
-
+        m_pbBuffer = NULL;
+    }
+
+    m_cbAllocated = 0;
+    m_cbSize = 0;
+    m_cbOffset = 0;
+}
+
+/**
+ * Returns a 64-bit signed integer of a specified key.
+ *
+ * @return  IPRT status code. VERR_NOT_FOUND if key was not found.
+ * @param  pszKey               Name of key to get the value for.
+ * @param  piVal                Pointer to value to return.
+ */
 int GuestProcessStream::GetInt64Ex(const char *pszKey, int64_t *piVal)
 {
@@ -167,18 +193,19 @@
 }
 
-uint32_t GuestProcessStream::GetOffsetBuffer()
-{
-    return m_cbOffsetBuffer;
-}
-
-uint32_t GuestProcessStream::GetOffsetParser()
-{
-    return m_cbOffsetParser;
-}
-
-/**
- * Returns a 32-bit unsigned integer of a specified key.
- *
- * @return  uint32_t            Value to return, 0 if not found / on failure.
+/**
+ * Returns the current offset of the parser within
+ * the internal data buffer.
+ *
+ * @return  uint32_t            Parser offset.
+ */
+uint32_t GuestProcessStream::GetOffset()
+{
+    return m_cbOffset;
+}
+
+/**
+ * Returns a string value of a specified key.
+ *
+ * @return  uint32_t            Pointer to string to return, NULL if not found / on failure.
  * @param   pszKey              Name of key to get the value for.
  */
@@ -200,4 +227,11 @@
 }
 
+/**
+ * Returns a 32-bit unsigned integer of a specified key.
+ *
+ * @return  IPRT status code. VERR_NOT_FOUND if key was not found.
+ * @param  pszKey               Name of key to get the value for.
+ * @param  puVal                Pointer to value to return.
+ */
 int GuestProcessStream::GetUInt32Ex(const char *pszKey, uint32_t *puVal)
 {
@@ -227,13 +261,23 @@
 }
 
-int GuestProcessStream::Parse()
+/**
+ * Try to parse the next upcoming pair block within the internal
+ * buffer. Old pairs from a previously parsed block will be removed first!
+ *
+ * @return  IPRT status code.
+ */
+int GuestProcessStream::ParseBlock()
 {
     AssertPtrReturn(m_pbBuffer, VINF_SUCCESS);
     AssertReturn(m_cbSize, VINF_SUCCESS);
-    AssertReturn(m_cbOffsetParser <= m_cbSize, VERR_INVALID_PARAMETER);
+    AssertReturn(m_cbOffset <= m_cbSize, VERR_INVALID_PARAMETER);
+
+    /* Since we want to (try to) parse another block, clear
+     * all pairs from a previously parsed block. */
+    ClearPairs();
 
     int rc = VINF_SUCCESS;
 
-    size_t uCur = m_cbOffsetParser;
+    size_t uCur = m_cbOffset;
     for (;uCur < m_cbSize;)
     {
@@ -263,5 +307,5 @@
                 || pszSep == pszEnd)
             {
-                m_cbOffsetParser =  uCur - uPairLen - 1;
+                m_cbOffset =  uCur - uPairLen - 1;
                 rc = VERR_MORE_DATA;
             }
@@ -304,5 +348,5 @@
                 RTMemFree(pszKey);
 
-                m_cbOffsetParser += uCur - m_cbOffsetParser;
+                m_cbOffset += uCur - m_cbOffset;
             }
         }
@@ -313,5 +357,5 @@
                 if (*pszEnd == '\0')
                 {
-                    m_cbOffsetParser = uCur;
+                    m_cbOffset = uCur;
                     rc = VERR_MORE_DATA;
                     break;
@@ -325,5 +369,5 @@
     }
 
-    RT_CLAMP(m_cbOffsetParser, 0, m_cbSize);
+    RT_CLAMP(m_cbOffset, 0, m_cbSize);
 
     return rc;
Index: trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 38212)
+++ trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 38235)
@@ -41,994 +41,4 @@
 
 #include <memory>
-
-struct Guest::TaskGuest
-{
-    enum TaskType
-    {
-        /** Copies a file from host to the guest. */
-        CopyFileToGuest   = 50,
-        /** Copies a file from guest to the host. */
-        CopyFileFromGuest = 55,
-
-        /** Update Guest Additions by directly copying the required installer
-         *  off the .ISO file, transfer it to the guest and execute the installer
-         *  with system privileges. */
-        UpdateGuestAdditions = 100
-    };
-
-    TaskGuest(TaskType aTaskType, Guest *aThat, Progress *aProgress)
-        : taskType(aTaskType),
-          pGuest(aThat),
-          progress(aProgress),
-          rc(S_OK)
-    {}
-    virtual ~TaskGuest() {}
-
-    int startThread();
-    static int taskThread(RTTHREAD aThread, void *pvUser);
-    static int uploadProgress(unsigned uPercent, void *pvUser);
-
-    static HRESULT setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, const char * pszText, ...);
-    static HRESULT setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, ComObjPtr<Guest> pGuest);
-
-    TaskType taskType;
-    Guest *pGuest;
-    ComObjPtr<Progress> progress;
-    HRESULT rc;
-
-    /* Task data. */
-    Utf8Str strSource;
-    Utf8Str strDest;
-    Utf8Str strUserName;
-    Utf8Str strPassword;
-    ULONG   uFlags;
-};
-
-int Guest::TaskGuest::startThread()
-{
-    int vrc = RTThreadCreate(NULL, Guest::TaskGuest::taskThread, this,
-                             0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
-                             "Guest::Task");
-
-    if (RT_FAILURE(vrc))
-        return Guest::setErrorStatic(E_FAIL, Utf8StrFmt("Could not create taskThreadGuest (%Rrc)\n", vrc));
-
-    return vrc;
-}
-
-/* static */
-DECLCALLBACK(int) Guest::TaskGuest::taskThread(RTTHREAD /* aThread */, void *pvUser)
-{
-    std::auto_ptr<TaskGuest> task(static_cast<TaskGuest*>(pvUser));
-    AssertReturn(task.get(), VERR_GENERAL_FAILURE);
-
-    Guest *pGuest = task->pGuest;
-
-    LogFlowFuncEnter();
-    LogFlowFunc(("Guest %p\n", pGuest));
-
-    HRESULT rc = S_OK;
-
-    switch (task->taskType)
-    {
-#ifdef VBOX_WITH_GUEST_CONTROL
-        case TaskGuest::CopyFileToGuest:
-        {
-            rc = pGuest->taskCopyFileToGuest(task.get());
-            break;
-        }
-        case TaskGuest::CopyFileFromGuest:
-        {
-            rc = pGuest->taskCopyFileFromGuest(task.get());
-            break;
-        }
-        case TaskGuest::UpdateGuestAdditions:
-        {
-            rc = pGuest->taskUpdateGuestAdditions(task.get());
-            break;
-        }
-#endif
-        default:
-            AssertMsgFailed(("Invalid task type %u specified!\n", task->taskType));
-            break;
-    }
-
-    LogFlowFunc(("rc=%Rhrc\n", rc));
-    LogFlowFuncLeave();
-
-    return VINF_SUCCESS;
-}
-
-/* static */
-int Guest::TaskGuest::uploadProgress(unsigned uPercent, void *pvUser)
-{
-    Guest::TaskGuest *pTask = *(Guest::TaskGuest**)pvUser;
-
-    if (pTask &&
-        !pTask->progress.isNull())
-    {
-        BOOL fCanceled;
-        pTask->progress->COMGETTER(Canceled)(&fCanceled);
-        if (fCanceled)
-            return -1;
-        pTask->progress->SetCurrentOperationProgress(uPercent);
-    }
-    return VINF_SUCCESS;
-}
-
-/* static */
-HRESULT Guest::TaskGuest::setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, const char *pszText, ...)
-{
-    BOOL fCanceled;
-    BOOL fCompleted;
-    if (   SUCCEEDED(pProgress->COMGETTER(Canceled(&fCanceled)))
-        && !fCanceled
-        && SUCCEEDED(pProgress->COMGETTER(Completed(&fCompleted)))
-        && !fCompleted)
-    {
-        va_list va;
-        va_start(va, pszText);
-        HRESULT hr2 = pProgress->notifyCompleteV(hr,
-                                                 COM_IIDOF(IGuest),
-                                                 Guest::getStaticComponentName(),
-                                                 pszText,
-                                                 va);
-        va_end(va);
-        if (hr2 == S_OK) /* If unable to retrieve error, return input error. */
-            hr2 = hr;
-        return hr2;
-    }
-    return S_OK;
-}
-
-/* static */
-HRESULT Guest::TaskGuest::setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, ComObjPtr<Guest> pGuest)
-{
-    return setProgressErrorInfo(hr, pProgress,
-                                Utf8Str(com::ErrorInfo((IGuest*)pGuest, COM_IIDOF(IGuest)).getText()).c_str());
-}
-
-#ifdef VBOX_WITH_GUEST_CONTROL
-HRESULT Guest::taskCopyFileToGuest(TaskGuest *aTask)
-{
-    LogFlowFuncEnter();
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    /*
-     * Do *not* take a write lock here since we don't (and won't)
-     * touch any class-specific data (of IGuest) here - only the member functions
-     * which get called here can do that.
-     */
-
-    HRESULT rc = S_OK;
-
-    try
-    {
-        Guest *pGuest = aTask->pGuest;
-        AssertPtr(pGuest);
-
-        /* Does our source file exist? */
-        if (!RTFileExists(aTask->strSource.c_str()))
-        {
-            rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                 Guest::tr("Source file \"%s\" does not exist, or is not a file"),
-                                                 aTask->strSource.c_str());
-        }
-        else
-        {
-            RTFILE fileSource;
-            int vrc = RTFileOpen(&fileSource, aTask->strSource.c_str(),
-                                 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
-            if (RT_FAILURE(vrc))
-            {
-                rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                     Guest::tr("Could not open source file \"%s\" for reading (%Rrc)"),
-                                                     aTask->strSource.c_str(),  vrc);
-            }
-            else
-            {
-                uint64_t cbSize;
-                vrc = RTFileGetSize(fileSource, &cbSize);
-                if (RT_FAILURE(vrc))
-                {
-                    rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                         Guest::tr("Could not query file size of \"%s\" (%Rrc)"),
-                                                         aTask->strSource.c_str(), vrc);
-                }
-                else
-                {
-                    com::SafeArray<IN_BSTR> args;
-                    com::SafeArray<IN_BSTR> env;
-
-                    /*
-                     * Prepare tool command line.
-                     */
-                    char szOutput[RTPATH_MAX];
-                    if (RTStrPrintf(szOutput, sizeof(szOutput), "--output=%s", aTask->strDest.c_str()) <= sizeof(szOutput) - 1)
-                    {
-                        /*
-                         * Normalize path slashes, based on the detected guest.
-                         */
-                        Utf8Str osType = mData.mOSTypeId;
-                        if (   osType.contains("Microsoft", Utf8Str::CaseInsensitive)
-                            || osType.contains("Windows", Utf8Str::CaseInsensitive))
-                        {
-                            /* We have a Windows guest. */
-                            RTPathChangeToDosSlashes(szOutput, true /* Force conversion. */);
-                        }
-                        else /* ... or something which isn't from Redmond ... */
-                        {
-                            RTPathChangeToUnixSlashes(szOutput, true /* Force conversion. */);
-                        }
-
-                        args.push_back(Bstr(szOutput).raw());             /* We want to write a file ... */
-                    }
-                    else
-                    {
-                        rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                             Guest::tr("Error preparing command line"));
-                    }
-
-                    ComPtr<IProgress> execProgress;
-                    ULONG uPID;
-                    if (SUCCEEDED(rc))
-                    {
-                        LogRel(("Copying file \"%s\" to guest \"%s\" (%u bytes) ...\n",
-                                aTask->strSource.c_str(), aTask->strDest.c_str(), cbSize));
-                        /*
-                         * Okay, since we gathered all stuff we need until now to start the
-                         * actual copying, start the guest part now.
-                         */
-                        rc = pGuest->ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
-                                                      ExecuteProcessFlag_Hidden
-                                                    | ExecuteProcessFlag_WaitForProcessStartOnly,
-                                                    ComSafeArrayAsInParam(args),
-                                                    ComSafeArrayAsInParam(env),
-                                                    Bstr(aTask->strUserName).raw(),
-                                                    Bstr(aTask->strPassword).raw(),
-                                                    5 * 1000 /* Wait 5s for getting the process started. */,
-                                                    &uPID, execProgress.asOutParam());
-                        if (FAILED(rc))
-                            rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
-                    }
-
-                    if (SUCCEEDED(rc))
-                    {
-                        BOOL fCompleted = FALSE;
-                        BOOL fCanceled = FALSE;
-
-                        size_t cbToRead = cbSize;
-                        size_t cbTransfered = 0;
-                        size_t cbRead;
-                        SafeArray<BYTE> aInputData(_64K);
-                        while (   SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted)))
-                               && !fCompleted)
-                        {
-                            if (!cbToRead)
-                                cbRead = 0;
-                            else
-                            {
-                                vrc = RTFileRead(fileSource, (uint8_t*)aInputData.raw(),
-                                                 RT_MIN(cbToRead, _64K), &cbRead);
-                                /*
-                                 * Some other error occured? There might be a chance that RTFileRead
-                                 * could not resolve/map the native error code to an IPRT code, so just
-                                 * print a generic error.
-                                 */
-                                if (RT_FAILURE(vrc))
-                                {
-                                    rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                         Guest::tr("Could not read from file \"%s\" (%Rrc)"),
-                                                                         aTask->strSource.c_str(), vrc);
-                                    break;
-                                }
-                            }
-
-                            /* Resize buffer to reflect amount we just have read.
-                             * Size 0 is allowed! */
-                            aInputData.resize(cbRead);
-
-                            ULONG uFlags = ProcessInputFlag_None;
-                            /* Did we reach the end of the content we want to transfer (last chunk)? */
-                            if (   (cbRead < _64K)
-                                /* Did we reach the last block which is exactly _64K? */
-                                || (cbToRead - cbRead == 0)
-                                /* ... or does the user want to cancel? */
-                                || (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
-                                    && fCanceled)
-                               )
-                            {
-                                uFlags |= ProcessInputFlag_EndOfFile;
-                            }
-
-                            /* Transfer the current chunk ... */
-                            ULONG uBytesWritten;
-                            rc = pGuest->SetProcessInput(uPID, uFlags,
-                                                         10 * 1000 /* Wait 10s for getting the input data transfered. */,
-                                                         ComSafeArrayAsInParam(aInputData), &uBytesWritten);
-                            if (FAILED(rc))
-                            {
-                                rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
-                                break;
-                            }
-
-                            Assert(cbRead <= cbToRead);
-                            Assert(cbToRead >= cbRead);
-                            cbToRead -= cbRead;
-
-                            cbTransfered += uBytesWritten;
-                            Assert(cbTransfered <= cbSize);
-                            aTask->progress->SetCurrentOperationProgress(cbTransfered / (cbSize / 100.0));
-
-                            /* End of file reached? */
-                            if (cbToRead == 0)
-                                break;
-
-                            /* Did the user cancel the operation above? */
-                            if (fCanceled)
-                                break;
-
-                            /* Progress canceled by Main API? */
-                            if (   SUCCEEDED(execProgress->COMGETTER(Canceled(&fCanceled)))
-                                && fCanceled)
-                            {
-                                rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                     Guest::tr("Copy operation of file \"%s\" was canceled on guest side"),
-                                                                     aTask->strSource.c_str());
-                                break;
-                            }
-                        }
-
-                        if (SUCCEEDED(rc))
-                        {
-                            /*
-                             * If we got here this means the started process either was completed,
-                             * canceled or we simply got all stuff transferred.
-                             */
-                            ExecuteProcessStatus_T retStatus;
-                            ULONG uRetExitCode;
-                            rc = pGuest->waitForProcessStatusChange(uPID, &retStatus, &uRetExitCode, 10 * 1000 /* 10s timeout. */);
-                            if (FAILED(rc))
-                            {
-                                rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
-                            }
-                            else
-                            {
-                                if (   uRetExitCode != 0
-                                    || retStatus    != ExecuteProcessStatus_TerminatedNormally)
-                                {
-                                    rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                         Guest::tr("Guest reported error %u while copying file \"%s\" to \"%s\""),
-                                                                         uRetExitCode, aTask->strSource.c_str(), aTask->strDest.c_str());
-                                }
-                            }
-                        }
-
-                        if (SUCCEEDED(rc))
-                        {
-                            if (fCanceled)
-                            {
-                                /*
-                                 * In order to make the progress object to behave nicely, we also have to
-                                 * notify the object with a complete event when it's canceled.
-                                 */
-                                aTask->progress->notifyComplete(VBOX_E_IPRT_ERROR,
-                                                                COM_IIDOF(IGuest),
-                                                                Guest::getStaticComponentName(),
-                                                                Guest::tr("Copying file \"%s\" canceled"), aTask->strSource.c_str());
-                            }
-                            else
-                            {
-                                /*
-                                 * Even if we succeeded until here make sure to check whether we really transfered
-                                 * everything.
-                                 */
-                                if (   cbSize > 0
-                                    && cbTransfered == 0)
-                                {
-                                    /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
-                                     * to the destination -> access denied. */
-                                    rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                         Guest::tr("Access denied when copying file \"%s\" to \"%s\""),
-                                                                         aTask->strSource.c_str(), aTask->strDest.c_str());
-                                }
-                                else if (cbTransfered < cbSize)
-                                {
-                                    /* If we did not copy all let the user know. */
-                                    rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                         Guest::tr("Copying file \"%s\" failed (%u/%u bytes transfered)"),
-                                                                         aTask->strSource.c_str(), cbTransfered, cbSize);
-                                }
-                                else /* Yay, all went fine! */
-                                    aTask->progress->notifyComplete(S_OK);
-                            }
-                        }
-                    }
-                }
-                RTFileClose(fileSource);
-            }
-        }
-    }
-    catch (HRESULT aRC)
-    {
-        rc = aRC;
-    }
-
-    /* Clean up */
-    aTask->rc = rc;
-
-    LogFlowFunc(("rc=%Rhrc\n", rc));
-    LogFlowFuncLeave();
-
-    return VINF_SUCCESS;
-}
-
-HRESULT Guest::taskCopyFileFromGuest(TaskGuest *aTask)
-{
-    LogFlowFuncEnter();
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    /*
-     * Do *not* take a write lock here since we don't (and won't)
-     * touch any class-specific data (of IGuest) here - only the member functions
-     * which get called here can do that.
-     */
-
-    HRESULT rc = S_OK;
-
-    try
-    {
-        Guest *pGuest = aTask->pGuest;
-        AssertPtr(pGuest);
-
-        /* Does our source file exist? */
-        BOOL fFileExists;
-        rc = pGuest->FileExists(Bstr(aTask->strSource).raw(),
-                                Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(),
-                                &fFileExists);
-        if (SUCCEEDED(rc))
-        {
-            if (!fFileExists)
-                rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                     Guest::tr("Source file \"%s\" does not exist, or is not a file"),
-                                                     aTask->strSource.c_str());
-        }
-
-        /* Query file size to make an estimate for our progress object. */
-        if (SUCCEEDED(rc))
-        {
-            LONG64 lFileSize;
-            rc = pGuest->FileQuerySize(Bstr(aTask->strSource).raw(),
-                                       Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(),
-                                       &lFileSize);
-            if (FAILED(rc))
-                rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
-
-            com::SafeArray<IN_BSTR> args;
-            com::SafeArray<IN_BSTR> env;
-
-            if (SUCCEEDED(rc))
-            {
-                /*
-                 * Prepare tool command line.
-                 */
-                char szSource[RTPATH_MAX];
-                if (RTStrPrintf(szSource, sizeof(szSource), "%s", aTask->strSource.c_str()) <= sizeof(szSource) - 1)
-                {
-                    /*
-                     * Normalize path slashes, based on the detected guest.
-                     */
-                    Utf8Str osType = mData.mOSTypeId;
-                    if (   osType.contains("Microsoft", Utf8Str::CaseInsensitive)
-                        || osType.contains("Windows", Utf8Str::CaseInsensitive))
-                    {
-                        /* We have a Windows guest. */
-                        RTPathChangeToDosSlashes(szSource, true /* Force conversion. */);
-                    }
-                    else /* ... or something which isn't from Redmond ... */
-                    {
-                        RTPathChangeToUnixSlashes(szSource, true /* Force conversion. */);
-                    }
-
-                    args.push_back(Bstr(szSource).raw()); /* Tell our cat tool which file to output. */
-                }
-                else
-                    rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                         Guest::tr("Error preparing command line"));
-            }
-
-            ComPtr<IProgress> execProgress;
-            ULONG uPID;
-            if (SUCCEEDED(rc))
-            {
-                LogRel(("Copying file \"%s\" to host \"%s\" (%u bytes) ...\n",
-                        aTask->strSource.c_str(), aTask->strDest.c_str(), lFileSize));
-
-                /*
-                 * Okay, since we gathered all stuff we need until now to start the
-                 * actual copying, start the guest part now.
-                 */
-                rc = pGuest->ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
-                                            ExecuteProcessFlag_Hidden,
-                                            ComSafeArrayAsInParam(args),
-                                            ComSafeArrayAsInParam(env),
-                                            Bstr(aTask->strUserName).raw(),
-                                            Bstr(aTask->strPassword).raw(),
-                                            5 * 1000 /* Wait 5s for getting the process started. */,
-                                            &uPID, execProgress.asOutParam());
-                if (FAILED(rc))
-                    rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
-            }
-
-            if (SUCCEEDED(rc))
-            {
-                BOOL fCompleted = FALSE;
-                BOOL fCanceled = FALSE;
-
-                RTFILE hFileDest;
-                int vrc = RTFileOpen(&hFileDest, aTask->strDest.c_str(),
-                                     RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
-                if (RT_FAILURE(vrc))
-                    rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                         Guest::tr("Unable to create/open destination file \"%s\", rc=%Rrc"),
-                                                         aTask->strDest.c_str(), vrc);
-                else
-                {
-                    size_t cbToRead = lFileSize;
-                    size_t cbTransfered = 0;
-                    SafeArray<BYTE> aOutputData(_64K);
-                    while (SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted))))
-                    {
-                        rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None,
-                                                    10 * 1000 /* Timeout in ms */,
-                                                    _64K, ComSafeArrayAsOutParam(aOutputData));
-                        if (SUCCEEDED(rc))
-                        {
-                            if (!aOutputData.size())
-                            {
-                                if (cbToRead)
-                                    rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                         Guest::tr("Unexpected end of file \"%s\" (%u bytes left)"),
-                                                                         aTask->strSource.c_str(), cbToRead);
-                                break;
-                            }
-
-                            vrc = RTFileWrite(hFileDest, aOutputData.raw(), aOutputData.size(), NULL /* No partial writes */);
-                            if (RT_FAILURE(vrc))
-                            {
-                                rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                     Guest::tr("Error writing to file \"%s\" (%u bytes left), rc=%Rrc"),
-                                                                     aTask->strSource.c_str(), cbToRead, vrc);
-                                break;
-                            }
-
-                            cbToRead -= aOutputData.size();
-                            cbTransfered += aOutputData.size();
-
-                            aTask->progress->SetCurrentOperationProgress(cbTransfered / (lFileSize / 100.0));
-                        }
-                        else
-                        {
-                            rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
-                            break;
-                        }
-                    }
-
-                    if (SUCCEEDED(rc))
-                        aTask->progress->notifyComplete(S_OK);
-
-                    RTFileClose(hFileDest);
-                }
-            }
-        }
-    }
-    catch (HRESULT aRC)
-    {
-        rc = aRC;
-    }
-
-    /* Clean up */
-    aTask->rc = rc;
-
-    LogFlowFunc(("rc=%Rhrc\n", rc));
-    LogFlowFuncLeave();
-
-    return VINF_SUCCESS;
-}
-
-HRESULT Guest::taskUpdateGuestAdditions(TaskGuest *aTask)
-{
-    LogFlowFuncEnter();
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    /*
-     * Do *not* take a write lock here since we don't (and won't)
-     * touch any class-specific data (of IGuest) here - only the member functions
-     * which get called here can do that.
-     */
-
-    HRESULT rc = S_OK;
-    BOOL fCompleted;
-    BOOL fCanceled;
-
-    try
-    {
-        Guest *pGuest = aTask->pGuest;
-        AssertPtr(pGuest);
-
-        aTask->progress->SetCurrentOperationProgress(10);
-
-        /*
-         * Determine guest OS type and the required installer image.
-         * At the moment only Windows guests are supported.
-         */
-        Utf8Str installerImage;
-        Bstr osTypeId;
-        if (   SUCCEEDED(pGuest->COMGETTER(OSTypeId(osTypeId.asOutParam())))
-            && !osTypeId.isEmpty())
-        {
-            Utf8Str osTypeIdUtf8(osTypeId); /* Needed for .contains(). */
-            if (   osTypeIdUtf8.contains("Microsoft", Utf8Str::CaseInsensitive)
-                || osTypeIdUtf8.contains("Windows", Utf8Str::CaseInsensitive))
-            {
-                if (osTypeIdUtf8.contains("64", Utf8Str::CaseInsensitive))
-                    installerImage = "VBOXWINDOWSADDITIONS_AMD64.EXE";
-                else
-                    installerImage = "VBOXWINDOWSADDITIONS_X86.EXE";
-                /* Since the installers are located in the root directory,
-                 * no further path processing needs to be done (yet). */
-            }
-            else /* Everything else is not supported (yet). */
-                throw TaskGuest::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
-                                                      Guest::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"),
-                                                      osTypeIdUtf8.c_str());
-        }
-        else
-            throw TaskGuest::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
-                                                  Guest::tr("Could not detected guest OS type/version, please update manually"));
-        Assert(!installerImage.isEmpty());
-
-        /*
-         * Try to open the .ISO file and locate the specified installer.
-         */
-        RTISOFSFILE iso;
-        int vrc = RTIsoFsOpen(&iso, aTask->strSource.c_str());
-        if (RT_FAILURE(vrc))
-        {
-            rc = TaskGuest::setProgressErrorInfo(VBOX_E_FILE_ERROR, aTask->progress,
-                                                 Guest::tr("Invalid installation medium detected: \"%s\""),
-                                                 aTask->strSource.c_str());
-        }
-        else
-        {
-            uint32_t cbOffset;
-            size_t cbLength;
-            vrc = RTIsoFsGetFileInfo(&iso, installerImage.c_str(), &cbOffset, &cbLength);
-            if (   RT_SUCCESS(vrc)
-                && cbOffset
-                && cbLength)
-            {
-                vrc = RTFileSeek(iso.file, cbOffset, RTFILE_SEEK_BEGIN, NULL);
-                if (RT_FAILURE(vrc))
-                    rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                         Guest::tr("Could not seek to setup file on installation medium \"%s\" (%Rrc)"),
-                                                         aTask->strSource.c_str(), vrc);
-            }
-            else
-            {
-                switch (vrc)
-                {
-                    case VERR_FILE_NOT_FOUND:
-                        rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                             Guest::tr("Setup file was not found on installation medium \"%s\""),
-                                                             aTask->strSource.c_str());
-                        break;
-
-                    default:
-                        rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                             Guest::tr("An unknown error (%Rrc) occured while retrieving information of setup file on installation medium \"%s\""),
-                                                             vrc, aTask->strSource.c_str());
-                        break;
-                }
-            }
-
-            /* Specify the ouput path on the guest side. */
-            Utf8Str strInstallerPath = "%TEMP%\\VBoxWindowsAdditions.exe";
-
-            if (RT_SUCCESS(vrc))
-            {
-                /* Okay, we're ready to start our copy routine on the guest! */
-                aTask->progress->SetCurrentOperationProgress(15);
-
-                /* Prepare command line args. */
-                com::SafeArray<IN_BSTR> args;
-                com::SafeArray<IN_BSTR> env;
-
-                args.push_back(Bstr("--output").raw());               /* We want to write a file ... */
-                args.push_back(Bstr(strInstallerPath.c_str()).raw()); /* ... with this path. */
-
-                if (SUCCEEDED(rc))
-                {
-                    ComPtr<IProgress> progressCat;
-                    ULONG uPID;
-
-                    /*
-                     * Start built-in "vbox_cat" tool (inside VBoxService) to
-                     * copy over/pipe the data into a file on the guest (with
-                     * system rights, no username/password specified).
-                     */
-                    rc = pGuest->executeProcessInternal(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
-                                                          ExecuteProcessFlag_Hidden
-                                                        | ExecuteProcessFlag_WaitForProcessStartOnly,
-                                                        ComSafeArrayAsInParam(args),
-                                                        ComSafeArrayAsInParam(env),
-                                                        Bstr("").raw() /* Username. */,
-                                                        Bstr("").raw() /* Password */,
-                                                        5 * 1000 /* Wait 5s for getting the process started. */,
-                                                        &uPID, progressCat.asOutParam(), &vrc);
-                    if (FAILED(rc))
-                    {
-                        /* Errors which return VBOX_E_NOT_SUPPORTED can be safely skipped by the caller
-                         * to silently fall back to "normal" (old) .ISO mounting. */
-
-                        /* Due to a very limited COM error range we use vrc for a more detailed error
-                         * lookup to figure out what went wrong. */
-                        switch (vrc)
-                        {
-                            /* Guest execution service is not (yet) ready. This basically means that either VBoxService
-                             * is not running (yet) or that the Guest Additions are too old (because VBoxService does not
-                             * support the guest execution feature in this version). */
-                            case VERR_NOT_FOUND:
-                                LogRel(("Guest Additions seem not to be installed yet\n"));
-                                rc = TaskGuest::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
-                                                                     Guest::tr("Guest Additions seem not to be installed or are not ready to update yet"));
-                                break;
-
-                            /* Getting back a VERR_INVALID_PARAMETER indicates that the installed Guest Additions are supporting the guest
-                             * execution but not the built-in "vbox_cat" tool of VBoxService (< 4.0). */
-                            case VERR_INVALID_PARAMETER:
-                                LogRel(("Guest Additions are installed but don't supported automatic updating\n"));
-                                rc = TaskGuest::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
-                                                                     Guest::tr("Installed Guest Additions do not support automatic updating"));
-                                break;
-
-                            case VERR_TIMEOUT:
-                                LogRel(("Guest was unable to start copying the Guest Additions setup within time\n"));
-                                rc = TaskGuest::setProgressErrorInfo(E_FAIL, aTask->progress,
-                                                                     Guest::tr("Guest was unable to start copying the Guest Additions setup within time"));
-                                break;
-
-                            default:
-                                rc = TaskGuest::setProgressErrorInfo(E_FAIL, aTask->progress,
-                                                                     Guest::tr("Error copying Guest Additions setup file to guest path \"%s\" (%Rrc)"),
-                                                                     strInstallerPath.c_str(), vrc);
-                                break;
-                        }
-                    }
-                    else
-                    {
-                        LogRel(("Automatic update of Guest Additions started, using \"%s\"\n", aTask->strSource.c_str()));
-                        LogRel(("Copying Guest Additions installer \"%s\" to \"%s\" on guest ...\n",
-                                installerImage.c_str(), strInstallerPath.c_str()));
-                        aTask->progress->SetCurrentOperationProgress(20);
-
-                        /* Wait for process to exit ... */
-                        SafeArray<BYTE> aInputData(_64K);
-                        while (   SUCCEEDED(progressCat->COMGETTER(Completed(&fCompleted)))
-                               && !fCompleted)
-                        {
-                            size_t cbRead;
-                            /* cbLength contains remaining bytes of our installer file
-                             * opened above to read. */
-                            size_t cbToRead = RT_MIN(cbLength, _64K);
-                            if (cbToRead)
-                            {
-                                vrc = RTFileRead(iso.file, (uint8_t*)aInputData.raw(), cbToRead, &cbRead);
-                                if (   cbRead
-                                    && RT_SUCCESS(vrc))
-                                {
-                                    /* Resize buffer to reflect amount we just have read. */
-                                    if (cbRead > 0)
-                                        aInputData.resize(cbRead);
-
-                                    /* Did we reach the end of the content we want to transfer (last chunk)? */
-                                    ULONG uFlags = ProcessInputFlag_None;
-                                    if (   (cbRead < _64K)
-                                        /* Did we reach the last block which is exactly _64K? */
-                                        || (cbToRead - cbRead == 0)
-                                        /* ... or does the user want to cancel? */
-                                        || (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
-                                            && fCanceled)
-                                       )
-                                    {
-                                        uFlags |= ProcessInputFlag_EndOfFile;
-                                    }
-
-                                    /* Transfer the current chunk ... */
-                                #ifdef DEBUG_andy
-                                    LogRel(("Copying Guest Additions (%u bytes left) ...\n", cbLength));
-                                #endif
-                                    ULONG uBytesWritten;
-                                    rc = pGuest->SetProcessInput(uPID, uFlags,
-                                                                 10 * 1000 /* Wait 10s for getting the input data transfered. */,
-                                                                 ComSafeArrayAsInParam(aInputData), &uBytesWritten);
-                                    if (FAILED(rc))
-                                    {
-                                        rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
-                                        break;
-                                    }
-
-                                    /* If task was canceled above also cancel the process execution. */
-                                    if (fCanceled)
-                                        progressCat->Cancel();
-
-                                #ifdef DEBUG_andy
-                                    LogRel(("Copying Guest Additions (%u bytes written) ...\n", uBytesWritten));
-                                #endif
-                                    Assert(cbLength >= uBytesWritten);
-                                    cbLength -= uBytesWritten;
-                                }
-                                else if (RT_FAILURE(vrc))
-                                {
-                                    rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                         Guest::tr("Error while reading setup file \"%s\" (To read: %u, Size: %u) from installation medium (%Rrc)"),
-                                                                         installerImage.c_str(), cbToRead, cbLength, vrc);
-                                }
-                            }
-
-                            /* Internal progress canceled? */
-                            if (   SUCCEEDED(progressCat->COMGETTER(Canceled(&fCanceled)))
-                                && fCanceled)
-                            {
-                                aTask->progress->Cancel();
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-            RTIsoFsClose(&iso);
-
-            if (   SUCCEEDED(rc)
-                && (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
-                    && !fCanceled
-                   )
-               )
-            {
-                /*
-                 * Installer was transferred successfully, so let's start it
-                 * (with system rights).
-                 */
-                LogRel(("Preparing to execute Guest Additions update ...\n"));
-                aTask->progress->SetCurrentOperationProgress(66);
-
-                /* Prepare command line args for installer. */
-                com::SafeArray<IN_BSTR> installerArgs;
-                com::SafeArray<IN_BSTR> installerEnv;
-
-                /** @todo Only Windows! */
-                installerArgs.push_back(Bstr(strInstallerPath).raw()); /* The actual (internal) installer image (as argv[0]). */
-                /* Note that starting at Windows Vista the lovely session 0 separation applies:
-                 * This means that if we run an application with the profile/security context
-                 * of VBoxService (system rights!) we're not able to show any UI. */
-                installerArgs.push_back(Bstr("/S").raw());      /* We want to install in silent mode. */
-                installerArgs.push_back(Bstr("/l").raw());      /* ... and logging enabled. */
-                /* Don't quit VBoxService during upgrade because it still is used for this
-                 * piece of code we're in right now (that is, here!) ... */
-                installerArgs.push_back(Bstr("/no_vboxservice_exit").raw());
-                /* Tell the installer to report its current installation status
-                 * using a running VBoxTray instance via balloon messages in the
-                 * Windows taskbar. */
-                installerArgs.push_back(Bstr("/post_installstatus").raw());
-
-                /*
-                 * Start the just copied over installer with system rights
-                 * in silent mode on the guest. Don't use the hidden flag since there
-                 * may be pop ups the user has to process.
-                 */
-                ComPtr<IProgress> progressInstaller;
-                ULONG uPID;
-                rc = pGuest->executeProcessInternal(Bstr(strInstallerPath).raw(),
-                                                    ExecuteProcessFlag_WaitForProcessStartOnly,
-                                                    ComSafeArrayAsInParam(installerArgs),
-                                                    ComSafeArrayAsInParam(installerEnv),
-                                                    Bstr("").raw() /* Username */,
-                                                    Bstr("").raw() /* Password */,
-                                                    10 * 1000 /* Wait 10s for getting the process started */,
-                                                    &uPID, progressInstaller.asOutParam(), &vrc);
-                if (SUCCEEDED(rc))
-                {
-                    LogRel(("Guest Additions update is running ...\n"));
-
-                    /* If the caller does not want to wait for out guest update process to end,
-                     * complete the progress object now so that the caller can do other work. */
-                    if (aTask->uFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly)
-                        aTask->progress->notifyComplete(S_OK);
-                    else
-                        aTask->progress->SetCurrentOperationProgress(70);
-
-                    /* Wait until the Guest Additions installer finishes ... */
-                    while (   SUCCEEDED(progressInstaller->COMGETTER(Completed(&fCompleted)))
-                           && !fCompleted)
-                    {
-                        if (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
-                            && fCanceled)
-                        {
-                            progressInstaller->Cancel();
-                            break;
-                        }
-                        /* Progress canceled by Main API? */
-                        if (   SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled)))
-                            && fCanceled)
-                        {
-                            break;
-                        }
-                        RTThreadSleep(100);
-                    }
-
-                    ExecuteProcessStatus_T retStatus;
-                    ULONG uRetExitCode, uRetFlags;
-                    rc = pGuest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
-                    if (SUCCEEDED(rc))
-                    {
-                        if (fCompleted)
-                        {
-                            if (uRetExitCode == 0)
-                            {
-                                LogRel(("Guest Additions update successful!\n"));
-                                if (   SUCCEEDED(aTask->progress->COMGETTER(Completed(&fCompleted)))
-                                    && !fCompleted)
-                                    aTask->progress->notifyComplete(S_OK);
-                            }
-                            else
-                            {
-                                LogRel(("Guest Additions update failed (Exit code=%u, Status=%u, Flags=%u)\n",
-                                        uRetExitCode, retStatus, uRetFlags));
-                                rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                     Guest::tr("Guest Additions update failed with exit code=%u (status=%u, flags=%u)"),
-                                                                     uRetExitCode, retStatus, uRetFlags);
-                            }
-                        }
-                        else if (   SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled)))
-                                 && fCanceled)
-                        {
-                            LogRel(("Guest Additions update was canceled\n"));
-                            rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                 Guest::tr("Guest Additions update was canceled by the guest with exit code=%u (status=%u, flags=%u)"),
-                                                                 uRetExitCode, retStatus, uRetFlags);
-                        }
-                        else
-                        {
-                            LogRel(("Guest Additions update was canceled by the user\n"));
-                        }
-                    }
-                    else
-                        rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
-                }
-                else
-                    rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
-            }
-        }
-    }
-    catch (HRESULT aRC)
-    {
-        rc = aRC;
-    }
-
-    /* Clean up */
-    aTask->rc = rc;
-
-    LogFlowFunc(("rc=%Rhrc\n", rc));
-    LogFlowFuncLeave();
-
-    return VINF_SUCCESS;
-}
-#endif
 
 // public methods only for internal purposes
@@ -2111,4 +1121,5 @@
 }
 
+#ifdef VBOX_WITH_GUEST_CONTROL
 HRESULT Guest::executeProcessInternal(IN_BSTR aCommand, ULONG aFlags,
                                       ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
@@ -2118,7 +1129,4 @@
 /** @todo r=bird: Eventually we should clean up all the timeout parameters
  *        in the API and have the same way of specifying infinite waits!  */
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else  /* VBOX_WITH_GUEST_CONTROL */
     using namespace guestControl;
 
@@ -2354,6 +1362,6 @@
     }
     return rc;
+}
 #endif /* VBOX_WITH_GUEST_CONTROL */
-}
 
 STDMETHODIMP Guest::SetProcessInput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ComSafeArrayIn(BYTE, aData), ULONG *aBytesWritten)
@@ -2812,7 +1820,7 @@
 
         /* Initialize our worker task. */
-        TaskGuest *pTask = new TaskGuest(TaskGuest::CopyFileFromGuest, this, progress);
+        GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileFromGuest, this, progress);
         AssertPtr(pTask);
-        std::auto_ptr<TaskGuest> task(pTask);
+        std::auto_ptr<GuestTask> task(pTask);
 
         /* Assign data - aSource is the source file on the host,
@@ -2887,7 +1895,7 @@
 
         /* Initialize our worker task. */
-        TaskGuest *pTask = new TaskGuest(TaskGuest::CopyFileToGuest, this, progress);
+        GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileToGuest, this, progress);
         AssertPtr(pTask);
-        std::auto_ptr<TaskGuest> task(pTask);
+        std::auto_ptr<GuestTask> task(pTask);
 
         /* Assign data - aSource is the source file on the host,
@@ -2919,699 +1927,4 @@
 }
 
-STDMETHODIMP Guest::DirectoryClose(ULONG aHandle)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else /* VBOX_WITH_GUEST_CONTROL */
-    using namespace guestControl;
-
-    if (directoryHandleExists(aHandle))
-    {
-        directoryDestroyHandle(aHandle);
-        return S_OK;
-    }
-
-    return setError(VBOX_E_IPRT_ERROR,
-                    Guest::tr("Directory handle is invalid"));
-#endif
-}
-
-STDMETHODIMP Guest::DirectoryCreate(IN_BSTR aDirectory,
-                                    IN_BSTR aUserName, IN_BSTR aPassword,
-                                    ULONG aMode, ULONG aFlags)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else  /* VBOX_WITH_GUEST_CONTROL */
-    using namespace guestControl;
-
-    CheckComArgStrNotEmptyOrNull(aDirectory);
-
-    /* Do not allow anonymous executions (with system rights). */
-    if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
-        return setError(E_INVALIDARG, tr("No user name specified"));
-
-    LogRel(("Creating guest directory \"%s\" as  user \"%s\" ...\n",
-            Utf8Str(aDirectory).c_str(), Utf8Str(aUserName).c_str()));
-
-    return directoryCreateInternal(aDirectory,
-                                   aUserName, aPassword,
-                                   aMode, aFlags, NULL /* rc */);
-#endif
-}
-
-HRESULT Guest::directoryCreateInternal(IN_BSTR aDirectory,
-                                       IN_BSTR aUserName, IN_BSTR aPassword,
-                                       ULONG aMode, ULONG aFlags, int *pRC)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else /* VBOX_WITH_GUEST_CONTROL */
-    using namespace guestControl;
-
-    CheckComArgStrNotEmptyOrNull(aDirectory);
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    /* Validate flags. */
-    if (aFlags != DirectoryCreateFlag_None)
-    {
-        if (!(aFlags & DirectoryCreateFlag_Parents))
-        {
-            return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
-        }
-    }
-
-    HRESULT rc = S_OK;
-    try
-    {
-        Utf8Str Utf8Directory(aDirectory);
-        Utf8Str Utf8UserName(aUserName);
-        Utf8Str Utf8Password(aPassword);
-
-        com::SafeArray<IN_BSTR> args;
-        com::SafeArray<IN_BSTR> env;
-
-        /*
-         * Prepare tool command line.
-         */
-        if (aFlags & DirectoryCreateFlag_Parents)
-            args.push_back(Bstr("--parents").raw());        /* We also want to create the parent directories. */
-        if (aMode > 0)
-        {
-            args.push_back(Bstr("--mode").raw());           /* Set the creation mode. */
-
-            char szMode[16];
-            RTStrPrintf(szMode, sizeof(szMode), "%o", aMode);
-            args.push_back(Bstr(szMode).raw());
-        }
-        args.push_back(Bstr(Utf8Directory).raw());  /* The directory we want to create. */
-
-        /*
-         * Execute guest process.
-         */
-        ComPtr<IProgress> progressExec;
-        ULONG uPID;
-        if (SUCCEEDED(rc))
-        {
-            rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_MKDIR).raw(),
-                                ExecuteProcessFlag_Hidden,
-                                ComSafeArrayAsInParam(args),
-                                ComSafeArrayAsInParam(env),
-                                Bstr(Utf8UserName).raw(),
-                                Bstr(Utf8Password).raw(),
-                                5 * 1000 /* Wait 5s for getting the process started. */,
-                                &uPID, progressExec.asOutParam());
-        }
-
-        if (SUCCEEDED(rc))
-        {
-            /* Wait for process to exit ... */
-            rc = progressExec->WaitForCompletion(-1);
-            if (FAILED(rc)) return rc;
-
-            BOOL fCompleted = FALSE;
-            BOOL fCanceled = FALSE;
-            progressExec->COMGETTER(Completed)(&fCompleted);
-            if (!fCompleted)
-                progressExec->COMGETTER(Canceled)(&fCanceled);
-
-            if (fCompleted)
-            {
-                ExecuteProcessStatus_T retStatus;
-                ULONG uRetExitCode, uRetFlags;
-                if (SUCCEEDED(rc))
-                {
-                    rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
-                    if (SUCCEEDED(rc) && uRetExitCode != 0)
-                    {
-                        rc = setError(VBOX_E_IPRT_ERROR,
-                                      tr("Error %u while creating guest directory"), uRetExitCode);
-                    }
-                }
-            }
-            else if (fCanceled)
-                rc = setError(VBOX_E_IPRT_ERROR,
-                              tr("Guest directory creation was aborted"));
-            else
-                AssertReleaseMsgFailed(("Guest directory creation neither completed nor canceled!?\n"));
-        }
-    }
-    catch (std::bad_alloc &)
-    {
-        rc = E_OUTOFMEMORY;
-    }
-    return rc;
-#endif /* VBOX_WITH_GUEST_CONTROL */
-}
-
-/**
- * Creates a new directory handle ID and returns it.
- *
- * @return IPRT status code.
- * @param puHandle             Pointer where the handle gets stored to.
- * @param pszDirectory         Directory the handle is assigned to.
- * @param pszFilter            Directory filter.  Optional.
- * @param uFlags               Directory open flags.
- *
- */
-int Guest::directoryCreateHandle(ULONG *puHandle, const char *pszDirectory, const char *pszFilter, ULONG uFlags)
-{
-    AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
-    AssertPtrReturn(pszDirectory, VERR_INVALID_POINTER);
-    /* pszFilter is optional. */
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    int rc = VERR_TOO_MUCH_DATA;
-    for (uint32_t i = 0; i < UINT32_MAX; i++)
-    {
-        /* Create a new context ID ... */
-        uint32_t uHandleTry = ASMAtomicIncU32(&mNextDirectoryID);
-        GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandleTry);
-        if (mGuestDirectoryMap.end() == it)
-        {
-            rc = VINF_SUCCESS;
-            if (!RTStrAPrintf(&mGuestDirectoryMap[uHandleTry].mpszDirectory, pszDirectory))
-                rc = VERR_NO_MEMORY;
-            else
-            {
-                /* Filter is optional. */
-                if (pszFilter)
-                {
-                    if (!RTStrAPrintf(&mGuestDirectoryMap[uHandleTry].mpszFilter, pszFilter))
-                        rc = VERR_NO_MEMORY;
-                }
-
-                if (RT_SUCCESS(rc))
-                {
-                    mGuestDirectoryMap[uHandleTry].uFlags = uFlags;
-                    *puHandle = uHandleTry;
-
-                    break;
-                }
-            }
-
-            if (RT_FAILURE(rc))
-                break;
-
-            Assert(mGuestDirectoryMap.size());
-        }
-    }
-
-    return rc;
-}
-
-void Guest::directoryDestroyHandle(uint32_t uHandle)
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
-    if (it != mGuestDirectoryMap.end())
-    {
-        RTStrFree(it->second.mpszDirectory);
-        RTStrFree(it->second.mpszFilter);
-
-        /* Remove callback context (not used anymore). */
-        mGuestDirectoryMap.erase(it);
-    }
-}
-
-uint32_t Guest::directoryGetPID(uint32_t uHandle)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
-    if (it != mGuestDirectoryMap.end())
-        return it->second.mPID;
-
-    return 0;
-}
-
-bool Guest::directoryHandleExists(uint32_t uHandle)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
-    if (it != mGuestDirectoryMap.end())
-        return true;
-
-    return false;
-}
-
-STDMETHODIMP Guest::DirectoryOpen(IN_BSTR aDirectory, IN_BSTR aFilter,
-                                  ULONG aFlags, IN_BSTR aUserName, IN_BSTR aPassword,
-                                  ULONG *aHandle)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else /* VBOX_WITH_GUEST_CONTROL */
-    using namespace guestControl;
-
-    CheckComArgStrNotEmptyOrNull(aDirectory);
-    CheckComArgNotNull(aHandle);
-
-    /* Do not allow anonymous executions (with system rights). */
-    if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
-        return setError(E_INVALIDARG, tr("No user name specified"));
-
-    return directoryOpenInternal(aDirectory, aFilter,
-                                 aFlags,
-                                 aUserName, aPassword,
-                                 aHandle, NULL /* rc */);
-#endif
-}
-
-HRESULT Guest::directoryOpenInternal(IN_BSTR aDirectory, IN_BSTR aFilter,
-                                     ULONG aFlags,
-                                     IN_BSTR aUserName, IN_BSTR aPassword,
-                                     ULONG *aHandle, int *pRC)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else /* VBOX_WITH_GUEST_CONTROL */
-    using namespace guestControl;
-
-    CheckComArgStrNotEmptyOrNull(aDirectory);
-    CheckComArgNotNull(aHandle);
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    /* Validate flags. No flags supported yet. */
-    if (aFlags != DirectoryOpenFlag_None)
-        return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
-
-    HRESULT rc = S_OK;
-    try
-    {
-        Utf8Str Utf8Directory(aDirectory);
-        Utf8Str Utf8Filter(aFilter);
-        Utf8Str Utf8UserName(aUserName);
-        Utf8Str Utf8Password(aPassword);
-
-        com::SafeArray<IN_BSTR> args;
-        com::SafeArray<IN_BSTR> env;
-
-        /*
-         * Prepare tool command line.
-         */
-
-        /* We need to get output which is machine-readable in form
-         * of "key=value\0..key=value\0\0". */
-        args.push_back(Bstr("--machinereadable").raw());
-
-        /* We want the long output format. Handy for getting a lot of
-         * details we could (should?) use (later). */
-        args.push_back(Bstr("-l").raw());
-
-        /* As we want to keep this stuff simple we don't do recursive (-R)
-         * or dereferencing (--dereference) lookups here. This has to be done by
-         * the user. */
-
-        /* Construct and hand in actual directory name + filter we want to open. */
-        char *pszDirectoryFinal;
-        int cbRet;
-        if (Utf8Filter.isEmpty())
-            cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s", Utf8Directory.c_str());
-        else
-            cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s/%s",
-                                 Utf8Directory.c_str(), Utf8Filter.c_str());
-        if (!cbRet)
-            return setError(E_OUTOFMEMORY, tr("Out of memory while allocating final directory"));
-
-        args.push_back(Bstr(pszDirectoryFinal).raw());  /* The directory we want to open. */
-
-        /*
-         * Execute guest process.
-         */
-        ComPtr<IProgress> progressExec;
-        ULONG uPID;
-
-        rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_LS).raw(),
-                            ExecuteProcessFlag_Hidden,
-                            ComSafeArrayAsInParam(args),
-                            ComSafeArrayAsInParam(env),
-                            Bstr(Utf8UserName).raw(),
-                            Bstr(Utf8Password).raw(),
-                            30 * 1000 /* Wait 30s for getting the process started. */,
-                            &uPID, progressExec.asOutParam());
-
-        RTStrFree(pszDirectoryFinal);
-
-        if (SUCCEEDED(rc))
-        {
-            /* Wait for process to exit ... */
-            rc = progressExec->WaitForCompletion(-1);
-            if (FAILED(rc)) return rc;
-
-            BOOL fCompleted = FALSE;
-            BOOL fCanceled = FALSE;
-            progressExec->COMGETTER(Completed)(&fCompleted);
-            if (!fCompleted)
-                progressExec->COMGETTER(Canceled)(&fCanceled);
-
-            if (fCompleted)
-            {
-                ExecuteProcessStatus_T retStatus;
-                ULONG uRetExitCode, uRetFlags;
-                if (SUCCEEDED(rc))
-                {
-                    rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
-                    if (SUCCEEDED(rc) && uRetExitCode != 0)
-                    {
-                        rc = setError(VBOX_E_IPRT_ERROR,
-                                      tr("Error %u while opening guest directory"), uRetExitCode);
-                    }
-                }
-            }
-            else if (fCanceled)
-                rc = setError(VBOX_E_IPRT_ERROR,
-                              tr("Guest directory opening was aborted"));
-            else
-                AssertReleaseMsgFailed(("Guest directory opening neither completed nor canceled!?\n"));
-
-            if (SUCCEEDED(rc))
-            {
-                /* Assign new directory handle ID. */
-                int vrc = directoryCreateHandle(aHandle,
-                                                Utf8Directory.c_str(),
-                                                Utf8Filter.isEmpty() ? NULL : Utf8Filter.c_str(),
-                                                aFlags);
-                if (RT_FAILURE(vrc))
-                {
-                    rc = setError(VBOX_E_IPRT_ERROR,
-                                  tr("Unable to create guest directory handle (%Rrc)"), vrc);
-                }
-            }
-        }
-    }
-    catch (std::bad_alloc &)
-    {
-        rc = E_OUTOFMEMORY;
-    }
-    return rc;
-#endif /* VBOX_WITH_GUEST_CONTROL */
-}
-
-STDMETHODIMP Guest::DirectoryRead(ULONG aHandle, IGuestDirEntry **aDirEntry)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else /* VBOX_WITH_GUEST_CONTROL */
-    using namespace guestControl;
-
-    uint32_t uPID = directoryGetPID(aHandle);
-    if (uPID)
-    {
-        SafeArray<BYTE> aOutputData;
-        ULONG cbOutputData = 0;
-
-        HRESULT rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None,
-                                            30 * 1000 /* Timeout in ms */,
-                                            _64K, ComSafeArrayAsOutParam(aOutputData));
-        if (SUCCEEDED(rc))
-        {
-
-        }
-
-        return rc;
-    }
-
-    return setError(VBOX_E_IPRT_ERROR,
-                    Guest::tr("Directory handle is invalid"));
-#endif
-}
-
-STDMETHODIMP Guest::FileExists(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else /* VBOX_WITH_GUEST_CONTROL */
-    using namespace guestControl;
-
-    CheckComArgStrNotEmptyOrNull(aFile);
-
-    /* Do not allow anonymous executions (with system rights). */
-    if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
-        return setError(E_INVALIDARG, tr("No user name specified"));
-
-    return fileExistsInternal(aFile,
-                              aUserName, aPassword, aExists,
-                              NULL /* rc */);
-#endif
-}
-
-HRESULT Guest::fileExistsInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists, int *pRC)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else /* VBOX_WITH_GUEST_CONTROL */
-    using namespace guestControl;
-
-    CheckComArgStrNotEmptyOrNull(aFile);
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    HRESULT rc = S_OK;
-    try
-    {
-        Utf8Str Utf8File(aFile);
-        Utf8Str Utf8UserName(aUserName);
-        Utf8Str Utf8Password(aPassword);
-
-        com::SafeArray<IN_BSTR> args;
-        com::SafeArray<IN_BSTR> env;
-
-        /*
-         * Prepare tool command line.
-         */
-
-        /* We need to get output which is machine-readable in form
-         * of "key=value\0..key=value\0\0". */
-        args.push_back(Bstr("--machinereadable").raw());
-
-        /* Only the actual file name to chekc is needed for now. */
-        args.push_back(Bstr(Utf8File).raw());
-
-        /*
-         * Execute guest process.
-         */
-        ComPtr<IProgress> progressExec;
-        ULONG uPID;
-
-        rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_STAT).raw(),
-                            ExecuteProcessFlag_Hidden,
-                            ComSafeArrayAsInParam(args),
-                            ComSafeArrayAsInParam(env),
-                            Bstr(Utf8UserName).raw(),
-                            Bstr(Utf8Password).raw(),
-                            30 * 1000 /* Wait 30s for getting the process started. */,
-                            &uPID, progressExec.asOutParam());
-
-        if (SUCCEEDED(rc))
-        {
-            /* Wait for process to exit ... */
-            rc = progressExec->WaitForCompletion(-1);
-            if (FAILED(rc)) return rc;
-
-            BOOL fCompleted = FALSE;
-            BOOL fCanceled = FALSE;
-            progressExec->COMGETTER(Completed)(&fCompleted);
-            if (!fCompleted)
-                progressExec->COMGETTER(Canceled)(&fCanceled);
-
-            if (fCompleted)
-            {
-                ExecuteProcessStatus_T retStatus;
-                ULONG uRetExitCode, uRetFlags;
-                if (SUCCEEDED(rc))
-                {
-                    rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
-                    if (SUCCEEDED(rc))
-                    {
-                        *aExists = uRetExitCode == 0 ? TRUE : FALSE;
-                    }
-                    else
-                        rc = setError(VBOX_E_IPRT_ERROR,
-                                      tr("Error %u while checking for existence of file \"%s\""),
-                                      uRetExitCode, Utf8File.c_str());
-                }
-            }
-            else if (fCanceled)
-                rc = setError(VBOX_E_IPRT_ERROR,
-                              tr("Checking for file existence was aborted"));
-            else
-                AssertReleaseMsgFailed(("Checking for file existence neither completed nor canceled!?\n"));
-        }
-    }
-    catch (std::bad_alloc &)
-    {
-        rc = E_OUTOFMEMORY;
-    }
-    return rc;
-#endif
-}
-
-STDMETHODIMP Guest::FileQuerySize(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else /* VBOX_WITH_GUEST_CONTROL */
-    using namespace guestControl;
-
-    CheckComArgStrNotEmptyOrNull(aFile);
-
-    /* Do not allow anonymous executions (with system rights). */
-    if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
-        return setError(E_INVALIDARG, tr("No user name specified"));
-
-    return fileQuerySizeInternal(aFile,
-                                 aUserName, aPassword, aSize,
-                                 NULL /* rc */);
-#endif
-}
-
-HRESULT Guest::fileQuerySizeInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize, int *pRC)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else /* VBOX_WITH_GUEST_CONTROL */
-    using namespace guestControl;
-
-    CheckComArgStrNotEmptyOrNull(aFile);
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    HRESULT rc = S_OK;
-    try
-    {
-        Utf8Str Utf8File(aFile);
-        Utf8Str Utf8UserName(aUserName);
-        Utf8Str Utf8Password(aPassword);
-
-        com::SafeArray<IN_BSTR> args;
-        com::SafeArray<IN_BSTR> env;
-
-        /*
-         * Prepare tool command line.
-         */
-
-        /* We need to get output which is machine-readable in form
-         * of "key=value\0..key=value\0\0". */
-        args.push_back(Bstr("--machinereadable").raw());
-
-        /* Only the actual file name to chekc is needed for now. */
-        args.push_back(Bstr(Utf8File).raw());
-
-        /*
-         * Execute guest process.
-         */
-        ComPtr<IProgress> progressExec;
-        ULONG uPID;
-
-        rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_STAT).raw(),
-                            ExecuteProcessFlag_Hidden,
-                            ComSafeArrayAsInParam(args),
-                            ComSafeArrayAsInParam(env),
-                            Bstr(Utf8UserName).raw(),
-                            Bstr(Utf8Password).raw(),
-                            30 * 1000 /* Wait 30s for getting the process started. */,
-                            &uPID, progressExec.asOutParam());
-
-        if (SUCCEEDED(rc))
-        {
-            /* Wait for process to exit ... */
-            rc = progressExec->WaitForCompletion(-1);
-            if (FAILED(rc)) return rc;
-
-            BOOL fCompleted = FALSE;
-            BOOL fCanceled = FALSE;
-            progressExec->COMGETTER(Completed)(&fCompleted);
-            if (!fCompleted)
-                progressExec->COMGETTER(Canceled)(&fCanceled);
-
-            if (fCompleted)
-            {
-                ExecuteProcessStatus_T retStatus;
-                ULONG uRetExitCode, uRetFlags;
-                if (SUCCEEDED(rc))
-                {
-                    rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
-                    if (SUCCEEDED(rc))
-                    {
-                        if (uRetExitCode == 0)
-                        {
-                            /* Get file size from output stream. */
-                            SafeArray<BYTE> aOutputData;
-                            ULONG cbOutputData = 0;
-
-                            GuestProcessStream guestStream;
-                            int vrc = VINF_SUCCESS;
-                            for (;;)
-                            {
-                                rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None,
-                                                            10 * 1000 /* Timeout in ms */,
-                                                            _64K, ComSafeArrayAsOutParam(aOutputData));
-                                /** @todo Do stream header validation! */
-                                if (   SUCCEEDED(rc)
-                                    && aOutputData.size())
-                                {
-                                    vrc = guestStream.AddData(aOutputData.raw(), aOutputData.size());
-                                    if (RT_UNLIKELY(RT_FAILURE(vrc)))
-                                        rc = setError(VBOX_E_IPRT_ERROR,
-                                                      tr("Query file size: Error while adding guest output to stream buffer for file \"%s\" (%Rrc)"),
-                                                      Utf8File.c_str(), vrc);
-                                }
-                                else /* No more output! */
-                                    break;
-                            }
-
-                            if (SUCCEEDED(rc))
-                            {
-                                vrc = guestStream.Parse();
-                                if (   RT_SUCCESS(vrc)
-                                    || vrc == VERR_MORE_DATA)
-                                {
-                                    int64_t iVal;
-                                    vrc = guestStream.GetInt64Ex("st_size", &iVal);
-                                    if (RT_SUCCESS(vrc))
-                                        *aSize = iVal;
-                                    else
-                                        rc = setError(VBOX_E_IPRT_ERROR,
-                                                      tr("Query file size: Unable to retrieve file size for file \"%s\" (%Rrc)"),
-                                                      Utf8File.c_str(), vrc);
-                                }
-                                else
-                                    rc = setError(VBOX_E_IPRT_ERROR,
-                                                  tr("Query file size: Error while parsing guest output for file \"%s\" (%Rrc)"),
-                                                  Utf8File.c_str(), vrc);
-                            }
-                        }
-                        else
-                            rc = setError(VBOX_E_IPRT_ERROR,
-                                          tr("Query file size: Error querying file size for file \"%s\" (exit code %u)"),
-                                          Utf8File.c_str(), uRetExitCode);
-                    }
-                }
-            }
-            else if (fCanceled)
-                rc = setError(VBOX_E_IPRT_ERROR,
-                              tr("Query file size: Checking for file size was aborted"));
-            else
-                AssertReleaseMsgFailed(("Checking for file size neither completed nor canceled!?\n"));
-        }
-    }
-    catch (std::bad_alloc &)
-    {
-        rc = E_OUTOFMEMORY;
-    }
-    return rc;
-#endif
-}
-
 STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ULONG aFlags, IProgress **aProgress)
 {
@@ -3648,7 +1961,7 @@
 
         /* Initialize our worker task. */
-        TaskGuest *pTask = new TaskGuest(TaskGuest::UpdateGuestAdditions, this, progress);
+        GuestTask *pTask = new GuestTask(GuestTask::TaskType_UpdateGuestAdditions, this, progress);
         AssertPtr(pTask);
-        std::auto_ptr<TaskGuest> task(pTask);
+        std::auto_ptr<GuestTask> task(pTask);
 
         /* Assign data - in that case aSource is the full path
Index: trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp	(revision 38235)
+++ trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp	(revision 38235)
@@ -0,0 +1,480 @@
+/* $Id: */
+/** @file
+ * VirtualBox Guest Control - Guest directory handling.
+ */
+
+/*
+ * Copyright (C) 2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "GuestImpl.h"
+#include "GuestCtrlImplPrivate.h"
+
+#include "Global.h"
+#include "ConsoleImpl.h"
+#include "ProgressImpl.h"
+#include "VMMDev.h"
+
+#include "AutoCaller.h"
+#include "Logging.h"
+
+#include <VBox/VMMDev.h>
+#ifdef VBOX_WITH_GUEST_CONTROL
+# include <VBox/com/array.h>
+# include <VBox/com/ErrorInfo.h>
+#endif
+
+STDMETHODIMP Guest::DirectoryClose(ULONG aHandle)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else /* VBOX_WITH_GUEST_CONTROL */
+    using namespace guestControl;
+
+    if (directoryHandleExists(aHandle))
+    {
+        directoryDestroyHandle(aHandle);
+        return S_OK;
+    }
+
+    return setError(VBOX_E_IPRT_ERROR,
+                    Guest::tr("Directory handle is invalid"));
+#endif
+}
+
+STDMETHODIMP Guest::DirectoryCreate(IN_BSTR aDirectory,
+                                    IN_BSTR aUserName, IN_BSTR aPassword,
+                                    ULONG aMode, ULONG aFlags)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else  /* VBOX_WITH_GUEST_CONTROL */
+    using namespace guestControl;
+
+    CheckComArgStrNotEmptyOrNull(aDirectory);
+
+    /* Do not allow anonymous executions (with system rights). */
+    if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
+        return setError(E_INVALIDARG, tr("No user name specified"));
+
+    LogRel(("Creating guest directory \"%s\" as  user \"%s\" ...\n",
+            Utf8Str(aDirectory).c_str(), Utf8Str(aUserName).c_str()));
+
+    return directoryCreateInternal(aDirectory,
+                                   aUserName, aPassword,
+                                   aMode, aFlags, NULL /* rc */);
+#endif
+}
+
+#ifdef VBOX_WITH_GUEST_CONTROL
+HRESULT Guest::directoryCreateInternal(IN_BSTR aDirectory,
+                                       IN_BSTR aUserName, IN_BSTR aPassword,
+                                       ULONG aMode, ULONG aFlags, int *pRC)
+{
+    using namespace guestControl;
+
+    CheckComArgStrNotEmptyOrNull(aDirectory);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    /* Validate flags. */
+    if (aFlags != DirectoryCreateFlag_None)
+    {
+        if (!(aFlags & DirectoryCreateFlag_Parents))
+        {
+            return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
+        }
+    }
+
+    HRESULT rc = S_OK;
+    try
+    {
+        Utf8Str Utf8Directory(aDirectory);
+        Utf8Str Utf8UserName(aUserName);
+        Utf8Str Utf8Password(aPassword);
+
+        com::SafeArray<IN_BSTR> args;
+        com::SafeArray<IN_BSTR> env;
+
+        /*
+         * Prepare tool command line.
+         */
+        if (aFlags & DirectoryCreateFlag_Parents)
+            args.push_back(Bstr("--parents").raw());        /* We also want to create the parent directories. */
+        if (aMode > 0)
+        {
+            args.push_back(Bstr("--mode").raw());           /* Set the creation mode. */
+
+            char szMode[16];
+            RTStrPrintf(szMode, sizeof(szMode), "%o", aMode);
+            args.push_back(Bstr(szMode).raw());
+        }
+        args.push_back(Bstr(Utf8Directory).raw());  /* The directory we want to create. */
+
+        /*
+         * Execute guest process.
+         */
+        ComPtr<IProgress> progressExec;
+        ULONG uPID;
+        if (SUCCEEDED(rc))
+        {
+            rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_MKDIR).raw(),
+                                ExecuteProcessFlag_Hidden,
+                                ComSafeArrayAsInParam(args),
+                                ComSafeArrayAsInParam(env),
+                                Bstr(Utf8UserName).raw(),
+                                Bstr(Utf8Password).raw(),
+                                5 * 1000 /* Wait 5s for getting the process started. */,
+                                &uPID, progressExec.asOutParam());
+        }
+
+        if (SUCCEEDED(rc))
+        {
+            /* Wait for process to exit ... */
+            rc = progressExec->WaitForCompletion(-1);
+            if (FAILED(rc)) return rc;
+
+            BOOL fCompleted = FALSE;
+            BOOL fCanceled = FALSE;
+            progressExec->COMGETTER(Completed)(&fCompleted);
+            if (!fCompleted)
+                progressExec->COMGETTER(Canceled)(&fCanceled);
+
+            if (fCompleted)
+            {
+                ExecuteProcessStatus_T retStatus;
+                ULONG uRetExitCode, uRetFlags;
+                if (SUCCEEDED(rc))
+                {
+                    rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
+                    if (SUCCEEDED(rc) && uRetExitCode != 0)
+                    {
+                        rc = setError(VBOX_E_IPRT_ERROR,
+                                      tr("Error %u while creating guest directory"), uRetExitCode);
+                    }
+                }
+            }
+            else if (fCanceled)
+                rc = setError(VBOX_E_IPRT_ERROR,
+                              tr("Guest directory creation was aborted"));
+            else
+                AssertReleaseMsgFailed(("Guest directory creation neither completed nor canceled!?\n"));
+        }
+    }
+    catch (std::bad_alloc &)
+    {
+        rc = E_OUTOFMEMORY;
+    }
+    return rc;
+}
+
+/**
+ * Creates a new directory handle ID and returns it. Returns VERR_TOO_MUCH_DATA
+ * if no free handles left, otherwise VINF_SUCCESS.
+ *
+ * @return IPRT status code.
+ * @param puHandle             Pointer where the handle gets stored to.
+ * @param uPID                 PID of guest process running the associated "vbox_ls".
+ * @param pszDirectory         Directory the handle is assigned to.
+ * @param pszFilter            Directory filter.  Optional.
+ * @param uFlags               Directory open flags.
+ *
+ */
+int Guest::directoryCreateHandle(ULONG *puHandle, ULONG uPID,
+                                 const char *pszDirectory, const char *pszFilter, ULONG uFlags)
+{
+    AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszDirectory, VERR_INVALID_POINTER);
+    /* pszFilter is optional. */
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    int rc = VERR_TOO_MUCH_DATA;
+    for (uint32_t i = 0; i < UINT32_MAX - 1; i++)
+    {
+        /* Create a new context ID ... */
+        uint32_t uHandleTry = ASMAtomicIncU32(&mNextDirectoryID);
+        GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandleTry);
+        if (it == mGuestDirectoryMap.end())
+        {
+            rc = VINF_SUCCESS;
+            if (!RTStrAPrintf(&mGuestDirectoryMap[uHandleTry].mpszDirectory, pszDirectory))
+                rc = VERR_NO_MEMORY;
+            else
+            {
+                /* Filter is optional. */
+                if (pszFilter)
+                {
+                    if (!RTStrAPrintf(&mGuestDirectoryMap[uHandleTry].mpszFilter, pszFilter))
+                        rc = VERR_NO_MEMORY;
+                }
+
+                if (RT_SUCCESS(rc))
+                {
+                    mGuestDirectoryMap[uHandleTry].mPID = uPID;
+                    mGuestDirectoryMap[uHandleTry].mFlags = uFlags;
+                    *puHandle = uHandleTry;
+
+                    break;
+                }
+            }
+
+            if (RT_FAILURE(rc))
+                break;
+
+            Assert(mGuestDirectoryMap.size());
+        }
+    }
+
+    return rc;
+}
+
+/**
+ * Destroys a previously created directory handle and its
+ * associated data.
+ *
+ * @return  IPRT status code.
+ * @param   uHandle             Handle to destroy.
+ */
+void Guest::directoryDestroyHandle(uint32_t uHandle)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
+    if (it != mGuestDirectoryMap.end())
+    {
+        RTStrFree(it->second.mpszDirectory);
+        RTStrFree(it->second.mpszFilter);
+
+        /* Remove callback context (not used anymore). */
+        mGuestDirectoryMap.erase(it);
+    }
+}
+
+/**
+ * Gets the associated PID from a directory handle.
+ *
+ * @return  uint32_t            Associated PID, 0 if handle not found/invalid.
+ * @param   uHandle             Directory handle to get PID for.
+ */
+uint32_t Guest::directoryGetPID(uint32_t uHandle)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
+    if (it != mGuestDirectoryMap.end())
+        return it->second.mPID;
+
+    return 0;
+}
+
+/**
+ * Checks whether a specified directory handle exists (is valid)
+ * or not.
+ *
+ * @return  bool                True if handle exists, false if not.
+ * @param   uHandle             Directory handle to check.
+ */
+bool Guest::directoryHandleExists(uint32_t uHandle)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
+    if (it != mGuestDirectoryMap.end())
+        return true;
+
+    return false;
+}
+#endif /* VBOX_WITH_GUEST_CONTROL */
+
+STDMETHODIMP Guest::DirectoryOpen(IN_BSTR aDirectory, IN_BSTR aFilter,
+                                  ULONG aFlags, IN_BSTR aUserName, IN_BSTR aPassword,
+                                  ULONG *aHandle)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else /* VBOX_WITH_GUEST_CONTROL */
+    using namespace guestControl;
+
+    CheckComArgStrNotEmptyOrNull(aDirectory);
+    CheckComArgNotNull(aHandle);
+
+    /* Do not allow anonymous executions (with system rights). */
+    if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
+        return setError(E_INVALIDARG, tr("No user name specified"));
+
+    return directoryOpenInternal(aDirectory, aFilter,
+                                 aFlags,
+                                 aUserName, aPassword,
+                                 aHandle, NULL /* rc */);
+#endif
+}
+
+#ifdef VBOX_WITH_GUEST_CONTROL
+HRESULT Guest::directoryOpenInternal(IN_BSTR aDirectory, IN_BSTR aFilter,
+                                     ULONG aFlags,
+                                     IN_BSTR aUserName, IN_BSTR aPassword,
+                                     ULONG *aHandle, int *pRC)
+{
+    using namespace guestControl;
+
+    CheckComArgStrNotEmptyOrNull(aDirectory);
+    CheckComArgNotNull(aHandle);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    /* Validate flags. No flags supported yet. */
+    if (aFlags != DirectoryOpenFlag_None)
+        return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
+
+    HRESULT rc = S_OK;
+    try
+    {
+        Utf8Str Utf8Directory(aDirectory);
+        Utf8Str Utf8Filter(aFilter);
+        Utf8Str Utf8UserName(aUserName);
+        Utf8Str Utf8Password(aPassword);
+
+        com::SafeArray<IN_BSTR> args;
+        com::SafeArray<IN_BSTR> env;
+
+        /*
+         * Prepare tool command line.
+         */
+
+        /* We need to get output which is machine-readable in form
+         * of "key=value\0..key=value\0\0". */
+        args.push_back(Bstr("--machinereadable").raw());
+
+        /* We want the long output format. Handy for getting a lot of
+         * details we could (should?) use (later). */
+        args.push_back(Bstr("-l").raw());
+
+        /* As we want to keep this stuff simple we don't do recursive (-R)
+         * or dereferencing (--dereference) lookups here. This has to be done by
+         * the user. */
+
+        /* Construct and hand in actual directory name + filter we want to open. */
+        char *pszDirectoryFinal;
+        int cbRet;
+        if (Utf8Filter.isEmpty())
+            cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s", Utf8Directory.c_str());
+        else
+            cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s/%s",
+                                 Utf8Directory.c_str(), Utf8Filter.c_str());
+        if (!cbRet)
+            return setError(E_OUTOFMEMORY, tr("Out of memory while allocating final directory"));
+
+        args.push_back(Bstr(pszDirectoryFinal).raw());  /* The directory we want to open. */
+
+        /*
+         * Execute guest process.
+         */
+        ComPtr<IProgress> progressExec;
+        ULONG uPID;
+
+        rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_LS).raw(),
+                            ExecuteProcessFlag_Hidden,
+                            ComSafeArrayAsInParam(args),
+                            ComSafeArrayAsInParam(env),
+                            Bstr(Utf8UserName).raw(),
+                            Bstr(Utf8Password).raw(),
+                            30 * 1000 /* Wait 30s for getting the process started. */,
+                            &uPID, progressExec.asOutParam());
+
+        RTStrFree(pszDirectoryFinal);
+
+        if (SUCCEEDED(rc))
+        {
+            /* Wait for process to exit ... */
+            rc = progressExec->WaitForCompletion(-1);
+            if (FAILED(rc)) return rc;
+
+            BOOL fCompleted = FALSE;
+            BOOL fCanceled = FALSE;
+            progressExec->COMGETTER(Completed)(&fCompleted);
+            if (!fCompleted)
+                progressExec->COMGETTER(Canceled)(&fCanceled);
+
+            if (fCompleted)
+            {
+                ExecuteProcessStatus_T retStatus;
+                ULONG uRetExitCode, uRetFlags;
+                if (SUCCEEDED(rc))
+                {
+                    rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
+                    if (SUCCEEDED(rc) && uRetExitCode != 0)
+                    {
+                        rc = setError(VBOX_E_IPRT_ERROR,
+                                      tr("Error %u while opening guest directory"), uRetExitCode);
+                    }
+                }
+            }
+            else if (fCanceled)
+                rc = setError(VBOX_E_IPRT_ERROR,
+                              tr("Guest directory opening was aborted"));
+            else
+                AssertReleaseMsgFailed(("Guest directory opening neither completed nor canceled!?\n"));
+
+            if (SUCCEEDED(rc))
+            {
+                /* Assign new directory handle ID. */
+                int vrc = directoryCreateHandle(aHandle, uPID,
+                                                Utf8Directory.c_str(),
+                                                Utf8Filter.isEmpty() ? NULL : Utf8Filter.c_str(),
+                                                aFlags);
+                if (RT_FAILURE(vrc))
+                {
+                    rc = setError(VBOX_E_IPRT_ERROR,
+                                  tr("Unable to create guest directory handle (%Rrc)"), vrc);
+                }
+            }
+        }
+    }
+    catch (std::bad_alloc &)
+    {
+        rc = E_OUTOFMEMORY;
+    }
+    return rc;
+}
+#endif /* VBOX_WITH_GUEST_CONTROL */
+
+STDMETHODIMP Guest::DirectoryRead(ULONG aHandle, IGuestDirEntry **aDirEntry)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else /* VBOX_WITH_GUEST_CONTROL */
+    using namespace guestControl;
+
+    uint32_t uPID = directoryGetPID(aHandle);
+    if (uPID)
+    {
+        SafeArray<BYTE> aOutputData;
+        ULONG cbOutputData = 0;
+
+        HRESULT rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None,
+                                            30 * 1000 /* Timeout in ms */,
+                                            _64K, ComSafeArrayAsOutParam(aOutputData));
+        if (SUCCEEDED(rc))
+        {
+
+        }
+
+        return rc;
+    }
+
+    return setError(VBOX_E_IPRT_ERROR,
+                    Guest::tr("Directory handle is invalid"));
+#endif
+}
+
Index: trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp	(revision 38235)
+++ trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp	(revision 38235)
@@ -0,0 +1,299 @@
+/* $Id: */
+/** @file
+ * VirtualBox Guest Control - Guest file handling.
+ */
+
+/*
+ * Copyright (C) 2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "GuestImpl.h"
+#include "GuestCtrlImplPrivate.h"
+
+#include "Global.h"
+#include "ConsoleImpl.h"
+#include "ProgressImpl.h"
+#include "VMMDev.h"
+
+#include "AutoCaller.h"
+#include "Logging.h"
+
+#include <VBox/VMMDev.h>
+#ifdef VBOX_WITH_GUEST_CONTROL
+# include <VBox/com/array.h>
+# include <VBox/com/ErrorInfo.h>
+#endif
+
+STDMETHODIMP Guest::FileExists(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else /* VBOX_WITH_GUEST_CONTROL */
+    using namespace guestControl;
+
+    CheckComArgStrNotEmptyOrNull(aFile);
+
+    /* Do not allow anonymous executions (with system rights). */
+    if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
+        return setError(E_INVALIDARG, tr("No user name specified"));
+
+    return fileExistsInternal(aFile,
+                              aUserName, aPassword, aExists,
+                              NULL /* rc */);
+#endif
+}
+
+#ifdef VBOX_WITH_GUEST_CONTROL
+HRESULT Guest::fileExistsInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists, int *pRC)
+{
+    using namespace guestControl;
+
+    CheckComArgStrNotEmptyOrNull(aFile);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    HRESULT rc = S_OK;
+    try
+    {
+        Utf8Str Utf8File(aFile);
+        Utf8Str Utf8UserName(aUserName);
+        Utf8Str Utf8Password(aPassword);
+
+        com::SafeArray<IN_BSTR> args;
+        com::SafeArray<IN_BSTR> env;
+
+        /*
+         * Prepare tool command line.
+         */
+
+        /* We need to get output which is machine-readable in form
+         * of "key=value\0..key=value\0\0". */
+        args.push_back(Bstr("--machinereadable").raw());
+
+        /* Only the actual file name to chekc is needed for now. */
+        args.push_back(Bstr(Utf8File).raw());
+
+        /*
+         * Execute guest process.
+         */
+        ComPtr<IProgress> progressExec;
+        ULONG uPID;
+
+        rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_STAT).raw(),
+                            ExecuteProcessFlag_Hidden,
+                            ComSafeArrayAsInParam(args),
+                            ComSafeArrayAsInParam(env),
+                            Bstr(Utf8UserName).raw(),
+                            Bstr(Utf8Password).raw(),
+                            30 * 1000 /* Wait 30s for getting the process started. */,
+                            &uPID, progressExec.asOutParam());
+
+        if (SUCCEEDED(rc))
+        {
+            /* Wait for process to exit ... */
+            rc = progressExec->WaitForCompletion(-1);
+            if (FAILED(rc)) return rc;
+
+            BOOL fCompleted = FALSE;
+            BOOL fCanceled = FALSE;
+            progressExec->COMGETTER(Completed)(&fCompleted);
+            if (!fCompleted)
+                progressExec->COMGETTER(Canceled)(&fCanceled);
+
+            if (fCompleted)
+            {
+                ExecuteProcessStatus_T retStatus;
+                ULONG uRetExitCode, uRetFlags;
+                if (SUCCEEDED(rc))
+                {
+                    rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
+                    if (SUCCEEDED(rc))
+                    {
+                        *aExists = uRetExitCode == 0 ? TRUE : FALSE;
+                    }
+                    else
+                        rc = setError(VBOX_E_IPRT_ERROR,
+                                      tr("Error %u while checking for existence of file \"%s\""),
+                                      uRetExitCode, Utf8File.c_str());
+                }
+            }
+            else if (fCanceled)
+                rc = setError(VBOX_E_IPRT_ERROR,
+                              tr("Checking for file existence was aborted"));
+            else
+                AssertReleaseMsgFailed(("Checking for file existence neither completed nor canceled!?\n"));
+        }
+    }
+    catch (std::bad_alloc &)
+    {
+        rc = E_OUTOFMEMORY;
+    }
+    return rc;
+}
+#endif /* VBOX_WITH_GUEST_CONTROL */
+
+STDMETHODIMP Guest::FileQuerySize(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else /* VBOX_WITH_GUEST_CONTROL */
+    using namespace guestControl;
+
+    CheckComArgStrNotEmptyOrNull(aFile);
+
+    /* Do not allow anonymous executions (with system rights). */
+    if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
+        return setError(E_INVALIDARG, tr("No user name specified"));
+
+    return fileQuerySizeInternal(aFile,
+                                 aUserName, aPassword, aSize,
+                                 NULL /* rc */);
+#endif
+}
+
+#ifdef VBOX_WITH_GUEST_CONTROL
+HRESULT Guest::fileQuerySizeInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize, int *pRC)
+{
+    using namespace guestControl;
+
+    CheckComArgStrNotEmptyOrNull(aFile);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    HRESULT rc = S_OK;
+    try
+    {
+        Utf8Str Utf8File(aFile);
+        Utf8Str Utf8UserName(aUserName);
+        Utf8Str Utf8Password(aPassword);
+
+        com::SafeArray<IN_BSTR> args;
+        com::SafeArray<IN_BSTR> env;
+
+        /*
+         * Prepare tool command line.
+         */
+
+        /* We need to get output which is machine-readable in form
+         * of "key=value\0..key=value\0\0". */
+        args.push_back(Bstr("--machinereadable").raw());
+
+        /* Only the actual file name to chekc is needed for now. */
+        args.push_back(Bstr(Utf8File).raw());
+
+        /*
+         * Execute guest process.
+         */
+        ComPtr<IProgress> progressExec;
+        ULONG uPID;
+
+        rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_STAT).raw(),
+                            ExecuteProcessFlag_Hidden,
+                            ComSafeArrayAsInParam(args),
+                            ComSafeArrayAsInParam(env),
+                            Bstr(Utf8UserName).raw(),
+                            Bstr(Utf8Password).raw(),
+                            30 * 1000 /* Wait 30s for getting the process started. */,
+                            &uPID, progressExec.asOutParam());
+
+        if (SUCCEEDED(rc))
+        {
+            /* Wait for process to exit ... */
+            rc = progressExec->WaitForCompletion(-1);
+            if (FAILED(rc)) return rc;
+
+            BOOL fCompleted = FALSE;
+            BOOL fCanceled = FALSE;
+            progressExec->COMGETTER(Completed)(&fCompleted);
+            if (!fCompleted)
+                progressExec->COMGETTER(Canceled)(&fCanceled);
+
+            if (fCompleted)
+            {
+                ExecuteProcessStatus_T retStatus;
+                ULONG uRetExitCode, uRetFlags;
+                if (SUCCEEDED(rc))
+                {
+                    rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
+                    if (SUCCEEDED(rc))
+                    {
+                        if (uRetExitCode == 0)
+                        {
+                            /* Get file size from output stream. */
+                            SafeArray<BYTE> aOutputData;
+                            ULONG cbOutputData = 0;
+
+                            GuestProcessStream guestStream;
+                            int vrc = VINF_SUCCESS;
+                            for (;;)
+                            {
+                                rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None,
+                                                            10 * 1000 /* Timeout in ms */,
+                                                            _64K, ComSafeArrayAsOutParam(aOutputData));
+                                /** @todo Do stream header validation! */
+                                if (   SUCCEEDED(rc)
+                                    && aOutputData.size())
+                                {
+                                    vrc = guestStream.AddData(aOutputData.raw(), aOutputData.size());
+                                    if (RT_UNLIKELY(RT_FAILURE(vrc)))
+                                        rc = setError(VBOX_E_IPRT_ERROR,
+                                                      tr("Query file size: Error while adding guest output to stream buffer for file \"%s\" (%Rrc)"),
+                                                      Utf8File.c_str(), vrc);
+                                }
+                                else /* No more output! */
+                                    break;
+                            }
+
+                            if (SUCCEEDED(rc))
+                            {
+                                vrc = guestStream.ParseBlock(); /* We only need one (the first) block. */
+                                if (   RT_SUCCESS(vrc)
+                                    || vrc == VERR_MORE_DATA)
+                                {
+                                    int64_t iVal;
+                                    vrc = guestStream.GetInt64Ex("st_size", &iVal);
+                                    if (RT_SUCCESS(vrc))
+                                        *aSize = iVal;
+                                    else
+                                        rc = setError(VBOX_E_IPRT_ERROR,
+                                                      tr("Query file size: Unable to retrieve file size for file \"%s\" (%Rrc)"),
+                                                      Utf8File.c_str(), vrc);
+                                }
+                                else
+                                    rc = setError(VBOX_E_IPRT_ERROR,
+                                                  tr("Query file size: Error while parsing guest output for file \"%s\" (%Rrc)"),
+                                                  Utf8File.c_str(), vrc);
+                            }
+                        }
+                        else
+                            rc = setError(VBOX_E_IPRT_ERROR,
+                                          tr("Query file size: Error querying file size for file \"%s\" (exit code %u)"),
+                                          Utf8File.c_str(), uRetExitCode);
+                    }
+                }
+            }
+            else if (fCanceled)
+                rc = setError(VBOX_E_IPRT_ERROR,
+                              tr("Query file size: Checking for file size was aborted"));
+            else
+                AssertReleaseMsgFailed(("Checking for file size neither completed nor canceled!?\n"));
+        }
+    }
+    catch (std::bad_alloc &)
+    {
+        rc = E_OUTOFMEMORY;
+    }
+    return rc;
+}
+#endif /* VBOX_WITH_GUEST_CONTROL */
+
Index: trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp	(revision 38235)
+++ trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp	(revision 38235)
@@ -0,0 +1,997 @@
+/* $Id: */
+/** @file
+ * VirtualBox Guest Control - Threaded operations (tasks).
+ */
+
+/*
+ * Copyright (C) 2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "GuestImpl.h"
+#include "GuestCtrlImplPrivate.h"
+
+#include "Global.h"
+#include "ConsoleImpl.h"
+#include "ProgressImpl.h"
+#include "VMMDev.h"
+
+#include "AutoCaller.h"
+#include "Logging.h"
+
+#include <VBox/VMMDev.h>
+#ifdef VBOX_WITH_GUEST_CONTROL
+# include <VBox/com/array.h>
+# include <VBox/com/ErrorInfo.h>
+#endif
+
+#include <iprt/file.h>
+#include <iprt/isofs.h>
+#include <iprt/list.h>
+#include <iprt/path.h>
+
+GuestTask::GuestTask(TaskType aTaskType, Guest *aThat, Progress *aProgress)
+    : taskType(aTaskType),
+      pGuest(aThat),
+      progress(aProgress),
+      rc(S_OK)
+{
+
+}
+
+GuestTask::~GuestTask()
+{
+
+}
+
+int GuestTask::startThread()
+{
+    return RTThreadCreate(NULL, GuestTask::taskThread, this,
+                          0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
+                          "GuestTask");
+}
+
+/* static */
+DECLCALLBACK(int) GuestTask::taskThread(RTTHREAD /* aThread */, void *pvUser)
+{
+    std::auto_ptr<GuestTask> task(static_cast<GuestTask*>(pvUser));
+    AssertReturn(task.get(), VERR_GENERAL_FAILURE);
+
+    Guest *pGuest = task->pGuest;
+
+    LogFlowFuncEnter();
+    LogFlowFunc(("Guest %p\n", pGuest));
+
+    HRESULT rc = S_OK;
+
+    switch (task->taskType)
+    {
+#ifdef VBOX_WITH_GUEST_CONTROL
+        case TaskType_CopyFileToGuest:
+        {
+            rc = pGuest->taskCopyFileToGuest(task.get());
+            break;
+        }
+        case TaskType_CopyFileFromGuest:
+        {
+            rc = pGuest->taskCopyFileFromGuest(task.get());
+            break;
+        }
+        case TaskType_UpdateGuestAdditions:
+        {
+            rc = pGuest->taskUpdateGuestAdditions(task.get());
+            break;
+        }
+#endif
+        default:
+            AssertMsgFailed(("Invalid task type %u specified!\n", task->taskType));
+            break;
+    }
+
+    LogFlowFunc(("rc=%Rhrc\n", rc));
+    LogFlowFuncLeave();
+
+    return VINF_SUCCESS;
+}
+
+/* static */
+int GuestTask::uploadProgress(unsigned uPercent, void *pvUser)
+{
+    GuestTask *pTask = *(GuestTask**)pvUser;
+
+    if (    pTask
+        && !pTask->progress.isNull())
+    {
+        BOOL fCanceled;
+        pTask->progress->COMGETTER(Canceled)(&fCanceled);
+        if (fCanceled)
+            return -1;
+        pTask->progress->SetCurrentOperationProgress(uPercent);
+    }
+    return VINF_SUCCESS;
+}
+
+/* static */
+HRESULT GuestTask::setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress,
+                                               const char *pszText, ...)
+{
+    BOOL fCanceled;
+    BOOL fCompleted;
+    if (   SUCCEEDED(pProgress->COMGETTER(Canceled(&fCanceled)))
+        && !fCanceled
+        && SUCCEEDED(pProgress->COMGETTER(Completed(&fCompleted)))
+        && !fCompleted)
+    {
+        va_list va;
+        va_start(va, pszText);
+        HRESULT hr2 = pProgress->notifyCompleteV(hr,
+                                                 COM_IIDOF(IGuest),
+                                                 Guest::getStaticComponentName(),
+                                                 pszText,
+                                                 va);
+        va_end(va);
+        if (hr2 == S_OK) /* If unable to retrieve error, return input error. */
+            hr2 = hr;
+        return hr2;
+    }
+    return S_OK;
+}
+
+/* static */
+HRESULT GuestTask::setProgressErrorInfo(HRESULT hr,
+                                        ComObjPtr<Progress> pProgress, ComObjPtr<Guest> pGuest)
+{
+    return setProgressErrorInfo(hr, pProgress,
+                                Utf8Str(com::ErrorInfo((IGuest*)pGuest, COM_IIDOF(IGuest)).getText()).c_str());
+}
+
+#ifdef VBOX_WITH_GUEST_CONTROL
+HRESULT Guest::taskCopyFileToGuest(GuestTask *aTask)
+{
+    LogFlowFuncEnter();
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    /*
+     * Do *not* take a write lock here since we don't (and won't)
+     * touch any class-specific data (of IGuest) here - only the member functions
+     * which get called here can do that.
+     */
+
+    HRESULT rc = S_OK;
+
+    try
+    {
+        Guest *pGuest = aTask->pGuest;
+        AssertPtr(pGuest);
+
+        /* Does our source file exist? */
+        if (!RTFileExists(aTask->strSource.c_str()))
+        {
+            rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                 Guest::tr("Source file \"%s\" does not exist, or is not a file"),
+                                                 aTask->strSource.c_str());
+        }
+        else
+        {
+            RTFILE fileSource;
+            int vrc = RTFileOpen(&fileSource, aTask->strSource.c_str(),
+                                 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
+            if (RT_FAILURE(vrc))
+            {
+                rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                     Guest::tr("Could not open source file \"%s\" for reading (%Rrc)"),
+                                                     aTask->strSource.c_str(),  vrc);
+            }
+            else
+            {
+                uint64_t cbSize;
+                vrc = RTFileGetSize(fileSource, &cbSize);
+                if (RT_FAILURE(vrc))
+                {
+                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                         Guest::tr("Could not query file size of \"%s\" (%Rrc)"),
+                                                         aTask->strSource.c_str(), vrc);
+                }
+                else
+                {
+                    com::SafeArray<IN_BSTR> args;
+                    com::SafeArray<IN_BSTR> env;
+
+                    /*
+                     * Prepare tool command line.
+                     */
+                    char szOutput[RTPATH_MAX];
+                    if (RTStrPrintf(szOutput, sizeof(szOutput), "--output=%s", aTask->strDest.c_str()) <= sizeof(szOutput) - 1)
+                    {
+                        /*
+                         * Normalize path slashes, based on the detected guest.
+                         */
+                        Utf8Str osType = mData.mOSTypeId;
+                        if (   osType.contains("Microsoft", Utf8Str::CaseInsensitive)
+                            || osType.contains("Windows", Utf8Str::CaseInsensitive))
+                        {
+                            /* We have a Windows guest. */
+                            RTPathChangeToDosSlashes(szOutput, true /* Force conversion. */);
+                        }
+                        else /* ... or something which isn't from Redmond ... */
+                        {
+                            RTPathChangeToUnixSlashes(szOutput, true /* Force conversion. */);
+                        }
+
+                        args.push_back(Bstr(szOutput).raw());             /* We want to write a file ... */
+                    }
+                    else
+                    {
+                        rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                             Guest::tr("Error preparing command line"));
+                    }
+
+                    ComPtr<IProgress> execProgress;
+                    ULONG uPID;
+                    if (SUCCEEDED(rc))
+                    {
+                        LogRel(("Copying file \"%s\" to guest \"%s\" (%u bytes) ...\n",
+                                aTask->strSource.c_str(), aTask->strDest.c_str(), cbSize));
+                        /*
+                         * Okay, since we gathered all stuff we need until now to start the
+                         * actual copying, start the guest part now.
+                         */
+                        rc = pGuest->ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
+                                                      ExecuteProcessFlag_Hidden
+                                                    | ExecuteProcessFlag_WaitForProcessStartOnly,
+                                                    ComSafeArrayAsInParam(args),
+                                                    ComSafeArrayAsInParam(env),
+                                                    Bstr(aTask->strUserName).raw(),
+                                                    Bstr(aTask->strPassword).raw(),
+                                                    5 * 1000 /* Wait 5s for getting the process started. */,
+                                                    &uPID, execProgress.asOutParam());
+                        if (FAILED(rc))
+                            rc = GuestTask::setProgressErrorInfo(rc, aTask->progress, pGuest);
+                    }
+
+                    if (SUCCEEDED(rc))
+                    {
+                        BOOL fCompleted = FALSE;
+                        BOOL fCanceled = FALSE;
+
+                        size_t cbToRead = cbSize;
+                        size_t cbTransfered = 0;
+                        size_t cbRead;
+                        SafeArray<BYTE> aInputData(_64K);
+                        while (   SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted)))
+                               && !fCompleted)
+                        {
+                            if (!cbToRead)
+                                cbRead = 0;
+                            else
+                            {
+                                vrc = RTFileRead(fileSource, (uint8_t*)aInputData.raw(),
+                                                 RT_MIN(cbToRead, _64K), &cbRead);
+                                /*
+                                 * Some other error occured? There might be a chance that RTFileRead
+                                 * could not resolve/map the native error code to an IPRT code, so just
+                                 * print a generic error.
+                                 */
+                                if (RT_FAILURE(vrc))
+                                {
+                                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                                         Guest::tr("Could not read from file \"%s\" (%Rrc)"),
+                                                                         aTask->strSource.c_str(), vrc);
+                                    break;
+                                }
+                            }
+
+                            /* Resize buffer to reflect amount we just have read.
+                             * Size 0 is allowed! */
+                            aInputData.resize(cbRead);
+
+                            ULONG uFlags = ProcessInputFlag_None;
+                            /* Did we reach the end of the content we want to transfer (last chunk)? */
+                            if (   (cbRead < _64K)
+                                /* Did we reach the last block which is exactly _64K? */
+                                || (cbToRead - cbRead == 0)
+                                /* ... or does the user want to cancel? */
+                                || (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
+                                    && fCanceled)
+                               )
+                            {
+                                uFlags |= ProcessInputFlag_EndOfFile;
+                            }
+
+                            /* Transfer the current chunk ... */
+                            ULONG uBytesWritten;
+                            rc = pGuest->SetProcessInput(uPID, uFlags,
+                                                         10 * 1000 /* Wait 10s for getting the input data transfered. */,
+                                                         ComSafeArrayAsInParam(aInputData), &uBytesWritten);
+                            if (FAILED(rc))
+                            {
+                                rc = GuestTask::setProgressErrorInfo(rc, aTask->progress, pGuest);
+                                break;
+                            }
+
+                            Assert(cbRead <= cbToRead);
+                            Assert(cbToRead >= cbRead);
+                            cbToRead -= cbRead;
+
+                            cbTransfered += uBytesWritten;
+                            Assert(cbTransfered <= cbSize);
+                            aTask->progress->SetCurrentOperationProgress(cbTransfered / (cbSize / 100.0));
+
+                            /* End of file reached? */
+                            if (cbToRead == 0)
+                                break;
+
+                            /* Did the user cancel the operation above? */
+                            if (fCanceled)
+                                break;
+
+                            /* Progress canceled by Main API? */
+                            if (   SUCCEEDED(execProgress->COMGETTER(Canceled(&fCanceled)))
+                                && fCanceled)
+                            {
+                                rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                                     Guest::tr("Copy operation of file \"%s\" was canceled on guest side"),
+                                                                     aTask->strSource.c_str());
+                                break;
+                            }
+                        }
+
+                        if (SUCCEEDED(rc))
+                        {
+                            /*
+                             * If we got here this means the started process either was completed,
+                             * canceled or we simply got all stuff transferred.
+                             */
+                            ExecuteProcessStatus_T retStatus;
+                            ULONG uRetExitCode;
+                            rc = pGuest->waitForProcessStatusChange(uPID, &retStatus, &uRetExitCode, 10 * 1000 /* 10s timeout. */);
+                            if (FAILED(rc))
+                            {
+                                rc = GuestTask::setProgressErrorInfo(rc, aTask->progress, pGuest);
+                            }
+                            else
+                            {
+                                if (   uRetExitCode != 0
+                                    || retStatus    != ExecuteProcessStatus_TerminatedNormally)
+                                {
+                                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                                         Guest::tr("Guest reported error %u while copying file \"%s\" to \"%s\""),
+                                                                         uRetExitCode, aTask->strSource.c_str(), aTask->strDest.c_str());
+                                }
+                            }
+                        }
+
+                        if (SUCCEEDED(rc))
+                        {
+                            if (fCanceled)
+                            {
+                                /*
+                                 * In order to make the progress object to behave nicely, we also have to
+                                 * notify the object with a complete event when it's canceled.
+                                 */
+                                aTask->progress->notifyComplete(VBOX_E_IPRT_ERROR,
+                                                                COM_IIDOF(IGuest),
+                                                                Guest::getStaticComponentName(),
+                                                                Guest::tr("Copying file \"%s\" canceled"), aTask->strSource.c_str());
+                            }
+                            else
+                            {
+                                /*
+                                 * Even if we succeeded until here make sure to check whether we really transfered
+                                 * everything.
+                                 */
+                                if (   cbSize > 0
+                                    && cbTransfered == 0)
+                                {
+                                    /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
+                                     * to the destination -> access denied. */
+                                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                                         Guest::tr("Access denied when copying file \"%s\" to \"%s\""),
+                                                                         aTask->strSource.c_str(), aTask->strDest.c_str());
+                                }
+                                else if (cbTransfered < cbSize)
+                                {
+                                    /* If we did not copy all let the user know. */
+                                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                                         Guest::tr("Copying file \"%s\" failed (%u/%u bytes transfered)"),
+                                                                         aTask->strSource.c_str(), cbTransfered, cbSize);
+                                }
+                                else /* Yay, all went fine! */
+                                    aTask->progress->notifyComplete(S_OK);
+                            }
+                        }
+                    }
+                }
+                RTFileClose(fileSource);
+            }
+        }
+    }
+    catch (HRESULT aRC)
+    {
+        rc = aRC;
+    }
+
+    /* Clean up */
+    aTask->rc = rc;
+
+    LogFlowFunc(("rc=%Rhrc\n", rc));
+    LogFlowFuncLeave();
+
+    return VINF_SUCCESS;
+}
+
+HRESULT Guest::taskCopyFileFromGuest(GuestTask *aTask)
+{
+    LogFlowFuncEnter();
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    /*
+     * Do *not* take a write lock here since we don't (and won't)
+     * touch any class-specific data (of IGuest) here - only the member functions
+     * which get called here can do that.
+     */
+
+    HRESULT rc = S_OK;
+
+    try
+    {
+        Guest *pGuest = aTask->pGuest;
+        AssertPtr(pGuest);
+
+        /* Does our source file exist? */
+        BOOL fFileExists;
+        rc = pGuest->FileExists(Bstr(aTask->strSource).raw(),
+                                Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(),
+                                &fFileExists);
+        if (SUCCEEDED(rc))
+        {
+            if (!fFileExists)
+                rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                     Guest::tr("Source file \"%s\" does not exist, or is not a file"),
+                                                     aTask->strSource.c_str());
+        }
+
+        /* Query file size to make an estimate for our progress object. */
+        if (SUCCEEDED(rc))
+        {
+            LONG64 lFileSize;
+            rc = pGuest->FileQuerySize(Bstr(aTask->strSource).raw(),
+                                       Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(),
+                                       &lFileSize);
+            if (FAILED(rc))
+                rc = GuestTask::setProgressErrorInfo(rc, aTask->progress, pGuest);
+
+            com::SafeArray<IN_BSTR> args;
+            com::SafeArray<IN_BSTR> env;
+
+            if (SUCCEEDED(rc))
+            {
+                /*
+                 * Prepare tool command line.
+                 */
+                char szSource[RTPATH_MAX];
+                if (RTStrPrintf(szSource, sizeof(szSource), "%s", aTask->strSource.c_str()) <= sizeof(szSource) - 1)
+                {
+                    /*
+                     * Normalize path slashes, based on the detected guest.
+                     */
+                    Utf8Str osType = mData.mOSTypeId;
+                    if (   osType.contains("Microsoft", Utf8Str::CaseInsensitive)
+                        || osType.contains("Windows", Utf8Str::CaseInsensitive))
+                    {
+                        /* We have a Windows guest. */
+                        RTPathChangeToDosSlashes(szSource, true /* Force conversion. */);
+                    }
+                    else /* ... or something which isn't from Redmond ... */
+                    {
+                        RTPathChangeToUnixSlashes(szSource, true /* Force conversion. */);
+                    }
+
+                    args.push_back(Bstr(szSource).raw()); /* Tell our cat tool which file to output. */
+                }
+                else
+                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                         Guest::tr("Error preparing command line"));
+            }
+
+            ComPtr<IProgress> execProgress;
+            ULONG uPID;
+            if (SUCCEEDED(rc))
+            {
+                LogRel(("Copying file \"%s\" to host \"%s\" (%u bytes) ...\n",
+                        aTask->strSource.c_str(), aTask->strDest.c_str(), lFileSize));
+
+                /*
+                 * Okay, since we gathered all stuff we need until now to start the
+                 * actual copying, start the guest part now.
+                 */
+                rc = pGuest->ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
+                                            ExecuteProcessFlag_Hidden,
+                                            ComSafeArrayAsInParam(args),
+                                            ComSafeArrayAsInParam(env),
+                                            Bstr(aTask->strUserName).raw(),
+                                            Bstr(aTask->strPassword).raw(),
+                                            5 * 1000 /* Wait 5s for getting the process started. */,
+                                            &uPID, execProgress.asOutParam());
+                if (FAILED(rc))
+                    rc = GuestTask::setProgressErrorInfo(rc, aTask->progress, pGuest);
+            }
+
+            if (SUCCEEDED(rc))
+            {
+                BOOL fCompleted = FALSE;
+                BOOL fCanceled = FALSE;
+
+                RTFILE hFileDest;
+                int vrc = RTFileOpen(&hFileDest, aTask->strDest.c_str(),
+                                     RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
+                if (RT_FAILURE(vrc))
+                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                         Guest::tr("Unable to create/open destination file \"%s\", rc=%Rrc"),
+                                                         aTask->strDest.c_str(), vrc);
+                else
+                {
+                    size_t cbToRead = lFileSize;
+                    size_t cbTransfered = 0;
+                    SafeArray<BYTE> aOutputData(_64K);
+                    while (SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted))))
+                    {
+                        rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None,
+                                                    10 * 1000 /* Timeout in ms */,
+                                                    _64K, ComSafeArrayAsOutParam(aOutputData));
+                        if (SUCCEEDED(rc))
+                        {
+                            if (!aOutputData.size())
+                            {
+                                if (cbToRead)
+                                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                                         Guest::tr("Unexpected end of file \"%s\" (%u bytes left)"),
+                                                                         aTask->strSource.c_str(), cbToRead);
+                                break;
+                            }
+
+                            vrc = RTFileWrite(hFileDest, aOutputData.raw(), aOutputData.size(), NULL /* No partial writes */);
+                            if (RT_FAILURE(vrc))
+                            {
+                                rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                                     Guest::tr("Error writing to file \"%s\" (%u bytes left), rc=%Rrc"),
+                                                                     aTask->strSource.c_str(), cbToRead, vrc);
+                                break;
+                            }
+
+                            cbToRead -= aOutputData.size();
+                            cbTransfered += aOutputData.size();
+
+                            aTask->progress->SetCurrentOperationProgress(cbTransfered / (lFileSize / 100.0));
+                        }
+                        else
+                        {
+                            rc = GuestTask::setProgressErrorInfo(rc, aTask->progress, pGuest);
+                            break;
+                        }
+                    }
+
+                    if (SUCCEEDED(rc))
+                        aTask->progress->notifyComplete(S_OK);
+
+                    RTFileClose(hFileDest);
+                }
+            }
+        }
+    }
+    catch (HRESULT aRC)
+    {
+        rc = aRC;
+    }
+
+    /* Clean up */
+    aTask->rc = rc;
+
+    LogFlowFunc(("rc=%Rhrc\n", rc));
+    LogFlowFuncLeave();
+
+    return VINF_SUCCESS;
+}
+
+HRESULT Guest::taskUpdateGuestAdditions(GuestTask *aTask)
+{
+    LogFlowFuncEnter();
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    /*
+     * Do *not* take a write lock here since we don't (and won't)
+     * touch any class-specific data (of IGuest) here - only the member functions
+     * which get called here can do that.
+     */
+
+    HRESULT rc = S_OK;
+    BOOL fCompleted;
+    BOOL fCanceled;
+
+    try
+    {
+        Guest *pGuest = aTask->pGuest;
+        AssertPtr(pGuest);
+
+        aTask->progress->SetCurrentOperationProgress(10);
+
+        /*
+         * Determine guest OS type and the required installer image.
+         * At the moment only Windows guests are supported.
+         */
+        Utf8Str installerImage;
+        Bstr osTypeId;
+        if (   SUCCEEDED(pGuest->COMGETTER(OSTypeId(osTypeId.asOutParam())))
+            && !osTypeId.isEmpty())
+        {
+            Utf8Str osTypeIdUtf8(osTypeId); /* Needed for .contains(). */
+            if (   osTypeIdUtf8.contains("Microsoft", Utf8Str::CaseInsensitive)
+                || osTypeIdUtf8.contains("Windows", Utf8Str::CaseInsensitive))
+            {
+                if (osTypeIdUtf8.contains("64", Utf8Str::CaseInsensitive))
+                    installerImage = "VBOXWINDOWSADDITIONS_AMD64.EXE";
+                else
+                    installerImage = "VBOXWINDOWSADDITIONS_X86.EXE";
+                /* Since the installers are located in the root directory,
+                 * no further path processing needs to be done (yet). */
+            }
+            else /* Everything else is not supported (yet). */
+                throw GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
+                                                      Guest::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"),
+                                                      osTypeIdUtf8.c_str());
+        }
+        else
+            throw GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
+                                                  Guest::tr("Could not detected guest OS type/version, please update manually"));
+        Assert(!installerImage.isEmpty());
+
+        /*
+         * Try to open the .ISO file and locate the specified installer.
+         */
+        RTISOFSFILE iso;
+        int vrc = RTIsoFsOpen(&iso, aTask->strSource.c_str());
+        if (RT_FAILURE(vrc))
+        {
+            rc = GuestTask::setProgressErrorInfo(VBOX_E_FILE_ERROR, aTask->progress,
+                                                 Guest::tr("Invalid installation medium detected: \"%s\""),
+                                                 aTask->strSource.c_str());
+        }
+        else
+        {
+            uint32_t cbOffset;
+            size_t cbLength;
+            vrc = RTIsoFsGetFileInfo(&iso, installerImage.c_str(), &cbOffset, &cbLength);
+            if (   RT_SUCCESS(vrc)
+                && cbOffset
+                && cbLength)
+            {
+                vrc = RTFileSeek(iso.file, cbOffset, RTFILE_SEEK_BEGIN, NULL);
+                if (RT_FAILURE(vrc))
+                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                         Guest::tr("Could not seek to setup file on installation medium \"%s\" (%Rrc)"),
+                                                         aTask->strSource.c_str(), vrc);
+            }
+            else
+            {
+                switch (vrc)
+                {
+                    case VERR_FILE_NOT_FOUND:
+                        rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                             Guest::tr("Setup file was not found on installation medium \"%s\""),
+                                                             aTask->strSource.c_str());
+                        break;
+
+                    default:
+                        rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                             Guest::tr("An unknown error (%Rrc) occured while retrieving information of setup file on installation medium \"%s\""),
+                                                             vrc, aTask->strSource.c_str());
+                        break;
+                }
+            }
+
+            /* Specify the ouput path on the guest side. */
+            Utf8Str strInstallerPath = "%TEMP%\\VBoxWindowsAdditions.exe";
+
+            if (RT_SUCCESS(vrc))
+            {
+                /* Okay, we're ready to start our copy routine on the guest! */
+                aTask->progress->SetCurrentOperationProgress(15);
+
+                /* Prepare command line args. */
+                com::SafeArray<IN_BSTR> args;
+                com::SafeArray<IN_BSTR> env;
+
+                args.push_back(Bstr("--output").raw());               /* We want to write a file ... */
+                args.push_back(Bstr(strInstallerPath.c_str()).raw()); /* ... with this path. */
+
+                if (SUCCEEDED(rc))
+                {
+                    ComPtr<IProgress> progressCat;
+                    ULONG uPID;
+
+                    /*
+                     * Start built-in "vbox_cat" tool (inside VBoxService) to
+                     * copy over/pipe the data into a file on the guest (with
+                     * system rights, no username/password specified).
+                     */
+                    rc = pGuest->executeProcessInternal(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
+                                                          ExecuteProcessFlag_Hidden
+                                                        | ExecuteProcessFlag_WaitForProcessStartOnly,
+                                                        ComSafeArrayAsInParam(args),
+                                                        ComSafeArrayAsInParam(env),
+                                                        Bstr("").raw() /* Username. */,
+                                                        Bstr("").raw() /* Password */,
+                                                        5 * 1000 /* Wait 5s for getting the process started. */,
+                                                        &uPID, progressCat.asOutParam(), &vrc);
+                    if (FAILED(rc))
+                    {
+                        /* Errors which return VBOX_E_NOT_SUPPORTED can be safely skipped by the caller
+                         * to silently fall back to "normal" (old) .ISO mounting. */
+
+                        /* Due to a very limited COM error range we use vrc for a more detailed error
+                         * lookup to figure out what went wrong. */
+                        switch (vrc)
+                        {
+                            /* Guest execution service is not (yet) ready. This basically means that either VBoxService
+                             * is not running (yet) or that the Guest Additions are too old (because VBoxService does not
+                             * support the guest execution feature in this version). */
+                            case VERR_NOT_FOUND:
+                                LogRel(("Guest Additions seem not to be installed yet\n"));
+                                rc = GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
+                                                                     Guest::tr("Guest Additions seem not to be installed or are not ready to update yet"));
+                                break;
+
+                            /* Getting back a VERR_INVALID_PARAMETER indicates that the installed Guest Additions are supporting the guest
+                             * execution but not the built-in "vbox_cat" tool of VBoxService (< 4.0). */
+                            case VERR_INVALID_PARAMETER:
+                                LogRel(("Guest Additions are installed but don't supported automatic updating\n"));
+                                rc = GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
+                                                                     Guest::tr("Installed Guest Additions do not support automatic updating"));
+                                break;
+
+                            case VERR_TIMEOUT:
+                                LogRel(("Guest was unable to start copying the Guest Additions setup within time\n"));
+                                rc = GuestTask::setProgressErrorInfo(E_FAIL, aTask->progress,
+                                                                     Guest::tr("Guest was unable to start copying the Guest Additions setup within time"));
+                                break;
+
+                            default:
+                                rc = GuestTask::setProgressErrorInfo(E_FAIL, aTask->progress,
+                                                                     Guest::tr("Error copying Guest Additions setup file to guest path \"%s\" (%Rrc)"),
+                                                                     strInstallerPath.c_str(), vrc);
+                                break;
+                        }
+                    }
+                    else
+                    {
+                        LogRel(("Automatic update of Guest Additions started, using \"%s\"\n", aTask->strSource.c_str()));
+                        LogRel(("Copying Guest Additions installer \"%s\" to \"%s\" on guest ...\n",
+                                installerImage.c_str(), strInstallerPath.c_str()));
+                        aTask->progress->SetCurrentOperationProgress(20);
+
+                        /* Wait for process to exit ... */
+                        SafeArray<BYTE> aInputData(_64K);
+                        while (   SUCCEEDED(progressCat->COMGETTER(Completed(&fCompleted)))
+                               && !fCompleted)
+                        {
+                            size_t cbRead;
+                            /* cbLength contains remaining bytes of our installer file
+                             * opened above to read. */
+                            size_t cbToRead = RT_MIN(cbLength, _64K);
+                            if (cbToRead)
+                            {
+                                vrc = RTFileRead(iso.file, (uint8_t*)aInputData.raw(), cbToRead, &cbRead);
+                                if (   cbRead
+                                    && RT_SUCCESS(vrc))
+                                {
+                                    /* Resize buffer to reflect amount we just have read. */
+                                    if (cbRead > 0)
+                                        aInputData.resize(cbRead);
+
+                                    /* Did we reach the end of the content we want to transfer (last chunk)? */
+                                    ULONG uFlags = ProcessInputFlag_None;
+                                    if (   (cbRead < _64K)
+                                        /* Did we reach the last block which is exactly _64K? */
+                                        || (cbToRead - cbRead == 0)
+                                        /* ... or does the user want to cancel? */
+                                        || (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
+                                            && fCanceled)
+                                       )
+                                    {
+                                        uFlags |= ProcessInputFlag_EndOfFile;
+                                    }
+
+                                    /* Transfer the current chunk ... */
+                                #ifdef DEBUG_andy
+                                    LogRel(("Copying Guest Additions (%u bytes left) ...\n", cbLength));
+                                #endif
+                                    ULONG uBytesWritten;
+                                    rc = pGuest->SetProcessInput(uPID, uFlags,
+                                                                 10 * 1000 /* Wait 10s for getting the input data transfered. */,
+                                                                 ComSafeArrayAsInParam(aInputData), &uBytesWritten);
+                                    if (FAILED(rc))
+                                    {
+                                        rc = GuestTask::setProgressErrorInfo(rc, aTask->progress, pGuest);
+                                        break;
+                                    }
+
+                                    /* If task was canceled above also cancel the process execution. */
+                                    if (fCanceled)
+                                        progressCat->Cancel();
+
+                                #ifdef DEBUG_andy
+                                    LogRel(("Copying Guest Additions (%u bytes written) ...\n", uBytesWritten));
+                                #endif
+                                    Assert(cbLength >= uBytesWritten);
+                                    cbLength -= uBytesWritten;
+                                }
+                                else if (RT_FAILURE(vrc))
+                                {
+                                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                                         Guest::tr("Error while reading setup file \"%s\" (To read: %u, Size: %u) from installation medium (%Rrc)"),
+                                                                         installerImage.c_str(), cbToRead, cbLength, vrc);
+                                }
+                            }
+
+                            /* Internal progress canceled? */
+                            if (   SUCCEEDED(progressCat->COMGETTER(Canceled(&fCanceled)))
+                                && fCanceled)
+                            {
+                                aTask->progress->Cancel();
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+            RTIsoFsClose(&iso);
+
+            if (   SUCCEEDED(rc)
+                && (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
+                    && !fCanceled
+                   )
+               )
+            {
+                /*
+                 * Installer was transferred successfully, so let's start it
+                 * (with system rights).
+                 */
+                LogRel(("Preparing to execute Guest Additions update ...\n"));
+                aTask->progress->SetCurrentOperationProgress(66);
+
+                /* Prepare command line args for installer. */
+                com::SafeArray<IN_BSTR> installerArgs;
+                com::SafeArray<IN_BSTR> installerEnv;
+
+                /** @todo Only Windows! */
+                installerArgs.push_back(Bstr(strInstallerPath).raw()); /* The actual (internal) installer image (as argv[0]). */
+                /* Note that starting at Windows Vista the lovely session 0 separation applies:
+                 * This means that if we run an application with the profile/security context
+                 * of VBoxService (system rights!) we're not able to show any UI. */
+                installerArgs.push_back(Bstr("/S").raw());      /* We want to install in silent mode. */
+                installerArgs.push_back(Bstr("/l").raw());      /* ... and logging enabled. */
+                /* Don't quit VBoxService during upgrade because it still is used for this
+                 * piece of code we're in right now (that is, here!) ... */
+                installerArgs.push_back(Bstr("/no_vboxservice_exit").raw());
+                /* Tell the installer to report its current installation status
+                 * using a running VBoxTray instance via balloon messages in the
+                 * Windows taskbar. */
+                installerArgs.push_back(Bstr("/post_installstatus").raw());
+
+                /*
+                 * Start the just copied over installer with system rights
+                 * in silent mode on the guest. Don't use the hidden flag since there
+                 * may be pop ups the user has to process.
+                 */
+                ComPtr<IProgress> progressInstaller;
+                ULONG uPID;
+                rc = pGuest->executeProcessInternal(Bstr(strInstallerPath).raw(),
+                                                    ExecuteProcessFlag_WaitForProcessStartOnly,
+                                                    ComSafeArrayAsInParam(installerArgs),
+                                                    ComSafeArrayAsInParam(installerEnv),
+                                                    Bstr("").raw() /* Username */,
+                                                    Bstr("").raw() /* Password */,
+                                                    10 * 1000 /* Wait 10s for getting the process started */,
+                                                    &uPID, progressInstaller.asOutParam(), &vrc);
+                if (SUCCEEDED(rc))
+                {
+                    LogRel(("Guest Additions update is running ...\n"));
+
+                    /* If the caller does not want to wait for out guest update process to end,
+                     * complete the progress object now so that the caller can do other work. */
+                    if (aTask->uFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly)
+                        aTask->progress->notifyComplete(S_OK);
+                    else
+                        aTask->progress->SetCurrentOperationProgress(70);
+
+                    /* Wait until the Guest Additions installer finishes ... */
+                    while (   SUCCEEDED(progressInstaller->COMGETTER(Completed(&fCompleted)))
+                           && !fCompleted)
+                    {
+                        if (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
+                            && fCanceled)
+                        {
+                            progressInstaller->Cancel();
+                            break;
+                        }
+                        /* Progress canceled by Main API? */
+                        if (   SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled)))
+                            && fCanceled)
+                        {
+                            break;
+                        }
+                        RTThreadSleep(100);
+                    }
+
+                    ExecuteProcessStatus_T retStatus;
+                    ULONG uRetExitCode, uRetFlags;
+                    rc = pGuest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
+                    if (SUCCEEDED(rc))
+                    {
+                        if (fCompleted)
+                        {
+                            if (uRetExitCode == 0)
+                            {
+                                LogRel(("Guest Additions update successful!\n"));
+                                if (   SUCCEEDED(aTask->progress->COMGETTER(Completed(&fCompleted)))
+                                    && !fCompleted)
+                                    aTask->progress->notifyComplete(S_OK);
+                            }
+                            else
+                            {
+                                LogRel(("Guest Additions update failed (Exit code=%u, Status=%u, Flags=%u)\n",
+                                        uRetExitCode, retStatus, uRetFlags));
+                                rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                                     Guest::tr("Guest Additions update failed with exit code=%u (status=%u, flags=%u)"),
+                                                                     uRetExitCode, retStatus, uRetFlags);
+                            }
+                        }
+                        else if (   SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled)))
+                                 && fCanceled)
+                        {
+                            LogRel(("Guest Additions update was canceled\n"));
+                            rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                                 Guest::tr("Guest Additions update was canceled by the guest with exit code=%u (status=%u, flags=%u)"),
+                                                                 uRetExitCode, retStatus, uRetFlags);
+                        }
+                        else
+                        {
+                            LogRel(("Guest Additions update was canceled by the user\n"));
+                        }
+                    }
+                    else
+                        rc = GuestTask::setProgressErrorInfo(rc, aTask->progress, pGuest);
+                }
+                else
+                    rc = GuestTask::setProgressErrorInfo(rc, aTask->progress, pGuest);
+            }
+        }
+    }
+    catch (HRESULT aRC)
+    {
+        rc = aRC;
+    }
+
+    /* Clean up */
+    aTask->rc = rc;
+
+    LogFlowFunc(("rc=%Rhrc\n", rc));
+    LogFlowFuncLeave();
+
+    return VINF_SUCCESS;
+}
+#endif
+
