Index: /trunk/src/VBox/Main/include/GuestSessionImplTasks.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestSessionImplTasks.h	(revision 71816)
+++ /trunk/src/VBox/Main/include/GuestSessionImplTasks.h	(revision 71817)
@@ -79,10 +79,10 @@
     /** @name File handling primitives.
      * @{ */
-    int fileCopyFromEx(ComObjPtr<GuestFile> &srcFile, PRTFILE phDstFile, FileCopyFlag_T enmFileCopyFlags,
-                       uint64_t cbOffset, uint64_t cbSize);
-    int fileCopyFrom(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
-    int fileCopyToEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags, PRTFILE pFile,
-                     uint64_t cbOffset, uint64_t cbSize); /**< r=bird: 'cbOffset' makes no sense what so ever. It should be 'off', or do you mean sizeof(uint64_t)? */
-    int fileCopyTo(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
+    int fileCopyFromGuestInner(ComObjPtr<GuestFile> &srcFile, PRTFILE phDstFile, FileCopyFlag_T fFileCopyFlags,
+                               uint64_t offCopy, uint64_t cbSize);
+    int fileCopyFromGuest(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T fFileCopyFlags);
+    int fileCopyToGuestInner(PRTFILE phSrcFile, ComObjPtr<GuestFile> &dstFile, FileCopyFlag_T fFileCopyFlags,
+                             uint64_t offCopy, uint64_t cbSize);
+    int fileCopyToGuest(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T fFileCopyFlags);
     /** @}  */
 
@@ -139,13 +139,44 @@
 };
 
+class GuestSessionCopyTask : public GuestSessionTask
+{
+public:
+
+    GuestSessionCopyTask(GuestSession *pSession)
+        : GuestSessionTask(pSession) { RT_ZERO(u); }
+
+    virtual ~GuestSessionCopyTask() { }
+
+protected:
+
+    Utf8Str mSource;
+    Utf8Str mDest;
+    Utf8Str mFilter;
+
+    union
+    {
+        struct
+        {
+            DirectoryCopyFlag_T fCopyFlags;
+        } Dir;
+        struct
+        {
+            FileCopyFlag_T      fCopyFlags;
+            PRTFILE             phFile;
+            size_t              offStart;
+            uint64_t            cbSize;
+        } File;
+    } u;
+};
+
 /**
  * Task for copying directories from guest to the host.
  */
-class SessionTaskCopyDirFrom : public GuestSessionTask
+class SessionTaskCopyDirFrom : public GuestSessionCopyTask
 {
 public:
 
     SessionTaskCopyDirFrom(GuestSession *pSession, const Utf8Str &strSource, const Utf8Str &strDest, const Utf8Str &strFilter,
-                           DirectoryCopyFlag_T enmDirCopyFlags);
+                           DirectoryCopyFlag_T fDirCopyFlags);
     virtual ~SessionTaskCopyDirFrom(void);
     int Run(void);
@@ -155,10 +186,4 @@
     int directoryCopyToHost(const Utf8Str &strSource, const Utf8Str &strFilter, const Utf8Str &strDest, bool fRecursive,
                             bool fFollowSymlinks, const Utf8Str &strSubDir /* For recursion. */);
-protected:
-
-    Utf8Str             mSource;
-    Utf8Str             mDest;
-    Utf8Str             mFilter;
-    DirectoryCopyFlag_T mDirCopyFlags;
 };
 
@@ -166,10 +191,10 @@
  * Task for copying directories from host to the guest.
  */
-class SessionTaskCopyDirTo : public GuestSessionTask
+class SessionTaskCopyDirTo : public GuestSessionCopyTask
 {
 public:
 
     SessionTaskCopyDirTo(GuestSession *pSession, const Utf8Str &strSource, const Utf8Str &strDest, const Utf8Str &strFilter,
-                         DirectoryCopyFlag_T enmDirCopyFlags);
+                         DirectoryCopyFlag_T fDirCopyFlags);
     virtual ~SessionTaskCopyDirTo(void);
     int Run(void);
@@ -179,10 +204,4 @@
     int directoryCopyToGuest(const Utf8Str &strSource, const Utf8Str &strFilter, const Utf8Str &strDest, bool fRecursive,
                              bool fFollowSymlinks, const Utf8Str &strSubDir /* For recursion. */);
-protected:
-
-    Utf8Str             mSource;
-    Utf8Str             mDest;
-    Utf8Str             mFilter;
-    DirectoryCopyFlag_T mDirCopyFlags;
 };
 
@@ -190,24 +209,12 @@
  * Task for copying files from host to the guest.
  */
-class SessionTaskCopyFileTo : public GuestSessionTask
+class SessionTaskCopyFileTo : public GuestSessionCopyTask
 {
 public:
 
     SessionTaskCopyFileTo(GuestSession *pSession,
-                          const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
-    SessionTaskCopyFileTo(GuestSession *pSession,
-                          PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize,
-                          const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
+                          const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T fFileCopyFlags);
     virtual ~SessionTaskCopyFileTo(void);
     int Run(void);
-
-protected:
-
-    Utf8Str        mSource;
-    PRTFILE        mSourceFile;
-    size_t         mSourceOffset;
-    uint64_t       mSourceSize;
-    Utf8Str        mDest;
-    FileCopyFlag_T mFileCopyFlags;
 };
 
@@ -215,18 +222,12 @@
  * Task for copying files from guest to the host.
  */
-class SessionTaskCopyFileFrom : public GuestSessionTask
+class SessionTaskCopyFileFrom : public GuestSessionCopyTask
 {
 public:
 
     SessionTaskCopyFileFrom(GuestSession *pSession,
-                        const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
+                            const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T fFileCopyFlags);
     virtual ~SessionTaskCopyFileFrom(void);
     int Run(void);
-
-protected:
-
-    Utf8Str        mSource;
-    Utf8Str        mDest;
-    FileCopyFlag_T mFileCopyFlags;
 };
 
@@ -240,5 +241,5 @@
     SessionTaskUpdateAdditions(GuestSession *pSession,
                                const Utf8Str &strSource, const ProcessArguments &aArguments,
-                               uint32_t uFlags);
+                               uint32_t fFlags);
     virtual ~SessionTaskUpdateAdditions(void);
     int Run(void);
@@ -296,5 +297,5 @@
 
     int addProcessArguments(ProcessArguments &aArgumentsDest, const ProcessArguments &aArgumentsSource);
-    int copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO, Utf8Str const &strFileSource, const Utf8Str &strFileDest, bool fOptional, uint32_t *pcbSize);
+    int copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO, Utf8Str const &strFileSource, const Utf8Str &strFileDest, bool fOptional);
     int runFileOnGuest(GuestSession *pSession, GuestProcessStartupInfo &procInfo);
 
Index: /trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp	(revision 71816)
+++ /trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp	(revision 71817)
@@ -263,17 +263,17 @@
 
 /**
- * Copies a file from the guest to the host, extended version.
+ * Main function for copying a file from guest to the host.
  *
  * @return VBox status code.
  * @param  srcFile            Guest file (source) to copy to the host. Must be in opened and ready state already.
  * @param  phDstFile          Pointer to host file handle (destination) to copy to. Must be in opened and ready state already.
- * @param  enmFileCopyFlags   File copy flags.
- * @param  uOffset            Offset (in bytes) where to start copying the source file.
+ * @param  fFileCopyFlags     File copy flags.
+ * @param  offCopy            Offset (in bytes) where to start copying the source file.
  * @param  cbSize             Size (in bytes) to copy from the source file.
  */
-int GuestSessionTask::fileCopyFromEx(ComObjPtr<GuestFile> &srcFile, PRTFILE phDstFile, FileCopyFlag_T enmFileCopyFlags,
-                                     uint64_t uOffset, uint64_t cbSize)
-{
-    RT_NOREF(enmFileCopyFlags);
+int GuestSessionTask::fileCopyFromGuestInner(ComObjPtr<GuestFile> &srcFile, PRTFILE phDstFile, FileCopyFlag_T fFileCopyFlags,
+                                            uint64_t offCopy, uint64_t cbSize)
+{
+    RT_NOREF(fFileCopyFlags);
 
     BOOL fCanceled = FALSE;
@@ -285,12 +285,12 @@
     int rc = VINF_SUCCESS;
 
-    if (uOffset)
-    {
-        uint64_t puOffset;
-        rc = srcFile->i_seekAt(uOffset, GUEST_FILE_SEEKTYPE_BEGIN, uTimeoutMs, &puOffset);
+    if (offCopy)
+    {
+        uint64_t offActual;
+        rc = srcFile->i_seekAt(offCopy, GUEST_FILE_SEEKTYPE_BEGIN, uTimeoutMs, &offActual);
         if (RT_FAILURE(rc))
         {
             setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                Utf8StrFmt(GuestSession::tr("Seeking to offset %RU64) failed: %Rrc"), uOffset, rc));
+                                Utf8StrFmt(GuestSession::tr("Seeking to offset %RU64 failed: %Rrc"), offCopy, rc));
             return rc;
         }
@@ -370,9 +370,9 @@
  * @param  strSource            Full path of source file on the guest to copy.
  * @param  strDest              Full destination path and file name (host style) to copy file to.
- * @param  enmFileCopyFlags     File copy flags.
+ * @param  fFileCopyFlags       File copy flags.
  */
-int GuestSessionTask::fileCopyFrom(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)
-{
-    LogFlowThisFunc(("strSource=%s, strDest=%s, enmFileCopyFlags=0x%x\n", strSource.c_str(), strDest.c_str(), enmFileCopyFlags));
+int GuestSessionTask::fileCopyFromGuest(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T fFileCopyFlags)
+{
+    LogFlowThisFunc(("strSource=%s, strDest=%s, enmFileCopyFlags=0x%x\n", strSource.c_str(), strDest.c_str(), fFileCopyFlags));
 
     GuestFileOpenInfo srcOpenInfo;
@@ -389,5 +389,5 @@
 
     int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
-    int rc = mSession->i_fsQueryInfo(strSource.c_str(), TRUE /* fFollowSymlinks */, srcObjData, &rcGuest);
+    int rc = mSession->i_fsQueryInfo(strSource, TRUE /* fFollowSymlinks */, srcObjData, &rcGuest);
     if (RT_FAILURE(rc))
     {
@@ -413,5 +413,5 @@
 
             case FsObjType_Symlink:
-                if (!(enmFileCopyFlags & FileCopyFlag_FollowLinks))
+                if (!(fFileCopyFlags & FileCopyFlag_FollowLinks))
                 {
                     setProgressErrorMsg(VBOX_E_IPRT_ERROR,
@@ -464,5 +464,5 @@
         if (RT_SUCCESS(rc))
         {
-            if (enmFileCopyFlags & FileCopyFlag_NoReplace)
+            if (fFileCopyFlags & FileCopyFlag_NoReplace)
             {
                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
@@ -471,5 +471,5 @@
             }
 
-            if (enmFileCopyFlags & FileCopyFlag_Update)
+            if (fFileCopyFlags & FileCopyFlag_Update)
             {
                 RTTIMESPEC srcModificationTimeTS;
@@ -504,5 +504,5 @@
         if (RTFS_IS_FILE(dstObjInfo.Attr.fMode))
         {
-            if (enmFileCopyFlags & FileCopyFlag_NoReplace)
+            if (fFileCopyFlags & FileCopyFlag_NoReplace)
             {
                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
@@ -537,5 +537,5 @@
         else if (RTFS_IS_SYMLINK(dstObjInfo.Attr.fMode))
         {
-            if (!(enmFileCopyFlags & FileCopyFlag_FollowLinks))
+            if (!(fFileCopyFlags & FileCopyFlag_FollowLinks))
             {
                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
@@ -573,5 +573,5 @@
                 LogFlowThisFunc(("Copying '%s' to '%s' (%RI64 bytes) ...\n", strSource.c_str(), pszDstFile, srcObjData.mObjectSize));
 
-                rc = fileCopyFromEx(srcFile, &hDstFile, enmFileCopyFlags, 0 /* Offset, unused */, (uint64_t)srcObjData.mObjectSize);
+                rc = fileCopyFromGuestInner(srcFile, &hDstFile, fFileCopyFlags, 0 /* Offset, unused */, (uint64_t)srcObjData.mObjectSize);
 
                 int rc2 = RTFileClose(hDstFile);
@@ -595,51 +595,124 @@
 
 /**
- * Copies a file from the host to the guest, extended version.
+ * Main function for copying a file from host to the guest.
  *
  * @return VBox status code.
+ * @param  phSrcFile          Pointer to host file handle (source) to copy from. Must be in opened and ready state already.
+ * @param  dstFile            Guest file (destination) to copy to the guest. Must be in opened and ready state already.
+ * @param  fFileCopyFlags     File copy flags.
+ * @param  offCopy            Offset (in bytes) where to start copying the source file.
+ * @param  cbSize             Size (in bytes) to copy from the source file.
+ */
+int GuestSessionTask::fileCopyToGuestInner(PRTFILE phSrcFile, ComObjPtr<GuestFile> &dstFile, FileCopyFlag_T fFileCopyFlags,
+                                           uint64_t offCopy, uint64_t cbSize)
+{
+    RT_NOREF(fFileCopyFlags);
+
+    BOOL fCanceled = FALSE;
+    uint64_t cbWrittenTotal = 0;
+    uint64_t cbToRead       = cbSize;
+
+    uint32_t uTimeoutMs = 30 * 1000; /* 30s timeout. */
+
+    int rc = VINF_SUCCESS;
+
+    if (offCopy)
+    {
+        uint64_t offActual;
+        rc = RTFileSeek(*phSrcFile, offCopy, RTFILE_SEEK_END, &offActual);
+        if (RT_FAILURE(rc))
+        {
+            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                Utf8StrFmt(GuestSession::tr("Seeking to offset %RU64 failed: %Rrc"), offCopy, rc));
+            return rc;
+        }
+    }
+
+    BYTE byBuf[_64K];
+    while (cbToRead)
+    {
+        size_t cbRead;
+        const uint32_t cbChunk = RT_MIN(cbToRead, sizeof(byBuf));
+        rc = RTFileRead(*phSrcFile, byBuf, cbChunk, &cbRead);
+        if (RT_FAILURE(rc))
+        {
+            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                Utf8StrFmt(GuestSession::tr("Reading %RU32 bytes @ %RU64, failed: %Rrc"), cbChunk, cbWrittenTotal, rc));
+            break;
+        }
+
+        rc = dstFile->i_writeData(uTimeoutMs, byBuf, cbRead, NULL /* No partial writes */);
+        if (RT_FAILURE(rc))
+        {
+            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                Utf8StrFmt(GuestSession::tr("Writing to %RU32 bytes to file failed: %Rrc"), cbRead, rc));
+            break;
+        }
+
+        Assert(cbToRead >= cbRead);
+        cbToRead -= cbRead;
+
+        /* Update total bytes written to the guest. */
+        cbWrittenTotal += cbRead;
+        Assert(cbWrittenTotal <= cbSize);
+
+        /* Did the user cancel the operation above? */
+        if (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
+            && fCanceled)
+            break;
+
+        rc = setProgress((ULONG)(cbWrittenTotal / ((uint64_t)cbSize / 100.0)));
+        if (RT_FAILURE(rc))
+            break;
+    }
+
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /*
+     * Even if we succeeded until here make sure to check whether we really transfered
+     * everything.
+     */
+    if (   cbSize > 0
+        && cbWrittenTotal == 0)
+    {
+        /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
+         * to the destination -> access denied. */
+        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                            Utf8StrFmt(GuestSession::tr("Writing to destination file failed: Access denied")));
+        rc = VERR_ACCESS_DENIED;
+    }
+    else if (cbWrittenTotal < cbSize)
+    {
+        /* If we did not copy all let the user know. */
+        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                            Utf8StrFmt(GuestSession::tr("Copying to destination failed (%RU64/%RU64 bytes transfered)"),
+                                       cbWrittenTotal, cbSize));
+        rc = VERR_INTERRUPTED;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/**
+ * Copies a file from the guest to the host.
+ *
+ * @return VBox status code. VINF_NO_CHANGE if file was skipped.
  * @param  strSource            Full path of source file on the host to copy.
  * @param  strDest              Full destination path and file name (guest style) to copy file to.
- * @param  enmFileCopyFlags     File copy flags.
- * @param  pFile                Source file handle to use for accessing the host file.
- *                              The caller is responsible of opening / closing the file accordingly.
- * @param  cbOffset             Offset (in bytes) where to start copying the source file.
- * @param  cbSize               Size (in bytes) to copy from the source file.
+ * @param  fFileCopyFlags       File copy flags.
  */
-int GuestSessionTask::fileCopyToEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags,
-                                   PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize)
-{
-    /** @todo Implement sparse file support? */
-
-    if (   enmFileCopyFlags & FileCopyFlag_NoReplace
-        || enmFileCopyFlags & FileCopyFlag_FollowLinks
-        || enmFileCopyFlags & FileCopyFlag_Update)
-    {
-        return VERR_NOT_IMPLEMENTED;
-    }
-
-    RTMSINTERVAL msTimeout = 30 * 1000; /** @todo 30s timeout for all actions. Make this configurable? */
-
-    /*
-     * Start the actual copying process by cat'ing the source file to the
-     * destination file on the guest.
-     */
-    GuestProcessStartupInfo procInfo;
-    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT);
-    procInfo.mFlags      = ProcessCreateFlag_Hidden;
-
-    /* Set arguments.*/
-    procInfo.mArguments.push_back(procInfo.mExecutable);                       /* Set argv0. */
-    procInfo.mArguments.push_back(Utf8StrFmt("--output=%s", strDest.c_str()));
-
-    /* Startup process. */
-    ComObjPtr<GuestProcess> pProcess;
-    int rc = mSession->i_processCreateEx(procInfo, pProcess);
+int GuestSessionTask::fileCopyToGuest(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T fFileCopyFlags)
+{
+    LogFlowThisFunc(("strSource=%s, strDest=%s, fFileCopyFlags=0x%x\n", strSource.c_str(), strDest.c_str(), fFileCopyFlags));
+
+    Utf8Str strDestFinal = strDest;
+
+    GuestFsObjData dstObjData;
+    RT_ZERO(dstObjData);
 
     int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
-    if (RT_SUCCESS(rc))
-    {
-        Assert(!pProcess.isNull());
-        rc = pProcess->i_startProcess(msTimeout, &rcGuest);
-    }
+    int rc = mSession->i_fsQueryInfo(strDest, TRUE /* fFollowSymlinks */, dstObjData, &rcGuest);
     if (RT_FAILURE(rc))
     {
@@ -647,268 +720,171 @@
         {
             case VERR_GSTCTL_GUEST_ERROR:
-                setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
+                if (rcGuest == VERR_FILE_NOT_FOUND) /* File might not exist on the guest yet. */
+                {
+                    rc = VINF_SUCCESS;
+                }
+                else
+                   setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(rcGuest));
                 break;
 
             default:
                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                    Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
-                                               strSource.c_str(), rc));
-                break;
-        }
+                                    Utf8StrFmt(GuestSession::tr("Destination file lookup for \"%s\" failed: %Rrc"),
+                                               strDest.c_str(), rc));
+                break;
+        }
+    }
+    else
+    {
+        switch (dstObjData.mType)
+        {
+            case FsObjType_Directory:
+            {
+                if (   strDest.endsWith("\\")
+                    || strDest.endsWith("/"))
+                {
+                    /* Build the final file name with destination path (on the host). */
+                    char szDstPath[RTPATH_MAX];
+                    RTStrPrintf2(szDstPath, sizeof(szDstPath), "%s", strDest.c_str());
+
+                    RTPathAppend(szDstPath, sizeof(szDstPath), RTPathFilename(strSource.c_str()));
+
+                    strDestFinal = szDstPath;
+                }
+                else
+                {
+                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                        Utf8StrFmt(GuestSession::tr("Destination directory \"%s\" already exists"),
+                                                   strDest.c_str(), rc));
+                    rc = VERR_ALREADY_EXISTS;
+                }
+                break;
+            }
+
+            case FsObjType_File:
+                if (fFileCopyFlags & FileCopyFlag_NoReplace)
+                {
+                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                        Utf8StrFmt(GuestSession::tr("Destination file \"%s\" already exists"),
+                                                   strDest.c_str(), rc));
+                    rc = VERR_ALREADY_EXISTS;
+                }
+                break;
+
+            case FsObjType_Symlink:
+                if (!(fFileCopyFlags & FileCopyFlag_FollowLinks))
+                {
+                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                        Utf8StrFmt(GuestSession::tr("Destination file \"%s\" is a symbolic link"),
+                                                   strDest.c_str(), rc));
+                    rc = VERR_IS_A_SYMLINK;
+                }
+                break;
+
+            default:
+                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                    Utf8StrFmt(GuestSession::tr("Destination element \"%s\" not supported"), strDest.c_str()));
+                rc = VERR_NOT_SUPPORTED;
+                break;
+        }
+    }
+
+    if (RT_FAILURE(rc))
         return rc;
-    }
-
-    ProcessWaitResult_T waitRes;
-    BYTE byBuf[_64K];
-
-    BOOL fCanceled = FALSE;
-    uint64_t cbWrittenTotal = 0;
-    uint64_t cbToRead = cbSize;
-
-    for (;;)
-    {
-        rc = pProcess->i_waitFor(ProcessWaitForFlag_StdIn, msTimeout, waitRes, &rcGuest);
-        if (   RT_FAILURE(rc)
-            || (   waitRes != ProcessWaitResult_StdIn
-                && waitRes != ProcessWaitResult_WaitFlagNotSupported))
-        {
-            break;
-        }
-
-        /* If the guest does not support waiting for stdin, we now yield in
-         * order to reduce the CPU load due to busy waiting. */
-        if (waitRes == ProcessWaitResult_WaitFlagNotSupported)
-            RTThreadYield(); /* Optional, don't check rc. */
-
-        size_t cbRead = 0;
-        if (cbSize) /* If we have nothing to write, take a shortcut. */
-        {
-            /** @todo Not very efficient, but works for now. */
-            rc = RTFileSeek(*pFile, cbOffset + cbWrittenTotal,
-                            RTFILE_SEEK_BEGIN, NULL /* poffActual */);
-            if (RT_SUCCESS(rc))
-            {
-                rc = RTFileRead(*pFile, (uint8_t*)byBuf,
-                                RT_MIN((size_t)cbToRead, sizeof(byBuf)), &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(rc))
+
+    GuestFileOpenInfo dstOpenInfo;
+    RT_ZERO(dstOpenInfo);
+    dstOpenInfo.mFileName        = strDestFinal;
+    if (fFileCopyFlags & FileCopyFlag_NoReplace)
+        dstOpenInfo.mOpenAction  = FileOpenAction_CreateNew;
+    else
+        dstOpenInfo.mOpenAction  = FileOpenAction_CreateOrReplace;
+    dstOpenInfo.mAccessMode      = FileAccessMode_WriteOnly;
+    dstOpenInfo.mSharingMode     = FileSharingMode_All; /** @todo Use _Read when implemented. */
+
+    ComObjPtr<GuestFile> dstFile;
+    rc = mSession->i_fileOpen(dstOpenInfo, dstFile, &rcGuest);
+    if (RT_FAILURE(rc))
+    {
+        switch (rc)
+        {
+            case VERR_GSTCTL_GUEST_ERROR:
+                setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(rcGuest));
+                break;
+
+            default:
+                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                    Utf8StrFmt(GuestSession::tr("Destination file \"%s\" could not be opened: %Rrc"),
+                                               strDestFinal, rc));
+                break;
+        }
+    }
+
+    if (RT_FAILURE(rc))
+        return rc;
+
+    RTFSOBJINFO srcObjInfo;
+    RT_ZERO(srcObjInfo);
+
+    bool fSkip = false; /* Whether to skip handling the file. */
+
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTPathQueryInfo(strSource.c_str(), &srcObjInfo, RTFSOBJATTRADD_NOTHING);
+        if (RT_SUCCESS(rc))
+        {
+            if (fFileCopyFlags & FileCopyFlag_Update)
+            {
+                RTTIMESPEC dstModificationTimeTS;
+                RTTimeSpecSetSeconds(&dstModificationTimeTS, dstObjData.mModificationTime);
+                if (RTTimeSpecCompare(&dstModificationTimeTS, &srcObjInfo.ModificationTime) <= 0)
                 {
                     setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                        Utf8StrFmt(GuestSession::tr("Could not read from host file \"%s\" (%Rrc)"),
-                                                   strSource.c_str(), rc));
-                    break;
-                }
-            }
-            else
-            {
-                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                    Utf8StrFmt(GuestSession::tr("Seeking host file \"%s\" to offset %RU64 failed: %Rrc"),
-                                               strSource.c_str(), cbWrittenTotal, rc));
-                break;
-            }
-        }
-
-        uint32_t fFlags = ProcessInputFlag_None;
-
-        /* Did we reach the end of the content we want to transfer (last chunk)? */
-        if (   (cbRead < sizeof(byBuf))
-            /* Did we reach the last block which is exactly _64K? */
-            || (cbToRead - cbRead == 0)
-            /* ... or does the user want to cancel? */
-            || (   !mProgress.isNull()
-                && SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
-                && fCanceled)
-           )
-        {
-            LogFlowThisFunc(("Writing last chunk cbRead=%RU64\n", cbRead));
-            fFlags |= ProcessInputFlag_EndOfFile;
-        }
-
-        uint32_t cbWritten;
-        Assert(sizeof(byBuf) >= cbRead);
-        rc = pProcess->i_writeData(0 /* StdIn */, fFlags, byBuf, cbRead, msTimeout, &cbWritten, &rcGuest);
-        if (RT_FAILURE(rc))
-        {
-            switch (rc)
-            {
-                case VERR_GSTCTL_GUEST_ERROR:
-                    setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
-                    break;
-
-                default:
-                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                        Utf8StrFmt(GuestSession::tr("Writing to guest file \"%s\" (offset %RU64) failed: %Rrc"),
-                                        strDest.c_str(), cbWrittenTotal, rc));
-                    break;
-            }
-
-            break;
-        }
-
-        /* Only subtract bytes reported written by the guest. */
-        Assert(cbToRead >= cbWritten);
-        cbToRead -= cbWritten;
-
-        /* Update total bytes written to the guest. */
-        cbWrittenTotal += cbWritten;
-        Assert(cbWrittenTotal <= cbSize);
-
-        LogFlowThisFunc(("rc=%Rrc, cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n",
-                         rc, cbWritten, cbToRead, cbWrittenTotal, cbSize));
-
-        /* Did the user cancel the operation above? */
-        if (fCanceled)
-            break;
-
-        /* Update the progress.
-         * Watch out for division by zero. */
-        cbSize > 0
-            ? rc = setProgress((ULONG)(cbWrittenTotal * 100 / cbSize))
-            : rc = setProgress(100);
-        if (RT_FAILURE(rc))
-            break;
-
-        /* End of file reached? */
-        if (!cbToRead)
-            break;
-    } /* for */
-
-    LogFlowThisFunc(("Copy loop ended with rc=%Rrc, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n",
-                     rc, cbToRead, cbWrittenTotal, cbSize));
-
-    /*
-     * Wait on termination of guest process until it completed all operations.
-     */
-    if (   !fCanceled
-        || RT_SUCCESS(rc))
-    {
-        rc = pProcess->i_waitFor(ProcessWaitForFlag_Terminate, msTimeout, waitRes, &rcGuest);
-        if (   RT_FAILURE(rc)
-            || waitRes != ProcessWaitResult_Terminate)
-        {
-            if (RT_FAILURE(rc))
-                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                    Utf8StrFmt(
-                                    GuestSession::tr("Waiting on termination for copying file \"%s\" to guest failed: %Rrc"),
-                                    strSource.c_str(), rc));
-            else
-            {
-                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                    Utf8StrFmt(GuestSession::tr(
-                                               "Waiting on termination for copying file \"%s\" to guest failed with wait result %ld"),
-                                               strSource.c_str(), waitRes));
-                rc = VERR_GENERAL_FAILURE; /* Fudge. */
-            }
-        }
+                                        Utf8StrFmt(GuestSession::tr("Destination file \"%s\" has same or newer modification date"),
+                                                   strDestFinal.c_str()));
+                    fSkip = true;
+                }
+            }
+        }
+        else
+        {
+            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                Utf8StrFmt(GuestSession::tr("Source file lookup for \"%s\" failed: %Rrc"),
+                                           strSource.c_str(), rc));
+        }
+    }
+
+    if (fSkip)
+    {
+        int rc2 = dstFile->i_closeFile(&rcGuest);
+        AssertRC(rc2);
+        return VINF_SUCCESS;
     }
 
     if (RT_SUCCESS(rc))
     {
-        /*
-         * Newer VBoxService toolbox versions report what went wrong via exit code.
-         * So handle this first.
-         */
-        /** @todo This code sequence is duplicated in CopyFrom...   */
-        ProcessStatus_T procStatus = ProcessStatus_TerminatedAbnormally;
-        HRESULT hrc = pProcess->COMGETTER(Status(&procStatus));
-        if (!SUCCEEDED(hrc))
-            procStatus = ProcessStatus_TerminatedAbnormally;
-
-        LONG exitCode = 42424242;
-        hrc = pProcess->COMGETTER(ExitCode(&exitCode));
-        if (!SUCCEEDED(hrc))
-            exitCode = 42424242;
-
-        if (   procStatus != ProcessStatus_TerminatedNormally
-            || exitCode != 0)
-        {
-            LogFlowThisFunc(("procStatus=%d, exitCode=%d\n", procStatus, exitCode));
-            if (procStatus == ProcessStatus_TerminatedNormally)
-                rc = GuestProcessTool::exitCodeToRc(procInfo, exitCode);
-            else
-                rc = VERR_GENERAL_FAILURE;
+        RTFILE hSrcFile;
+        rc = RTFileOpen(&hSrcFile, strSource.c_str(),
+                        RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */
+        if (RT_SUCCESS(rc))
+        {
+            LogFlowThisFunc(("Copying '%s' to '%s' (%RI64 bytes) ...\n",
+                             strSource.c_str(), strDestFinal.c_str(), srcObjInfo.cbObject));
+
+            rc = fileCopyToGuestInner(&hSrcFile, dstFile, fFileCopyFlags, 0 /* Offset, unused */, srcObjInfo.cbObject);
+
+            int rc2 = RTFileClose(hSrcFile);
+            AssertRC(rc2);
+        }
+        else
             setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to guest failed: %Rrc"),
+                                Utf8StrFmt(GuestSession::tr("Opening source file \"%s\" failed: %Rrc"),
                                            strSource.c_str(), rc));
-        }
-        /*
-         * Even if we succeeded until here make sure to check whether we really transfered
-         * everything.
-         */
-        else if (   cbSize > 0
-                 && cbWrittenTotal == 0)
-        {
-            /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
-             * to the destination -> access denied. */
-            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to guest \"%s\""),
-                                           strSource.c_str(), strDest.c_str()));
-            rc = VERR_ACCESS_DENIED;
-        }
-        else if (cbWrittenTotal < cbSize)
-        {
-            /* If we did not copy all let the user know. */
-            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to guest failed (%RU64/%RU64 bytes transfered)"),
-                                           strSource.c_str(), cbWrittenTotal, cbSize));
-            rc = VERR_INTERRUPTED;
-        }
-    }
-
-    return rc;
-}
-
-/**
- * Copies a file from the host to the guest.
- *
- * @return VBox status code.
- * @param  strSource            Full path of source file on the host to copy.
- * @param  strDest              Full destination path and file name (guest style) to copy file to.
- * @param  enmFileCopyFlags     File copy flags.
- */
-int GuestSessionTask::fileCopyTo(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)
-{
-    int rc;
-
-    /* Does our source file exist? */
-    if (!RTFileExists(strSource.c_str()))
-    {
-        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                            Utf8StrFmt(GuestSession::tr("Host file \"%s\" does not exist or is not a file"),
-                                       strSource.c_str()));
-        rc  = VERR_FILE_NOT_FOUND;
-    }
-    else
-    {
-        RTFILE hFile;
-        rc = RTFileOpen(&hFile, strSource.c_str(),
-                        RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
-        if (RT_FAILURE(rc))
-        {
-            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                Utf8StrFmt(GuestSession::tr("Could not open host file \"%s\" for reading: %Rrc"),
-                                           strSource.c_str(), rc));
-        }
-        else
-        {
-            uint64_t cbSize;
-            rc = RTFileGetSize(hFile, &cbSize);
-            if (RT_FAILURE(rc))
-            {
-                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                    Utf8StrFmt(GuestSession::tr("Could not query host file size of \"%s\": %Rrc"),
-                                               strSource.c_str(), rc));
-            }
-            else
-                rc = fileCopyToEx(strSource, strDest, enmFileCopyFlags, &hFile, 0 /* Offset */, cbSize);
-
-             RTFileClose(hFile);
-        }
-    }
-
+    }
+
+    int rc2 = dstFile->i_closeFile(&rcGuest);
+    AssertRC(rc2);
+
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -964,17 +940,18 @@
 
 SessionTaskCopyDirFrom::SessionTaskCopyDirFrom(GuestSession *pSession, const Utf8Str &strSource, const Utf8Str &strDest, const Utf8Str &strFilter,
-                                               DirectoryCopyFlag_T enmDirCopyFlags)
-                                               : GuestSessionTask(pSession)
-                                               , mSource(strSource)
-                                               , mDest(strDest)
-                                               , mFilter(strFilter)
-                                               , mDirCopyFlags(enmDirCopyFlags)
+                                               DirectoryCopyFlag_T fDirCopyFlags)
+                                               : GuestSessionCopyTask(pSession)
 {
     m_strTaskName = "gctlCpyDirFrm";
+
+    mSource = strSource;
+    mDest   = strDest;
+    mFilter = strFilter;
+
+    u.Dir.fCopyFlags = fDirCopyFlags;
 }
 
 SessionTaskCopyDirFrom::~SessionTaskCopyDirFrom(void)
 {
-
 }
 
@@ -1115,5 +1092,5 @@
                     Utf8Str strSrcFile = strSrcDir + strSrcSubDir + strName;
                     Utf8Str strDstFile = strDstDir + strSrcSubDir + strName;
-                    rc = fileCopyFrom(strSrcFile, strDstFile, FileCopyFlag_None);
+                    rc = fileCopyFromGuest(strSrcFile, strDstFile, FileCopyFlag_None);
                 }
                 break;
@@ -1147,21 +1124,34 @@
     int rc = VINF_SUCCESS;
 
+    /* Figure out if we need to copy the entire source directory or just its contents. */
+    Utf8Str strSrcDir = mSource;
+    Utf8Str strDstDir = mDest;
+    if (   !strSrcDir.endsWith("/")
+        && !strSrcDir.endsWith("\\"))
+    {
+        if (   !strDstDir.endsWith("/")
+            && !strDstDir.endsWith("\\"))
+            strDstDir += "/";
+
+        strDstDir += Utf8StrFmt("%s", RTPathFilename(strSrcDir.c_str()));
+    }
+
     /* Create the root target directory on the host.
-     * The target directory might already exist on the host (based on mDirCopyFlags). */
-    const bool fExists = RTDirExists(mDest.c_str());
+     * The target directory might already exist on the host (based on u.Dir.fCopyFlags). */
+    const bool fExists = RTDirExists(strDstDir.c_str());
     if (   fExists
-        && !(mDirCopyFlags & DirectoryCopyFlag_CopyIntoExisting))
+        && !(u.Dir.fCopyFlags & DirectoryCopyFlag_CopyIntoExisting))
     {
         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                            Utf8StrFmt(GuestSession::tr("Destination directory \"%s\" exists when it must not"), mDest.c_str()));
+                            Utf8StrFmt(GuestSession::tr("Destination directory \"%s\" exists when it must not"), strDstDir.c_str()));
         rc = VERR_ALREADY_EXISTS;
     }
     else if (!fExists)
     {
-        rc = RTDirCreate(mDest.c_str(), fDirMode, 0);
+        rc = RTDirCreate(strDstDir.c_str(), fDirMode, 0);
         if (RT_FAILURE(rc))
             setProgressErrorMsg(VBOX_E_IPRT_ERROR,
                                 Utf8StrFmt(GuestSession::tr("Error creating destination directory \"%s\", rc=%Rrc"),
-                                           mDest.c_str(), rc));
+                                           strDstDir.c_str(), rc));
     }
 
@@ -1170,10 +1160,10 @@
 
     RTDIR hDir;
-    rc = RTDirOpen(&hDir, mDest.c_str());
+    rc = RTDirOpen(&hDir, strDstDir.c_str());
     if (RT_FAILURE(rc))
     {
         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
                             Utf8StrFmt(GuestSession::tr("Error opening destination directory \"%s\", rc=%Rrc"),
-                                       mDest.c_str(), rc));
+                                       strDstDir.c_str(), rc));
         return rc;
     }
@@ -1181,5 +1171,5 @@
     /* At this point the directory on the host was created and (hopefully) is ready
      * to receive further content. */
-    rc = directoryCopyToHost(mSource, mFilter, mDest, fRecursive, fFollowSymlinks,
+    rc = directoryCopyToHost(strSrcDir, mFilter, strDstDir, fRecursive, fFollowSymlinks,
                              "" /* strSubDir; for recursion */);
     if (RT_SUCCESS(rc))
@@ -1194,12 +1184,14 @@
 SessionTaskCopyDirTo::SessionTaskCopyDirTo(GuestSession *pSession,
                                            const Utf8Str &strSource, const Utf8Str &strDest, const Utf8Str &strFilter,
-                                           DirectoryCopyFlag_T enmDirCopyFlags)
-                                           : GuestSessionTask(pSession)
-                                           , mSource(strSource)
-                                           , mDest(strDest)
-                                           , mFilter(strFilter)
-                                           , mDirCopyFlags(enmDirCopyFlags)
+                                           DirectoryCopyFlag_T fDirCopyFlags)
+                                           : GuestSessionCopyTask(pSession)
 {
     m_strTaskName = "gctlCpyDirTo";
+
+    mSource = strSource;
+    mDest   = strDest;
+    mFilter = strFilter;
+
+    u.Dir.fCopyFlags = fDirCopyFlags;
 }
 
@@ -1324,5 +1316,5 @@
                         Utf8Str strSrcFile = strSrcDir + strSrcSubDir + Utf8Str(pDirEntry->szName);
                         Utf8Str strDstFile = strDstDir + strSrcSubDir + Utf8Str(pDirEntry->szName);
-                        rc = fileCopyTo(strSrcFile, strDstFile, FileCopyFlag_None);
+                        rc = fileCopyToGuest(strSrcFile, strDstFile, FileCopyFlag_None);
                     }
                     break;
@@ -1355,12 +1347,25 @@
     const uint32_t uDirMode    = 0700; /* Play safe by default. */
 
+    /* Figure out if we need to copy the entire source directory or just its contents. */
+    Utf8Str strSrcDir = mSource;
+    Utf8Str strDstDir = mDest;
+    if (   !strSrcDir.endsWith("/")
+        && !strSrcDir.endsWith("\\"))
+    {
+        if (   !strDstDir.endsWith("/")
+            && !strDstDir.endsWith("\\"))
+            strDstDir += "/";
+
+        strDstDir += Utf8StrFmt("%s", RTPathFilename(strSrcDir.c_str()));
+    }
+
     /* Create the root target directory on the guest.
-     * The target directory might already exist on the guest (based on mDirCopyFlags). */
-    int rc = directoryCreate(mDest, DirectoryCreateFlag_None, uDirMode, fFollowSymlinks);
+     * The target directory might already exist on the guest (based on u.Dir.fCopyFlags). */
+    int rc = directoryCreate(strDstDir, DirectoryCreateFlag_None, uDirMode, fFollowSymlinks);
     if (   rc == VWRN_ALREADY_EXISTS
-        && !(mDirCopyFlags & DirectoryCopyFlag_CopyIntoExisting))
+        && !(u.Dir.fCopyFlags & DirectoryCopyFlag_CopyIntoExisting))
     {
         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                            Utf8StrFmt(GuestSession::tr("Destination directory \"%s\" exists when it must not"), mDest.c_str()));
+                            Utf8StrFmt(GuestSession::tr("Destination directory \"%s\" exists when it must not"), strDstDir.c_str()));
     }
 
@@ -1370,5 +1375,5 @@
     /* At this point the directory on the guest was created and (hopefully) is ready
      * to receive further content. */
-    rc = directoryCopyToGuest(mSource, mFilter, mDest, fRecursive, fFollowSymlinks,
+    rc = directoryCopyToGuest(strSrcDir, mFilter, strDstDir, fRecursive, fFollowSymlinks,
                               "" /* strSubDir; for recursion */);
     if (RT_SUCCESS(rc))
@@ -1380,27 +1385,13 @@
 
 SessionTaskCopyFileTo::SessionTaskCopyFileTo(GuestSession *pSession,
-                                             const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)
-                                             : GuestSessionTask(pSession)
-                                             , mSource(strSource)
-                                             , mSourceFile(NULL)
-                                             , mSourceOffset(0)
-                                             , mSourceSize(0)
-                                             , mDest(strDest)
-                                             , mFileCopyFlags(enmFileCopyFlags)
+                                             const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T fFileCopyFlags)
+                                             : GuestSessionCopyTask(pSession)
 {
     m_strTaskName = "gctlCpyFileTo";
-}
-
-SessionTaskCopyFileTo::SessionTaskCopyFileTo(GuestSession *pSession,
-                                             PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize,
-                                             const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)
-                                             : GuestSessionTask(pSession)
-                                             , mSourceFile(pSourceFile)
-                                             , mSourceOffset(cbSourceOffset)
-                                             , mSourceSize(cbSourceSize)
-                                             , mDest(strDest)
-                                             , mFileCopyFlags(enmFileCopyFlags)
-{
-    m_strTaskName = "gctlCpyFileToH";
+
+    mSource = strSource;
+    mDest   = strDest;
+
+    u.File.fCopyFlags = fFileCopyFlags;
 }
 
@@ -1417,102 +1408,7 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    if (mSource.isEmpty())
-    {
-        setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("No source file specified")));
-        return VERR_INVALID_PARAMETER;
-    }
-
-    if (mDest.isEmpty())
-    {
-        setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("No destintation file specified")));
-        return VERR_INVALID_PARAMETER;
-    }
-
-    const char *pszSrcFile = mSource.c_str();
-
-    if (   !pszSrcFile
-        || !RTFileExists(pszSrcFile))
-    {
-        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                            Utf8StrFmt(GuestSession::tr("Source file \"%s\" not valid or does not exist"), pszSrcFile));
-        return VERR_FILE_NOT_FOUND;
-    }
-
-    if (mFileCopyFlags)
-    {
-        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                            Utf8StrFmt(GuestSession::tr("Copy flags (%#x) not implemented yet"),
-                            mFileCopyFlags));
-        return VERR_NOT_IMPLEMENTED;
-    }
-
-    /** @todo Try to lock the destination file / directory on the guest here first? */
-    char *pszDstFile = NULL;
-
-    int rc = VINF_SUCCESS;
-
-    /*
-     * Query information about our destination first.
-     */
-    if (   mDest.endsWith("/")
-        || mDest.endsWith("\\"))
-    {
-        int rcGuest;
-        GuestFsObjData objData;
-        rc = mSession->i_fsQueryInfo(mDest, true /* fFollowSymlinks */, objData, &rcGuest);
-        if (RT_SUCCESS(rc))
-        {
-            if (objData.mType != FsObjType_Directory)
-            {
-                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                    Utf8StrFmt(GuestSession::tr("Path \"%s\" is not a directory on guest"), pszDstFile));
-                rc = VERR_NOT_A_DIRECTORY;
-            }
-            else
-            {
-                /* Build the final file name with destination path (on the guest). */
-                char szDstPath[RTPATH_MAX];
-                RTStrPrintf2(szDstPath, sizeof(szDstPath), "%s", mDest.c_str());
-
-                RTPathAppend(szDstPath, sizeof(szDstPath), RTPathFilename(pszSrcFile));
-
-                pszDstFile = RTStrDup(szDstPath);
-            }
-        }
-        else
-        {
-            switch (rc)
-            {
-                case VERR_GSTCTL_GUEST_ERROR:
-                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                        GuestProcess::i_guestErrorToString(rcGuest));
-                    break;
-
-                default:
-                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                        Utf8StrFmt(GuestSession::tr("Unable to query information for directory \"%s\" on the guest: %Rrc"),
-                                                   pszDstFile, rc));
-                    break;
-            }
-        }
-    }
-    else
-        pszDstFile = RTStrDup(mDest.c_str());
-
+    int rc = fileCopyToGuest(mSource, mDest, u.File.fCopyFlags);
     if (RT_SUCCESS(rc))
-    {
-        AssertPtrReturn(pszDstFile, VERR_NO_MEMORY);
-
-        if (mSourceFile) /* Use existing file handle. */
-            rc = fileCopyToEx(pszSrcFile, pszDstFile, (FileCopyFlag_T)mFileCopyFlags, mSourceFile, mSourceOffset, mSourceSize);
-        else
-            rc = fileCopyTo(pszSrcFile, pszDstFile, (FileCopyFlag_T)mFileCopyFlags);
-
-        if (RT_SUCCESS(rc))
-            rc = setProgressSuccess();
-    }
-
-    if (pszDstFile)
-        RTStrFree(pszDstFile);
+        rc = setProgressSuccess();
 
     LogFlowFuncLeaveRC(rc);
@@ -1521,11 +1417,13 @@
 
 SessionTaskCopyFileFrom::SessionTaskCopyFileFrom(GuestSession *pSession,
-                                                 const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)
-                                                 : GuestSessionTask(pSession)
-                                                 , mSource(strSource)
-                                                 , mDest(strDest)
-                                                 , mFileCopyFlags(enmFileCopyFlags)
+                                                 const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T fFileCopyFlags)
+                                                 : GuestSessionCopyTask(pSession)
 {
     m_strTaskName = "gctlCpyFileFrm";
+
+    mSource = strSource;
+    mDest   = strDest;
+
+    u.File.fCopyFlags = fFileCopyFlags;
 }
 
@@ -1542,5 +1440,5 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    int rc = fileCopyFrom(mSource, mDest, mFileCopyFlags);
+    int rc = fileCopyFromGuest(mSource, mDest, u.File.fCopyFlags);
     if (RT_SUCCESS(rc))
         rc = setProgressSuccess();
@@ -1553,11 +1451,12 @@
                                                        const Utf8Str &strSource,
                                                        const ProcessArguments &aArguments,
-                                                       uint32_t uFlags)
+                                                       uint32_t fFlags)
                                                        : GuestSessionTask(pSession)
 {
-    mSource = strSource;
+    m_strTaskName = "gctlUpGA";
+
+    mSource    = strSource;
     mArguments = aArguments;
-    mFlags  = uFlags;
-    m_strTaskName = "gctlUpGA";
+    mFlags     = fFlags;
 }
 
@@ -1607,14 +1506,13 @@
 int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO,
                                                 Utf8Str const &strFileSource, const Utf8Str &strFileDest,
-                                                bool fOptional, uint32_t *pcbSize)
+                                                bool fOptional)
 {
     AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     AssertPtrReturn(pISO, VERR_INVALID_POINTER);
-    /* pcbSize is optional. */
-
-    uint32_t cbOffset;
-    size_t cbSize;
-
-    int rc = RTIsoFsGetFileInfo(pISO, strFileSource.c_str(), &cbOffset, &cbSize);
+
+    uint32_t cbSrcOffset;
+    size_t cbSrcSize;
+
+    int rc = RTIsoFsGetFileInfo(pISO, strFileSource.c_str(), &cbSrcOffset, &cbSrcSize);
     if (RT_FAILURE(rc))
     {
@@ -1625,10 +1523,7 @@
     }
 
-    Assert(cbOffset);
-    Assert(cbSize);
-    rc = RTFileSeek(pISO->file, cbOffset, RTFILE_SEEK_BEGIN, NULL);
-
-    HRESULT hr = S_OK;
-    /* Copy over the Guest Additions file to the guest. */
+    Assert(cbSrcOffset);
+    Assert(cbSrcSize);
+    rc = RTFileSeek(pISO->file, cbSrcOffset, RTFILE_SEEK_BEGIN, NULL);
     if (RT_SUCCESS(rc))
     {
@@ -1636,121 +1531,38 @@
                 strFileSource.c_str(), strFileDest.c_str()));
 
-        if (RT_SUCCESS(rc))
-        {
-            SessionTaskCopyFileTo *pTask = NULL;
-            ComObjPtr<Progress> pProgressCopyTo;
-            try
-            {
-                try
-                {
-                    pTask = new SessionTaskCopyFileTo(pSession /* GuestSession */,
-                                                      &pISO->file, cbOffset, cbSize,
-                                                      strFileDest, FileCopyFlag_None);
-                }
-                catch(...)
-                {
-                    hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                  GuestSession::tr("Failed to create SessionTaskCopyTo object "));
-                    throw;
-                }
-
-                hr = pTask->Init(Utf8StrFmt(GuestSession::tr("Copying Guest Additions installer file \"%s\" to \"%s\" on guest"),
-                                            mSource.c_str(), strFileDest.c_str()));
-                if (FAILED(hr))
-                {
-                    delete pTask;
-                    hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                  GuestSession::tr("Creating progress object for SessionTaskCopyTo object failed"));
-                    throw hr;
-                }
-
-                hr = pTask->createThreadWithType(RTTHREADTYPE_MAIN_HEAVY_WORKER);
-
-                if (SUCCEEDED(hr))
-                {
-                    /* Return progress to the caller. */
-                    pProgressCopyTo = pTask->GetProgressObject();
-                }
-                else
-                    hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                  GuestSession::tr("Starting thread for updating additions failed "));
-            }
-            catch(std::bad_alloc &)
-            {
-                hr = E_OUTOFMEMORY;
-            }
-            catch(HRESULT eHR)
-            {
-                hr = eHR;
-                LogFlowThisFunc(("Exception was caught in the function \n"));
-            }
-
-            if (SUCCEEDED(hr))
-            {
-                BOOL fCanceled = FALSE;
-                hr = pProgressCopyTo->WaitForCompletion(-1);
-                if (   SUCCEEDED(pProgressCopyTo->COMGETTER(Canceled)(&fCanceled))
-                    && fCanceled)
-                {
-                    rc = VERR_GENERAL_FAILURE; /* Fudge. */
-                }
-                else if (FAILED(hr))
-                {
-                    Assert(FAILED(hr));
-                    rc = VERR_GENERAL_FAILURE; /* Fudge. */
-                }
-            }
-        }
-    }
-
-    /** @todo Note: Since there is no file locking involved at the moment, there can be modifications
-     *              between finished copying, the verification and the actual execution. */
-
-    /* Determine where the installer image ended up and if it has the correct size. */
-    if (RT_SUCCESS(rc))
-    {
-        LogRel(("Verifying Guest Additions installer file \"%s\" ...\n",
-                strFileDest.c_str()));
-
-        GuestFsObjData objData;
-        int64_t cbSizeOnGuest;
-        int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
-        rc = pSession->i_fileQuerySize(strFileDest, false /*fFollowSymlinks*/, &cbSizeOnGuest, &rcGuest);
-        if (   RT_SUCCESS(rc)
-            && cbSize == (uint64_t)cbSizeOnGuest)
-        {
-            LogFlowThisFunc(("Guest Additions installer file \"%s\" successfully verified\n",
-                             strFileDest.c_str()));
+        GuestFileOpenInfo dstOpenInfo;
+        RT_ZERO(dstOpenInfo);
+        dstOpenInfo.mFileName    = strFileDest;
+        dstOpenInfo.mOpenAction  = FileOpenAction_CreateOrReplace;
+        dstOpenInfo.mAccessMode  = FileAccessMode_WriteOnly;
+        dstOpenInfo.mSharingMode = FileSharingMode_All; /** @todo Use _Read when implemented. */
+
+        ComObjPtr<GuestFile> dstFile; int rcGuest;
+        rc = mSession->i_fileOpen(dstOpenInfo, dstFile, &rcGuest);
+        if (RT_FAILURE(rc))
+        {
+            switch (rc)
+            {
+                case VERR_GSTCTL_GUEST_ERROR:
+                    setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(rcGuest));
+                    break;
+
+                default:
+                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                        Utf8StrFmt(GuestSession::tr("Destination file \"%s\" could not be opened: %Rrc"),
+                                                   strFileDest, rc));
+                    break;
+            }
         }
         else
         {
-            if (RT_SUCCESS(rc)) /* Size does not match. */
-            {
-                LogRel(("Size of Guest Additions installer file \"%s\" does not match: %RI64 bytes copied, %RU64 bytes expected\n",
-                        strFileDest.c_str(), cbSizeOnGuest, cbSize));
-                rc = VERR_BROKEN_PIPE; /** @todo Find a better error. */
-            }
-            else
-            {
-                switch (rc)
-                {
-                    case VERR_GSTCTL_GUEST_ERROR:
-                        setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
-                        break;
-
-                    default:
-                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                            Utf8StrFmt(GuestSession::tr("Error while querying size for file \"%s\": %Rrc"),
-                                                       strFileDest.c_str(), rc));
-                        break;
-                }
-            }
-        }
-
-        if (RT_SUCCESS(rc))
-        {
-            if (pcbSize)
-                *pcbSize = (uint32_t)cbSizeOnGuest;
-        }
+            rc = fileCopyToGuestInner(&pISO->file, dstFile, FileCopyFlag_None, cbSrcOffset, cbSrcSize);
+
+            int rc2 = dstFile->i_closeFile(&rcGuest);
+            AssertRC(rc2);
+        }
+
+        if (RT_FAILURE(rc))
+            return rc;
     }
 
@@ -2185,6 +1997,5 @@
                         if (itFiles->fFlags & ISOFILE_FLAG_OPTIONAL)
                             fOptional = true;
-                        rc = copyFileToGuest(pSession, &iso, itFiles->strSource, itFiles->strDest,
-                                               fOptional, NULL /* cbSize */);
+                        rc = copyFileToGuest(pSession, &iso, itFiles->strSource, itFiles->strDest, fOptional);
                         if (RT_FAILURE(rc))
                         {
