VirtualBox

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

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

DnD: Protocol overhaul with versioning added which now can communicate with Main.

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

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