VirtualBox

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

Last change on this file since 65314 was 62816, checked in by vboxsync, 8 years ago

GuestHost/DragAndDrop: warnings

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