Changeset 85371 in vbox for trunk/src/VBox/GuestHost
- Timestamp:
- Jul 17, 2020 10:02:58 AM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 139382
- Location:
- trunk/src/VBox/GuestHost/DragAndDrop
- Files:
-
- 4 edited
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp
r85028 r85371 27 27 #include <iprt/err.h> 28 28 #include <iprt/file.h> 29 #include <iprt/mem.h> 29 30 #include <iprt/path.h> 30 31 #include <iprt/string.h> 31 32 32 33 33 #include <VBox/log.h> 34 34 35 DnDDroppedFiles::DnDDroppedFiles(void) 36 : m_fOpen(0) 37 , m_hDir(NULL) { } 38 39 DnDDroppedFiles::DnDDroppedFiles(const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */) 40 : m_fOpen(0) 41 , m_hDir(NULL) 42 { 43 OpenEx(pszPath, fFlags); 44 } 45 46 DnDDroppedFiles::~DnDDroppedFiles(void) 35 36 /********************************************************************************************************************************* 37 * Prototypes * 38 *********************************************************************************************************************************/ 39 static int dndDroppedFilesCloseInternal(PDNDDROPPEDFILES pDF); 40 41 42 int DnDDroppedFilesInit(PDNDDROPPEDFILES pDF, 43 const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */) 44 { 45 pDF->m_fOpen = 0; 46 pDF->m_hDir = NIL_RTDIR; 47 48 return DnDDroppedFilesOpenEx(pDF, pszPath, fFlags); 49 } 50 51 void DnDDroppedFilesDestroy(PDNDDROPPEDFILES pDF) 47 52 { 48 53 /* Only make sure to not leak any handles and stuff, don't delete any 49 54 * directories / files here. */ 50 closeInternal();55 dndDroppedFilesCloseInternal(pDF); 51 56 } 52 57 … … 57 62 * @param pszFile Path of file entry to add. 58 63 */ 59 int DnDDroppedFiles ::AddFile(const char *pszFile)64 int DnDDroppedFilesAddFile(PDNDDROPPEDFILES pDF, const char *pszFile) 60 65 { 61 66 AssertPtrReturn(pszFile, VERR_INVALID_POINTER); 62 67 63 if (!this->m_lstFiles.contains(pszFile)) 64 this->m_lstFiles.append(pszFile); 65 return VINF_SUCCESS; 68 PDNDDROPPEDFILESENTRY pEntry = (PDNDDROPPEDFILESENTRY)RTMemAlloc(sizeof(DNDDROPPEDFILESENTRY)); 69 if (!pEntry) 70 return VERR_NO_MEMORY; 71 72 pEntry->pszPath = RTStrDup(pszFile); 73 if (pEntry->pszPath) 74 { 75 RTListAppend(&pDF->m_lstFiles, &pEntry->Node); 76 return VINF_SUCCESS; 77 } 78 79 RTMemFree(pEntry); 80 return VERR_NO_MEMORY; 66 81 } 67 82 … … 73 88 * @param pszDir Path of directory entry to add. 74 89 */ 75 int DnDDroppedFiles ::AddDir(const char *pszDir)90 int DnDDroppedFilesAddDir(PDNDDROPPEDFILES pDF, const char *pszDir) 76 91 { 77 92 AssertPtrReturn(pszDir, VERR_INVALID_POINTER); 78 93 79 if (!this->m_lstDirs.contains(pszDir)) 80 this->m_lstDirs.append(pszDir); 81 return VINF_SUCCESS; 94 PDNDDROPPEDFILESENTRY pEntry = (PDNDDROPPEDFILESENTRY)RTMemAlloc(sizeof(DNDDROPPEDFILESENTRY)); 95 if (!pEntry) 96 return VERR_NO_MEMORY; 97 98 pEntry->pszPath = RTStrDup(pszDir); 99 if (pEntry->pszPath) 100 { 101 RTListAppend(&pDF->m_lstDirs, &pEntry->Node); 102 return VINF_SUCCESS; 103 } 104 105 RTMemFree(pEntry); 106 return VERR_NO_MEMORY; 82 107 } 83 108 … … 87 112 * @returns VBox status code. 88 113 */ 89 int DnDDroppedFiles::closeInternal(void)114 static int dndDroppedFilesCloseInternal(PDNDDROPPEDFILES pDF) 90 115 { 91 116 int rc; 92 if ( this->m_hDir != NULL)93 { 94 rc = RTDirClose( this->m_hDir);117 if (pDF->m_hDir != NULL) 118 { 119 rc = RTDirClose(pDF->m_hDir); 95 120 if (RT_SUCCESS(rc)) 96 this->m_hDir = NULL;121 pDF->m_hDir = NULL; 97 122 } 98 123 else … … 108 133 * @returns VBox status code. 109 134 */ 110 int DnDDroppedFiles ::Close(void)111 { 112 return closeInternal();135 int DnDDroppedFilesClose(PDNDDROPPEDFILES pDF) 136 { 137 return dndDroppedFilesCloseInternal(pDF); 113 138 } 114 139 … … 118 143 * @returns Pointer to absolute path of the dropped files directory. 119 144 */ 120 const char *DnDDroppedFiles ::GetDirAbs(void) const121 { 122 return this->m_strPathAbs.c_str();145 const char *DnDDroppedFilesGetDirAbs(PDNDDROPPEDFILES pDF) 146 { 147 return pDF->pszPathAbs; 123 148 } 124 149 … … 128 153 * @returns \c true if open, \c false if not. 129 154 */ 130 bool DnDDroppedFiles ::IsOpen(void) const131 { 132 return ( this->m_hDir != NULL);155 bool DnDDroppedFilesIsOpen(PDNDDROPPEDFILES pDF) 156 { 157 return (pDF->m_hDir != NULL); 133 158 } 134 159 … … 140 165 * @param fFlags Dropped files flags to use for this directory. 141 166 */ 142 int DnDDroppedFiles::OpenEx(const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */) 167 int DnDDroppedFilesOpenEx(PDNDDROPPEDFILES pDF, 168 const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */) 143 169 { 144 170 AssertPtrReturn(pszPath, VERR_INVALID_POINTER); … … 179 205 } 180 206 181 rc = DnDPathSanitize (szTime, sizeof(szTime));207 rc = DnDPathSanitizeFileName(szTime, sizeof(szTime)); 182 208 if (RT_FAILURE(rc)) 183 209 break; … … 195 221 if (RT_SUCCESS(rc)) 196 222 { 197 this->m_hDir= hDir;198 this->m_strPathAbs = szDropDir;199 this->m_fOpen= fFlags;223 pDF->m_hDir = hDir; 224 pDF->pszPathAbs = szDropDir; 225 pDF->m_fOpen = fFlags; 200 226 } 201 227 } … … 213 239 * @param fFlags Dropped files flags to use for this directory. 214 240 */ 215 int DnDDroppedFiles ::OpenTemp(DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */)241 int DnDDroppedFilesOpenTemp(PDNDDROPPEDFILES pDF, DNDURIDROPPEDFILEFLAGS fFlags) 216 242 { 217 243 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /* Flags not supported yet. */ … … 225 251 int rc = RTPathTemp(szTemp, sizeof(szTemp)); 226 252 if (RT_SUCCESS(rc)) 227 rc = OpenEx(szTemp, fFlags); 228 229 return rc; 253 rc = DnDDroppedFilesOpenEx(pDF, szTemp, fFlags); 254 255 return rc; 256 } 257 258 static void dndDroppedFilesEntryFree(PDNDDROPPEDFILESENTRY pEntry) 259 { 260 if (!pEntry) 261 return; 262 RTStrFree(pEntry->pszPath); 263 RTListNodeRemove(&pEntry->Node); 264 RTMemFree(pEntry); 265 } 266 267 static void dndDroppedFilesResetList(PRTLISTANCHOR pListAnchor) 268 { 269 PDNDDROPPEDFILESENTRY pEntryCur, pEntryNext; 270 RTListForEachSafe(pListAnchor, pEntryCur, pEntryNext, DNDDROPPEDFILESENTRY, Node) 271 dndDroppedFilesEntryFree(pEntryCur); 272 Assert(RTListIsEmpty(pListAnchor)); 230 273 } 231 274 … … 237 280 * or just clear the internal references. 238 281 */ 239 int DnDDroppedFiles ::Reset(bool fDelete)240 { 241 int rc = closeInternal();282 int DnDDroppedFilesReset(PDNDDROPPEDFILES pDF, bool fDelete) 283 { 284 int rc = dndDroppedFilesCloseInternal(pDF); 242 285 if (RT_SUCCESS(rc)) 243 286 { 244 287 if (fDelete) 245 288 { 246 rc = Rollback();289 rc = DnDDroppedFilesRollback(pDF); 247 290 } 248 291 else 249 292 { 250 this->m_lstDirs.clear();251 this->m_lstFiles.clear();293 dndDroppedFilesResetList(&pDF->m_lstDirs); 294 dndDroppedFilesResetList(&pDF->m_lstFiles); 252 295 } 253 296 } … … 262 305 * @returns VBox status code, or VERR_NOT_FOUND if the dropped files directory has not been opened before. 263 306 */ 264 int DnDDroppedFiles ::Reopen(void)265 { 266 if ( this->m_strPathAbs.isEmpty())307 int DnDDroppedFilesReopen(PDNDDROPPEDFILES pDF) 308 { 309 if (!pDF->pszPathAbs) 267 310 return VERR_NOT_FOUND; 268 311 269 return OpenEx(this->m_strPathAbs.c_str(), this->m_fOpen);312 return DnDDroppedFilesOpenEx(pDF, pDF->pszPathAbs, pDF->m_fOpen); 270 313 } 271 314 … … 276 319 * @returns VBox status code. 277 320 */ 278 int DnDDroppedFiles ::Rollback(void)279 { 280 if ( this->m_strPathAbs.isEmpty())321 int DnDDroppedFilesRollback(PDNDDROPPEDFILES pDF) 322 { 323 if (!pDF->pszPathAbs) 281 324 return VINF_SUCCESS; 282 325 … … 287 330 * anything recursive here! Steam (tm) knows best ... :-) */ 288 331 int rc2; 289 for (size_t i = 0; i < this->m_lstFiles.size(); i++) 290 { 291 rc2 = RTFileDelete(this->m_lstFiles.at(i).c_str()); 332 PDNDDROPPEDFILESENTRY pEntryCur, pEntryNext; 333 RTListForEachSafe(&pDF->m_lstFiles, pEntryCur, pEntryNext, DNDDROPPEDFILESENTRY, Node) 334 { 335 rc2 = RTFileDelete(pEntryCur->pszPath); 292 336 if (RT_SUCCESS(rc2)) 293 this->m_lstFiles.removeAt(i);337 dndDroppedFilesEntryFree(pEntryCur); 294 338 else if (RT_SUCCESS(rc)) 295 339 rc = rc2; … … 297 341 } 298 342 299 for (size_t i = 0; i < this->m_lstDirs.size(); i++)300 { 301 rc2 = RTDirRemove( this->m_lstDirs.at(i).c_str());343 RTListForEachSafe(&pDF->m_lstDirs, pEntryCur, pEntryNext, DNDDROPPEDFILESENTRY, Node) 344 { 345 rc2 = RTDirRemove(pEntryCur->pszPath); 302 346 if (RT_SUCCESS(rc2)) 303 this->m_lstDirs.removeAt(i);347 dndDroppedFilesEntryFree(pEntryCur); 304 348 else if (RT_SUCCESS(rc)) 305 349 rc = rc2; … … 309 353 if (RT_SUCCESS(rc)) 310 354 { 311 Assert(this->m_lstFiles.isEmpty()); 312 Assert(this->m_lstDirs.isEmpty()); 313 314 rc2 = closeInternal(); 355 rc2 = dndDroppedFilesCloseInternal(pDF); 315 356 if (RT_SUCCESS(rc2)) 316 357 { 317 358 /* Try to remove the empty root dropped files directory as well. 318 359 * Might return VERR_DIR_NOT_EMPTY or similar. */ 319 rc2 = RTDirRemove( this->m_strPathAbs.c_str());360 rc2 = RTDirRemove(pDF->pszPathAbs); 320 361 } 321 362 if (RT_SUCCESS(rc)) -
trunk/src/VBox/GuestHost/DragAndDrop/DnDMIME.cpp
r82968 r85371 35 35 bool DnDMIMENeedsDropDir(const char *pcszFormat, size_t cchFormatMax) 36 36 { 37 bool fNeedsDropDir = false; 38 if (!RTStrNICmp(pcszFormat, "text/uri-list", cchFormatMax)) /** @todo Add "x-special/gnome-icon-list"? */ 39 fNeedsDropDir = true; 40 41 return fNeedsDropDir; 37 return DnDMIMEHasFileURLs(pcszFormat, cchFormatMax); 42 38 } 43 39 -
trunk/src/VBox/GuestHost/DragAndDrop/DnDPath.cpp
r85028 r85371 28 28 #include <iprt/path.h> 29 29 #include <iprt/string.h> 30 31 32 /** 33 * Sanitizes a path so that unsupported characters will be replaced by an underscore ("_"). 30 #include <iprt/uri.h> 31 32 33 /** 34 * Sanitizes the file name portion of a path so that unsupported characters will be replaced by an underscore ("_"). 34 35 * 35 36 * @return IPRT status code. 36 * @param psz Path Pathto sanitize.37 * @param cb Path Size (in bytes) of pathto sanitize.38 */ 39 int DnDPathSanitize (char *pszPath, size_t cbPath)40 { 41 if (!psz Path) /* No path given? Bail out early. */37 * @param pszFileName File name to sanitize. 38 * @param cbFileName Size (in bytes) of file name to sanitize. 39 */ 40 int DnDPathSanitizeFileName(char *pszFileName, size_t cbFileName) 41 { 42 if (!pszFileName) /* No path given? Bail out early. */ 42 43 return VINF_SUCCESS; 43 44 44 AssertReturn(cb Path, VERR_INVALID_PARAMETER);45 AssertReturn(cbFileName, VERR_INVALID_PARAMETER); 45 46 46 47 int rc = VINF_SUCCESS; 47 48 #ifdef RT_OS_WINDOWS 48 RT_NOREF1(cb Path);49 RT_NOREF1(cbFileName); 49 50 /* Replace out characters not allowed on Windows platforms, put in by RTTimeSpecToString(). */ 50 51 /** @todo Use something like RTPathSanitize() if available later some time. */ … … 62 63 }; 63 64 64 ssize_t cReplaced = RTStrPurgeComplementSet(psz Path, s_uszValidRangePairs, '_' /* chReplacement */);65 ssize_t cReplaced = RTStrPurgeComplementSet(pszFileName, s_uszValidRangePairs, '_' /* chReplacement */); 65 66 if (cReplaced < 0) 66 67 rc = VERR_INVALID_UTF8_ENCODING; 67 68 #else 68 RT_NOREF2(psz Path, cbPath);69 RT_NOREF2(pszFileName, cbFileName); 69 70 #endif 70 71 return rc; … … 73 74 /** 74 75 * Validates whether a given path matches our set of rules or not. 76 * 77 * Rules: 78 * - An empty path is allowed. 79 * - Dot components ("." or "..") are forbidden. 80 * - If \a fMustExist is \c true, the path either has to be a file or a directory and must exist. 81 * - Symbolic links are forbidden. 75 82 * 76 83 * @returns VBox status code. … … 81 88 int DnDPathValidate(const char *pcszPath, bool fMustExist) 82 89 { 90 if (!pcszPath) 91 return VERR_INVALID_POINTER; 92 83 93 int rc = VINF_SUCCESS; 84 85 if (!strlen(pcszPath))86 rc = VERR_INVALID_PARAMETER;87 94 88 95 if ( RT_SUCCESS(rc) … … 136 143 AssertReturn(!(fFlags & ~DNDPATHCONVERT_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 137 144 138 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) 139 if (fFlags & DNDPATHCONVERT_FLAGS_TO_NATIVE) 140 RTPathChangeToDosSlashes(pszPath, true); 145 if (fFlags & DNDPATHCONVERT_FLAGS_TO_DOS) 146 RTPathChangeToDosSlashes(pszPath, true /* fForce */); 141 147 else 142 #else143 RT_NOREF(fFlags);144 #endif145 {146 148 RTPathChangeToUnixSlashes(pszPath, true /* fForce */); 147 }148 149 149 150 return VINF_SUCCESS; 150 151 } 151 152 153 /** 154 * Rebases an absolute path from an old path base to a new path base. 155 * Note: Does *not* do any path conversion. 156 * 157 * @return IPRT status code. 158 * @param pcszPath Path to rebase. 159 * @param strBaseOld Old base path to rebase from. Optional and can be NULL. 160 * @param strBaseNew New base path to rebase to. 161 * @param ppszPath Where to store the allocated rebased path on success. Needs to be free'd with RTStrFree(). 162 */ 163 int DnDPathRebase(const char *pcszPath, const char *pcszBaseOld, const char *pcszBaseNew, 164 char **ppszPath) 165 { 166 AssertPtrReturn(pcszPath, VERR_INVALID_POINTER); 167 AssertPtrReturn(pcszBaseOld, VERR_INVALID_POINTER); 168 AssertPtrReturn(pcszBaseNew, VERR_INVALID_POINTER); 169 AssertPtrReturn(ppszPath, VERR_INVALID_POINTER); 170 171 char szPath[RTPATH_MAX]; 172 173 /* Do we need to see if the given path is part of the old base? */ 174 size_t idxBase; 175 if ( pcszBaseOld 176 && RTPathStartsWith(pcszPath, pcszBaseOld)) 177 { 178 idxBase = strlen(pcszBaseOld); 179 } 180 else 181 idxBase = 0; 182 183 int rc = RTStrCopy(szPath, sizeof(szPath), pcszBaseNew); 184 if (RT_SUCCESS(rc)) 185 { 186 rc = RTPathAppend(szPath, sizeof(szPath), &pcszPath[idxBase]); 187 if (RT_SUCCESS(rc)) 188 rc = DnDPathValidate(szPath, false /* fMustExist */); 189 } 190 191 if (RT_SUCCESS(rc)) 192 { 193 char *pszPath = RTStrDup(szPath); 194 if (pszPath) 195 *ppszPath = pszPath; 196 else 197 rc = VERR_NO_MEMORY; 198 } 199 200 return rc; 201 } 202 -
trunk/src/VBox/GuestHost/DragAndDrop/DnDTransferList.cpp
r85369 r85371 1 1 /* $Id$ */ 2 2 /** @file 3 * DnD - URI list class.3 * DnD - transfer list implemenation. 4 4 */ 5 5 … … 27 27 #include <iprt/file.h> 28 28 #include <iprt/fs.h> 29 #include <iprt/mem.h> 29 30 #include <iprt/path.h> 30 31 #include <iprt/string.h> … … 35 36 36 37 37 DnDURIList::DnDURIList(void) 38 : m_cTotal(0) 39 , m_cbTotal(0) 40 { 41 } 42 43 DnDURIList::~DnDURIList(void) 44 { 45 Clear(); 46 } 47 48 int DnDURIList::addEntry(const char *pcszSource, const char *pcszTarget, DNDURILISTFLAGS fFlags) 49 { 50 AssertPtrReturn(pcszSource, VERR_INVALID_POINTER); 51 AssertPtrReturn(pcszTarget, VERR_INVALID_POINTER); 52 53 LogFlowFunc(("pcszSource=%s, pcszTarget=%s, fFlags=0x%x\n", pcszSource, pcszTarget, fFlags)); 54 55 RTFSOBJINFO objInfo; 56 int rc = RTPathQueryInfo(pcszSource, &objInfo, RTFSOBJATTRADD_NOTHING); 38 /********************************************************************************************************************************* 39 * Prototypes * 40 *********************************************************************************************************************************/ 41 static int dndTransferListSetRootPath(PDNDTRANSFERLIST pList, const char *pcszRootPathAbs); 42 43 static int dndTransferListRootAdd(PDNDTRANSFERLIST pList, const char *pcszRoot); 44 static void dndTransferListRootFree(PDNDTRANSFERLIST pList, PDNDTRANSFERLISTROOT pRootObj); 45 46 static int dndTransferListObjAdd(PDNDTRANSFERLIST pList, const char *pcszSrcAbs, RTFMODE fMode, DNDTRANSFERLISTFLAGS fFlags); 47 static void dndTransferListObjFree(PDNDTRANSFERLIST pList, PDNDTRANSFEROBJECT pLstObj); 48 49 50 /** The size of the directory entry buffer we're using. */ 51 #define DNDTRANSFERLIST_DIRENTRY_BUF_SIZE (sizeof(RTDIRENTRYEX) + RTPATH_MAX) 52 53 54 /** 55 * Initializes a transfer list. 56 * 57 * @returns VBox status code. 58 * @param pList Transfer list to initialize. 59 * @param pcszRootPathAbs Absolute root path to use for this list. Optional and can be NULL. 60 */ 61 int DnDTransferListInit(PDNDTRANSFERLIST pList, const char *pcszRootPathAbs) 62 { 63 AssertPtrReturn(pList, VERR_INVALID_POINTER); 64 /* pcszRootPathAbs is optional. */ 65 66 if (!strlen(pcszRootPathAbs)) 67 return VERR_INVALID_PARAMETER; 68 69 if (pList->pszPathRootAbs) 70 return VERR_WRONG_ORDER; 71 72 pList->pszPathRootAbs = NULL; 73 74 RTListInit(&pList->lstRoot); 75 pList->cRoots = 0; 76 77 RTListInit(&pList->lstObj); 78 pList->cObj = 0; 79 pList->cbObjTotal = 0; 80 81 if (pcszRootPathAbs) 82 return dndTransferListSetRootPath(pList, pcszRootPathAbs); 83 84 return VINF_SUCCESS; 85 } 86 87 /** 88 * Destroys a transfer list. 89 * 90 * @param pList Transfer list to destroy. 91 */ 92 void DnDTransferListDestroy(PDNDTRANSFERLIST pList) 93 { 94 if (!pList) 95 return; 96 97 DnDTransferListReset(pList); 98 99 RTStrFree(pList->pszPathRootAbs); 100 pList->pszPathRootAbs = NULL; 101 } 102 103 /** 104 * Resets a transfer list. 105 * 106 * Note: Does *not* clear the root path! 107 * 108 * @param pList Transfer list to clear. 109 */ 110 void DnDTransferListReset(PDNDTRANSFERLIST pList) 111 { 112 AssertPtrReturnVoid(pList); 113 114 /* Note: This does not clear the root path! */ 115 116 PDNDTRANSFERLISTROOT pRootCur, pRootNext; 117 RTListForEachSafe(&pList->lstRoot, pRootCur, pRootNext, DNDTRANSFERLISTROOT, Node) 118 dndTransferListRootFree(pList, pRootCur); 119 Assert(RTListIsEmpty(&pList->lstRoot)); 120 121 PDNDTRANSFEROBJECT pObjCur, pObjNext; 122 RTListForEachSafe(&pList->lstObj, pObjCur, pObjNext, DNDTRANSFEROBJECT, Node) 123 dndTransferListObjFree(pList, pObjCur); 124 Assert(RTListIsEmpty(&pList->lstObj)); 125 126 Assert(pList->cRoots == 0); 127 Assert(pList->cObj == 0); 128 129 pList->cbObjTotal = 0; 130 } 131 132 /** 133 * Adds a single transfer object entry to a transfer List. 134 * 135 * @returns VBox status code. 136 * @param pList Transfer list to add entry to. 137 * @param pcszSrcAbs Absolute source path (local) to use. 138 * @param fMode File mode of entry to add. 139 * @param fFlags Transfer list flags to use for appending. 140 */ 141 static int dndTransferListObjAdd(PDNDTRANSFERLIST pList, const char *pcszSrcAbs, RTFMODE fMode, DNDTRANSFERLISTFLAGS fFlags) 142 { 143 AssertPtrReturn(pList, VERR_INVALID_POINTER); 144 AssertPtrReturn(pcszSrcAbs, VERR_INVALID_POINTER); 145 146 LogFlowFunc(("pcszSrcAbs=%s, fMode=%#x, fFlags=0x%x\n", pcszSrcAbs, fMode, fFlags)); 147 148 int rc = VINF_SUCCESS; 149 150 if ( !RTFS_IS_FILE(fMode) 151 && !RTFS_IS_DIRECTORY(fMode)) 152 /** @todo Symlinks not allowed. */ 153 { 154 rc = VERR_NOT_SUPPORTED; 155 } 156 57 157 if (RT_SUCCESS(rc)) 58 158 { 59 if (RTFS_IS_FILE(objInfo.Attr.fMode)) 60 { 61 LogFlowFunc(("File '%s' -> '%s' (%RU64 bytes, file mode 0x%x)\n", 62 pcszSource, pcszTarget, (uint64_t)objInfo.cbObject, objInfo.Attr.fMode)); 63 64 DnDURIObject *pObjFile = new DnDURIObject(DnDURIObject::Type_File, pcszSource); 65 if (pObjFile) 159 /* Calculate the path to add as the destination path to our URI object. */ 160 const size_t idxPathToAdd = strlen(pList->pszPathRootAbs); 161 AssertReturn(strlen(pcszSrcAbs) > idxPathToAdd, VERR_INVALID_PARAMETER); /* Should never happen (tm). */ 162 163 PDNDTRANSFEROBJECT pObj = (PDNDTRANSFEROBJECT)RTMemAllocZ(sizeof(DNDTRANSFEROBJECT)); 164 if (pObj) 165 { 166 pObj = (PDNDTRANSFEROBJECT)RTMemAllocZ(sizeof(DNDTRANSFEROBJECT)); 167 if (pObj) 66 168 { 67 /** @todo Add a standard fOpen mode for this list. */ 68 rc = pObjFile->Open(RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); 169 const bool fIsFile = RTFS_IS_FILE(fMode); 170 171 rc = DnDTransferObjectInit(pObj, fIsFile ? DNDTRANSFEROBJTYPE_FILE : DNDTRANSFEROBJTYPE_DIRECTORY, 172 pList->pszPathRootAbs, &pcszSrcAbs[idxPathToAdd]); 69 173 if (RT_SUCCESS(rc)) 70 174 { 71 m_lstTree.append(pObjFile); 72 73 m_cTotal++; 74 m_cbTotal += pObjFile->GetSize(); 75 76 if (!(fFlags & DNDURILIST_FLAGS_KEEP_OPEN)) /* Shall we keep the file open while being added to this list? */ 77 pObjFile->Close(); 175 if (fIsFile) 176 rc = DnDTransferObjectOpen(pObj, 177 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, /** @todo Add a standard fOpen mode for this list. */ 178 0 /* fMode */, DNDTRANSFEROBJECT_FLAGS_NONE); 179 if (RT_SUCCESS(rc)) 180 { 181 RTListAppend(&pList->lstObj, &pObj->Node); 182 183 pList->cObj++; 184 if (fIsFile) 185 pList->cbObjTotal += DnDTransferObjectGetSize(pObj); 186 187 if ( fIsFile 188 && !(fFlags & DNDTRANSFERLIST_FLAGS_KEEP_OPEN)) /* Shall we keep the file open while being added to this list? */ 189 DnDTransferObjectClose(pObj); 190 } 191 192 if (RT_FAILURE(rc)) 193 DnDTransferObjectDestroy(pObj); 78 194 } 79 195 80 196 if (RT_FAILURE(rc)) 81 delete pObjFile;197 RTMemFree(pObj); 82 198 } 83 199 else 84 200 rc = VERR_NO_MEMORY; 85 } 86 else if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) 87 { 88 LogFlowFunc(("Directory '%s' -> '%s' (file mode 0x%x)\n", pcszSource, pcszTarget, objInfo.Attr.fMode)); 89 90 DnDURIObject *pObjDir = new DnDURIObject(DnDURIObject::Type_Directory, pcszSource); 91 if (pObjDir) 201 202 if (RT_FAILURE(rc)) 203 RTMemFree(pObj); 204 } 205 else 206 rc = VERR_NO_MEMORY; 207 } 208 209 if (RT_FAILURE(rc)) 210 LogRel(("DnD: Adding entry '%s' of type %#x failed with rc=%Rrc\n", pcszSrcAbs, fMode & RTFS_TYPE_MASK, rc)); 211 212 LogFlowFuncLeaveRC(rc); 213 return rc; 214 } 215 216 /** 217 * Frees an internal DnD transfer list object. 218 * 219 * @param pList Transfer list to free object for. 220 * @param pLstObj transfer list object to free. The pointer will be invalid after calling. 221 */ 222 static void dndTransferListObjFree(PDNDTRANSFERLIST pList, PDNDTRANSFEROBJECT pObj) 223 { 224 if (!pObj) 225 return; 226 227 DnDTransferObjectDestroy(pObj); 228 RTListNodeRemove(&pObj->Node); 229 RTMemFree(pObj); 230 231 AssertReturnVoid(pList->cObj); 232 pList->cObj--; 233 } 234 235 /** 236 * Helper routine for handling adding sub directories. 237 * 238 * @return IPRT status code. 239 * @param pList transfer list to add found entries to. 240 * @param pszDir Pointer to the directory buffer. 241 * @param cchDir The length of pszDir in pszDir. 242 * @param pDirEntry Pointer to the directory entry. 243 * @param fFlags Flags of type DNDTRANSFERLISTFLAGS. 244 */ 245 static int dndTransferListAppendPathRecursiveSub(PDNDTRANSFERLIST pList, 246 char *pszDir, size_t cchDir, PRTDIRENTRYEX pDirEntry, 247 DNDTRANSFERLISTFLAGS fFlags) 248 249 { 250 Assert(cchDir > 0); Assert(pszDir[cchDir] == '\0'); 251 252 /* Make sure we've got some room in the path, to save us extra work further down. */ 253 if (cchDir + 3 >= RTPATH_MAX) 254 return VERR_BUFFER_OVERFLOW; 255 256 /* Open directory. */ 257 RTDIR hDir; 258 int rc = RTDirOpen(&hDir, pszDir); 259 if (RT_FAILURE(rc)) 260 return rc; 261 262 /* Ensure we've got a trailing slash (there is space for it see above). */ 263 if (!RTPATH_IS_SEP(pszDir[cchDir - 1])) 264 { 265 pszDir[cchDir++] = RTPATH_SLASH; 266 pszDir[cchDir] = '\0'; 267 } 268 269 LogFlowFunc(("pszDir=%s\n", pszDir)); 270 271 /* 272 * Process the files and subdirs. 273 */ 274 for (;;) 275 { 276 /* Get the next directory. */ 277 size_t cbDirEntry = DNDTRANSFERLIST_DIRENTRY_BUF_SIZE; 278 rc = RTDirReadEx(hDir, pDirEntry, &cbDirEntry, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); 279 if (RT_FAILURE(rc)) 280 break; 281 282 /* Check length. */ 283 if (pDirEntry->cbName + cchDir + 3 >= RTPATH_MAX) 284 { 285 rc = VERR_BUFFER_OVERFLOW; 286 break; 287 } 288 289 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK) 290 { 291 case RTFS_TYPE_SYMLINK: 92 292 { 93 m_lstTree.append(pObjDir); 94 95 /** @todo Add DNDURILIST_FLAGS_KEEP_OPEN handling? */ 96 m_cTotal++; 293 if (!(fFlags & DNDTRANSFERLIST_FLAGS_RESOLVE_SYMLINKS)) 294 break; 295 RT_FALL_THRU(); 296 } 297 case RTFS_TYPE_DIRECTORY: 298 { 299 if (RTDirEntryExIsStdDotLink(pDirEntry)) 300 continue; 301 302 memcpy(&pszDir[cchDir], pDirEntry->szName, pDirEntry->cbName + 1); 303 int rc2 = dndTransferListAppendPathRecursiveSub(pList, pszDir, cchDir + pDirEntry->cbName, pDirEntry, fFlags); 304 if (RT_SUCCESS(rc)) 305 rc = rc2; 306 break; 307 } 308 309 case RTFS_TYPE_FILE: 310 { 311 memcpy(&pszDir[cchDir], pDirEntry->szName, pDirEntry->cbName + 1); 312 rc = dndTransferListObjAdd(pList, pszDir, pDirEntry->Info.Attr.fMode, fFlags); 313 break; 314 } 315 316 default: 317 { 318 319 break; 320 } 321 } 322 } 323 324 if (rc == VERR_NO_MORE_FILES) /* Done reading current directory? */ 325 { 326 rc = VINF_SUCCESS; 327 } 328 else if (RT_FAILURE(rc)) 329 LogRel(("DnD: Error while adding files recursively, rc=%Rrc\n", rc)); 330 331 int rc2 = RTDirClose(hDir); 332 if (RT_FAILURE(rc2)) 333 { 334 if (RT_SUCCESS(rc)) 335 rc = rc2; 336 } 337 338 return rc; 339 } 340 341 /** 342 * Appends a native system path recursively by adding these entries as transfer objects. 343 * 344 * @returns VBox status code. 345 * @param pList Transfer list to add found entries to. 346 * @param pcszPathAbs Absolute path to add. 347 * @param fFlags Flags of type DNDTRANSFERLISTFLAGS. 348 */ 349 static int dndTransferListAppendPathNativeRecursive(PDNDTRANSFERLIST pList, 350 const char *pcszPathAbs, DNDTRANSFERLISTFLAGS fFlags) 351 { 352 char szPathAbs[RTPATH_MAX]; 353 int rc = RTStrCopy(szPathAbs, sizeof(szPathAbs), pcszPathAbs); 354 if (RT_FAILURE(rc)) 355 return rc; 356 357 union 358 { 359 uint8_t abPadding[DNDTRANSFERLIST_DIRENTRY_BUF_SIZE]; 360 RTDIRENTRYEX DirEntry; 361 } uBuf; 362 const size_t cchPathAbs = strlen(szPathAbs); 363 if (!cchPathAbs) 364 return VINF_SUCCESS; 365 return dndTransferListAppendPathRecursiveSub(pList, szPathAbs, cchPathAbs, &uBuf.DirEntry, fFlags); 366 } 367 368 static int dndTransferListAppendPathNative(PDNDTRANSFERLIST pList, const char *pcszPath, DNDTRANSFERLISTFLAGS fFlags) 369 { 370 /* We don't want to have a relative directory here. */ 371 if (!RTPathStartsWithRoot(pcszPath)) 372 return VERR_INVALID_PARAMETER; 373 374 int rc = DnDPathValidate(pcszPath, false /* fMustExist */); 375 if (RT_FAILURE(rc)) 376 return rc; 377 378 char szPathAbs[RTPATH_MAX]; 379 rc = RTStrCopy(szPathAbs, sizeof(szPathAbs), pcszPath); 380 if (RT_FAILURE(rc)) 381 return rc; 382 383 size_t cchPathAbs = RTStrNLen(szPathAbs, sizeof(szPathAbs)); 384 AssertReturn(cchPathAbs, VERR_INVALID_PARAMETER); 385 386 /* Convert path to transport style. */ 387 rc = DnDPathConvert(szPathAbs, sizeof(szPathAbs), DNDPATHCONVERT_FLAGS_TRANSPORT); 388 if (RT_SUCCESS(rc)) 389 { 390 /* Make sure the path has the same root path as our list. */ 391 if (RTPathStartsWith(szPathAbs, pList->pszPathRootAbs)) 392 { 393 RTDIR hDir; 394 rc = RTDirOpen(&hDir, szPathAbs); 395 if (RT_SUCCESS(rc)) 396 { 397 for (;;) 398 { 399 /* Get the next directory. */ 400 RTDIRENTRYEX dirEntry; 401 rc = RTDirReadEx(hDir, &dirEntry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK /** @todo No symlinks yet. */); 402 if (RT_SUCCESS(rc)) 403 { 404 if (RTDirEntryExIsStdDotLink(&dirEntry)) 405 continue; 406 407 /* Check length. */ 408 if (dirEntry.cbName + cchPathAbs + 3 >= sizeof(szPathAbs)) 409 { 410 rc = VERR_BUFFER_OVERFLOW; 411 break; 412 } 413 414 /* Append the directory entry to our absolute path. */ 415 memcpy(&szPathAbs[cchPathAbs], dirEntry.szName, dirEntry.cbName + 1); 416 417 LogFlowFunc(("szName=%s, szPathAbs=%s\n", dirEntry.szName, szPathAbs)); 418 419 switch (dirEntry.Info.Attr.fMode & RTFS_TYPE_MASK) 420 { 421 case RTFS_TYPE_DIRECTORY: 422 { 423 rc = dndTransferListAppendPathNativeRecursive(pList, szPathAbs, fFlags); 424 break; 425 } 426 427 case RTFS_TYPE_FILE: 428 { 429 rc = dndTransferListObjAdd(pList, szPathAbs, dirEntry.Info.Attr.fMode, fFlags); 430 break; 431 } 432 433 default: 434 rc = VERR_NOT_SUPPORTED; 435 break; 436 } 437 438 if (RT_SUCCESS(rc)) 439 rc = dndTransferListRootAdd(pList, dirEntry.szName); 440 } 441 else if (rc == VERR_NO_MORE_FILES) 442 { 443 rc = VINF_SUCCESS; 444 break; 445 } 446 else 447 break; 448 449 if (RT_FAILURE(rc)) 450 break; 451 } 452 } 453 } 454 else 455 rc = VERR_INVALID_PARAMETER; 456 } 457 458 if (RT_FAILURE(rc)) 459 LogRel(("DnD: Adding native path '%s' failed with rc=%Rrc\n", pcszPath, rc)); 460 461 return rc; 462 } 463 464 static int dndTransferListAppendPathURI(PDNDTRANSFERLIST pList, const char *pcszPath, DNDTRANSFERLISTFLAGS fFlags) 465 { 466 RT_NOREF(fFlags); 467 468 /* Query the path component of a file URI. If this hasn't a 469 * file scheme, NULL is returned. */ 470 char *pszFilePath; 471 int rc = RTUriFilePathEx(pcszPath, RTPATH_STR_F_STYLE_UNIX, &pszFilePath, 0 /*cbPath*/, NULL /*pcchPath*/); 472 if (RT_SUCCESS(rc)) 473 { 474 LogFlowFunc(("pcszPath=%s -> pszFilePath=%s\n", pcszPath, pszFilePath)); 475 rc = dndTransferListRootAdd(pList, pszFilePath); 476 RTStrFree(pszFilePath); 477 478 } 479 480 if (RT_FAILURE(rc)) 481 LogRel(("DnD: Adding URI path '%s' failed with rc=%Rrc\n", pcszPath, rc)); 482 483 return rc; 484 } 485 486 /** 487 * Appends a single path to a transfer list. 488 * 489 * @returns VBox status code. VERR_NOT_SUPPORTED if the path is not supported. 490 * @param pList Transfer list to append to. 491 * @param enmFmt Format of \a pszPaths to append. 492 * @param pcszPath Path to append. Must be part of the list's set root path. 493 * @param fFlags Transfer list flags to use for appending. 494 */ 495 int DnDTransferListAppendPath(PDNDTRANSFERLIST pList, 496 DNDTRANSFERLISTFMT enmFmt, const char *pcszPath, DNDTRANSFERLISTFLAGS fFlags) 497 { 498 AssertPtrReturn(pList, VERR_INVALID_POINTER); 499 AssertPtrReturn(pcszPath, VERR_INVALID_POINTER); 500 AssertReturn(!(fFlags & ~DNDTRANSFERLIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 501 AssertReturn(!(fFlags & DNDTRANSFERLIST_FLAGS_RESOLVE_SYMLINKS), VERR_NOT_SUPPORTED); 502 503 int rc; 504 505 switch (enmFmt) 506 { 507 case DNDTRANSFERLISTFMT_NATIVE: 508 rc = dndTransferListAppendPathNative(pList, pcszPath, fFlags); 509 break; 510 511 case DNDTRANSFERLISTFMT_URI: 512 rc = dndTransferListAppendPathURI(pList, pcszPath, fFlags); 513 break; 514 515 default: 516 AssertFailedStmt(rc = VERR_NOT_SUPPORTED); 517 break; /* Never reached */ 518 } 519 520 return rc; 521 } 522 523 /** 524 * Appends native paths to a transfer list. 525 * 526 * @returns VBox status code. 527 * @param pList Transfer list to append to. 528 * @param enmFmt Format of \a pszPaths to append. 529 * @param pszPaths Buffer of paths to append. 530 * @param cbPaths Size (in bytes) of buffer of paths to append. 531 * @param pcszSeparator Separator string to use. 532 * @param fFlags Transfer list flags to use for appending. 533 */ 534 int DnDTransferListAppendPathsFromBuffer(PDNDTRANSFERLIST pList, 535 DNDTRANSFERLISTFMT enmFmt, const char *pszPaths, size_t cbPaths, 536 const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags) 537 { 538 AssertPtrReturn(pList, VERR_INVALID_POINTER); 539 AssertPtrReturn(pszPaths, VERR_INVALID_POINTER); 540 AssertReturn(cbPaths, VERR_INVALID_PARAMETER); 541 542 char **papszPaths = NULL; 543 size_t cPaths = 0; 544 int rc = RTStrSplit(pszPaths, cbPaths, pcszSeparator, &papszPaths, &cPaths); 545 if (RT_SUCCESS(rc)) 546 rc = DnDTransferListAppendPathsFromArray(pList, enmFmt, papszPaths, cPaths, fFlags); 547 548 for (size_t i = 0; i < cPaths; ++i) 549 RTStrFree(papszPaths[i]); 550 RTMemFree(papszPaths); 551 552 return rc; 553 } 554 555 /** 556 * Appends paths to a transfer list. 557 * 558 * @returns VBox status code. Will return VERR_INVALID_PARAMETER if a common root path could not be found. 559 * @param pList Transfer list to append path to. 560 * @param enmFmt Format of \a papcszPaths to append. 561 * @param papcszPaths Array of paths to append. 562 * @param cPaths Number of paths in \a papcszPaths to append. 563 * @param fFlags Transfer list flags to use for appending. 564 */ 565 int DnDTransferListAppendPathsFromArray(PDNDTRANSFERLIST pList, 566 DNDTRANSFERLISTFMT enmFmt, 567 const char * const *papcszPaths, size_t cPaths, DNDTRANSFERLISTFLAGS fFlags) 568 { 569 AssertPtrReturn(pList, VERR_INVALID_POINTER); 570 AssertPtrReturn(papcszPaths, VERR_INVALID_POINTER); 571 AssertReturn(!(fFlags & ~DNDTRANSFERLIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 572 573 int rc = VINF_SUCCESS; 574 575 if (!cPaths) /* Nothing to add? Bail out. */ 576 return VINF_SUCCESS; 577 578 /* If we don't have a root path set, try to find the common path of all handed-in paths. */ 579 if (!pList->pszPathRootAbs) 580 { 581 size_t cchRootPath = RTPathFindCommon(papcszPaths, cPaths); 582 if (cchRootPath) 583 { 584 /* Just use the first path in the array as the reference. */ 585 char *pszRootPath = RTStrDupN(papcszPaths[0], cchRootPath); 586 if (pszRootPath) 587 { 588 LogRel2(("DnD: Determined root path is '%s'\n", pszRootPath)); 589 rc = dndTransferListSetRootPath(pList, pszRootPath); 590 RTStrFree(pszRootPath); 97 591 } 98 592 else 99 593 rc = VERR_NO_MEMORY; 100 594 } 101 /* Note: Symlinks already should have been resolved at this point. */ 595 } 596 597 /* 598 * Go through the created list and make sure all entries have the same root path. 599 */ 600 for (size_t i = 0; i < cPaths; i++) 601 { 602 rc = DnDTransferListAppendPath(pList, enmFmt, papcszPaths[i], fFlags); 603 if (RT_FAILURE(rc)) 604 break; 605 } 606 607 LogFlowFuncLeaveRC(rc); 608 return rc; 609 } 610 611 /** 612 * Returns the first transfer object in a list. 613 * 614 * @returns Pointer to transfer object if found, or NULL if not found. 615 * @param pList Transfer list to get first transfer object from. 616 */ 617 PDNDTRANSFEROBJECT DnDTransferListObjGetFirst(PDNDTRANSFERLIST pList) 618 { 619 AssertPtrReturn(pList, NULL); 620 621 return RTListGetFirst(&pList->lstObj, DNDTRANSFEROBJECT, Node); 622 } 623 624 /** 625 * Removes the first DnD transfer object from a transfer list. 626 * 627 * @param pList Transfer list to remove first entry for. 628 */ 629 void DnDTransferListObjRemoveFirst(PDNDTRANSFERLIST pList) 630 { 631 AssertPtrReturnVoid(pList); 632 633 if (!pList->cObj) 634 return; 635 636 PDNDTRANSFEROBJECT pObj = RTListGetFirst(&pList->lstObj, DNDTRANSFEROBJECT, Node); 637 AssertPtr(pObj); 638 639 uint64_t cbSize = DnDTransferObjectGetSize(pObj); 640 Assert(pList->cbObjTotal >= cbSize); 641 pList->cbObjTotal -= cbSize; /* Adjust total size. */ 642 643 dndTransferListObjFree(pList, pObj); 644 } 645 646 /** 647 * Returns all root entries of a transfer list as a string. 648 * 649 * @returns VBox status code. 650 * @param pList Transfer list to return root paths for. 651 * @param pcszPathBase Root path to use as a base path. If NULL, the list's absolute root path will be used (if any). 652 * @param pcszSeparator Separator to use for separating the root entries. 653 * @param ppszBuffer Where to return the allocated string on success. Needs to be free'd with RTStrFree(). 654 * @param pcbBuffer Where to return the size (in bytes) of the allocated string on success, including terminator. 655 */ 656 int DnDTransferListGetRootsEx(PDNDTRANSFERLIST pList, 657 DNDTRANSFERLISTFMT enmFmt, const char *pcszPathBase, const char *pcszSeparator, 658 char **ppszBuffer, size_t *pcbBuffer) 659 { 660 AssertPtrReturn(pList, VERR_INVALID_POINTER); 661 /* pcszPathBase can be NULL. */ 662 AssertPtrReturn(pcszSeparator, VERR_INVALID_POINTER); 663 AssertPtrReturn(ppszBuffer, VERR_INVALID_POINTER); 664 AssertPtrReturn(pcbBuffer, VERR_INVALID_POINTER); 665 666 char *pszString = NULL; 667 668 /* Find out which root path to use. */ 669 const char *pcszPathRootTmp = pcszPathBase ? pcszPathBase : pList->pszPathRootAbs; 670 /* pcszPathRootTmp can be NULL*/ 671 672 LogFlowFunc(("Using root path '%s'\n", pcszPathRootTmp ? pcszPathRootTmp : "<None>")); 673 674 int rc = DnDPathValidate(pcszPathRootTmp, false /* fMustExist */); 675 if (RT_FAILURE(rc)) 676 return rc; 677 678 char szPath[RTPATH_MAX]; 679 680 PDNDTRANSFERLISTROOT pRoot; 681 RTListForEach(&pList->lstRoot, pRoot, DNDTRANSFERLISTROOT, Node) 682 { 683 if (pcszPathRootTmp) 684 { 685 rc = RTStrCopy(szPath, sizeof(szPath), pcszPathRootTmp); 686 AssertRCBreak(rc); 687 } 688 689 rc = RTPathAppend(szPath, sizeof(szPath), pRoot->pszPathRoot); 690 AssertRCBreak(rc); 691 692 if (enmFmt == DNDTRANSFERLISTFMT_URI) 693 { 694 char *pszPathURI = RTUriFileCreate(szPath); 695 AssertPtrBreakStmt(pszPathURI, rc = VERR_NO_MEMORY); 696 697 rc = RTStrAAppend(&pszString, pszPathURI); 698 RTStrFree(pszPathURI); 699 AssertRCBreak(rc); 700 } 102 701 else 103 rc = VERR_NOT_SUPPORTED; 104 } 105 106 LogFlowFuncLeaveRC(rc); 107 return rc; 108 } 109 110 int DnDURIList::appendPathRecursive(const char *pcszSrcPath, 111 const char *pcszDstPath, const char *pcszDstBase, size_t cchDstBase, 112 DNDURILISTFLAGS fFlags) 113 { 114 AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER); 115 AssertPtrReturn(pcszDstBase, VERR_INVALID_POINTER); 116 AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER); 117 118 LogFlowFunc(("pcszSrcPath=%s, pcszDstPath=%s, pcszDstBase=%s, cchDstBase=%zu, fFlags=0x%x\n", 119 pcszSrcPath, pcszDstPath, pcszDstBase, cchDstBase, fFlags)); 120 121 RTFSOBJINFO objInfo; 122 int rc = RTPathQueryInfo(pcszSrcPath, &objInfo, RTFSOBJATTRADD_NOTHING); 702 { 703 rc = RTStrAAppend(&pszString, szPath); 704 AssertRCBreak(rc); 705 } 706 707 rc = RTStrAAppend(&pszString, pcszSeparator); 708 AssertRCBreak(rc); 709 } 710 123 711 if (RT_SUCCESS(rc)) 124 712 { 125 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) 126 { 127 rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags); 713 *ppszBuffer = pszString; 714 *pcbBuffer = pszString ? strlen(pszString) + 1 /* Include termination */ : 0; 715 } 716 else 717 RTStrFree(pszString); 718 return rc; 719 } 720 721 int DnDTransferListGetRoots(PDNDTRANSFERLIST pList, 722 DNDTRANSFERLISTFMT enmFmt, char **ppszBuffer, size_t *pcbBuffer) 723 { 724 return DnDTransferListGetRootsEx(pList, enmFmt, "" /* pcszPathRoot */, DND_PATH_SEPARATOR, 725 ppszBuffer, pcbBuffer); 726 } 727 728 /** 729 * Returns the total root entries count for a DnD transfer list. 730 * 731 * @returns Total number of root entries. 732 * @param pList Transfer list to return total number of root entries for. 733 */ 734 uint64_t DnDTransferListGetRootCount(PDNDTRANSFERLIST pList) 735 { 736 AssertPtrReturn(pList, 0); 737 return pList->cRoots; 738 } 739 740 /** 741 * Returns the absolute root path for a DnD transfer list. 742 * 743 * @returns Pointer to the root path. 744 * @param pList Transfer list to return root path for. 745 */ 746 const char *DnDTransferListGetRootPathAbs(PDNDTRANSFERLIST pList) 747 { 748 AssertPtrReturn(pList, NULL); 749 return pList->pszPathRootAbs; 750 } 751 752 /** 753 * Returns the total transfer object count for a DnD transfer list. 754 * 755 * @returns Total number of transfer objects. 756 * @param pList Transfer list to return total number of transfer objects for. 757 */ 758 uint64_t DnDTransferListObjCount(PDNDTRANSFERLIST pList) 759 { 760 AssertPtrReturn(pList, 0); 761 return pList->cObj; 762 } 763 764 /** 765 * Returns the total bytes of all handled transfer objects for a DnD transfer list. 766 * 767 * @returns VBox status code. 768 * @param pList Transfer list to return total bytes for. 769 */ 770 uint64_t DnDTransferListObjTotalBytes(PDNDTRANSFERLIST pList) 771 { 772 AssertPtrReturn(pList, 0); 773 return pList->cbObjTotal; 774 } 775 776 /** 777 * Sets the absolute root path of a transfer list. 778 * 779 * @returns VBox status code. 780 * @param pList Transfer list to set root path for. 781 * @param pcszRootPathAbs Absolute root path to set. 782 */ 783 static int dndTransferListSetRootPath(PDNDTRANSFERLIST pList, const char *pcszRootPathAbs) 784 { 785 AssertPtrReturn(pList, VERR_INVALID_POINTER); 786 AssertPtrReturn(pcszRootPathAbs, VERR_INVALID_POINTER); 787 AssertReturn(pList->pszPathRootAbs == NULL, VERR_WRONG_ORDER); /* Already initialized? */ 788 789 LogFlowFunc(("pcszRootPathAbs=%s\n", pcszRootPathAbs)); 790 791 char szRootPath[RTPATH_MAX]; 792 int rc = RTStrCopy(szRootPath, sizeof(szRootPath), pcszRootPathAbs); 793 if (RT_FAILURE(rc)) 794 return rc; 795 796 /* Note: The list's root path is kept in native style, so no conversion needed here. */ 797 798 RTPathEnsureTrailingSeparatorEx(szRootPath, sizeof(szRootPath), RTPATH_STR_F_STYLE_HOST); 799 800 pList->pszPathRootAbs = RTStrDup(szRootPath); 801 if (pList->pszPathRootAbs) 802 { 803 LogFlowFunc(("Root path is '%s'\n", pList->pszPathRootAbs)); 804 } 805 else 806 rc = VERR_NO_MEMORY; 807 808 return rc; 809 } 810 811 static int dndTransferListRootAdd(PDNDTRANSFERLIST pList, const char *pcszRoot) 812 { 813 int rc; 814 815 PDNDTRANSFERLISTROOT pRoot = (PDNDTRANSFERLISTROOT)RTMemAllocZ(sizeof(DNDTRANSFERLISTROOT)); 816 if (pRoot) 817 { 818 pRoot->pszPathRoot = RTStrDup(pcszRoot); 819 if (pRoot->pszPathRoot) 820 { 821 RTListAppend(&pList->lstRoot, &pRoot->Node); 822 pList->cRoots++; 823 824 rc = VINF_SUCCESS; 825 } 826 else 827 rc = VERR_NO_MEMORY; 828 829 if (RT_FAILURE(rc)) 830 { 831 RTMemFree(pRoot); 832 pRoot = NULL; 833 } 834 } 835 else 836 rc = VERR_NO_MEMORY; 837 838 return rc; 839 } 840 841 /** 842 * Frees an internal DnD transfer root. 843 * 844 * @param pList Transfer list to free root for. 845 * @param pRootObj Transfer list root to free. The pointer will be invalid after calling. 846 */ 847 static void dndTransferListRootFree(PDNDTRANSFERLIST pList, PDNDTRANSFERLISTROOT pRootObj) 848 { 849 if (!pRootObj) 850 return; 851 852 RTStrFree(pRootObj->pszPathRoot); 853 854 RTListNodeRemove(&pRootObj->Node); 855 RTMemFree(pRootObj); 856 857 AssertReturnVoid(pList->cRoots); 858 pList->cRoots--; 859 } 860 861 862 #if 0 863 /** 864 * Appends a single URI path to a transfer list. 865 * 866 * @returns VBox status code. 867 * @param pList Transfer list to append URI path to. 868 * @param pszURIPath URI path to append. 869 * @param fFlags Transfer list flags to use for appending. 870 */ 871 int DnDTransferListURIAppendPath(PDNDTRANSFERLIST pList, const char *pszURIPath, DNDTRANSFERLISTFLAGS fFlags) 872 { 873 AssertPtrReturn(pList, VERR_INVALID_POINTER); 874 AssertPtrReturn(pszURIPath, VERR_INVALID_POINTER); 875 AssertReturn(!(fFlags & ~DNDTRANSFERLIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 876 877 in rc; 878 879 /* Query the path component of a file URI. If this hasn't a 880 * file scheme, NULL is returned. */ 881 char *pszFilePath = RTUriFilePathEx(pszURIPath, RTPATH_STR_F_STYLE_UNIX, &pszFilePath, 0 /*cbPath*/, NULL /*pcchPath*/); 882 LogFlowFunc(("pszPath=%s, pszFilePath=%s\n", pszFilePath)); 883 if (pszFilePath) 884 { 885 rc = DnDPathValidate(pszFilePath, false /* fMustExist */); 886 if (RT_SUCCESS(rc)) 887 { 888 uint32_t fPathConvert = DNDPATHCONVERT_FLAGS_TRANSPORT; 889 #ifdef RT_OS_WINDOWS 890 fPathConvert |= DNDPATHCONVERT_FLAGS_TO_DOS; 891 #endif 892 rc = DnDPathConvert(pszFilePath, strlen(pszFilePath) + 1, fPathConvert); 128 893 if (RT_SUCCESS(rc)) 129 894 { 130 RTDIR hDir; 131 rc = RTDirOpen(&hDir, pcszSrcPath); 132 if (RT_SUCCESS(rc)) 895 LogRel2(("DnD: Got URI data item '%s'\n", pszFilePath)); 896 897 PDNDTRANSFERLISTROOT pRoot = (PDNDTRANSFERLISTROOT)RTMemAlloc(sizeof(DNDTRANSFERLISTROOT)); 898 if (pRoot) 133 899 { 134 size_t cbDirEntry = 0; 135 PRTDIRENTRYEX pDirEntry = NULL; 136 do 137 { 138 /* Retrieve the next directory entry. */ 139 rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); 140 if (RT_FAILURE(rc)) 141 { 142 if (rc == VERR_NO_MORE_FILES) 143 rc = VINF_SUCCESS; 144 break; 145 } 146 147 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK) 148 { 149 case RTFS_TYPE_DIRECTORY: 150 { 151 /* Skip "." and ".." entries. */ 152 if (RTDirEntryExIsStdDotLink(pDirEntry)) 153 break; 154 155 char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName); 156 if (pszSrc) 157 { 158 char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName); 159 if (pszDst) 160 { 161 rc = appendPathRecursive(pszSrc, pszDst, pcszDstBase, cchDstBase, fFlags); 162 RTStrFree(pszDst); 163 } 164 else 165 rc = VERR_NO_MEMORY; 166 167 RTStrFree(pszSrc); 168 } 169 else 170 rc = VERR_NO_MEMORY; 171 break; 172 } 173 174 case RTFS_TYPE_FILE: 175 { 176 char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName); 177 if (pszSrc) 178 { 179 char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName); 180 if (pszDst) 181 { 182 rc = addEntry(pszSrc, &pszDst[cchDstBase], fFlags); 183 RTStrFree(pszDst); 184 } 185 else 186 rc = VERR_NO_MEMORY; 187 RTStrFree(pszSrc); 188 } 189 else 190 rc = VERR_NO_MEMORY; 191 break; 192 } 193 case RTFS_TYPE_SYMLINK: 194 { 195 if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS) 196 { 197 char *pszSrc = RTPathRealDup(pcszDstBase); 198 if (pszSrc) 199 { 200 rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING); 201 if (RT_SUCCESS(rc)) 202 { 203 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) 204 { 205 LogFlowFunc(("Directory entry is symlink to directory\n")); 206 rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags); 207 } 208 else if (RTFS_IS_FILE(objInfo.Attr.fMode)) 209 { 210 LogFlowFunc(("Directory entry is symlink to file\n")); 211 rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags); 212 } 213 else 214 rc = VERR_NOT_SUPPORTED; 215 } 216 217 RTStrFree(pszSrc); 218 } 219 else 220 rc = VERR_NO_MEMORY; 221 } 222 break; 223 } 224 225 default: 226 break; 227 } 228 229 } while (RT_SUCCESS(rc)); 230 231 RTDirReadExAFree(&pDirEntry, &cbDirEntry); 232 RTDirClose(hDir); 233 } 234 } 235 } 236 else if (RTFS_IS_FILE(objInfo.Attr.fMode)) 237 { 238 rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags); 239 } 240 else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode)) 241 { 242 if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS) 243 { 244 char *pszSrc = RTPathRealDup(pcszSrcPath); 245 if (pszSrc) 246 { 247 rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING); 248 if (RT_SUCCESS(rc)) 249 { 250 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) 251 { 252 LogFlowFunc(("Symlink to directory\n")); 253 rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags); 254 } 255 else if (RTFS_IS_FILE(objInfo.Attr.fMode)) 256 { 257 LogFlowFunc(("Symlink to file\n")); 258 rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags); 259 } 260 else 261 rc = VERR_NOT_SUPPORTED; 262 } 263 264 RTStrFree(pszSrc); 900 pRoot->pszPathRoot = pszFilePath; 901 902 RTListAppend(&pList->lstRoot, &pRoot->Node); 903 pList->cRoots++; 904 265 905 } 266 906 else 267 907 rc = VERR_NO_MEMORY; 268 908 } 909 else 910 LogRel(("DnD: Path conversion of URI data item '%s' failed with %Rrc\n", pszFilePath, rc)); 269 911 } 270 912 else 271 rc = VERR_NOT_SUPPORTED; 913 LogRel(("DnD: Path validation for URI data item '%s' failed with %Rrc\n", pszFilePath, rc)); 914 915 if (RT_FAILURE(rc)) 916 RTStrFree(pszFilePath); 272 917 } 273 918 … … 276 921 } 277 922 278 int DnDURIList::AppendNativePath(const char *pszPath, DNDURILISTFLAGS fFlags) 279 { 280 AssertPtrReturn(pszPath, VERR_INVALID_POINTER); 281 282 int rc; 283 char *pszPathNative = RTStrDup(pszPath); 284 if (pszPathNative) 285 { 286 RTPathChangeToUnixSlashes(pszPathNative, true /* fForce */); 287 288 char *pszPathURI = RTUriCreate("file" /* pszScheme */, NULL /* pszAuthority */, 289 pszPathNative, NULL /* pszQuery */, NULL /* pszFragment */); 290 if (pszPathURI) 291 { 292 rc = AppendURIPath(pszPathURI, fFlags); 293 RTStrFree(pszPathURI); 294 } 295 else 296 rc = VERR_INVALID_PARAMETER; 297 298 RTStrFree(pszPathNative); 299 } 300 else 301 rc = VERR_NO_MEMORY; 302 303 return rc; 304 } 305 306 int DnDURIList::AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths, 307 DNDURILISTFLAGS fFlags) 308 { 309 AssertPtrReturn(pszNativePaths, VERR_INVALID_POINTER); 310 AssertReturn(cbNativePaths, VERR_INVALID_PARAMETER); 311 312 RTCList<RTCString> lstPaths 313 = RTCString(pszNativePaths, cbNativePaths - 1).split("\r\n"); 314 return AppendNativePathsFromList(lstPaths, fFlags); 315 } 316 317 int DnDURIList::AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths, 318 DNDURILISTFLAGS fFlags) 319 { 320 int rc = VINF_SUCCESS; 321 322 for (size_t i = 0; i < lstNativePaths.size(); i++) 323 { 324 const RTCString &strPath = lstNativePaths.at(i); 325 rc = AppendNativePath(strPath.c_str(), fFlags); 326 if (RT_FAILURE(rc)) 327 break; 328 } 329 330 LogFlowFuncLeaveRC(rc); 331 return rc; 332 } 333 334 int DnDURIList::AppendURIPath(const char *pszURI, DNDURILISTFLAGS fFlags) 335 { 336 AssertPtrReturn(pszURI, VERR_INVALID_POINTER); 337 AssertReturn(!(fFlags & ~DNDURILIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 338 /** @todo Check for string termination? */ 339 340 RTURIPARSED Parsed; 341 int rc = RTUriParse(pszURI, &Parsed); 342 if (RT_FAILURE(rc)) 343 return rc; 344 345 char *pszSrcPath = NULL; 346 347 /* file://host.example.com/path/to/file.txt */ 348 const char *pszParsedAuthority = RTUriParsedAuthority(pszURI, &Parsed); 349 if ( pszParsedAuthority 350 && pszParsedAuthority[0] != '\0') /* Authority present? */ 351 { 352 const char *pszParsedPath = RTUriParsedPath(pszURI, &Parsed); 353 if (pszParsedPath) 354 { 355 /* Always use UNIXy paths internally. */ 356 if (RTStrAPrintf(&pszSrcPath, "//%s%s", pszParsedAuthority, pszParsedPath) == -1) 357 rc = VERR_NO_MEMORY; 358 } 359 else 360 rc = VERR_INVALID_PARAMETER; 361 } 362 else 363 { 364 pszSrcPath = RTUriFilePath(pszURI); 365 if (!pszSrcPath) 366 rc = VERR_INVALID_PARAMETER; 367 } 368 369 LogFlowFunc(("pszURI=%s, fFlags=0x%x -> pszParsedAuthority=%s, pszSrcPath=%s, rc=%Rrc\n", 370 pszURI, fFlags, pszParsedAuthority ? pszParsedAuthority : "<None>", pszSrcPath, rc)); 371 372 if (RT_SUCCESS(rc)) 373 { 374 /* Add the path to our internal file list (recursive in 375 * the case of a directory). */ 376 size_t cbPathLen = RTPathStripTrailingSlash(pszSrcPath); 377 if (cbPathLen) 378 { 379 char *pszFileName = RTPathFilename(pszSrcPath); 380 if (pszFileName) 381 { 382 Assert(pszFileName >= pszSrcPath); 383 size_t cchDstBase = (fFlags & DNDURILIST_FLAGS_ABSOLUTE_PATHS) 384 ? 0 /* Use start of path as root. */ 385 : pszFileName - pszSrcPath; 386 char *pszDstPath = &pszSrcPath[cchDstBase]; 387 rc = DnDPathConvert(pszDstPath, strlen(pszDstPath), DNDPATHCONVERT_FLAGS_NONE); 388 if (RT_SUCCESS(rc)) 389 { 390 m_lstRoot.append(pszDstPath); 391 392 LogFlowFunc(("pszSrcPath=%s, pszFileName=%s, pszDstPath=%s\n", 393 pszSrcPath, pszFileName, pszDstPath)); 394 395 rc = appendPathRecursive(pszSrcPath, pszSrcPath, pszSrcPath, cchDstBase, fFlags); 396 } 397 } 398 else 399 rc = VERR_PATH_NOT_FOUND; 400 } 401 else 402 rc = VERR_INVALID_PARAMETER; 403 } 404 405 RTStrFree(pszSrcPath); 406 407 LogFlowFuncLeaveRC(rc); 408 return rc; 409 } 410 411 int DnDURIList::AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths, 412 DNDURILISTFLAGS fFlags) 413 { 923 /** 924 * Appends transfer list items from an URI string buffer. 925 * 926 * @returns VBox status code. 927 * @param pList Transfer list to append list data to. 928 * @param pszURIPaths String list to append. 929 * @param cbURIPaths Size (in bytes) of string list to append. 930 * @param pcszSeparator Separator string to use for separating strings of \a pszURIPathsAbs. 931 * @param fFlags Transfer list flags to use for appending. 932 */ 933 int DnDTransferListURIAppendFromBuffer(PDNDTRANSFERLIST pList, 934 const char *pszURIPaths, size_t cbURIPaths, 935 const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags) 936 { 937 AssertPtrReturn(pList, VERR_INVALID_POINTER); 414 938 AssertPtrReturn(pszURIPaths, VERR_INVALID_POINTER); 415 939 AssertReturn(cbURIPaths, VERR_INVALID_PARAMETER); 416 417 RTCList<RTCString> lstPaths 418 = RTCString(pszURIPaths, cbURIPaths - 1).split("\r\n"); 419 return AppendURIPathsFromList(lstPaths, fFlags); 420 } 421 422 int DnDURIList::AppendURIPathsFromList(const RTCList<RTCString> &lstURI, 423 DNDURILISTFLAGS fFlags) 424 { 425 int rc = VINF_SUCCESS; 426 427 for (size_t i = 0; i < lstURI.size(); i++) 428 { 429 RTCString strURI = lstURI.at(i); 430 rc = AppendURIPath(strURI.c_str(), fFlags); 431 432 if (RT_FAILURE(rc)) 433 break; 940 AssertReturn(!(fFlags & ~DNDTRANSFERLIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 941 942 char **papszPaths = NULL; 943 size_t cPaths = 0; 944 int rc = RTStrSplit(pszURIPaths, cbURIPaths, pcszSeparator, &papszPaths, &cPaths); 945 if (RT_SUCCESS(rc)) 946 { 947 for (size_t i = 0; i < cPaths; i++) 948 { 949 rc = DnDTransferListURIAppendPath(pList, papszPaths[i], fFlags); 950 if (RT_FAILURE(rc)) 951 break; 952 } 953 954 for (size_t i = 0; i < cPaths; ++i) 955 RTStrFree(papszPaths[i]); 956 RTMemFree(papszPaths); 434 957 } 435 958 … … 437 960 return rc; 438 961 } 439 440 void DnDURIList::Clear(void)441 {442 m_lstRoot.clear();443 444 for (size_t i = 0; i < m_lstTree.size(); i++)445 {446 DnDURIObject *pCurObj = m_lstTree.at(i);447 AssertPtr(pCurObj);448 delete pCurObj;449 }450 m_lstTree.clear();451 452 m_cTotal = 0;453 m_cbTotal = 0;454 }455 456 void DnDURIList::RemoveFirst(void)457 {458 if (m_lstTree.isEmpty())459 return;460 461 DnDURIObject *pCurObj = m_lstTree.first();462 AssertPtr(pCurObj);463 464 uint64_t cbSize = pCurObj->GetSize();465 Assert(m_cbTotal >= cbSize);466 m_cbTotal -= cbSize; /* Adjust total size. */467 468 pCurObj->Close();469 delete pCurObj;470 471 m_lstTree.removeFirst();472 }473 474 int DnDURIList::SetFromURIData(const void *pvData, size_t cbData, DNDURILISTFLAGS fFlags)475 {476 Assert(fFlags == 0); RT_NOREF1(fFlags);477 AssertPtrReturn(pvData, VERR_INVALID_POINTER);478 AssertReturn(cbData, VERR_INVALID_PARAMETER);479 480 if (!RTStrIsValidEncoding(static_cast<const char *>(pvData)))481 return VERR_INVALID_PARAMETER;482 483 RTCList<RTCString> lstURI =484 RTCString(static_cast<const char *>(pvData), cbData - 1).split("\r\n");485 if (lstURI.isEmpty())486 return VINF_SUCCESS;487 488 int rc = VINF_SUCCESS;489 490 for (size_t i = 0; i < lstURI.size(); ++i)491 {492 /* Query the path component of a file URI. If this hasn't a493 * file scheme, NULL is returned. */494 const char *pszURI = lstURI.at(i).c_str();495 char *pszFilePath = RTUriFilePath(pszURI);496 #ifdef DEBUG_andy497 LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath));498 962 #endif 499 if (pszFilePath)500 {501 rc = DnDPathConvert(pszFilePath, strlen(pszFilePath), DNDPATHCONVERT_FLAGS_NONE);502 if (RT_SUCCESS(rc))503 {504 m_lstRoot.append(pszFilePath);505 m_cTotal++;506 }507 508 RTStrFree(pszFilePath);509 }510 else511 rc = VERR_INVALID_PARAMETER;512 513 if (RT_FAILURE(rc))514 break;515 }516 517 return rc;518 }519 520 RTCString DnDURIList::GetRootEntries(const RTCString &strPathBase /* = "" */,521 const RTCString &strSeparator /* = "\r\n" */) const522 {523 RTCString strRet;524 for (size_t i = 0; i < m_lstRoot.size(); i++)525 {526 const char *pszCurRoot = m_lstRoot.at(i).c_str();527 #ifdef DEBUG_andy528 LogFlowFunc(("pszCurRoot=%s\n", pszCurRoot));529 #endif530 if (strPathBase.isNotEmpty())531 {532 char *pszPath = RTPathJoinA(strPathBase.c_str(), pszCurRoot);533 if (pszPath)534 {535 char *pszPathURI = RTUriFileCreate(pszPath);536 if (pszPathURI)537 {538 strRet += RTCString(pszPathURI) + strSeparator;539 LogFlowFunc(("URI (Base): %s\n", strRet.c_str()));540 RTStrFree(pszPathURI);541 }542 543 RTStrFree(pszPath);544 545 if (!pszPathURI)546 break;547 }548 else549 break;550 }551 else552 {553 char *pszPathURI = RTUriFileCreate(pszCurRoot);554 if (pszPathURI)555 {556 strRet += RTCString(pszPathURI) + strSeparator;557 LogFlowFunc(("URI: %s\n", strRet.c_str()));558 RTStrFree(pszPathURI);559 }560 else561 break;562 }563 }564 565 return strRet;566 }567 -
trunk/src/VBox/GuestHost/DragAndDrop/DnDTransferObject.cpp
r85369 r85371 1 1 /* $Id$ */ 2 2 /** @file 3 * DnD - URI object class. For handling creation/reading/writing to files and directories on host or guest side.3 * DnD - Transfer object implemenation for handling creation/reading/writing to files and directories on host or guest side. 4 4 */ 5 5 … … 28 28 #include <iprt/fs.h> 29 29 #include <iprt/path.h> 30 #include <iprt/string.h> 30 31 #include <iprt/uri.h> 31 32 32 33 #include <VBox/log.h> 33 34 34 35 DnDURIObject::DnDURIObject(Type enmType /* = Type_Unknown */, const RTCString &strPathAbs /* = "" */) 36 : m_enmType(Type_Unknown) 37 { 38 if ( enmType != Type_Unknown 39 && strPathAbs.isNotEmpty()) 40 { 41 int rc2 = Init(enmType, strPathAbs); 42 AssertRC(rc2); 43 } 44 } 45 46 DnDURIObject::~DnDURIObject(void) 47 { 48 closeInternal(); 35 /********************************************************************************************************************************* 36 * Prototypes * 37 *********************************************************************************************************************************/ 38 static void dndTransferObjectCloseInternal(PDNDTRANSFEROBJECT pObj); 39 static int dndTransferObjectQueryInfoInternal(PDNDTRANSFEROBJECT pObj); 40 41 42 /** 43 * Initializes the object with an expected object type and file path. 44 * 45 * @returns VBox status code. 46 * @param pObj DnD transfer object to initialize. 47 * @param enmType Type we expect this object to be. 48 * @param pcszPathSrcAbs Absolute source (local) path of file this object represents. Can be empty (e.g. for root stuff). 49 * @param pcszPathDst Relative path of file this object represents at the destination. 50 * Together with \a pcszPathSrcAbs this represents the complete absolute local path. 51 */ 52 int DnDTransferObjectInit(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJTYPE enmType, const char *pcszPathSrcAbs, const char *pcszPathDst) 53 { 54 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 55 AssertReturn(pObj->enmType == DNDTRANSFEROBJTYPE_UNKNOWN, VERR_WRONG_ORDER); /* Already initialized? */ 56 /* pcszPathSrcAbs can be empty. */ 57 AssertPtrReturn(pcszPathDst, VERR_INVALID_POINTER); 58 59 switch (enmType) 60 { 61 case DNDTRANSFEROBJTYPE_FILE: 62 { 63 pObj->u.File.hFile = NIL_RTFILE; 64 break; 65 } 66 67 case DNDTRANSFEROBJTYPE_DIRECTORY: 68 { 69 pObj->u.Dir.hDir = NIL_RTDIR; 70 break; 71 } 72 73 default: 74 AssertFailedReturn(VERR_NOT_IMPLEMENTED); 75 break; /* Never reached */ 76 } 77 78 int rc = DnDPathValidate(pcszPathDst, false /* Does not need to exist */); 79 if (RT_FAILURE(rc)) 80 return rc; 81 82 char szPath[RTPATH_MAX + 1]; 83 84 /* Save the index (in characters) where the first destination segment starts. */ 85 if ( pcszPathSrcAbs 86 && RTStrNLen(pcszPathSrcAbs, RTSTR_MAX)) 87 { 88 rc = DnDPathValidate(pcszPathSrcAbs, false /* Does not need to exist */); 89 if (RT_FAILURE(rc)) 90 return rc; 91 92 rc = RTStrCopy(szPath, sizeof(szPath), pcszPathSrcAbs); 93 if (RT_SUCCESS(rc)) 94 rc = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath)) == 0 ? VERR_BUFFER_OVERFLOW : VINF_SUCCESS; 95 96 /* Save the index (in characters) where the destination part starts. */ 97 pObj->idxDst = (uint16_t)RTStrNLen(szPath, RTSTR_MAX); 98 AssertReturn(pObj->idxDst != RTSTR_MAX, VERR_INVALID_PARAMETER); 99 } 100 else 101 { 102 szPath[0] = '\0'; /* Init empty string. */ 103 pObj->idxDst = 0; 104 } 105 106 if (RT_FAILURE(rc)) 107 return rc; 108 109 /* Append the destination part. */ 110 rc = RTPathAppend(szPath, sizeof(szPath), pcszPathDst); 111 if ( RT_SUCCESS(rc) 112 && enmType == DNDTRANSFEROBJTYPE_DIRECTORY) 113 rc = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath)) == 0 ? VERR_BUFFER_OVERFLOW : VINF_SUCCESS; 114 115 if (RT_FAILURE(rc)) 116 return rc; 117 118 pObj->pszPath = RTStrDup(szPath); 119 if (!pObj->pszPath) 120 return VERR_NO_MEMORY; 121 122 /* Convert paths into transport format. */ 123 rc = DnDPathConvert(pObj->pszPath, strlen(pObj->pszPath), DNDPATHCONVERT_FLAGS_TRANSPORT); 124 if (RT_FAILURE(rc)) 125 { 126 RTStrFree(pObj->pszPath); 127 pObj->pszPath = NULL; 128 return rc; 129 } 130 131 LogFlowFunc(("enmType=%RU32, pcszPathSrcAbs=%s, pcszPathDst=%s -> pszPath=%s\n", 132 enmType, pcszPathSrcAbs, pcszPathDst, pObj->pszPath)); 133 134 pObj->enmType = enmType; 135 136 return VINF_SUCCESS; 137 } 138 139 /** 140 * Destroys a DnD transfer object. 141 * 142 * @param pObj DnD transfer object to destroy. 143 */ 144 void DnDTransferObjectDestroy(PDNDTRANSFEROBJECT pObj) 145 { 146 if (!pObj) 147 return; 148 149 DnDTransferObjectReset(pObj); 49 150 } 50 151 51 152 /** 52 153 * Closes the object's internal handles (to files / ...). 53 */ 54 void DnDURIObject::closeInternal(void) 55 { 56 LogFlowThisFuncEnter(); 154 * 155 * @param pObj DnD transfer object to close internally. 156 */ 157 static void dndTransferObjectCloseInternal(PDNDTRANSFEROBJECT pObj) 158 { 159 AssertPtrReturnVoid(pObj); 57 160 58 161 int rc; 59 162 60 switch (m_enmType) 61 { 62 case Type_File: 63 { 64 if (RTFileIsValid(u.File.hFile)) 163 LogRel2(("DnD: Closing '%s'\n", pObj->pszPath)); 164 165 switch (pObj->enmType) 166 { 167 case DNDTRANSFEROBJTYPE_FILE: 168 { 169 if (RTFileIsValid(pObj->u.File.hFile)) 65 170 { 66 LogRel2(("DnD: Closing file '%s'\n", m_strPathAbs.c_str())); 67 68 rc = RTFileClose(u.File.hFile); 171 rc = RTFileClose(pObj->u.File.hFile); 69 172 if (RT_SUCCESS(rc)) 70 173 { 71 u.File.hFile = NIL_RTFILE;72 RT_ZERO( u.File.objInfo);174 pObj->u.File.hFile = NIL_RTFILE; 175 RT_ZERO(pObj->u.File.objInfo); 73 176 } 74 177 else 75 LogRel(("DnD: Closing file '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc));178 LogRel(("DnD: Closing file '%s' failed with %Rrc\n", pObj->pszPath, rc)); 76 179 } 77 180 break; 78 181 } 79 182 80 case Type_Directory:81 { 82 if (RTDirIsValid( u.Dir.hDir))183 case DNDTRANSFEROBJTYPE_DIRECTORY: 184 { 185 if (RTDirIsValid(pObj->u.Dir.hDir)) 83 186 { 84 LogRel2(("DnD: Closing directory '%s'\n", m_strPathAbs.c_str())); 85 86 rc = RTDirClose(u.Dir.hDir); 187 rc = RTDirClose(pObj->u.Dir.hDir); 87 188 if (RT_SUCCESS(rc)) 88 189 { 89 u.Dir.hDir = NIL_RTDIR;90 RT_ZERO( u.Dir.objInfo);190 pObj->u.Dir.hDir = NIL_RTDIR; 191 RT_ZERO(pObj->u.Dir.objInfo); 91 192 } 92 193 else 93 LogRel(("DnD: Closing directory '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc));194 LogRel(("DnD: Closing directory '%s' failed with %Rrc\n", pObj->pszPath, rc)); 94 195 } 95 196 break; … … 106 207 * Closes the object. 107 208 * This also closes the internal handles associated with the object (to files / ...). 108 */ 109 void DnDURIObject::Close(void) 110 { 111 closeInternal(); 209 * 210 * @param pObj DnD transfer object to close. 211 */ 212 void DnDTransferObjectClose(PDNDTRANSFEROBJECT pObj) 213 { 214 AssertPtrReturnVoid(pObj); 215 216 dndTransferObjectCloseInternal(pObj); 217 } 218 219 /** 220 * Returns the absolute source path of the object. 221 * 222 * @return Absolute source path of the object. 223 * @param pObj DnD transfer object to get source path for. 224 */ 225 const char *DnDTransferObjectGetSourcePath(PDNDTRANSFEROBJECT pObj) 226 { 227 AssertPtrReturn(pObj, NULL); 228 return pObj->pszPath; 229 } 230 231 /** 232 * Returns the (relative) destination path of the object, in transport style. 233 * 234 * @return Relative destination path of the object, or NULL if not set. 235 * @param pObj DnD transfer object to get destination path for. 236 */ 237 const char *DnDTransferObjectGetDestPath(PDNDTRANSFEROBJECT pObj) 238 { 239 AssertPtrReturn(pObj, NULL); 240 241 if (!pObj->pszPath) 242 return NULL; 243 244 AssertReturn(strlen(pObj->pszPath) >= pObj->idxDst, NULL); 245 246 return &pObj->pszPath[pObj->idxDst]; 247 } 248 249 /** 250 * Returns the (relative) destination path of the object, extended version. 251 * 252 * @return VBox status code, or VERR_NOT_FOUND if not initialized yet. 253 * @param pObj DnD transfer object to get destination path for. 254 * @param enmStyle Which path style to return. 255 * @param pszBuf Where to store the path. 256 * @param cbBuf Size (in bytes) where to store the path. 257 */ 258 int DnDTransferObjectGetDestPathEx(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJPATHSTYLE enmStyle, char *pszBuf, size_t cbBuf) 259 { 260 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 261 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER); 262 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 263 264 if (!pObj->pszPath) 265 return VERR_NOT_FOUND; 266 267 AssertReturn(strlen(pObj->pszPath) >= pObj->idxDst, VERR_INTERNAL_ERROR); 268 269 int rc = RTStrCopy(pszBuf, cbBuf, &pObj->pszPath[pObj->idxDst]); 270 if ( RT_SUCCESS(rc) 271 && enmStyle == DNDTRANSFEROBJPATHSTYLE_DOS) 272 rc = DnDPathConvert(pszBuf, cbBuf, DNDPATHCONVERT_FLAGS_TO_DOS); 273 274 return rc; 112 275 } 113 276 … … 116 279 * 117 280 * @return File / directory mode. 118 */ 119 RTFMODE DnDURIObject::GetMode(void) const 120 { 121 switch (m_enmType) 122 { 123 case Type_File: 124 return u.File.objInfo.Attr.fMode; 125 126 case Type_Directory: 127 return u.Dir.objInfo.Attr.fMode; 128 129 default: 130 break; 131 } 132 133 AssertFailed(); 281 * @param pObj DnD transfer object to get directory / file mode for. 282 */ 283 RTFMODE DnDTransferObjectGetMode(PDNDTRANSFEROBJECT pObj) 284 { 285 AssertPtrReturn(pObj, 0); 286 287 switch (pObj->enmType) 288 { 289 case DNDTRANSFEROBJTYPE_FILE: 290 return pObj->u.File.objInfo.Attr.fMode; 291 292 case DNDTRANSFEROBJTYPE_DIRECTORY: 293 return pObj->u.Dir.objInfo.Attr.fMode; 294 295 default: 296 break; 297 } 298 134 299 return 0; 135 300 } … … 138 303 * Returns the bytes already processed (read / written). 139 304 * 140 * Note: Only applies if the object is of type DnD URIObject::Type_File.305 * Note: Only applies if the object is of type DnDTransferObjectType_File. 141 306 * 142 307 * @return Bytes already processed (read / written). 143 */ 144 uint64_t DnDURIObject::GetProcessed(void) const 145 { 146 if (m_enmType == Type_File) 147 return u.File.cbProcessed; 308 * @param pObj DnD transfer object to get processed bytes for. 309 */ 310 uint64_t DnDTransferObjectGetProcessed(PDNDTRANSFEROBJECT pObj) 311 { 312 if (pObj->enmType == DNDTRANSFEROBJTYPE_FILE) 313 return pObj->u.File.cbProcessed; 148 314 149 315 return 0; … … 153 319 * Returns the file's logical size (in bytes). 154 320 * 155 * Note: Only applies if the object is of type DnD URIObject::Type_File.321 * Note: Only applies if the object is of type DnDTransferObjectType_File. 156 322 * 157 323 * @return The file's logical size (in bytes). 158 */ 159 uint64_t DnDURIObject::GetSize(void) const 160 { 161 if (m_enmType == Type_File) 162 return u.File.cbToProcess; 324 * @param pObj DnD transfer object to get size for. 325 */ 326 uint64_t DnDTransferObjectGetSize(PDNDTRANSFEROBJECT pObj) 327 { 328 if (pObj->enmType == DNDTRANSFEROBJTYPE_FILE) 329 return pObj->u.File.cbToProcess; 163 330 164 331 return 0; … … 166 333 167 334 /** 168 * Initializes the object with an expected object type and file path. 169 * 170 * @returns VBox status code. 171 * @param enmType Type we expect this object to be. 172 * @param strPathAbs Absolute path of file this object represents. Optional. 173 */ 174 int DnDURIObject::Init(Type enmType, const RTCString &strPathAbs /* = */) 175 { 176 AssertReturn(m_enmType == Type_Unknown, VERR_WRONG_ORDER); 177 178 int rc; 179 180 switch (enmType) 181 { 182 case Type_File: 183 { 184 u.File.hFile = NIL_RTFILE; 185 break; 186 } 187 188 case Type_Directory: 189 { 190 u.Dir.hDir = NIL_RTDIR; 191 break; 192 } 193 194 default: 195 break; 196 } 197 198 if (enmType != Type_Unknown) 199 { 200 AssertReturn(strPathAbs.isNotEmpty(), VERR_INVALID_PARAMETER); 201 RTCString strPathAbsCopy = strPathAbs; 202 rc = DnDPathConvert(strPathAbsCopy.mutableRaw(), strPathAbsCopy.capacity(), DNDPATHCONVERT_FLAGS_TO_NATIVE); 203 if (RT_SUCCESS(rc)) 204 { 205 m_enmType = enmType; 206 m_strPathAbs = strPathAbsCopy; 207 } 208 else 209 LogRel2(("DnD: Absolute file path for guest file on the host is now '%s'\n", strPathAbs.c_str())); 210 } 211 else 212 rc = VERR_INVALID_PARAMETER; 213 214 return rc; 335 * Returns the object's type. 336 * 337 * @return The object's type. 338 * @param pObj DnD transfer object to get type for. 339 */ 340 DNDTRANSFEROBJTYPE DnDTransferObjectGetType(PDNDTRANSFEROBJECT pObj) 341 { 342 return pObj->enmType; 215 343 } 216 344 … … 220 348 * 221 349 * @return True if complete, False if not. 222 */ 223 bool DnDURIObject::IsComplete(void) const 350 * @param pObj DnD transfer object to get completion status for. 351 */ 352 bool DnDTransferObjectIsComplete(PDNDTRANSFEROBJECT pObj) 224 353 { 225 354 bool fComplete; 226 355 227 switch ( m_enmType)228 { 229 case Type_File:230 Assert( u.File.cbProcessed <=u.File.cbToProcess);231 fComplete = u.File.cbProcessed ==u.File.cbToProcess;232 break; 233 234 case Type_Directory:356 switch (pObj->enmType) 357 { 358 case DNDTRANSFEROBJTYPE_FILE: 359 Assert(pObj->u.File.cbProcessed <= pObj->u.File.cbToProcess); 360 fComplete = pObj->u.File.cbProcessed == pObj->u.File.cbToProcess; 361 break; 362 363 case DNDTRANSFEROBJTYPE_DIRECTORY: 235 364 fComplete = true; 236 365 break; … … 246 375 /** 247 376 * Returns whether the object is in an open state or not. 248 */ 249 bool DnDURIObject::IsOpen(void) const 250 { 251 switch (m_enmType) 252 { 253 case Type_File: return RTFileIsValid(u.File.hFile); 254 case Type_Directory: return RTDirIsValid(u.Dir.hDir); 255 default: break; 377 * @param pObj DnD transfer object to get open status for. 378 */ 379 bool DnDTransferObjectIsOpen(PDNDTRANSFEROBJECT pObj) 380 { 381 switch (pObj->enmType) 382 { 383 case DNDTRANSFEROBJTYPE_FILE: return RTFileIsValid(pObj->u.File.hFile); 384 case DNDTRANSFEROBJTYPE_DIRECTORY: return RTDirIsValid(pObj->u.Dir.hDir); 385 default: break; 256 386 } 257 387 … … 263 393 * 264 394 * @return IPRT status code. 395 * @param pObj DnD transfer object to open. 265 396 * @param fOpen Open mode to use; only valid for file objects. 266 397 * @param fMode File mode to set; only valid for file objects. Depends on fOpen and and can be 0. 267 * @param fFlags Additional DnD URIobject flags.268 */ 269 int DnD URIObject::Open(uint64_t fOpen, RTFMODE fMode /* = 0 */,270 DNDURIOBJECTFLAGS fFlags /* = DNDURIOBJECT_FLAGS_NONE */) 271 { 398 * @param fFlags Additional DnD transfer object flags. 399 */ 400 int DnDTransferObjectOpen(PDNDTRANSFEROBJECT pObj, uint64_t fOpen, RTFMODE fMode, DNDTRANSFEROBJECTFLAGS fFlags) 401 { 402 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 272 403 AssertReturn(fOpen, VERR_INVALID_FLAGS); 273 404 /* fMode is optional. */ 274 AssertReturn(!(fFlags & ~DND URIOBJECT_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);405 AssertReturn(!(fFlags & ~DNDTRANSFEROBJECT_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 275 406 RT_NOREF1(fFlags); 276 407 277 408 int rc = VINF_SUCCESS; 278 409 279 if (fOpen) /* Opening mode specified? */ 280 { 281 LogFlowThisFunc(("strPath=%s, fOpen=0x%x, fMode=0x%x, fFlags=0x%x\n", 282 m_strPathAbs.c_str(), fOpen, fMode, fFlags)); 283 switch (m_enmType) 284 { 285 case Type_File: 410 LogFlowFunc(("pszPath=%s, fOpen=0x%x, fMode=0x%x, fFlags=0x%x\n", pObj->pszPath, fOpen, fMode, fFlags)); 411 412 switch (pObj->enmType) 413 { 414 case DNDTRANSFEROBJTYPE_FILE: 415 { 416 LogRel2(("DnD: Opening file '%s'\n", pObj->pszPath)); 417 418 /* 419 * Open files on the source with RTFILE_O_DENY_WRITE to prevent races 420 * where the OS writes to the file while the destination side transfers 421 * it over. 422 */ 423 rc = RTFileOpen(&pObj->u.File.hFile, pObj->pszPath, fOpen); 424 if (RT_SUCCESS(rc)) 286 425 { 287 LogRel2(("DnD: Opening file '%s'\n", m_strPathAbs.c_str())); 288 289 /* 290 * Open files on the source with RTFILE_O_DENY_WRITE to prevent races 291 * where the OS writes to the file while the destination side transfers 292 * it over. 293 */ 294 rc = RTFileOpen(&u.File.hFile, m_strPathAbs.c_str(), fOpen); 295 if (RT_SUCCESS(rc)) 426 if ( (fOpen & RTFILE_O_WRITE) /* Only set the file mode on write. */ 427 && fMode /* Some file mode to set specified? */) 296 428 { 297 if ( (fOpen & RTFILE_O_WRITE) /* Only set the file mode on write. */ 298 && fMode /* Some file mode to set specified? */) 299 { 300 rc = RTFileSetMode(u.File.hFile, fMode); 301 if (RT_FAILURE(rc)) 302 LogRel(("DnD: Setting mode %#x for file '%s' failed with %Rrc\n", fMode, m_strPathAbs.c_str(), rc)); 303 } 304 else if (fOpen & RTFILE_O_READ) 305 { 306 rc = queryInfoInternal(); 307 } 429 rc = RTFileSetMode(pObj->u.File.hFile, fMode); 430 if (RT_FAILURE(rc)) 431 LogRel(("DnD: Setting mode %#x for file '%s' failed with %Rrc\n", fMode, pObj->pszPath, rc)); 308 432 } 309 else 310 LogRel(("DnD: Opening file '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc)); 311 312 if (RT_SUCCESS(rc)) 433 else if (fOpen & RTFILE_O_READ) 313 434 { 314 LogFlowThisFunc(("File cbObject=%RU64, fMode=0x%x\n", 315 u.File.objInfo.cbObject, u.File.objInfo.Attr.fMode)); 316 u.File.cbToProcess = u.File.objInfo.cbObject; 317 u.File.cbProcessed = 0; 435 rc = dndTransferObjectQueryInfoInternal(pObj); 318 436 } 319 320 break;321 437 } 322 323 case Type_Directory: 438 else 439 LogRel(("DnD: Opening file '%s' failed with %Rrc\n", pObj->pszPath, rc)); 440 441 if (RT_SUCCESS(rc)) 324 442 { 325 LogRel2(("DnD: Opening directory '%s'\n", m_strPathAbs.c_str())); 326 327 rc = RTDirOpen(&u.Dir.hDir, m_strPathAbs.c_str()); 328 if (RT_SUCCESS(rc)) 329 { 330 rc = queryInfoInternal(); 331 } 332 else 333 LogRel(("DnD: Opening directory '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc)); 334 break; 443 LogFlowFunc(("File cbObject=%RU64, fMode=0x%x\n", 444 pObj->u.File.objInfo.cbObject, pObj->u.File.objInfo.Attr.fMode)); 445 pObj->u.File.cbToProcess = pObj->u.File.objInfo.cbObject; 446 pObj->u.File.cbProcessed = 0; 335 447 } 336 448 337 default: 338 rc = VERR_NOT_IMPLEMENTED; 339 break; 340 } 449 break; 450 } 451 452 case DNDTRANSFEROBJTYPE_DIRECTORY: 453 { 454 LogRel2(("DnD: Opening directory '%s'\n", pObj->pszPath)); 455 456 rc = RTDirOpen(&pObj->u.Dir.hDir, pObj->pszPath); 457 if (RT_SUCCESS(rc)) 458 { 459 rc = dndTransferObjectQueryInfoInternal(pObj); 460 } 461 else 462 LogRel(("DnD: Opening directory '%s' failed with %Rrc\n", pObj->pszPath, rc)); 463 break; 464 } 465 466 default: 467 rc = VERR_NOT_IMPLEMENTED; 468 break; 341 469 } 342 470 … … 349 477 * 350 478 * @return IPRT status code. 351 */ 352 int DnDURIObject::queryInfoInternal(void) 479 * @param pObj DnD transfer object to query info for. 480 */ 481 static int dndTransferObjectQueryInfoInternal(PDNDTRANSFEROBJECT pObj) 353 482 { 354 483 int rc; 355 484 356 switch ( m_enmType)357 { 358 case Type_File:359 AssertMsgReturn(RTFileIsValid( u.File.hFile), ("Object has invalid file handle\n"), VERR_INVALID_STATE);360 rc = RTFileQueryInfo( u.File.hFile, &u.File.objInfo, RTFSOBJATTRADD_NOTHING);361 break; 362 363 case Type_Directory:364 AssertMsgReturn(RTDirIsValid( u.Dir.hDir), ("Object has invalid directory handle\n"), VERR_INVALID_STATE);365 rc = RTDirQueryInfo( u.Dir.hDir, &u.Dir.objInfo, RTFSOBJATTRADD_NOTHING);485 switch (pObj->enmType) 486 { 487 case DNDTRANSFEROBJTYPE_FILE: 488 AssertMsgReturn(RTFileIsValid(pObj->u.File.hFile), ("Object has invalid file handle\n"), VERR_INVALID_STATE); 489 rc = RTFileQueryInfo(pObj->u.File.hFile, &pObj->u.File.objInfo, RTFSOBJATTRADD_NOTHING); 490 break; 491 492 case DNDTRANSFEROBJTYPE_DIRECTORY: 493 AssertMsgReturn(RTDirIsValid(pObj->u.Dir.hDir), ("Object has invalid directory handle\n"), VERR_INVALID_STATE); 494 rc = RTDirQueryInfo(pObj->u.Dir.hDir, &pObj->u.Dir.objInfo, RTFSOBJATTRADD_NOTHING); 366 495 break; 367 496 … … 372 501 373 502 if (RT_FAILURE(rc)) 374 LogRel(("DnD: Querying information for '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc));503 LogRel(("DnD: Querying information for '%s' failed with %Rrc\n", pObj->pszPath, rc)); 375 504 376 505 return rc; … … 381 510 * 382 511 * @return IPRT status code. 383 */ 384 int DnDURIObject::QueryInfo(void) 385 { 386 return queryInfoInternal(); 387 } 388 389 /** 390 * Rebases an absolute URI path from an old path base to a new path base. 391 * This function is needed in order to transform path from the source side to the target side. 512 * @param pObj DnD transfer object to query info for. 513 */ 514 int DnDTransferObjectQueryInfo(PDNDTRANSFEROBJECT pObj) 515 { 516 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 517 return dndTransferObjectQueryInfoInternal(pObj); 518 } 519 520 /** 521 * Reads data from the object. Only applies to files objects. 392 522 * 393 523 * @return IPRT status code. 394 * @param strPathAbs Absolute URI path to rebase. 395 * @param strBaseOld Old base path to rebase from. 396 * @param strBaseNew New base path to rebase to. 397 * 398 ** @todo Put this into an own class like DnDURIPath : public RTCString? 399 */ 400 /* static */ 401 int DnDURIObject::RebaseURIPath(RTCString &strPathAbs, 402 const RTCString &strBaseOld /* = "" */, 403 const RTCString &strBaseNew /* = "" */) 404 { 405 char *pszPath = RTUriFilePath(strPathAbs.c_str()); 406 if (!pszPath) /* No URI? */ 407 pszPath = RTStrDup(strPathAbs.c_str()); 408 409 int rc; 410 411 if (pszPath) 412 { 413 const char *pszPathStart = pszPath; 414 const char *pszBaseOld = strBaseOld.c_str(); 415 if ( pszBaseOld 416 && RTPathStartsWith(pszPath, pszBaseOld)) 417 { 418 pszPathStart += strlen(pszBaseOld); 419 } 420 421 rc = VINF_SUCCESS; 422 423 if (RT_SUCCESS(rc)) 424 { 425 char *pszPathNew = RTPathJoinA(strBaseNew.c_str(), pszPathStart); 426 if (pszPathNew) 427 { 428 rc = DnDPathValidate(pszPathNew, false /* fMustExist */); 429 if (RT_SUCCESS(rc)) 430 { 431 char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */, 432 pszPathNew /* pszPath */, 433 NULL /* pszQuery */, NULL /* pszFragment */); 434 if (pszPathURI) 435 { 436 LogFlowFunc(("Rebasing \"%s\" to \"%s\"\n", strPathAbs.c_str(), pszPathURI)); 437 438 strPathAbs = RTCString(pszPathURI) + "\r\n"; 439 RTStrFree(pszPathURI); 440 } 441 else 442 rc = VERR_INVALID_PARAMETER; 443 } 444 else 445 LogRel(("DnD: Path validation for '%s' failed with %Rrc\n", pszPathNew, rc)); 446 447 RTStrFree(pszPathNew); 448 } 449 else 450 rc = VERR_NO_MEMORY; 451 } 452 453 RTStrFree(pszPath); 454 } 455 else 456 rc = VERR_NO_MEMORY; 457 458 if (RT_FAILURE(rc)) 459 LogRel(("DnD: Rebasing absolute path '%s' (baseOld=%s, baseNew=%s) failed with %Rrc\n", 460 strPathAbs.c_str(), strBaseOld.c_str(), strBaseNew.c_str(), rc)); 461 462 return rc; 463 } 464 465 /** 466 * Reads data from the object. Only applies to files objects. 467 * 468 * @return IPRT status code. 524 * @param pObj DnD transfer object to read data from. 469 525 * @param pvBuf Buffer where to store the read data. 470 526 * @param cbBuf Size (in bytes) of the buffer. 471 527 * @param pcbRead Pointer where to store how many bytes were read. Optional. 472 528 */ 473 int DnDURIObject::Read(void *pvBuf, size_t cbBuf, uint32_t *pcbRead) 474 { 529 int DnDTransferObjectRead(PDNDTRANSFEROBJECT pObj, void *pvBuf, size_t cbBuf, uint32_t *pcbRead) 530 { 531 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 475 532 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 476 533 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); … … 480 537 481 538 int rc; 482 switch ( m_enmType)483 { 484 case Type_File:485 { 486 rc = RTFileRead( u.File.hFile, pvBuf, cbBuf, &cbRead);539 switch (pObj->enmType) 540 { 541 case DNDTRANSFEROBJTYPE_FILE: 542 { 543 rc = RTFileRead(pObj->u.File.hFile, pvBuf, cbBuf, &cbRead); 487 544 if (RT_SUCCESS(rc)) 488 545 { 489 u.File.cbProcessed += cbRead;490 Assert( u.File.cbProcessed <=u.File.cbToProcess);546 pObj->u.File.cbProcessed += cbRead; 547 Assert(pObj->u.File.cbProcessed <= pObj->u.File.cbToProcess); 491 548 492 549 /* End of file reached or error occurred? */ 493 if ( u.File.cbToProcess494 && u.File.cbProcessed ==u.File.cbToProcess)550 if ( pObj->u.File.cbToProcess 551 && pObj->u.File.cbProcessed == pObj->u.File.cbToProcess) 495 552 { 496 553 rc = VINF_EOF; … … 498 555 } 499 556 else 500 LogRel(("DnD: Reading from file '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc));501 break; 502 } 503 504 case Type_Directory:557 LogRel(("DnD: Reading from file '%s' failed with %Rrc\n", pObj->pszPath, rc)); 558 break; 559 } 560 561 case DNDTRANSFEROBJTYPE_DIRECTORY: 505 562 { 506 563 rc = VINF_SUCCESS; … … 519 576 } 520 577 521 LogFlowFunc(("Returning strSourcePath=%s, cbRead=%zu, rc=%Rrc\n", m_strPathAbs.c_str(), cbRead, rc));578 LogFlowFunc(("Returning cbRead=%zu, rc=%Rrc\n", cbRead, rc)); 522 579 return rc; 523 580 } … … 525 582 /** 526 583 * Resets the object's state and closes all related handles. 527 */ 528 void DnDURIObject::Reset(void) 529 { 530 LogFlowThisFuncEnter(); 531 532 Close(); 533 534 m_enmType = Type_Unknown; 535 m_strPathAbs = ""; 536 537 RT_ZERO(u); 584 * 585 * @param pObj DnD transfer object to reset. 586 */ 587 void DnDTransferObjectReset(PDNDTRANSFEROBJECT pObj) 588 { 589 AssertPtrReturnVoid(pObj); 590 591 LogFlowFuncEnter(); 592 593 dndTransferObjectCloseInternal(pObj); 594 595 pObj->enmType = DNDTRANSFEROBJTYPE_UNKNOWN; 596 pObj->idxDst = 0; 597 598 RTStrFree(pObj->pszPath); 599 pObj->pszPath = NULL; 600 601 RT_ZERO(pObj->u); 538 602 } 539 603 … … 541 605 * Sets the bytes to process by the object. 542 606 * 543 * Note: Only applies if the object is of type DnD URIObject::Type_File.607 * Note: Only applies if the object is of type DnDTransferObjectType_File. 544 608 * 545 609 * @return IPRT return code. 546 * @param cbSize Size (in bytes) to process. 547 */ 548 int DnDURIObject::SetSize(uint64_t cbSize) 549 { 550 AssertReturn(m_enmType == Type_File, VERR_INVALID_PARAMETER); 610 * @param pObj DnD transfer object to set size for. 611 * @param cbSize Size (in bytes) to process. 612 */ 613 int DnDTransferObjectSetSize(PDNDTRANSFEROBJECT pObj, uint64_t cbSize) 614 { 615 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 616 AssertReturn(pObj->enmType == DNDTRANSFEROBJTYPE_FILE, VERR_INVALID_PARAMETER); 551 617 552 618 /** @todo Implement sparse file support here. */ 553 619 554 u.File.cbToProcess = cbSize;620 pObj->u.File.cbToProcess = cbSize; 555 621 return VINF_SUCCESS; 556 622 } … … 560 626 * 561 627 * @return IPRT status code. 628 * @param pObj DnD transfer object to write to. 562 629 * @param pvBuf Buffer of data to write. 563 630 * @param cbBuf Size (in bytes) of data to write. 564 631 * @param pcbWritten Pointer where to store how many bytes were written. Optional. 565 632 */ 566 int DnDURIObject::Write(const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten) 567 { 633 int DnDTransferObjectWrite(PDNDTRANSFEROBJECT pObj, const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten) 634 { 635 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 568 636 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 569 637 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); … … 573 641 574 642 int rc; 575 switch ( m_enmType)576 { 577 case Type_File:578 { 579 rc = RTFileWrite( u.File.hFile, pvBuf, cbBuf, &cbWritten);643 switch (pObj->enmType) 644 { 645 case DNDTRANSFEROBJTYPE_FILE: 646 { 647 rc = RTFileWrite(pObj->u.File.hFile, pvBuf, cbBuf, &cbWritten); 580 648 if (RT_SUCCESS(rc)) 581 649 { 582 u.File.cbProcessed += cbWritten;650 pObj->u.File.cbProcessed += cbWritten; 583 651 } 584 652 else 585 LogRel(("DnD: Writing to file '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc));586 break; 587 } 588 589 case Type_Directory:653 LogRel(("DnD: Writing to file '%s' failed with %Rrc\n", pObj->pszPath, rc)); 654 break; 655 } 656 657 case DNDTRANSFEROBJTYPE_DIRECTORY: 590 658 { 591 659 rc = VINF_SUCCESS; … … 604 672 } 605 673 606 LogFlow ThisFunc(("Returning strSourcePathAbs=%s, cbWritten=%zu, rc=%Rrc\n", m_strPathAbs.c_str(), cbWritten, rc));674 LogFlowFunc(("Returning cbWritten=%zu, rc=%Rrc\n", cbWritten, rc)); 607 675 return rc; 608 676 } -
trunk/src/VBox/GuestHost/DragAndDrop/Makefile.kmk
r82968 r85371 19 19 include $(KBUILD_PATH)/subheader.kmk 20 20 21 ifdef VBOX_WITH_TESTCASES 22 include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk 23 endif 24 21 25 VBOX_DND_GUESTHOST_FILES := \ 22 26 DnDDroppedFiles.cpp \ 23 27 DnDMIME.cpp \ 24 28 DnDPath.cpp \ 25 DnD URIList.cpp \26 DnD URIObject.cpp29 DnDTransferObject.cpp \ 30 DnDTransferList.cpp 27 31 28 32 #
Note:
See TracChangeset
for help on using the changeset viewer.