VirtualBox

source: vbox/trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp@ 58312

Last change on this file since 58312 was 58212, checked in by vboxsync, 9 years ago

DnD: Updates.

  • Introduced protocol changelog in DragAndDropSvc.h.
  • Implemented protocol v3 with HOST_DND_HG_SND_DATA_HDR message for doing proper object accounting, among other parameters like checksumming and compression flags.
  • Encapsulated a lot of functionality in class hierarchies.
  • Renamed a lot of functions to make the usage more clear.
  • Various other bugfixes.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.4 KB
Line 
1/* $Id: DnDURIList.cpp 58212 2015-10-13 11:49:33Z vboxsync $ */
2/** @file
3 * DnD: URI list class.
4 */
5
6/*
7 * Copyright (C) 2014-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22
23#include <iprt/dir.h>
24#include <iprt/file.h>
25#include <iprt/fs.h>
26#include <iprt/path.h>
27#include <iprt/symlink.h>
28#include <iprt/uri.h>
29
30#ifdef LOG_GROUP
31 #undef LOG_GROUP
32#endif
33#define LOG_GROUP LOG_GROUP_GUEST_DND
34#include <VBox/log.h>
35
36#include <VBox/GuestHost/DragAndDrop.h>
37
38DnDURIList::DnDURIList(void)
39 : m_cTotal(0)
40 , m_cbTotal(0)
41{
42}
43
44DnDURIList::~DnDURIList(void)
45{
46 Clear();
47}
48
49int DnDURIList::addEntry(const char *pcszSource, const char *pcszTarget, uint32_t fFlags)
50{
51 AssertPtrReturn(pcszSource, VERR_INVALID_POINTER);
52 AssertPtrReturn(pcszTarget, VERR_INVALID_POINTER);
53
54 LogFlowFunc(("pcszSource=%s, pcszTarget=%s, fFlags=0x%x\n", pcszSource, pcszTarget, fFlags));
55
56 RTFSOBJINFO objInfo;
57 int rc = RTPathQueryInfo(pcszSource, &objInfo, RTFSOBJATTRADD_NOTHING);
58 if (RT_SUCCESS(rc))
59 {
60 if (RTFS_IS_FILE(objInfo.Attr.fMode))
61 {
62 LogFlowFunc(("File '%s' -> '%s' (%RU64 bytes, file mode 0x%x)\n",
63 pcszSource, pcszTarget, (uint64_t)objInfo.cbObject, objInfo.Attr.fMode));
64
65 DnDURIObject *pObjFile = new DnDURIObject(DnDURIObject::File, pcszSource, pcszTarget);
66 if (pObjFile)
67 {
68 if (fFlags & DNDURILIST_FLAGS_KEEP_OPEN) /* Shall we keep the file open while being added to this list? */
69 {
70 /** @todo Add a standard fOpen mode for this list. */
71 rc = pObjFile->Open(DnDURIObject::Source, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, objInfo.Attr.fMode);
72 }
73
74 if (RT_SUCCESS(rc))
75 {
76 m_lstTree.append(pObjFile);
77
78 m_cTotal++;
79 m_cbTotal += pObjFile->GetSize();
80 }
81 else
82 delete pObjFile;
83 }
84 else
85 rc = VERR_NO_MEMORY;
86 }
87 else if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
88 {
89 LogFlowFunc(("Directory '%s' -> '%s' (file mode 0x%x)\n", pcszSource, pcszTarget, objInfo.Attr.fMode));
90
91 DnDURIObject *pObjDir = new DnDURIObject(DnDURIObject::Directory, pcszSource, pcszTarget,
92 objInfo.Attr.fMode, 0 /* Size */);
93 if (pObjDir)
94 {
95 m_lstTree.append(pObjDir);
96
97 /** @todo Add DNDURILIST_FLAGS_KEEP_OPEN handling? */
98 m_cTotal++;
99 }
100 else
101 rc = VERR_NO_MEMORY;
102 }
103 /* Note: Symlinks already should have been resolved at this point. */
104 else
105 rc = VERR_NOT_SUPPORTED;
106 }
107
108 LogFlowFuncLeaveRC(rc);
109 return rc;
110}
111
112int DnDURIList::appendPathRecursive(const char *pcszSrcPath,
113 const char *pcszDstPath, const char *pcszDstBase, size_t cchDstBase, uint32_t fFlags)
114{
115 AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER);
116 AssertPtrReturn(pcszDstBase, VERR_INVALID_POINTER);
117 AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER);
118
119 LogFlowFunc(("pcszSrcPath=%s, pcszDstPath=%s, pcszDstBase=%s, cchDstBase=%zu\n",
120 pcszSrcPath, pcszDstPath, pcszDstBase, cchDstBase));
121
122 RTFSOBJINFO objInfo;
123 int rc = RTPathQueryInfo(pcszSrcPath, &objInfo, RTFSOBJATTRADD_NOTHING);
124 if (RT_SUCCESS(rc))
125 {
126 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
127 {
128 rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags);
129
130 PRTDIR hDir;
131 if (RT_SUCCESS(rc))
132 rc = RTDirOpen(&hDir, pcszSrcPath);
133 if (RT_SUCCESS(rc))
134 {
135 do
136 {
137 RTDIRENTRY DirEntry;
138 rc = RTDirRead(hDir, &DirEntry, NULL);
139 if (RT_FAILURE(rc))
140 {
141 if (rc == VERR_NO_MORE_FILES)
142 rc = VINF_SUCCESS;
143 break;
144 }
145
146 switch (DirEntry.enmType)
147 {
148 case RTDIRENTRYTYPE_DIRECTORY:
149 {
150 /* Skip "." and ".." entries. */
151 if ( RTStrCmp(DirEntry.szName, ".") == 0
152 || RTStrCmp(DirEntry.szName, "..") == 0)
153 break;
154
155 char *pszSrc = RTPathJoinA(pcszSrcPath, DirEntry.szName);
156 if (pszSrc)
157 {
158 char *pszDst = RTPathJoinA(pcszDstPath, DirEntry.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 RTDIRENTRYTYPE_FILE:
175 {
176 char *pszSrc = RTPathJoinA(pcszSrcPath, DirEntry.szName);
177 if (pszSrc)
178 {
179 char *pszDst = RTPathJoinA(pcszDstPath, DirEntry.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 RTDIRENTRYTYPE_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 RTDirClose(hDir);
232 }
233 }
234 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
235 {
236 rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags);
237 }
238 else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))
239 {
240 if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS)
241 {
242 char *pszSrc = RTPathRealDup(pcszSrcPath);
243 if (pszSrc)
244 {
245 rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING);
246 if (RT_SUCCESS(rc))
247 {
248 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
249 {
250 LogFlowFunc(("Symlink to directory\n"));
251 rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags);
252 }
253 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
254 {
255 LogFlowFunc(("Symlink to file\n"));
256 rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags);
257 }
258 else
259 rc = VERR_NOT_SUPPORTED;
260 }
261
262 RTStrFree(pszSrc);
263 }
264 else
265 rc = VERR_NO_MEMORY;
266 }
267 }
268 else
269 rc = VERR_NOT_SUPPORTED;
270 }
271
272 LogFlowFuncLeaveRC(rc);
273 return rc;
274}
275
276int DnDURIList::AppendNativePath(const char *pszPath, uint32_t fFlags)
277{
278 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
279
280 int rc;
281 char *pszPathNative = RTStrDup(pszPath);
282 if (pszPathNative)
283 {
284 RTPathChangeToUnixSlashes(pszPathNative, true /* fForce */);
285
286 char *pszPathURI = RTUriCreate("file" /* pszScheme */, NULL /* pszAuthority */,
287 pszPathNative, NULL /* pszQuery */, NULL /* pszFragment */);
288 if (pszPathURI)
289 {
290 rc = AppendURIPath(pszPathURI, fFlags);
291 RTStrFree(pszPathURI);
292 }
293 else
294 rc = VERR_INVALID_PARAMETER;
295
296 RTStrFree(pszPathNative);
297 }
298 else
299 rc = VERR_NO_MEMORY;
300
301 return rc;
302}
303
304int DnDURIList::AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths,
305 uint32_t fFlags)
306{
307 AssertPtrReturn(pszNativePaths, VERR_INVALID_POINTER);
308 AssertReturn(cbNativePaths, VERR_INVALID_PARAMETER);
309
310 RTCList<RTCString> lstPaths
311 = RTCString(pszNativePaths, cbNativePaths - 1).split("\r\n");
312 return AppendNativePathsFromList(lstPaths, fFlags);
313}
314
315int DnDURIList::AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths,
316 uint32_t fFlags)
317{
318 int rc = VINF_SUCCESS;
319
320 for (size_t i = 0; i < lstNativePaths.size(); i++)
321 {
322 const RTCString &strPath = lstNativePaths.at(i);
323 rc = AppendNativePath(strPath.c_str(), fFlags);
324 if (RT_FAILURE(rc))
325 break;
326 }
327
328 LogFlowFuncLeaveRC(rc);
329 return rc;
330}
331
332int DnDURIList::AppendURIPath(const char *pszURI, uint32_t fFlags)
333{
334 AssertPtrReturn(pszURI, VERR_INVALID_POINTER);
335
336 /** @todo Check for string termination? */
337#ifdef DEBUG_andy
338 LogFlowFunc(("pszPath=%s, fFlags=0x%x\n", pszURI, fFlags));
339#endif
340 int rc = VINF_SUCCESS;
341
342 /* Query the path component of a file URI. If this hasn't a
343 * file scheme NULL is returned. */
344 char *pszSrcPath = RTUriFilePath(pszURI);
345 if (pszSrcPath)
346 {
347 /* Add the path to our internal file list (recursive in
348 * the case of a directory). */
349 size_t cbPathLen = RTPathStripTrailingSlash(pszSrcPath);
350 if (cbPathLen)
351 {
352 char *pszFileName = RTPathFilename(pszSrcPath);
353 if (pszFileName)
354 {
355 Assert(pszFileName >= pszSrcPath);
356 size_t cchDstBase = (fFlags & DNDURILIST_FLAGS_ABSOLUTE_PATHS)
357 ? 0 /* Use start of path as root. */
358 : pszFileName - pszSrcPath;
359 char *pszDstPath = &pszSrcPath[cchDstBase];
360 m_lstRoot.append(pszDstPath);
361
362 LogFlowFunc(("pszFilePath=%s, pszFileName=%s, pszRoot=%s\n",
363 pszSrcPath, pszFileName, pszDstPath));
364
365 rc = appendPathRecursive(pszSrcPath, pszSrcPath, pszSrcPath, cchDstBase, fFlags);
366 }
367 else
368 rc = VERR_PATH_NOT_FOUND;
369 }
370 else
371 rc = VERR_INVALID_PARAMETER;
372
373 RTStrFree(pszSrcPath);
374 }
375 else
376 rc = VERR_INVALID_PARAMETER;
377
378 LogFlowFuncLeaveRC(rc);
379 return rc;
380}
381
382int DnDURIList::AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths,
383 uint32_t fFlags)
384{
385 AssertPtrReturn(pszURIPaths, VERR_INVALID_POINTER);
386 AssertReturn(cbURIPaths, VERR_INVALID_PARAMETER);
387
388 RTCList<RTCString> lstPaths
389 = RTCString(pszURIPaths, cbURIPaths - 1).split("\r\n");
390 return AppendURIPathsFromList(lstPaths, fFlags);
391}
392
393int DnDURIList::AppendURIPathsFromList(const RTCList<RTCString> &lstURI,
394 uint32_t fFlags)
395{
396 int rc = VINF_SUCCESS;
397
398 for (size_t i = 0; i < lstURI.size(); i++)
399 {
400 RTCString strURI = lstURI.at(i);
401 rc = AppendURIPath(strURI.c_str(), fFlags);
402
403 if (RT_FAILURE(rc))
404 break;
405 }
406
407 LogFlowFuncLeaveRC(rc);
408 return rc;
409}
410
411void DnDURIList::Clear(void)
412{
413 m_lstRoot.clear();
414
415 for (size_t i = 0; i < m_lstTree.size(); i++)
416 {
417 DnDURIObject *pCurObj = m_lstTree.at(i);
418 AssertPtr(pCurObj);
419 RTMemFree(pCurObj);
420 }
421 m_lstTree.clear();
422
423 m_cTotal = 0;
424 m_cbTotal = 0;
425}
426
427void DnDURIList::RemoveFirst(void)
428{
429 if (m_lstTree.isEmpty())
430 return;
431
432 DnDURIObject *pCurObj = m_lstTree.first();
433 AssertPtr(pCurObj);
434
435 uint64_t cbSize = pCurObj->GetSize();
436 Assert(m_cbTotal >= cbSize);
437 m_cbTotal -= cbSize; /* Adjust total size. */
438
439 pCurObj->Close();
440 RTMemFree(pCurObj);
441
442 m_lstTree.removeFirst();
443}
444
445int DnDURIList::RootFromURIData(const void *pvData, size_t cbData, uint32_t fFlags)
446{
447 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
448 AssertReturn(cbData, VERR_INVALID_PARAMETER);
449
450 RTCList<RTCString> lstURI =
451 RTCString(static_cast<const char*>(pvData), cbData - 1).split("\r\n");
452 if (lstURI.isEmpty())
453 return VINF_SUCCESS;
454
455 int rc = VINF_SUCCESS;
456
457 for (size_t i = 0; i < lstURI.size(); ++i)
458 {
459 /* Query the path component of a file URI. If this hasn't a
460 * file scheme, NULL is returned. */
461 const char *pszURI = lstURI.at(i).c_str();
462 char *pszFilePath = RTUriFilePath(pszURI);
463#ifdef DEBUG_andy
464 LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath));
465#endif
466 if (pszFilePath)
467 {
468 rc = DnDPathSanitize(pszFilePath, strlen(pszFilePath));
469 if (RT_SUCCESS(rc))
470 {
471 m_lstRoot.append(pszFilePath);
472 m_cTotal++;
473 }
474
475 RTStrFree(pszFilePath);
476 }
477 else
478 rc = VERR_INVALID_PARAMETER;
479
480 if (RT_FAILURE(rc))
481 break;
482 }
483
484 return rc;
485}
486
487RTCString DnDURIList::RootToString(const RTCString &strPathBase /* = "" */,
488 const RTCString &strSeparator /* = "\r\n" */) const
489{
490 RTCString strRet;
491 for (size_t i = 0; i < m_lstRoot.size(); i++)
492 {
493 const char *pszCurRoot = m_lstRoot.at(i).c_str();
494#ifdef DEBUG_andy
495 LogFlowFunc(("pszCurRoot=%s\n", pszCurRoot));
496#endif
497 if (strPathBase.isNotEmpty())
498 {
499 char *pszPath = RTPathJoinA(strPathBase.c_str(), pszCurRoot);
500 if (pszPath)
501 {
502 char *pszPathURI = RTUriFileCreate(pszPath);
503 if (pszPathURI)
504 {
505 strRet += RTCString(pszPathURI) + strSeparator;
506 LogFlowFunc(("URI (Base): %s\n", strRet.c_str()));
507 RTStrFree(pszPathURI);
508 }
509
510 RTStrFree(pszPath);
511
512 if (!pszPathURI)
513 break;
514 }
515 else
516 break;
517 }
518 else
519 {
520 char *pszPathURI = RTUriFileCreate(pszCurRoot);
521 if (pszPathURI)
522 {
523 strRet += RTCString(pszPathURI) + strSeparator;
524 LogFlowFunc(("URI: %s\n", strRet.c_str()));
525 RTStrFree(pszPathURI);
526 }
527 else
528 break;
529 }
530 }
531
532 return strRet;
533}
534
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette