VirtualBox

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

Last change on this file since 55998 was 55805, checked in by vboxsync, 10 years ago

DnDURIList: Implemented resolving symlinks.

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