VirtualBox

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

Last change on this file since 57067 was 56909, checked in by vboxsync, 10 years ago

DnD: Changed DnDURIList's allocation scheme for stored DnDURIObject objects.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.1 KB
Line 
1/* $Id: DnDURIList.cpp 56909 2015-07-10 06:09:14Z 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 * Header Files *
20 ******************************************************************************/
21
22#include <iprt/dir.h>
23#include <iprt/file.h>
24#include <iprt/fs.h>
25#include <iprt/path.h>
26#include <iprt/symlink.h>
27#include <iprt/uri.h>
28
29#ifdef LOG_GROUP
30 #undef LOG_GROUP
31#endif
32#define LOG_GROUP LOG_GROUP_GUEST_DND
33#include <VBox/log.h>
34
35#include <VBox/GuestHost/DragAndDrop.h>
36
37DnDURIList::DnDURIList(void)
38 : m_cTotal(0)
39 , m_cbTotal(0)
40{
41}
42
43DnDURIList::~DnDURIList(void)
44{
45 Clear();
46}
47
48int DnDURIList::addEntry(const char *pcszSource, const char *pcszTarget, uint32_t 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);
57 if (RT_SUCCESS(rc))
58 {
59 if (RTFS_IS_FILE(objInfo.Attr.fMode))
60 {
61 LogFlowFunc(("File '%s' -> '%s' (%RU64)\n", pcszSource, pcszTarget, (uint64_t)objInfo.cbObject));
62
63 DnDURIObject *pObjFile= new DnDURIObject(DnDURIObject::File, pcszSource, pcszTarget);
64 if (pObjFile)
65 {
66 if (fFlags & DNDURILIST_FLAGS_KEEP_OPEN) /* Shall we keep the file open while being added to this list? */
67 {
68 /** @todo Add a standard fOpen mode for this list. */
69 rc = pObjFile->Open(DnDURIObject::Source, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, objInfo.Attr.fMode);
70 }
71
72 if (RT_SUCCESS(rc))
73 {
74 m_lstTree.append(pObjFile);
75
76 m_cTotal++;
77 m_cbTotal += pObjFile->GetSize();
78 }
79 }
80 else
81 rc = VERR_NO_MEMORY;
82 }
83 else if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
84 {
85 LogFlowFunc(("Directory '%s' -> '%s' \n", pcszSource, pcszTarget));
86
87 DnDURIObject *pObjDir= new DnDURIObject(DnDURIObject::Directory, pcszSource, pcszTarget,
88 objInfo.Attr.fMode, 0 /* Size */);
89 if (pObjDir)
90 {
91 m_lstTree.append(pObjDir);
92 }
93 else
94 rc = VERR_NO_MEMORY;
95
96 /** @todo Add DNDURILIST_FLAGS_KEEP_OPEN handling. */
97
98 m_cTotal++;
99 }
100 /* Note: Symlinks already should have been resolved at this point. */
101 else
102 rc = VERR_NOT_SUPPORTED;
103 }
104
105 LogFlowFuncLeaveRC(rc);
106 return rc;
107}
108
109int DnDURIList::appendPathRecursive(const char *pcszSrcPath,
110 const char *pcszDstPath, const char *pcszDstBase, size_t cchDstBase, uint32_t fFlags)
111{
112 AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER);
113 AssertPtrReturn(pcszDstBase, VERR_INVALID_POINTER);
114 AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER);
115
116 LogFlowFunc(("pcszSrcPath=%s, pcszDstPath=%s, pcszDstBase=%s, cchDstBase=%zu\n",
117 pcszSrcPath, pcszDstPath, pcszDstBase, cchDstBase));
118
119 RTFSOBJINFO objInfo;
120 int rc = RTPathQueryInfo(pcszSrcPath, &objInfo, RTFSOBJATTRADD_NOTHING);
121 if (RT_SUCCESS(rc))
122 {
123 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
124 {
125 rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags);
126
127 PRTDIR hDir;
128 if (RT_SUCCESS(rc))
129 rc = RTDirOpen(&hDir, pcszSrcPath);
130 if (RT_SUCCESS(rc))
131 {
132 do
133 {
134 RTDIRENTRY DirEntry;
135 rc = RTDirRead(hDir, &DirEntry, NULL);
136 if (RT_FAILURE(rc))
137 {
138 if (rc == VERR_NO_MORE_FILES)
139 rc = VINF_SUCCESS;
140 break;
141 }
142
143 switch (DirEntry.enmType)
144 {
145 case RTDIRENTRYTYPE_DIRECTORY:
146 {
147 /* Skip "." and ".." entries. */
148 if ( RTStrCmp(DirEntry.szName, ".") == 0
149 || RTStrCmp(DirEntry.szName, "..") == 0)
150 break;
151
152 char *pszSrc = RTPathJoinA(pcszSrcPath, DirEntry.szName);
153 if (pszSrc)
154 {
155 char *pszDst = RTPathJoinA(pcszDstPath, DirEntry.szName);
156 if (pszDst)
157 {
158 rc = appendPathRecursive(pszSrc, pszDst, pcszDstBase, cchDstBase, fFlags);
159 RTStrFree(pszDst);
160 }
161 else
162 rc = VERR_NO_MEMORY;
163
164 RTStrFree(pszSrc);
165 }
166 else
167 rc = VERR_NO_MEMORY;
168 break;
169 }
170
171 case RTDIRENTRYTYPE_FILE:
172 {
173 char *pszSrc = RTPathJoinA(pcszSrcPath, DirEntry.szName);
174 if (pszSrc)
175 {
176 char *pszDst = RTPathJoinA(pcszDstPath, DirEntry.szName);
177 if (pszDst)
178 {
179 rc = addEntry(pszSrc, &pszDst[cchDstBase], fFlags);
180 RTStrFree(pszDst);
181 }
182 else
183 rc = VERR_NO_MEMORY;
184 RTStrFree(pszSrc);
185 }
186 else
187 rc = VERR_NO_MEMORY;
188 break;
189 }
190 case RTDIRENTRYTYPE_SYMLINK:
191 {
192 if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS)
193 {
194 char *pszSrc = RTPathRealDup(pcszDstBase);
195 if (pszSrc)
196 {
197 rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING);
198 if (RT_SUCCESS(rc))
199 {
200 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
201 {
202 LogFlowFunc(("Directory entry is symlink to directory\n"));
203 rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags);
204 }
205 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
206 {
207 LogFlowFunc(("Directory entry is symlink to file\n"));
208 rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags);
209 }
210 else
211 rc = VERR_NOT_SUPPORTED;
212 }
213
214 RTStrFree(pszSrc);
215 }
216 else
217 rc = VERR_NO_MEMORY;
218 }
219 break;
220 }
221
222 default:
223 break;
224 }
225
226 } while (RT_SUCCESS(rc));
227
228 RTDirClose(hDir);
229 }
230 }
231 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
232 {
233 rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags);
234 }
235 else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))
236 {
237 if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS)
238 {
239 char *pszSrc = RTPathRealDup(pcszSrcPath);
240 if (pszSrc)
241 {
242 rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING);
243 if (RT_SUCCESS(rc))
244 {
245 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
246 {
247 LogFlowFunc(("Symlink to directory\n"));
248 rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags);
249 }
250 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
251 {
252 LogFlowFunc(("Symlink to file\n"));
253 rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags);
254 }
255 else
256 rc = VERR_NOT_SUPPORTED;
257 }
258
259 RTStrFree(pszSrc);
260 }
261 else
262 rc = VERR_NO_MEMORY;
263 }
264 }
265 else
266 rc = VERR_NOT_SUPPORTED;
267 }
268
269 LogFlowFuncLeaveRC(rc);
270 return rc;
271}
272
273int DnDURIList::AppendNativePath(const char *pszPath, uint32_t fFlags)
274{
275 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
276
277 int rc;
278 char *pszPathNative = RTStrDup(pszPath);
279 if (pszPathNative)
280 {
281 RTPathChangeToUnixSlashes(pszPathNative, true /* fForce */);
282
283 char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */,
284 pszPathNative, NULL /* pszQuery */, NULL /* pszFragment */);
285 if (pszPathURI)
286 {
287 rc = AppendURIPath(pszPathURI, fFlags);
288 RTStrFree(pszPathURI);
289 }
290 else
291 rc = VERR_INVALID_PARAMETER;
292
293 RTStrFree(pszPathNative);
294 }
295 else
296 rc = VERR_NO_MEMORY;
297
298 return rc;
299}
300
301int DnDURIList::AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths,
302 uint32_t fFlags)
303{
304 AssertPtrReturn(pszNativePaths, VERR_INVALID_POINTER);
305 AssertReturn(cbNativePaths, VERR_INVALID_PARAMETER);
306
307 RTCList<RTCString> lstPaths
308 = RTCString(pszNativePaths, cbNativePaths - 1).split("\r\n");
309 return AppendNativePathsFromList(lstPaths, fFlags);
310}
311
312int DnDURIList::AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths,
313 uint32_t fFlags)
314{
315 int rc = VINF_SUCCESS;
316
317 for (size_t i = 0; i < lstNativePaths.size(); i++)
318 {
319 const RTCString &strPath = lstNativePaths.at(i);
320 rc = AppendNativePath(strPath.c_str(), fFlags);
321 if (RT_FAILURE(rc))
322 break;
323 }
324
325 LogFlowFuncLeaveRC(rc);
326 return rc;
327}
328
329int DnDURIList::AppendURIPath(const char *pszURI, uint32_t fFlags)
330{
331 AssertPtrReturn(pszURI, VERR_INVALID_POINTER);
332
333 /** @todo Check for string termination? */
334#ifdef DEBUG_andy
335 LogFlowFunc(("pszPath=%s, fFlags=0x%x\n", pszURI, fFlags));
336#endif
337 int rc = VINF_SUCCESS;
338
339 /* Query the path component of a file URI. If this hasn't a
340 * file scheme NULL is returned. */
341 char *pszSrcPath = RTUriFilePath(pszURI, URI_FILE_FORMAT_AUTO);
342 if (pszSrcPath)
343 {
344 /* Add the path to our internal file list (recursive in
345 * the case of a directory). */
346 size_t cbPathLen = RTPathStripTrailingSlash(pszSrcPath);
347 if (cbPathLen)
348 {
349 char *pszFileName = RTPathFilename(pszSrcPath);
350 if (pszFileName)
351 {
352 Assert(pszFileName >= pszSrcPath);
353 size_t cchDstBase = (fFlags & DNDURILIST_FLAGS_ABSOLUTE_PATHS)
354 ? 0 /* Use start of path as root. */
355 : pszFileName - pszSrcPath;
356 char *pszDstPath = &pszSrcPath[cchDstBase];
357 m_lstRoot.append(pszDstPath);
358
359 LogFlowFunc(("pszFilePath=%s, pszFileName=%s, pszRoot=%s\n",
360 pszSrcPath, pszFileName, pszDstPath));
361
362 rc = appendPathRecursive(pszSrcPath, pszSrcPath, pszSrcPath, cchDstBase, fFlags);
363 }
364 else
365 rc = VERR_PATH_NOT_FOUND;
366 }
367 else
368 rc = VERR_INVALID_PARAMETER;
369
370 RTStrFree(pszSrcPath);
371 }
372 else
373 rc = VERR_INVALID_PARAMETER;
374
375 LogFlowFuncLeaveRC(rc);
376 return rc;
377}
378
379int DnDURIList::AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths,
380 uint32_t fFlags)
381{
382 AssertPtrReturn(pszURIPaths, VERR_INVALID_POINTER);
383 AssertReturn(cbURIPaths, VERR_INVALID_PARAMETER);
384
385 RTCList<RTCString> lstPaths
386 = RTCString(pszURIPaths, cbURIPaths - 1).split("\r\n");
387 return AppendURIPathsFromList(lstPaths, fFlags);
388}
389
390int DnDURIList::AppendURIPathsFromList(const RTCList<RTCString> &lstURI,
391 uint32_t fFlags)
392{
393 int rc = VINF_SUCCESS;
394
395 for (size_t i = 0; i < lstURI.size(); i++)
396 {
397 RTCString strURI = lstURI.at(i);
398 rc = AppendURIPath(strURI.c_str(), fFlags);
399
400 if (RT_FAILURE(rc))
401 break;
402 }
403
404 LogFlowFuncLeaveRC(rc);
405 return rc;
406}
407
408void DnDURIList::Clear(void)
409{
410 m_lstRoot.clear();
411
412 for (size_t i = 0; i < m_lstTree.size(); i++)
413 {
414 DnDURIObject *pCurObj = m_lstTree.at(i);
415 AssertPtr(pCurObj);
416 RTMemFree(pCurObj);
417 }
418 m_lstTree.clear();
419
420 m_cTotal = 0;
421 m_cbTotal = 0;
422}
423
424void DnDURIList::RemoveFirst(void)
425{
426 if (m_lstTree.isEmpty())
427 return;
428
429 DnDURIObject *pCurObj = m_lstTree.first();
430 AssertPtr(pCurObj);
431
432 uint64_t cbSize = pCurObj->GetSize();
433 Assert(m_cbTotal >= cbSize);
434 m_cbTotal -= cbSize; /* Adjust total size. */
435
436 pCurObj->Close();
437 RTMemFree(pCurObj);
438
439 m_lstTree.removeFirst();
440}
441
442int DnDURIList::RootFromURIData(const void *pvData, size_t cbData, uint32_t fFlags)
443{
444 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
445 AssertReturn(cbData, VERR_INVALID_PARAMETER);
446
447 RTCList<RTCString> lstURI =
448 RTCString(static_cast<const char*>(pvData), cbData - 1).split("\r\n");
449 if (lstURI.isEmpty())
450 return VINF_SUCCESS;
451
452 int rc = VINF_SUCCESS;
453
454 for (size_t i = 0; i < lstURI.size(); ++i)
455 {
456 /* Query the path component of a file URI. If this hasn't a
457 * file scheme, NULL is returned. */
458 const char *pszURI = lstURI.at(i).c_str();
459 char *pszFilePath = RTUriFilePath(pszURI,
460 URI_FILE_FORMAT_AUTO);
461#ifdef DEBUG_andy
462 LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath));
463#endif
464 if (pszFilePath)
465 {
466 rc = DnDPathSanitize(pszFilePath, strlen(pszFilePath));
467 if (RT_SUCCESS(rc))
468 {
469 m_lstRoot.append(pszFilePath);
470 m_cTotal++;
471 }
472
473 RTStrFree(pszFilePath);
474 }
475 else
476 rc = VERR_INVALID_PARAMETER;
477
478 if (RT_FAILURE(rc))
479 break;
480 }
481
482 return rc;
483}
484
485RTCString DnDURIList::RootToString(const RTCString &strPathBase /* = "" */,
486 const RTCString &strSeparator /* = "\r\n" */)
487{
488 RTCString strRet;
489 for (size_t i = 0; i < m_lstRoot.size(); i++)
490 {
491 const char *pszCurRoot = m_lstRoot.at(i).c_str();
492#ifdef DEBUG_andy
493 LogFlowFunc(("pszCurRoot=%s\n", pszCurRoot));
494#endif
495 if (strPathBase.isNotEmpty())
496 {
497 char *pszPath = RTPathJoinA(strPathBase.c_str(), pszCurRoot);
498 if (pszPath)
499 {
500 char *pszPathURI = RTUriFileCreate(pszPath);
501 if (pszPathURI)
502 {
503 strRet += RTCString(pszPathURI) + strSeparator;
504 LogFlowFunc(("URI: %s\n", strRet.c_str()));
505 RTStrFree(pszPathURI);
506 }
507
508 RTStrFree(pszPath);
509
510 if (!pszPathURI)
511 break;
512 }
513 else
514 break;
515 }
516 else
517 {
518 char *pszPathURI = RTUriFileCreate(pszCurRoot);
519 if (pszPathURI)
520 {
521 strRet += RTCString(pszPathURI) + strSeparator;
522 LogFlowFunc(("URI: %s\n", strRet.c_str()));
523 RTStrFree(pszPathURI);
524 }
525 else
526 break;
527 }
528 }
529
530 return strRet;
531}
532
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