Index: /trunk/include/VBox/GuestHost/DragAndDrop.h
===================================================================
--- /trunk/include/VBox/GuestHost/DragAndDrop.h	(revision 55639)
+++ /trunk/include/VBox/GuestHost/DragAndDrop.h	(revision 55640)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2014 Oracle Corporation
+ * Copyright (C) 2014-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -30,4 +30,5 @@
 #include <iprt/assert.h>
 #include <iprt/cdefs.h>
+#include <iprt/dir.h>
 #include <iprt/err.h>
 #include <iprt/file.h>
@@ -37,6 +38,29 @@
 #include <iprt/cpp/ministring.h>
 
-int DnDDirCreateDroppedFilesEx(const char *pszPath, char *pszDropDir, size_t cbDropDir);
-int DnDDirCreateDroppedFiles(char *pszDropDir, size_t cbDropDir);
+/**
+ * Structure for maintaining a "dropped files" directory
+ * on the host or guest. This will contain all received files & directories
+ * for a single transfer.
+ */
+typedef struct DNDDIRDROPPEDFILES
+{
+    /** Directory handle for drop directory. */
+    PRTDIR                       hDir;
+    /** Absolute path to drop directory. */
+    RTCString                    strPathAbs;
+    /** List for holding created directories in the case of a rollback. */
+    RTCList<RTCString>           lstDirs;
+    /** List for holding created files in the case of a rollback. */
+    RTCList<RTCString>           lstFiles;
+
+} DNDDIRDROPPEDFILES, *PDNDDIRDROPPEDFILES;
+
+int DnDDirDroppedAddFile(PDNDDIRDROPPEDFILES pDir, const char *pszFile);
+int DnDDirDroppedAddDir(PDNDDIRDROPPEDFILES pDir, const char *pszDir);
+int DnDDirDroppedFilesCreateAndOpenEx(const char *pszPath, PDNDDIRDROPPEDFILES pDir);
+int DnDDirDroppedFilesCreateAndOpenTemp(PDNDDIRDROPPEDFILES pDir);
+int DnDDirDroppedFilesClose(PDNDDIRDROPPEDFILES pDir, bool fRemove);
+const char *DnDDirDroppedFilesGetDirAbs(PDNDDIRDROPPEDFILES pDir);
+int DnDDirDroppedFilesRollback(PDNDDIRDROPPEDFILES pDir);
 
 bool DnDMIMEHasFileURLs(const char *pcszFormat, size_t cchFormatMax);
@@ -77,5 +101,5 @@
     const RTCString &GetSourcePath(void) const { return m_strSrcPath; }
     const RTCString &GetDestPath(void) const { return m_strTgtPath; }
-    uint32_t GetMode(void) const { return m_fCreationMode; }
+    uint32_t GetMode(void) const { return m_fMode; }
     uint64_t GetProcessed(void) const { return m_cbProcessed; }
     uint64_t GetSize(void) const { return m_cbSize; }
@@ -91,6 +115,6 @@
     bool IsComplete(void) const;
     bool IsOpen(void) const;
-    int Open(Dest enmDest, uint64_t fOpen);
-    int OpenEx(const RTCString &strPath, Type enmType, Dest enmDest, uint64_t fMode = 0, uint32_t fFlags = 0);
+    int Open(Dest enmDest, uint64_t fOpen, uint32_t fMode = 0);
+    int OpenEx(const RTCString &strPath, Type enmType, Dest enmDest, uint64_t fOpen = 0, uint32_t fMode = 0, uint32_t fFlags = 0);
     int Read(void *pvBuf, size_t cbBuf, uint32_t *pcbRead);
     void Reset(void);
@@ -110,6 +134,6 @@
     RTCString m_strSrcPath;
     RTCString m_strTgtPath;
-    /** File creation mode. */
-    uint32_t  m_fCreationMode;
+    /** Object (file/directory) mode. */
+    uint32_t  m_fMode;
     /** Size (in bytes) to read/write. */
     uint64_t  m_cbSize;
@@ -144,5 +168,5 @@
     void RemoveFirst(void);
     int RootFromURIData(const void *pvData, size_t cbData, uint32_t fFlags);
-    RTCString RootToString(const RTCString &strBasePath = "", const RTCString &strSeparator = "\r\n");
+    RTCString RootToString(const RTCString &strPathBase = "", const RTCString &strSeparator = "\r\n");
     size_t RootCount(void) { return m_lstRoot.size(); }
     uint32_t TotalCount(void) { return m_cTotal; }
Index: /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp	(revision 55639)
+++ /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp	(revision 55640)
@@ -372,26 +372,14 @@
     void *pvTmpData = RTMemAlloc(cbTmpData);
     if (!pvTmpData)
-        rc = VERR_NO_MEMORY;
-
-    /* Create and query the (unique) drop target directory. */
+        return VERR_NO_MEMORY;
+
+    /* Create and query the (unique) drop target directory in the user's temporary directory. */
+    DNDDIRDROPPEDFILES dirDroppedFiles;
+    const char *pszDropDir;
+    rc = DnDDirDroppedFilesCreateAndOpenTemp(&dirDroppedFiles);
+    if (RT_SUCCESS(rc))
+        pszDropDir = DnDDirDroppedFilesGetDirAbs(&dirDroppedFiles);
+
     DnDURIList lstURI;
-    char szDropDir[RTPATH_MAX];
-    if (RT_SUCCESS(rc))
-        rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir));
-
-    if (RT_FAILURE(rc))
-    {
-        int rc2 = VbglR3DnDHGSetProgress(pCtx, DragAndDropSvc::DND_PROGRESS_ERROR, 100 /* Percent */, rc);
-        AssertRC(rc2);
-
-        if (pvTmpData)
-            RTMemFree(pvTmpData);
-        return rc;
-    }
-
-    /* Lists for holding created files & directories in the case of a rollback. */
-    RTCList<RTCString> guestDirList;
-    RTCList<RTCString> guestFileList;
-
     DnDURIObject objFile(DnDURIObject::File);
 
@@ -405,5 +393,4 @@
         uint32_t uNextMsg;
         uint32_t cNextParms;
-        LogFlowFunc(("Waiting for new message ...\n"));
         rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false /* fWait */);
         if (RT_SUCCESS(rc))
@@ -423,116 +410,107 @@
                                  szPathName, cbPathName, fMode, rc));
 
-                    /*
-                     * Important: HOST_DND_HG_SND_DIR sends the path (directory) name without URI specifications, that is,
-                     *            only the pure name! To match the accounting though we have to translate the pure name into
-                     *            a valid URI again.
-                     *
-                     ** @todo     Fix this URI translation!
-                     */
-                    RTCString strPath(szPathName);
-                    if (RT_SUCCESS(rc))
-                        rc = objFile.RebaseURIPath(strPath);
-                    if (RT_SUCCESS(rc))
+                    char *pszPathAbs = RTPathJoinA(pszDropDir, szPathName);
+                    if (pszPathAbs)
                     {
-                        rc = DnDPathSanitize(szPathName, sizeof(szPathName));
-                        char *pszNewDir = RTPathJoinA(szDropDir, szPathName);
-                        if (pszNewDir)
+                        rc = RTDirCreate(pszPathAbs, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0);
+                        if (RT_SUCCESS(rc))
+                            rc = DnDDirDroppedAddDir(&dirDroppedFiles, pszPathAbs);
+
+                        RTStrFree(pszPathAbs);
+                    }
+                    else
+                        rc = VERR_NO_MEMORY;
+                    break;
+                }
+                case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
+                case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
+                {
+                    if (uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR)
+                        rc = vbglR3DnDHGProcessSendFileHdrMessage(pCtx,
+                                                                  szPathName,
+                                                                  sizeof(szPathName),
+                                                                  &fFlags,
+                                                                  &fMode,
+                                                                  &cbDataToRead);
+                    else
+                        rc = vbglR3DnDHGProcessSendFileMessage(pCtx,
+                                                               szPathName,
+                                                               sizeof(szPathName),
+                                                               &cbPathName,
+                                                               pvTmpData,
+                                                               cbTmpData,
+                                                               &cbDataRecv,
+                                                               &fMode);
+                    if (   RT_SUCCESS(rc)
+                        && (   uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR
+                             /* Protocol v1 always sends the file name, so try opening every time. */
+                            || pCtx->uProtocol <= 1)
+                       )
+                    {
+                        char *pszPathAbs = RTPathJoinA(pszDropDir, szPathName);
+                        if (pszPathAbs)
                         {
-                            rc = RTDirCreate(pszNewDir, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0);
-                            RTStrFree(pszNewDir);
+                            LogFlowFunc(("Opening pszPathName=%s, cbPathName=%RU32, fMode=0x%x, cbSize=%RU64\n",
+                                         szPathName, cbPathName, fMode, cbDataToRead));
+
+                            uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_ALL;
+                            if (pCtx->uProtocol <= 1)
+                                fOpen |= RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND;
+                            else
+                                fOpen |= RTFILE_O_CREATE_REPLACE;
+
+                            /* Is there already a file open, e.g. in transfer? */
+                            if (!objFile.IsOpen())
+                            {
+
+                                RTCString strPathAbs(pszPathAbs);
+                                rc = objFile.OpenEx(strPathAbs, DnDURIObject::File, DnDURIObject::Target, fOpen,
+                                                    (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
+                                if (RT_SUCCESS(rc))
+                                {
+                                    rc = DnDDirDroppedAddFile(&dirDroppedFiles, strPathAbs.c_str());
+                                    if (RT_SUCCESS(rc))
+                                    {
+                                        cbDataWritten = 0;
+
+                                        if (pCtx->uProtocol >= 2) /* Set the expected file size. */
+                                            objFile.SetSize(cbDataToRead);
+                                    }
+                                }
+                            }
+                            else
+                                rc = VERR_WRONG_ORDER;
+
+                            RTStrFree(pszPathAbs);
                         }
                         else
                             rc = VERR_NO_MEMORY;
-
+                    }
+
+                    if (   RT_SUCCESS(rc)
+                        && uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA)
+                    {
+                        bool fClose = false;
+
+                        uint32_t cbWritten;
+                        rc = objFile.Write(pvTmpData, cbDataRecv, &cbWritten);
                         if (RT_SUCCESS(rc))
                         {
-                            if (!guestDirList.contains(strPath))
-                                guestDirList.append(strPath);
-                        }
-                    }
-                    break;
-                }
-                case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
-                {
-                    rc = vbglR3DnDHGProcessSendFileHdrMessage(pCtx,
-                                                              szPathName,
-                                                              sizeof(szPathName),
-                                                              &fFlags,
-                                                              &fMode,
-                                                              &cbDataToRead);
-                    LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR pszPathName=%s, fFlags=0x%x, fMode=0x%x, cbDataToRead=%RU64, rc=%Rrc\n",
-                                 szPathName, fFlags, fMode, cbDataToRead, rc));
-
-                    cbDataWritten = 0;
-                    break;
-                }
-                case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
-                {
-                    rc = vbglR3DnDHGProcessSendFileMessage(pCtx,
-                                                           szPathName,
-                                                           sizeof(szPathName),
-                                                           &cbPathName,
-                                                           pvTmpData,
-                                                           cbTmpData,
-                                                           &cbDataRecv,
-                                                           &fMode);
-                    LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA pszPathName=%s, cbPathName=%RU32, pvData=0x%p, cbDataRecv=%RU32, fMode=0x%x, rc=%Rrc\n",
-                                 szPathName, cbPathName, pvTmpData, cbDataRecv, fMode, rc));
-
-                    /*
-                     * Important: HOST_DND_HG_SND_FILE sends the path (directory) name without URI specifications, that is,
-                     *            only the pure name! To match the accounting though we have to translate the pure name into
-                     *            a valid URI again.
-                     *
-                     ** @todo     Fix this URI translation!
-                     */
-                    RTCString strPath(szPathName);
-                    if (RT_SUCCESS(rc))
-                        rc = objFile.RebaseURIPath(strPath);
-                    if (RT_SUCCESS(rc))
-                    {
-                        rc = DnDPathSanitize(szPathName, sizeof(szPathName));
-                        if (RT_SUCCESS(rc))
-                        {
-                            char *pszPathAbs = RTPathJoinA(szDropDir, szPathName);
-                            if (pszPathAbs)
+                            if (pCtx->uProtocol >= 2)
                             {
-                                RTFILE hFile;
-                                /** @todo r=andy Keep the file open and locked during the actual file transfer. Otherwise this will
-                                 *               create all sorts of funny races because we don't know if the guest has
-                                 *               modified the file in between the file data send calls.
-                                 *
-                                 *               See HOST_DND_HG_SND_FILE_HDR for a good place to do this. */
-                                rc = RTFileOpen(&hFile, pszPathAbs,
-                                                RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE);
-                                if (RT_SUCCESS(rc))
-                                {
-                                    /** @todo r=andy Not very safe to assume that we were last appending to the current file. */
-                                    rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
-                                    if (RT_SUCCESS(rc))
-                                    {
-                                        rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0);
-                                        if (RT_SUCCESS(rc))
-                                        {
-                                            if (fMode & RTFS_UNIX_MASK) /* Valid UNIX mode? */
-                                                rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
-
-                                            cbDataWritten += cbDataRecv;
-                                            Assert(cbDataWritten <= cbDataToRead);
-                                        }
-                                    }
-
-                                    RTFileClose(hFile);
-
-                                    if (!guestFileList.contains(pszPathAbs)) /* Add the file to (rollback) list. */
-                                        guestFileList.append(pszPathAbs);
-                                }
-                                else
-                                    LogFlowFunc(("Opening file failed with rc=%Rrc\n", rc));
-
-                                RTStrFree(pszPathAbs);
+                                /* Data transfer complete? Close the file. */
+                                fClose = objFile.IsComplete();
                             }
                             else
-                                rc = VERR_NO_MEMORY;
+                                fClose = true; /* Always close the file after each chunk. */
+
+                            cbDataWritten += cbWritten;
+                            Assert(cbDataWritten <= cbDataToRead);
+                        }
+
+                        if (fClose)
+                        {
+                            LogFlowFunc(("Closing file\n"));
+                            objFile.Close();
                         }
                     }
@@ -607,11 +585,4 @@
 #endif
         }
-        else
-        {
-            /* All URI data processed? */
-            if (rc == VERR_NO_DATA)
-                rc = VINF_SUCCESS;
-            break;
-        }
 
         if (RT_FAILURE(rc))
@@ -622,17 +593,17 @@
     LogFlowFunc(("Loop ended with %Rrc\n", rc));
 
+    /* All URI data processed? */
+    if (rc == VERR_NO_DATA)
+        rc = VINF_SUCCESS;
+
     if (pvTmpData)
         RTMemFree(pvTmpData);
 
-    /* Cleanup on failure or if the user has canceled the operation. */
+    /* Cleanup on failure or if the user has canceled the operation or
+     * something else went wrong. */
     if (RT_FAILURE(rc))
     {
-        LogFlowFunc(("Rolling back ...\n"));
-
-        /* Rollback by removing any stuff created. */
-        for (size_t i = 0; i < guestFileList.size(); ++i)
-            RTFileDelete(guestFileList.at(i).c_str());
-        for (size_t i = 0; i < guestDirList.size(); ++i)
-            RTDirRemove(guestDirList.at(i).c_str());
+        int rc2 = DnDDirDroppedFilesRollback(&dirDroppedFiles);
+        AssertRC(rc2); /* Not fatal, don't report back to host. */
     }
     else
@@ -647,5 +618,5 @@
             RTMemFree(pvData);
 
-            RTCString strData = lstURI.RootToString(szDropDir);
+            RTCString strData = lstURI.RootToString(pszDropDir);
             LogFlowFunc(("cbDataToRead: %zu -> %zu\n", cbDataToRead, strData.length() + 1));
 
@@ -663,8 +634,12 @@
     }
 
-    /* Try removing the (empty) drop directory in any case. */
-    int rc2 = RTDirRemove(szDropDir);
-    if (RT_FAILURE(rc2))
-        LogFunc(("Warning: Unable to remove drop directory \"%s\": %Rrc\n", szDropDir, rc2));
+    /*
+     * Close the dropped files directory.
+     * Don't try to remove it here, however, as the files are being needed
+     * by the client's drag'n drop operation lateron.
+     */
+    int rc2 = DnDDirDroppedFilesClose(&dirDroppedFiles, false);
+    if (RT_FAILURE(rc2)) /* Not fatal, don't report back to host. */
+        LogFlowFunc(("Closing dropped files directory failed with %Rrc\n", rc2));
 
     LogFlowFuncLeaveRC(rc);
@@ -872,4 +847,5 @@
         AssertPtr(pcbFormatRecv);
         if (DnDMIMEHasFileURLs(pszFormat, *pcbFormatRecv))
+        {
             rc = vbglR3DnDHGProcessURIMessages(pCtx,
                                                puScreenId,
@@ -880,6 +856,16 @@
                                                cbData,
                                                pcbDataRecv);
+        }
         else
             rc = VERR_NOT_SUPPORTED;
+
+        if (RT_FAILURE(rc))
+        {
+            if (RT_FAILURE(rc))
+            {
+                int rc2 = VbglR3DnDHGSetProgress(pCtx, DragAndDropSvc::DND_PROGRESS_ERROR, 100 /* Percent */, rc);
+                AssertRC(rc2);
+            }
+        }
     }
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp	(revision 55639)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp	(revision 55640)
@@ -1443,5 +1443,4 @@
 void UIMachineView::dragIsPending(void)
 {
-    /* At the moment we only support guest->host DnD. */
     /** @todo Add guest->guest DnD functionality here by getting
      *        the source of guest B (when copying from B to A). */
Index: /trunk/src/VBox/GuestHost/DragAndDrop/DnDDir.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/DragAndDrop/DnDDir.cpp	(revision 55639)
+++ /trunk/src/VBox/GuestHost/DragAndDrop/DnDDir.cpp	(revision 55640)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2014 Oracle Corporation
+ * Copyright (C) 2014-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -27,12 +27,31 @@
 #include <VBox/GuestHost/DragAndDrop.h>
 
-int DnDDirCreateDroppedFilesEx(const char *pszPath,
-                               char *pszDropDir, size_t cbDropDir)
+int DnDDirDroppedAddFile(PDNDDIRDROPPEDFILES pDir, const char *pszFile)
+{
+    AssertPtrReturn(pDir, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
+
+    if (!pDir->lstFiles.contains(pszFile))
+        pDir->lstFiles.append(pszFile);
+    return VINF_SUCCESS;
+}
+
+int DnDDirDroppedAddDir(PDNDDIRDROPPEDFILES pDir, const char *pszDir)
+{
+    AssertPtrReturn(pDir, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszDir, VERR_INVALID_POINTER);
+
+    if (!pDir->lstDirs.contains(pszDir))
+        pDir->lstDirs.append(pszDir);
+    return VINF_SUCCESS;
+}
+
+int DnDDirDroppedFilesCreateAndOpenEx(const char *pszPath, PDNDDIRDROPPEDFILES pDir)
 {
     AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
-    AssertPtrReturn(pszDropDir, VERR_INVALID_POINTER);
-    AssertReturn(cbDropDir, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pDir, VERR_INVALID_POINTER);
 
-    if (RTStrPrintf(pszDropDir, cbDropDir, "%s", pszPath) <= 0)
+    char pszDropDir[RTPATH_MAX];
+    if (RTStrPrintf(pszDropDir, sizeof(pszDropDir), "%s", pszPath) <= 0)
         return VERR_NO_MEMORY;
 
@@ -42,5 +61,5 @@
 
     /* Append our base drop directory. */
-    int rc = RTPathAppend(pszDropDir, cbDropDir, "VirtualBox Dropped Files");
+    int rc = RTPathAppend(pszDropDir, sizeof(pszDropDir), "VirtualBox Dropped Files"); /** @todo Make this tag configurable? */
     if (RT_FAILURE(rc))
         return rc;
@@ -64,27 +83,103 @@
         return rc;
 
-    rc = RTPathAppend(pszDropDir, cbDropDir, pszTime);
+    rc = RTPathAppend(pszDropDir, sizeof(pszDropDir), pszTime);
     if (RT_FAILURE(rc))
         return rc;
 
     /* Create it (only accessible by the current user) */
-    return RTDirCreateUniqueNumbered(pszDropDir, cbDropDir, RTFS_UNIX_IRWXU, 3, '-');
+    rc = RTDirCreateUniqueNumbered(pszDropDir, sizeof(pszDropDir), RTFS_UNIX_IRWXU, 3, '-');
+    if (RT_SUCCESS(rc))
+    {
+        PRTDIR phDir;
+        rc = RTDirOpen(&phDir, pszDropDir);
+        if (RT_SUCCESS(rc))
+        {
+            pDir->hDir       = phDir;
+            pDir->strPathAbs = pszDropDir;
+        }
+    }
+
+    return rc;
 }
 
-int DnDDirCreateDroppedFiles(char *pszDropDir, size_t cbDropDir)
+int DnDDirDroppedFilesCreateAndOpenTemp(PDNDDIRDROPPEDFILES pDir)
 {
-    AssertPtrReturn(pszDropDir, VERR_INVALID_POINTER);
-    AssertReturn(cbDropDir, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pDir, VERR_INVALID_POINTER);
 
     char szTemp[RTPATH_MAX];
 
-    /* Get the user's temp directory. Don't use the user's root directory (or
+    /*
+     * Get the user's temp directory. Don't use the user's root directory (or
      * something inside it) because we don't know for how long/if the data will
-     * be kept after the guest OS used it. */
+     * be kept after the guest OS used it.
+     */
     int rc = RTPathTemp(szTemp, sizeof(szTemp));
     if (RT_FAILURE(rc))
         return rc;
 
-    return DnDDirCreateDroppedFilesEx(szTemp, pszDropDir, cbDropDir);
+    return DnDDirDroppedFilesCreateAndOpenEx(szTemp, pDir);
 }
 
+int DnDDirDroppedFilesClose(PDNDDIRDROPPEDFILES pDir, bool fRemove)
+{
+    AssertPtrReturn(pDir, VERR_INVALID_POINTER);
+
+    int rc = RTDirClose(pDir->hDir);
+    if (RT_SUCCESS(rc))
+    {
+        pDir->lstDirs.clear();
+        pDir->lstFiles.clear();
+
+        if (fRemove)
+        {
+            /* Try removing the (empty) drop directory in any case. */
+            rc = RTDirRemove(pDir->strPathAbs.c_str());
+            if (RT_SUCCESS(rc)) /* Only clear if successfully removed. */
+                pDir->strPathAbs = "";
+        }
+    }
+
+    return rc;
+}
+
+const char *DnDDirDroppedFilesGetDirAbs(PDNDDIRDROPPEDFILES pDir)
+{
+    AssertPtrReturn(pDir, NULL);
+    return pDir->strPathAbs.c_str();
+}
+
+int DnDDirDroppedFilesRollback(PDNDDIRDROPPEDFILES pDir)
+{
+    AssertPtrReturn(pDir, VERR_INVALID_POINTER);
+
+    if (pDir->strPathAbs.isEmpty())
+        return VINF_SUCCESS;
+
+    int rc = VINF_SUCCESS;
+    int rc2;
+
+    /* Rollback by removing any stuff created.
+     * Note: Only remove empty directories, never ever delete
+     *       anything recursive here! Steam (tm) knows best ... :-) */
+    for (size_t i = 0; i < pDir->lstFiles.size(); i++)
+    {
+        rc2 = RTFileDelete(pDir->lstFiles.at(i).c_str());
+        if (RT_SUCCESS(rc))
+            rc = rc2;
+    }
+
+    for (size_t i = 0; i < pDir->lstDirs.size(); i++)
+    {
+        rc2 = RTDirRemove(pDir->lstDirs.at(i).c_str());
+        if (RT_SUCCESS(rc))
+            rc = rc2;
+    }
+
+    /* Try to remove the empty root dropped files directory as well. */
+    rc2 = RTDirRemove(pDir->strPathAbs.c_str());
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    return rc;
+}
+
Index: /trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp	(revision 55639)
+++ /trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp	(revision 55640)
@@ -336,6 +336,5 @@
 }
 
-int DnDURIList::RootFromURIData(const void *pvData, size_t cbData,
-                                uint32_t fFlags)
+int DnDURIList::RootFromURIData(const void *pvData, size_t cbData, uint32_t fFlags)
 {
     AssertPtrReturn(pvData, VERR_INVALID_POINTER);
@@ -380,5 +379,5 @@
 }
 
-RTCString DnDURIList::RootToString(const RTCString &strBasePath /* = "" */,
+RTCString DnDURIList::RootToString(const RTCString &strPathBase /* = "" */,
                                    const RTCString &strSeparator /* = "\r\n" */)
 {
@@ -390,7 +389,7 @@
         LogFlowFunc(("pszCurRoot=%s\n", pszCurRoot));
 #endif
-        if (strBasePath.isNotEmpty())
-        {
-            char *pszPath = RTPathJoinA(strBasePath.c_str(), pszCurRoot);
+        if (strPathBase.isNotEmpty())
+        {
+            char *pszPath = RTPathJoinA(strPathBase.c_str(), pszCurRoot);
             if (pszPath)
             {
@@ -399,7 +398,5 @@
                 {
                     strRet += RTCString(pszPathURI) + strSeparator;
-#ifdef DEBUG_andy
                     LogFlowFunc(("URI: %s\n", strRet.c_str()));
-#endif
                     RTStrFree(pszPathURI);
                 }
@@ -417,7 +414,5 @@
             {
                 strRet += RTCString(pszPathURI) + strSeparator;
-#ifdef DEBUG_andy
                 LogFlowFunc(("URI: %s\n", strRet.c_str()));
-#endif
                 RTStrFree(pszPathURI);
             }
Index: /trunk/src/VBox/GuestHost/DragAndDrop/DnDURIObject.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/DragAndDrop/DnDURIObject.cpp	(revision 55639)
+++ /trunk/src/VBox/GuestHost/DragAndDrop/DnDURIObject.cpp	(revision 55640)
@@ -37,5 +37,5 @@
 DnDURIObject::DnDURIObject(void)
     : m_Type(Unknown)
-    , m_fCreationMode(0)
+    , m_fMode(0)
     , m_cbSize(0)
     , m_cbProcessed(0)
@@ -51,5 +51,5 @@
     , m_strSrcPath(strSrcPath)
     , m_strTgtPath(strDstPath)
-    , m_fCreationMode(fMode)
+    , m_fMode(fMode)
     , m_cbSize(cbSize)
     , m_cbProcessed(0)
@@ -155,13 +155,13 @@
 }
 
-int DnDURIObject::Open(Dest enmDest, uint64_t fOpen)
+int DnDURIObject::Open(Dest enmDest, uint64_t fOpen /* = 0 */, uint32_t fMode /* = 0 */)
 {
     return OpenEx(  enmDest == Source
                   ? m_strSrcPath : m_strTgtPath
-                  , m_Type, enmDest, fOpen, 0 /* fFlag s*/);
+                  , m_Type, enmDest, fOpen, fMode, 0 /* fFlags */);
 }
 
 int DnDURIObject::OpenEx(const RTCString &strPath, Type enmType, Dest enmDest,
-                         uint64_t fOpen /* = 0 */, uint32_t fFlags /* = 0 */)
+                         uint64_t fOpen /* = 0 */, uint32_t fMode /* = 0 */, uint32_t fFlags /* = 0 */)
 {
     int rc = VINF_SUCCESS;
@@ -198,7 +198,12 @@
                     if (RT_SUCCESS(rc))
                         rc = RTFileGetSize(u.m_hFile, &m_cbSize);
+                    if (RT_SUCCESS(rc)
+                        && fMode)
+                    {
+                        rc = RTFileSetMode(u.m_hFile, fMode);
+                    }
                     if (RT_SUCCESS(rc))
                     {
-                        LogFlowFunc(("cbSize=%RU64, fMode=%RU32\n", m_cbSize, m_fCreationMode));
+                        LogFlowFunc(("cbSize=%RU64, fMode=%RU32\n", m_cbSize, m_fMode));
                         m_cbProcessed = 0;
                     }
@@ -293,6 +298,4 @@
         case File:
         {
-            bool fDone = false;
-
             rc = OpenEx(m_strSrcPath, File, Source,
                         /* Use some sensible defaults. */
@@ -307,15 +310,10 @@
 
                     /* End of file reached or error occurred? */
-                    if (m_cbProcessed == m_cbSize)
+                    if (   m_cbSize
+                        && m_cbProcessed == m_cbSize)
                     {
                         rc = VINF_EOF;
-                        fDone = true;
                     }
                 }
-                else
-                    fDone = true;
-
-                if (fDone)
-                    closeInternal();
             }
 
@@ -351,5 +349,5 @@
     m_strSrcPath    = "";
     m_strTgtPath    = "";
-    m_fCreationMode = 0;
+    m_fMode = 0;
     m_cbSize        = 0;
     m_cbProcessed   = 0;
@@ -369,6 +367,4 @@
         case File:
         {
-            bool fDone = false;
-
             rc = OpenEx(m_strTgtPath, File, Target,
                         /* Use some sensible defaults. */
@@ -379,9 +375,4 @@
                 if (RT_SUCCESS(rc))
                     m_cbProcessed += cbWritten;
-                else
-                    fDone = true;
-
-                if (fDone)
-                    closeInternal();
             }
 
Index: /trunk/src/VBox/HostServices/DragAndDrop/service.cpp
===================================================================
--- /trunk/src/VBox/HostServices/DragAndDrop/service.cpp	(revision 55639)
+++ /trunk/src/VBox/HostServices/DragAndDrop/service.cpp	(revision 55640)
@@ -712,36 +712,5 @@
         if (m_clientMap.size()) /* At least one client on the guest connected? */
         {
-            /*
-             * Did the host call something which needs immediate processing?
-             * Prepend the message instead of appending to the command queue then.
-             */
-            bool fAppend;
-            switch (u32Function)
-            {
-                /* Cancelling the drag'n drop operation has higher priority than
-                 * processing already buffered messages. */
-                case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
-                    fAppend = false;
-                    break;
-
-                default:
-                    fAppend = true;
-                    break;
-            }
-
-            /*
-             * If we prepending the message (instead of appending) this mean we need
-             * to re-schedule the message queue in order to get the new command executed as
-             * soon as possible.
-             */
-            bool fReschedule = !fAppend;
-
-            rc = m_pManager->addMessage(u32Function, cParms, paParms, fAppend);
-            if (   RT_SUCCESS(rc)
-                && fReschedule)
-            {
-                rc = m_pManager->doReschedule();
-            }
-
+            rc = m_pManager->addMessage(u32Function, cParms, paParms, true /* fAppend */);
             if (RT_SUCCESS(rc))
             {
Index: /trunk/src/VBox/Main/include/GuestDnDPrivate.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestDnDPrivate.h	(revision 55639)
+++ /trunk/src/VBox/Main/include/GuestDnDPrivate.h	(revision 55640)
@@ -106,8 +106,5 @@
     void Reset(void)
     {
-        strDropDir = "";
         lstURI.Clear();
-        lstDirs.clear();
-        lstFiles.clear();
 #if 0 /* Currently the scratch buffer will be maintained elswewhere. */
         if (pvScratchBuf)
@@ -123,47 +120,9 @@
     }
 
-    int Rollback(void)
-    {
-        if (strDropDir.isEmpty())
-            return VINF_SUCCESS;
-
-        int rc = VINF_SUCCESS;
-        int rc2;
-
-        /* Rollback by removing any stuff created.
-         * Note: Only remove empty directories, never ever delete
-         *       anything recursive here! Steam (tm) knows best ... :-) */
-        for (size_t i = 0; i < lstFiles.size(); i++)
-        {
-            rc2 = RTFileDelete(lstFiles.at(i).c_str());
-            if (RT_SUCCESS(rc))
-                rc = rc2;
-        }
-
-        for (size_t i = 0; i < lstDirs.size(); i++)
-        {
-            rc2 = RTDirRemove(lstDirs.at(i).c_str());
-            if (RT_SUCCESS(rc))
-                rc = rc2;
-        }
-
-        rc2 = RTDirRemove(strDropDir.c_str());
-        if (RT_SUCCESS(rc))
-            rc = rc2;
-
-        return rc;
-    }
-
-    /** Temporary drop directory on the host where to
-     *  put the files sent from the guest. */
-    com::Utf8Str                    strDropDir;
+    DNDDIRDROPPEDFILES              mDropDir;
     /** (Non-recursive) List of root URI objects to receive. */
     DnDURIList                      lstURI;
     /** Current object to receive. */
     DnDURIObject                    objURI;
-    /** List for holding created directories in the case of a rollback. */
-    RTCList<RTCString>              lstDirs;
-    /** List for holding created files in the case of a rollback. */
-    RTCList<RTCString>              lstFiles;
     /** Pointer to an optional scratch buffer to use for
      *  doing the actual chunk transfers. */
Index: /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp	(revision 55639)
+++ /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp	(revision 55640)
@@ -869,10 +869,20 @@
 int GuestDnDBase::sendCancel(void)
 {
-    LogFlowFunc(("Sending cancelation request to guest ...\n"));
-
-    GuestDnDMsg MsgCancel;
-    MsgCancel.setType(DragAndDropSvc::HOST_DND_HG_EVT_CANCEL);
-
-    return GuestDnDInst()->hostCall(MsgCancel.getType(), MsgCancel.getCount(), MsgCancel.getParms());
+    LogFlowFunc(("Generating cancel request ...\n"));
+
+    int rc;
+    try
+    {
+        GuestDnDMsg *pMsgCancel = new GuestDnDMsg();
+        pMsgCancel->setType(DragAndDropSvc::HOST_DND_HG_EVT_CANCEL);
+
+        rc = msgQueueAdd(pMsgCancel);
+    }
+    catch(std::bad_alloc & /*e*/)
+    {
+        rc = VERR_NO_MEMORY;
+    }
+
+    return rc;
 }
 
Index: /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp	(revision 55639)
+++ /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp	(revision 55640)
@@ -225,5 +225,5 @@
 }
 
-// implementation of wrapped IDnDTarget methods.
+// implementation of wrapped IDnDSource methods.
 /////////////////////////////////////////////////////////////////////////////
 
@@ -277,8 +277,4 @@
     }
 
-    if (RT_FAILURE(rc))
-        hr = setError(VBOX_E_IPRT_ERROR,
-                      tr("Error retrieving drag and drop pending status (%Rrc)\n"), rc);
-
     LogFlowFunc(("hr=%Rhrc, defaultAction=0x%x\n", hr, defaultAction));
     return hr;
@@ -383,5 +379,5 @@
         if (fHasURIList)
         {
-            Utf8Str strURIs = pCtx->mURI.lstURI.RootToString(pCtx->mURI.strDropDir);
+            Utf8Str strURIs = pCtx->mURI.lstURI.RootToString(RTCString(DnDDirDroppedFilesGetDirAbs(&pCtx->mURI.mDropDir)));
             cbData = strURIs.length();
 
@@ -489,5 +485,5 @@
 
     int rc;
-    char *pszDir = RTPathJoinA(pCtx->mURI.strDropDir.c_str(), pszPath);
+    char *pszDir = RTPathJoinA(DnDDirDroppedFilesGetDirAbs(&pCtx->mURI.mDropDir), pszPath);
     if (pszDir)
     {
@@ -571,5 +567,5 @@
 
         char pszPathAbs[RTPATH_MAX];
-        rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pCtx->mURI.strDropDir.c_str(), pszPath);
+        rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), DnDDirDroppedFilesGetDirAbs(&pCtx->mURI.mDropDir), pszPath);
         if (RT_FAILURE(rc))
         {
@@ -588,7 +584,7 @@
 
         /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */
-        /** @todo Add fMode to opening flags. */
         rc = pCtx->mURI.objURI.OpenEx(pszPathAbs, DnDURIObject::File, DnDURIObject::Target,
-                                      RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
+                                      RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE,
+                                      (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
         if (RT_SUCCESS(rc))
         {
@@ -898,11 +894,10 @@
     do
     {
-        char szDropDir[RTPATH_MAX];
-        rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir));
-        LogFlowFunc(("rc=%Rrc, szDropDir=%s\n", rc, szDropDir));
+        rc = DnDDirDroppedFilesCreateAndOpenTemp(&pCtx->mURI.mDropDir);
         if (RT_FAILURE(rc))
             break;
-
-        pCtx->mURI.strDropDir = szDropDir; /** @todo Keep directory handle open? */
+        LogFlowFunc(("strDropDir=%s\n", rc, DnDDirDroppedFilesGetDirAbs(&pCtx->mURI.mDropDir)));
+        if (RT_FAILURE(rc))
+            break;
 
         /*
@@ -936,7 +931,9 @@
 #undef UNREGISTER_CALLBACK
 
+    int rc2;
+
     if (rc == VERR_CANCELLED)
     {
-        int rc2 = sendCancel();
+        rc2 = sendCancel();
         AssertRC(rc2);
     }
@@ -944,7 +941,11 @@
     if (RT_FAILURE(rc))
     {
-        int rc2 = pCtx->mURI.Rollback(); /** @todo Inform user on rollback failure? */
+        rc2 = DnDDirDroppedFilesRollback(&pCtx->mURI.mDropDir); /** @todo Inform user on rollback failure? */
         LogFlowFunc(("Rolling back ended with rc=%Rrc\n", rc2));
     }
+
+    rc2 = DnDDirDroppedFilesClose(&pCtx->mURI.mDropDir, RT_FAILURE(rc) ? true : false /* fRemove */);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
 
     LogFlowFuncLeaveRC(rc);
Index: /trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp	(revision 55639)
+++ /trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp	(revision 55640)
@@ -821,8 +821,7 @@
             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
 
-            GuestDnDMsg *pMsg;
             try
             {
-                pMsg = new GuestDnDMsg();
+                GuestDnDMsg *pMsg = new GuestDnDMsg();
 
                 rc = pThis->i_sendURIDataLoop(pCtx, pMsg);
