VirtualBox

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

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

DnD: Bugfixes, cleanup, spelling.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1/* $Id: DnDURIList.cpp 55512 2015-04-29 11:34:53Z 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/uri.h>
27
28#ifdef LOG_GROUP
29 #undef LOG_GROUP
30#endif
31#define LOG_GROUP LOG_GROUP_GUEST_DND
32#include <VBox/log.h>
33
34#include <VBox/GuestHost/DragAndDrop.h>
35
36DnDURIList::DnDURIList(void)
37 : m_cTotal(0)
38 , m_cbTotal(0)
39{
40}
41
42DnDURIList::~DnDURIList(void)
43{
44}
45
46int DnDURIList::appendPathRecursive(const char *pcszPath, size_t cbBaseLen,
47 uint32_t fFlags)
48{
49 AssertPtrReturn(pcszPath, VERR_INVALID_POINTER);
50
51 RTFSOBJINFO objInfo;
52 int rc = RTPathQueryInfo(pcszPath, &objInfo, RTFSOBJATTRADD_NOTHING);
53 if (RT_FAILURE(rc))
54 return rc;
55
56 /*
57 * These are the types we currently support. Symlinks are not directly
58 * supported. First the guest could be an OS which doesn't support it and
59 * second the symlink could point to a file which is out of the base tree.
60 * Both things are hard to support. For now we just copy the target file in
61 * this case.
62 */
63 if (!( RTFS_IS_DIRECTORY(objInfo.Attr.fMode)
64 || RTFS_IS_FILE(objInfo.Attr.fMode)
65 || RTFS_IS_SYMLINK(objInfo.Attr.fMode)))
66 return VINF_SUCCESS;
67
68 uint64_t cbSize = 0;
69 rc = RTFileQuerySize(pcszPath, &cbSize);
70 if (rc == VERR_IS_A_DIRECTORY)
71 rc = VINF_SUCCESS;
72
73 if (RT_FAILURE(rc))
74 return rc;
75
76 m_lstTree.append(DnDURIObject( RTFS_IS_DIRECTORY(objInfo.Attr.fMode)
77 ? DnDURIObject::Directory
78 : DnDURIObject::File,
79 pcszPath, &pcszPath[cbBaseLen],
80 objInfo.Attr.fMode, cbSize));
81 m_cTotal++;
82 m_cbTotal += cbSize;
83#ifdef DEBUG_andy
84 LogFlowFunc(("strSrcPath=%s, strDstPath=%s, fMode=0x%x, cbSize=%RU64, cbTotal=%zu\n",
85 pcszPath, &pcszPath[cbBaseLen], objInfo.Attr.fMode, cbSize, m_cbTotal));
86#endif
87
88 PRTDIR hDir;
89 /* We have to try to open even symlinks, cause they could
90 * be symlinks to directories. */
91 rc = RTDirOpen(&hDir, pcszPath);
92 /* The following error happens when this was a symlink
93 * to an file or a regular file. */
94 if ( rc == VERR_PATH_NOT_FOUND
95 || rc == VERR_NOT_A_DIRECTORY)
96 return VINF_SUCCESS;
97 if (RT_FAILURE(rc))
98 return rc;
99
100 while (RT_SUCCESS(rc))
101 {
102 RTDIRENTRY DirEntry;
103 rc = RTDirRead(hDir, &DirEntry, NULL);
104 if (RT_FAILURE(rc))
105 {
106 if (rc == VERR_NO_MORE_FILES)
107 rc = VINF_SUCCESS;
108 break;
109 }
110 switch (DirEntry.enmType)
111 {
112 case RTDIRENTRYTYPE_DIRECTORY:
113 {
114 /* Skip "." and ".." entries. */
115 if ( RTStrCmp(DirEntry.szName, ".") == 0
116 || RTStrCmp(DirEntry.szName, "..") == 0)
117 break;
118
119 char *pszRecDir = RTPathJoinA(pcszPath, DirEntry.szName);
120 if (pszRecDir)
121 {
122 rc = appendPathRecursive(pszRecDir, cbBaseLen, fFlags);
123 RTStrFree(pszRecDir);
124 }
125 else
126 rc = VERR_NO_MEMORY;
127 break;
128 }
129 case RTDIRENTRYTYPE_SYMLINK:
130 case RTDIRENTRYTYPE_FILE:
131 {
132 char *pszNewFile = RTPathJoinA(pcszPath, DirEntry.szName);
133 if (pszNewFile)
134 {
135 /* We need the size and the mode of the file. */
136 RTFSOBJINFO objInfo1;
137 rc = RTPathQueryInfo(pszNewFile, &objInfo1, RTFSOBJATTRADD_NOTHING);
138 if (RT_FAILURE(rc))
139 return rc;
140 rc = RTFileQuerySize(pszNewFile, &cbSize);
141 if (rc == VERR_IS_A_DIRECTORY) /* Happens for symlinks. */
142 rc = VINF_SUCCESS;
143
144 if (RT_FAILURE(rc))
145 break;
146
147 if (RTFS_IS_FILE(objInfo.Attr.fMode))
148 {
149 m_lstTree.append(DnDURIObject(DnDURIObject::File,
150 pszNewFile, &pszNewFile[cbBaseLen],
151 objInfo1.Attr.fMode, cbSize));
152 m_cbTotal += cbSize;
153 }
154 else /* Handle symlink directories. */
155 rc = appendPathRecursive(pszNewFile, cbBaseLen, fFlags);
156#ifdef DEBUG_andy
157 LogFlowFunc(("strSrcPath=%s, strDstPath=%s, fMode=0x%x, cbSize=%RU64, cbTotal=%zu\n",
158 pszNewFile, &pszNewFile[cbBaseLen], objInfo1.Attr.fMode, cbSize, m_cbTotal));
159#endif
160 RTStrFree(pszNewFile);
161 }
162 else
163 rc = VERR_NO_MEMORY;
164 break;
165 }
166
167 default:
168 break;
169 }
170 }
171
172 RTDirClose(hDir);
173 return rc;
174}
175
176int DnDURIList::AppendNativePath(const char *pszPath, uint32_t fFlags)
177{
178 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
179
180 int rc;
181 char *pszPathNative = RTStrDup(pszPath);
182 if (pszPathNative)
183 {
184 RTPathChangeToUnixSlashes(pszPathNative, true /* fForce */);
185
186 char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */,
187 pszPathNative, NULL /* pszQuery */, NULL /* pszFragment */);
188 if (pszPathURI)
189 {
190 rc = AppendURIPath(pszPathURI, fFlags);
191 RTStrFree(pszPathURI);
192 }
193 else
194 rc = VERR_INVALID_PARAMETER;
195
196 RTStrFree(pszPathNative);
197 }
198 else
199 rc = VERR_NO_MEMORY;
200
201 return rc;
202}
203
204int DnDURIList::AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths,
205 uint32_t fFlags)
206{
207 AssertPtrReturn(pszNativePaths, VERR_INVALID_POINTER);
208 AssertReturn(cbNativePaths, VERR_INVALID_PARAMETER);
209
210 RTCList<RTCString> lstPaths
211 = RTCString(pszNativePaths, cbNativePaths - 1).split("\r\n");
212 return AppendNativePathsFromList(lstPaths, fFlags);
213}
214
215int DnDURIList::AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths,
216 uint32_t fFlags)
217{
218 int rc = VINF_SUCCESS;
219
220 for (size_t i = 0; i < lstNativePaths.size(); i++)
221 {
222 const RTCString &strPath = lstNativePaths.at(i);
223 rc = AppendNativePath(strPath.c_str(), fFlags);
224 if (RT_FAILURE(rc))
225 break;
226 }
227
228 LogFlowFuncLeaveRC(rc);
229 return rc;
230}
231
232int DnDURIList::AppendURIPath(const char *pszURI, uint32_t fFlags)
233{
234 AssertPtrReturn(pszURI, VERR_INVALID_POINTER);
235
236 /** @todo Check for string termination? */
237#ifdef DEBUG_andy
238 LogFlowFunc(("pszPath=%s, fFlags=0x%x\n", pszURI, fFlags));
239#endif
240 int rc = VINF_SUCCESS;
241
242 /* Query the path component of a file URI. If this hasn't a
243 * file scheme NULL is returned. */
244 char *pszFilePath = RTUriFilePath(pszURI, URI_FILE_FORMAT_AUTO);
245 if (pszFilePath)
246 {
247 /* Add the path to our internal file list (recursive in
248 * the case of a directory). */
249 size_t cbPathLen = RTPathStripTrailingSlash(pszFilePath);
250 if (cbPathLen)
251 {
252 char *pszFileName = RTPathFilename(pszFilePath);
253 if (pszFileName)
254 {
255 Assert(pszFileName >= pszFilePath);
256 size_t cbBase = (fFlags & DNDURILIST_FLAGS_ABSOLUTE_PATHS)
257 ? 0 /* Use start of path as root. */
258 : pszFileName - pszFilePath;
259 char *pszRoot = &pszFilePath[cbBase];
260 m_lstRoot.append(pszRoot);
261 m_cTotal++;
262#ifdef DEBUG_andy
263 LogFlowFunc(("pszFilePath=%s, pszFileName=%s, pszRoot=%s\n",
264 pszFilePath, pszFileName, pszRoot));
265#endif
266 rc = appendPathRecursive(pszFilePath, cbBase, fFlags);
267 }
268 else
269 rc = VERR_NOT_FOUND;
270 }
271 else
272 rc = VERR_INVALID_PARAMETER;
273
274 RTStrFree(pszFilePath);
275 }
276 else
277 rc = VERR_INVALID_PARAMETER;
278
279 LogFlowFuncLeaveRC(rc);
280 return rc;
281}
282
283int DnDURIList::AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths,
284 uint32_t fFlags)
285{
286 AssertPtrReturn(pszURIPaths, VERR_INVALID_POINTER);
287 AssertReturn(cbURIPaths, VERR_INVALID_PARAMETER);
288
289 RTCList<RTCString> lstPaths
290 = RTCString(pszURIPaths, cbURIPaths - 1).split("\r\n");
291 return AppendURIPathsFromList(lstPaths, fFlags);
292}
293
294int DnDURIList::AppendURIPathsFromList(const RTCList<RTCString> &lstURI,
295 uint32_t fFlags)
296{
297 int rc = VINF_SUCCESS;
298
299 for (size_t i = 0; i < lstURI.size(); i++)
300 {
301 RTCString strURI = lstURI.at(i);
302 rc = AppendURIPath(strURI.c_str(), fFlags);
303
304 if (RT_FAILURE(rc))
305 break;
306 }
307
308 LogFlowFuncLeaveRC(rc);
309 return rc;
310}
311
312void DnDURIList::Clear(void)
313{
314 m_lstRoot.clear();
315 m_lstTree.clear();
316
317 m_cbTotal = 0;
318}
319
320void DnDURIList::RemoveFirst(void)
321{
322 if (m_lstTree.isEmpty())
323 return;
324
325 DnDURIObject &curPath = m_lstTree.first();
326
327 uint64_t cbSize = curPath.GetSize();
328 Assert(m_cbTotal >= cbSize);
329 m_cbTotal -= cbSize; /* Adjust total size. */
330
331 m_lstTree.removeFirst();
332}
333
334int DnDURIList::RootFromURIData(const void *pvData, size_t cbData,
335 uint32_t fFlags)
336{
337 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
338 AssertReturn(cbData, VERR_INVALID_PARAMETER);
339
340 RTCList<RTCString> lstURI =
341 RTCString(static_cast<const char*>(pvData), cbData - 1).split("\r\n");
342 if (lstURI.isEmpty())
343 return VINF_SUCCESS;
344
345 int rc = VINF_SUCCESS;
346
347 for (size_t i = 0; i < lstURI.size(); ++i)
348 {
349 /* Query the path component of a file URI. If this hasn't a
350 * file scheme, NULL is returned. */
351 const char *pszURI = lstURI.at(i).c_str();
352 char *pszFilePath = RTUriFilePath(pszURI,
353 URI_FILE_FORMAT_AUTO);
354#ifdef DEBUG_andy
355 LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath));
356#endif
357 if (pszFilePath)
358 {
359 rc = DnDPathSanitize(pszFilePath, strlen(pszFilePath));
360 if (RT_SUCCESS(rc))
361 {
362 m_lstRoot.append(pszFilePath);
363 m_cTotal++;
364 }
365
366 RTStrFree(pszFilePath);
367 }
368 else
369 rc = VERR_INVALID_PARAMETER;
370
371 if (RT_FAILURE(rc))
372 break;
373 }
374
375 return rc;
376}
377
378RTCString DnDURIList::RootToString(const RTCString &strBasePath /* = "" */,
379 const RTCString &strSeparator /* = "\r\n" */)
380{
381 RTCString strRet;
382 for (size_t i = 0; i < m_lstRoot.size(); i++)
383 {
384 const char *pszCurRoot = m_lstRoot.at(i).c_str();
385#ifdef DEBUG_andy
386 LogFlowFunc(("pszCurRoot=%s\n", pszCurRoot));
387#endif
388 if (strBasePath.isNotEmpty())
389 {
390 char *pszPath = RTPathJoinA(strBasePath.c_str(), pszCurRoot);
391 if (pszPath)
392 {
393 char *pszPathURI = RTUriFileCreate(pszPath);
394 if (pszPathURI)
395 {
396 strRet += RTCString(pszPathURI) + strSeparator;
397#ifdef DEBUG_andy
398 LogFlowFunc(("URI: %s\n", strRet.c_str()));
399#endif
400 RTStrFree(pszPathURI);
401 }
402 else
403 break;
404 RTStrFree(pszPath);
405 }
406 else
407 break;
408 }
409 else
410 {
411 char *pszPathURI = RTUriFileCreate(pszCurRoot);
412 if (pszPathURI)
413 {
414 strRet += RTCString(pszPathURI) + strSeparator;
415#ifdef DEBUG_andy
416 LogFlowFunc(("URI: %s\n", strRet.c_str()));
417#endif
418 RTStrFree(pszPathURI);
419 }
420 else
421 break;
422 }
423 }
424
425 return strRet;
426}
427
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