diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
commit | f8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch) | |
tree | 26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp | |
parent | Initial commit. (diff) | |
download | virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.tar.xz virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.zip |
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp')
-rw-r--r-- | src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp | 565 |
1 files changed, 565 insertions, 0 deletions
diff --git a/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp b/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp new file mode 100644 index 00000000..0013d760 --- /dev/null +++ b/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp @@ -0,0 +1,565 @@ +/* $Id: DnDURIList.cpp $ */ +/** @file + * DnD - URI list class. + */ + +/* + * 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/dir.h> +#include <iprt/err.h> +#include <iprt/file.h> +#include <iprt/fs.h> +#include <iprt/path.h> +#include <iprt/string.h> +#include <iprt/symlink.h> +#include <iprt/uri.h> + +#include <VBox/log.h> + + +DnDURIList::DnDURIList(void) + : m_cTotal(0) + , m_cbTotal(0) +{ +} + +DnDURIList::~DnDURIList(void) +{ + Clear(); +} + +int DnDURIList::addEntry(const char *pcszSource, const char *pcszTarget, DNDURILISTFLAGS fFlags) +{ + AssertPtrReturn(pcszSource, VERR_INVALID_POINTER); + AssertPtrReturn(pcszTarget, VERR_INVALID_POINTER); + + LogFlowFunc(("pcszSource=%s, pcszTarget=%s, fFlags=0x%x\n", pcszSource, pcszTarget, fFlags)); + + RTFSOBJINFO objInfo; + int rc = RTPathQueryInfo(pcszSource, &objInfo, RTFSOBJATTRADD_NOTHING); + if (RT_SUCCESS(rc)) + { + if (RTFS_IS_FILE(objInfo.Attr.fMode)) + { + LogFlowFunc(("File '%s' -> '%s' (%RU64 bytes, file mode 0x%x)\n", + pcszSource, pcszTarget, (uint64_t)objInfo.cbObject, objInfo.Attr.fMode)); + + DnDURIObject *pObjFile = new DnDURIObject(DnDURIObject::Type_File, pcszSource, pcszTarget); + if (pObjFile) + { + if (fFlags & DNDURILIST_FLAGS_KEEP_OPEN) /* Shall we keep the file open while being added to this list? */ + { + /** @todo Add a standard fOpen mode for this list. */ + rc = pObjFile->Open(DnDURIObject::View_Source, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); + } + else /* Just query the information without opening the file. */ + rc = pObjFile->QueryInfo(DnDURIObject::View_Source); + + if (RT_SUCCESS(rc)) + { + m_lstTree.append(pObjFile); + + m_cTotal++; + m_cbTotal += pObjFile->GetSize(); + } + else + delete pObjFile; + } + else + rc = VERR_NO_MEMORY; + } + else if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) + { + LogFlowFunc(("Directory '%s' -> '%s' (file mode 0x%x)\n", pcszSource, pcszTarget, objInfo.Attr.fMode)); + + DnDURIObject *pObjDir = new DnDURIObject(DnDURIObject::Type_Directory, pcszSource, pcszTarget); + if (pObjDir) + { + m_lstTree.append(pObjDir); + + /** @todo Add DNDURILIST_FLAGS_KEEP_OPEN handling? */ + m_cTotal++; + } + else + rc = VERR_NO_MEMORY; + } + /* Note: Symlinks already should have been resolved at this point. */ + else + rc = VERR_NOT_SUPPORTED; + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + +int DnDURIList::appendPathRecursive(const char *pcszSrcPath, + const char *pcszDstPath, const char *pcszDstBase, size_t cchDstBase, + DNDURILISTFLAGS fFlags) +{ + AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER); + AssertPtrReturn(pcszDstBase, VERR_INVALID_POINTER); + AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER); + + LogFlowFunc(("pcszSrcPath=%s, pcszDstPath=%s, pcszDstBase=%s, cchDstBase=%zu, fFlags=0x%x\n", + pcszSrcPath, pcszDstPath, pcszDstBase, cchDstBase, fFlags)); + + RTFSOBJINFO objInfo; + int rc = RTPathQueryInfo(pcszSrcPath, &objInfo, RTFSOBJATTRADD_NOTHING); + if (RT_SUCCESS(rc)) + { + if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) + { + rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags); + if (RT_SUCCESS(rc)) + { + RTDIR hDir; + rc = RTDirOpen(&hDir, pcszSrcPath); + if (RT_SUCCESS(rc)) + { + size_t cbDirEntry = 0; + PRTDIRENTRYEX pDirEntry = NULL; + do + { + /* Retrieve the next directory entry. */ + rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); + if (RT_FAILURE(rc)) + { + if (rc == VERR_NO_MORE_FILES) + rc = VINF_SUCCESS; + break; + } + + switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK) + { + case RTFS_TYPE_DIRECTORY: + { + /* Skip "." and ".." entries. */ + if (RTDirEntryExIsStdDotLink(pDirEntry)) + break; + + char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName); + if (pszSrc) + { + char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName); + if (pszDst) + { + rc = appendPathRecursive(pszSrc, pszDst, pcszDstBase, cchDstBase, fFlags); + RTStrFree(pszDst); + } + else + rc = VERR_NO_MEMORY; + + RTStrFree(pszSrc); + } + else + rc = VERR_NO_MEMORY; + break; + } + + case RTFS_TYPE_FILE: + { + char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName); + if (pszSrc) + { + char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName); + if (pszDst) + { + rc = addEntry(pszSrc, &pszDst[cchDstBase], fFlags); + RTStrFree(pszDst); + } + else + rc = VERR_NO_MEMORY; + RTStrFree(pszSrc); + } + else + rc = VERR_NO_MEMORY; + break; + } + case RTFS_TYPE_SYMLINK: + { + if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS) + { + char *pszSrc = RTPathRealDup(pcszDstBase); + if (pszSrc) + { + rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING); + if (RT_SUCCESS(rc)) + { + if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) + { + LogFlowFunc(("Directory entry is symlink to directory\n")); + rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags); + } + else if (RTFS_IS_FILE(objInfo.Attr.fMode)) + { + LogFlowFunc(("Directory entry is symlink to file\n")); + rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags); + } + else + rc = VERR_NOT_SUPPORTED; + } + + RTStrFree(pszSrc); + } + else + rc = VERR_NO_MEMORY; + } + break; + } + + default: + break; + } + + } while (RT_SUCCESS(rc)); + + RTDirReadExAFree(&pDirEntry, &cbDirEntry); + RTDirClose(hDir); + } + } + } + else if (RTFS_IS_FILE(objInfo.Attr.fMode)) + { + rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags); + } + else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode)) + { + if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS) + { + char *pszSrc = RTPathRealDup(pcszSrcPath); + if (pszSrc) + { + rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING); + if (RT_SUCCESS(rc)) + { + if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) + { + LogFlowFunc(("Symlink to directory\n")); + rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags); + } + else if (RTFS_IS_FILE(objInfo.Attr.fMode)) + { + LogFlowFunc(("Symlink to file\n")); + rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags); + } + else + rc = VERR_NOT_SUPPORTED; + } + + RTStrFree(pszSrc); + } + else + rc = VERR_NO_MEMORY; + } + } + else + rc = VERR_NOT_SUPPORTED; + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + +int DnDURIList::AppendNativePath(const char *pszPath, DNDURILISTFLAGS fFlags) +{ + AssertPtrReturn(pszPath, VERR_INVALID_POINTER); + + int rc; + char *pszPathNative = RTStrDup(pszPath); + if (pszPathNative) + { + RTPathChangeToUnixSlashes(pszPathNative, true /* fForce */); + + char *pszPathURI = RTUriCreate("file" /* pszScheme */, NULL /* pszAuthority */, + pszPathNative, NULL /* pszQuery */, NULL /* pszFragment */); + if (pszPathURI) + { + rc = AppendURIPath(pszPathURI, fFlags); + RTStrFree(pszPathURI); + } + else + rc = VERR_INVALID_PARAMETER; + + RTStrFree(pszPathNative); + } + else + rc = VERR_NO_MEMORY; + + return rc; +} + +int DnDURIList::AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths, + DNDURILISTFLAGS fFlags) +{ + AssertPtrReturn(pszNativePaths, VERR_INVALID_POINTER); + AssertReturn(cbNativePaths, VERR_INVALID_PARAMETER); + + RTCList<RTCString> lstPaths + = RTCString(pszNativePaths, cbNativePaths - 1).split("\r\n"); + return AppendNativePathsFromList(lstPaths, fFlags); +} + +int DnDURIList::AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths, + DNDURILISTFLAGS fFlags) +{ + int rc = VINF_SUCCESS; + + for (size_t i = 0; i < lstNativePaths.size(); i++) + { + const RTCString &strPath = lstNativePaths.at(i); + rc = AppendNativePath(strPath.c_str(), fFlags); + if (RT_FAILURE(rc)) + break; + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + +int DnDURIList::AppendURIPath(const char *pszURI, DNDURILISTFLAGS fFlags) +{ + AssertPtrReturn(pszURI, VERR_INVALID_POINTER); + AssertReturn(!(fFlags & ~DNDURILIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); + /** @todo Check for string termination? */ + + RTURIPARSED Parsed; + int rc = RTUriParse(pszURI, &Parsed); + if (RT_FAILURE(rc)) + return rc; + + char *pszSrcPath = NULL; + + /* file://host.example.com/path/to/file.txt */ + const char *pszParsedAuthority = RTUriParsedAuthority(pszURI, &Parsed); + if ( pszParsedAuthority + && pszParsedAuthority[0] != '\0') /* Authority present? */ + { + const char *pszParsedPath = RTUriParsedPath(pszURI, &Parsed); + if (pszParsedPath) + { + /* Always use UNIXy paths internally. */ + if (RTStrAPrintf(&pszSrcPath, "//%s%s", pszParsedAuthority, pszParsedPath) == -1) + rc = VERR_NO_MEMORY; + } + else + rc = VERR_INVALID_PARAMETER; + } + else + { + pszSrcPath = RTUriFilePath(pszURI); + if (!pszSrcPath) + rc = VERR_INVALID_PARAMETER; + } + + LogFlowFunc(("pszURI=%s, fFlags=0x%x -> pszParsedAuthority=%s, pszSrcPath=%s, rc=%Rrc\n", + pszURI, fFlags, pszParsedAuthority ? pszParsedAuthority : "<None>", pszSrcPath, rc)); + + if (RT_SUCCESS(rc)) + { + /* Add the path to our internal file list (recursive in + * the case of a directory). */ + size_t cbPathLen = RTPathStripTrailingSlash(pszSrcPath); + if (cbPathLen) + { + char *pszFileName = RTPathFilename(pszSrcPath); + if (pszFileName) + { + Assert(pszFileName >= pszSrcPath); + size_t cchDstBase = (fFlags & DNDURILIST_FLAGS_ABSOLUTE_PATHS) + ? 0 /* Use start of path as root. */ + : pszFileName - pszSrcPath; + char *pszDstPath = &pszSrcPath[cchDstBase]; + m_lstRoot.append(pszDstPath); + + LogFlowFunc(("pszSrcPath=%s, pszFileName=%s, pszRoot=%s\n", + pszSrcPath, pszFileName, pszDstPath)); + + rc = appendPathRecursive(pszSrcPath, pszSrcPath, pszSrcPath, cchDstBase, fFlags); + } + else + rc = VERR_PATH_NOT_FOUND; + } + else + rc = VERR_INVALID_PARAMETER; + } + + RTStrFree(pszSrcPath); + + LogFlowFuncLeaveRC(rc); + return rc; +} + +int DnDURIList::AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths, + DNDURILISTFLAGS fFlags) +{ + AssertPtrReturn(pszURIPaths, VERR_INVALID_POINTER); + AssertReturn(cbURIPaths, VERR_INVALID_PARAMETER); + + RTCList<RTCString> lstPaths + = RTCString(pszURIPaths, cbURIPaths - 1).split("\r\n"); + return AppendURIPathsFromList(lstPaths, fFlags); +} + +int DnDURIList::AppendURIPathsFromList(const RTCList<RTCString> &lstURI, + DNDURILISTFLAGS fFlags) +{ + int rc = VINF_SUCCESS; + + for (size_t i = 0; i < lstURI.size(); i++) + { + RTCString strURI = lstURI.at(i); + rc = AppendURIPath(strURI.c_str(), fFlags); + + if (RT_FAILURE(rc)) + break; + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + +void DnDURIList::Clear(void) +{ + m_lstRoot.clear(); + + for (size_t i = 0; i < m_lstTree.size(); i++) + { + DnDURIObject *pCurObj = m_lstTree.at(i); + AssertPtr(pCurObj); + RTMemFree(pCurObj); + } + m_lstTree.clear(); + + m_cTotal = 0; + m_cbTotal = 0; +} + +void DnDURIList::RemoveFirst(void) +{ + if (m_lstTree.isEmpty()) + return; + + DnDURIObject *pCurObj = m_lstTree.first(); + AssertPtr(pCurObj); + + uint64_t cbSize = pCurObj->GetSize(); + Assert(m_cbTotal >= cbSize); + m_cbTotal -= cbSize; /* Adjust total size. */ + + pCurObj->Close(); + RTMemFree(pCurObj); + + m_lstTree.removeFirst(); +} + +int DnDURIList::SetFromURIData(const void *pvData, size_t cbData, DNDURILISTFLAGS fFlags) +{ + Assert(fFlags == 0); RT_NOREF1(fFlags); + AssertPtrReturn(pvData, VERR_INVALID_POINTER); + AssertReturn(cbData, VERR_INVALID_PARAMETER); + + if (!RTStrIsValidEncoding(static_cast<const char *>(pvData))) + return VERR_INVALID_PARAMETER; + + RTCList<RTCString> lstURI = + RTCString(static_cast<const char *>(pvData), cbData - 1).split("\r\n"); + if (lstURI.isEmpty()) + return VINF_SUCCESS; + + int rc = VINF_SUCCESS; + + for (size_t i = 0; i < lstURI.size(); ++i) + { + /* Query the path component of a file URI. If this hasn't a + * file scheme, NULL is returned. */ + const char *pszURI = lstURI.at(i).c_str(); + char *pszFilePath = RTUriFilePath(pszURI); +#ifdef DEBUG_andy + LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath)); +#endif + if (pszFilePath) + { + rc = DnDPathSanitize(pszFilePath, strlen(pszFilePath)); + if (RT_SUCCESS(rc)) + { + m_lstRoot.append(pszFilePath); + m_cTotal++; + } + + RTStrFree(pszFilePath); + } + else + rc = VERR_INVALID_PARAMETER; + + if (RT_FAILURE(rc)) + break; + } + + return rc; +} + +RTCString DnDURIList::GetRootEntries(const RTCString &strPathBase /* = "" */, + const RTCString &strSeparator /* = "\r\n" */) const +{ + RTCString strRet; + for (size_t i = 0; i < m_lstRoot.size(); i++) + { + const char *pszCurRoot = m_lstRoot.at(i).c_str(); +#ifdef DEBUG_andy + LogFlowFunc(("pszCurRoot=%s\n", pszCurRoot)); +#endif + if (strPathBase.isNotEmpty()) + { + char *pszPath = RTPathJoinA(strPathBase.c_str(), pszCurRoot); + if (pszPath) + { + char *pszPathURI = RTUriFileCreate(pszPath); + if (pszPathURI) + { + strRet += RTCString(pszPathURI) + strSeparator; + LogFlowFunc(("URI (Base): %s\n", strRet.c_str())); + RTStrFree(pszPathURI); + } + + RTStrFree(pszPath); + + if (!pszPathURI) + break; + } + else + break; + } + else + { + char *pszPathURI = RTUriFileCreate(pszCurRoot); + if (pszPathURI) + { + strRet += RTCString(pszPathURI) + strSeparator; + LogFlowFunc(("URI: %s\n", strRet.c_str())); + RTStrFree(pszPathURI); + } + else + break; + } + } + + return strRet; +} + |