summaryrefslogtreecommitdiffstats
path: root/src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp264
1 files changed, 264 insertions, 0 deletions
diff --git a/src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp b/src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp
new file mode 100644
index 00000000..1b3651cb
--- /dev/null
+++ b/src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp
@@ -0,0 +1,264 @@
+/* $Id: DnDDroppedFiles.cpp $ */
+/** @file
+ * DnD - Directory handling.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_GUEST_DND
+#include <VBox/GuestHost/DragAndDrop.h>
+
+#include <iprt/assert.h>
+#include <iprt/dir.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+
+
+#include <VBox/log.h>
+
+DnDDroppedFiles::DnDDroppedFiles(void)
+ : m_fOpen(0)
+ , m_hDir(NULL) { }
+
+DnDDroppedFiles::DnDDroppedFiles(const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */)
+ : m_fOpen(0)
+ , m_hDir(NULL)
+{
+ OpenEx(pszPath, fFlags);
+}
+
+DnDDroppedFiles::~DnDDroppedFiles(void)
+{
+ /* Only make sure to not leak any handles and stuff, don't delete any
+ * directories / files here. */
+ closeInternal();
+}
+
+int DnDDroppedFiles::AddFile(const char *pszFile)
+{
+ AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
+
+ if (!this->m_lstFiles.contains(pszFile))
+ this->m_lstFiles.append(pszFile);
+ return VINF_SUCCESS;
+}
+
+int DnDDroppedFiles::AddDir(const char *pszDir)
+{
+ AssertPtrReturn(pszDir, VERR_INVALID_POINTER);
+
+ if (!this->m_lstDirs.contains(pszDir))
+ this->m_lstDirs.append(pszDir);
+ return VINF_SUCCESS;
+}
+
+int DnDDroppedFiles::closeInternal(void)
+{
+ int rc;
+ if (this->m_hDir != NULL)
+ {
+ rc = RTDirClose(this->m_hDir);
+ if (RT_SUCCESS(rc))
+ this->m_hDir = NULL;
+ }
+ else
+ rc = VINF_SUCCESS;
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+int DnDDroppedFiles::Close(void)
+{
+ return closeInternal();
+}
+
+const char *DnDDroppedFiles::GetDirAbs(void) const
+{
+ return this->m_strPathAbs.c_str();
+}
+
+bool DnDDroppedFiles::IsOpen(void) const
+{
+ return (this->m_hDir != NULL);
+}
+
+int DnDDroppedFiles::OpenEx(const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */)
+{
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+ AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /* Flags not supported yet. */
+
+ int rc;
+
+ do
+ {
+ char pszDropDir[RTPATH_MAX];
+ RTStrPrintf(pszDropDir, sizeof(pszDropDir), "%s", pszPath);
+
+ /** @todo On Windows we also could use the registry to override
+ * this path, on Posix a dotfile and/or a guest property
+ * can be used. */
+
+ /* Append our base drop directory. */
+ rc = RTPathAppend(pszDropDir, sizeof(pszDropDir), "VirtualBox Dropped Files"); /** @todo Make this tag configurable? */
+ if (RT_FAILURE(rc))
+ break;
+
+ /* Create it when necessary. */
+ if (!RTDirExists(pszDropDir))
+ {
+ rc = RTDirCreateFullPath(pszDropDir, RTFS_UNIX_IRWXU);
+ if (RT_FAILURE(rc))
+ break;
+ }
+
+ /* The actually drop directory consist of the current time stamp and a
+ * unique number when necessary. */
+ char pszTime[64];
+ RTTIMESPEC time;
+ if (!RTTimeSpecToString(RTTimeNow(&time), pszTime, sizeof(pszTime)))
+ {
+ rc = VERR_BUFFER_OVERFLOW;
+ break;
+ }
+
+ rc = DnDPathSanitizeFilename(pszTime, sizeof(pszTime));
+ if (RT_FAILURE(rc))
+ break;
+
+ rc = RTPathAppend(pszDropDir, sizeof(pszDropDir), pszTime);
+ if (RT_FAILURE(rc))
+ break;
+
+ /* Create it (only accessible by the current user) */
+ rc = RTDirCreateUniqueNumbered(pszDropDir, sizeof(pszDropDir), RTFS_UNIX_IRWXU, 3, '-');
+ if (RT_SUCCESS(rc))
+ {
+ RTDIR hDir;
+ rc = RTDirOpen(&hDir, pszDropDir);
+ if (RT_SUCCESS(rc))
+ {
+ this->m_hDir = hDir;
+ this->m_strPathAbs = pszDropDir;
+ this->m_fOpen = fFlags;
+ }
+ }
+
+ } while (0);
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+int DnDDroppedFiles::OpenTemp(DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */)
+{
+ AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /* Flags not supported yet. */
+
+ /*
+ * 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.
+ */
+ char szTemp[RTPATH_MAX];
+ int rc = RTPathTemp(szTemp, sizeof(szTemp));
+ if (RT_SUCCESS(rc))
+ rc = OpenEx(szTemp, fFlags);
+
+ return rc;
+}
+
+int DnDDroppedFiles::Reset(bool fRemoveDropDir)
+{
+ int rc = closeInternal();
+ if (RT_SUCCESS(rc))
+ {
+ if (fRemoveDropDir)
+ {
+ rc = Rollback();
+ }
+ else
+ {
+ this->m_lstDirs.clear();
+ this->m_lstFiles.clear();
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+int DnDDroppedFiles::Reopen(void)
+{
+ if (this->m_strPathAbs.isEmpty())
+ return VERR_NOT_FOUND;
+
+ return OpenEx(this->m_strPathAbs.c_str(), this->m_fOpen);
+}
+
+int DnDDroppedFiles::Rollback(void)
+{
+ if (this->m_strPathAbs.isEmpty())
+ return VINF_SUCCESS;
+
+ int rc = VINF_SUCCESS;
+
+ /* Rollback by removing any stuff created.
+ * Note: Only remove empty directories, never ever delete
+ * anything recursive here! Steam (tm) knows best ... :-) */
+ int rc2;
+ for (size_t i = 0; i < this->m_lstFiles.size(); i++)
+ {
+ rc2 = RTFileDelete(this->m_lstFiles.at(i).c_str());
+ if (RT_SUCCESS(rc2))
+ this->m_lstFiles.removeAt(i);
+ else if (RT_SUCCESS(rc))
+ rc = rc2;
+ /* Keep going. */
+ }
+
+ for (size_t i = 0; i < this->m_lstDirs.size(); i++)
+ {
+ rc2 = RTDirRemove(this->m_lstDirs.at(i).c_str());
+ if (RT_SUCCESS(rc2))
+ this->m_lstDirs.removeAt(i);
+ else if (RT_SUCCESS(rc))
+ rc = rc2;
+ /* Keep going. */
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ Assert(this->m_lstFiles.isEmpty());
+ Assert(this->m_lstDirs.isEmpty());
+
+ rc2 = closeInternal();
+ if (RT_SUCCESS(rc2))
+ {
+ /* Try to remove the empty root dropped files directory as well.
+ * Might return VERR_DIR_NOT_EMPTY or similar. */
+ rc2 = RTDirRemove(this->m_strPathAbs.c_str());
+ }
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+