VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/ClipboardURIList.cpp@ 78651

Last change on this file since 78651 was 78648, checked in by vboxsync, 6 years ago

Shared Clipboard/URI: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.7 KB
Line 
1/* $Id: ClipboardURIList.cpp 78648 2019-05-22 09:30:34Z vboxsync $ */
2/** @file
3 * Shared Clipboard - URI list class.
4 */
5
6/*
7 * Copyright (C) 2019 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#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
23#include <VBox/GuestHost/SharedClipboard-uri.h>
24
25#include <iprt/dir.h>
26#include <iprt/err.h>
27#include <iprt/file.h>
28#include <iprt/fs.h>
29#include <iprt/path.h>
30#include <iprt/string.h>
31#include <iprt/symlink.h>
32#include <iprt/uri.h>
33
34#include <VBox/log.h>
35
36
37SharedClipboardURIList::SharedClipboardURIList(void)
38 : m_cTotal(0)
39 , m_cbTotal(0)
40{
41}
42
43SharedClipboardURIList::~SharedClipboardURIList(void)
44{
45 Clear();
46}
47
48int SharedClipboardURIList::addEntry(const char *pcszSource, const char *pcszTarget, SHAREDCLIPBOARDURILISTFLAGS 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 bytes, file mode 0x%x)\n",
62 pcszSource, pcszTarget, (uint64_t)objInfo.cbObject, objInfo.Attr.fMode));
63
64 SharedClipboardURIObject *pObjFile = new SharedClipboardURIObject(SharedClipboardURIObject::Type_File,
65 pcszSource, pcszTarget);
66 if (pObjFile)
67 {
68 /** @todo Add a standard fOpen mode for this list. */
69 rc = pObjFile->Open(SharedClipboardURIObject::View_Source, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
70 if (RT_SUCCESS(rc))
71 {
72 m_lstTree.append(pObjFile);
73
74 m_cTotal++;
75 m_cbTotal += pObjFile->GetSize();
76
77 if (!(fFlags & SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN)) /* Shall we keep the file open while being added to this list? */
78 pObjFile->Close();
79 }
80 else
81 delete pObjFile;
82 }
83 else
84 rc = VERR_NO_MEMORY;
85 }
86 else if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
87 {
88 LogFlowFunc(("Directory '%s' -> '%s' (file mode 0x%x)\n", pcszSource, pcszTarget, objInfo.Attr.fMode));
89
90 SharedClipboardURIObject *pObjDir = new SharedClipboardURIObject(SharedClipboardURIObject::Type_Directory,
91 pcszSource, pcszTarget);
92 if (pObjDir)
93 {
94 m_lstTree.append(pObjDir);
95
96 /** @todo Add SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN handling? */
97 m_cTotal++;
98 }
99 else
100 rc = VERR_NO_MEMORY;
101 }
102 /* Note: Symlinks already should have been resolved at this point. */
103 else
104 rc = VERR_NOT_SUPPORTED;
105 }
106
107 LogFlowFuncLeaveRC(rc);
108 return rc;
109}
110
111int SharedClipboardURIList::appendPathRecursive(const char *pcszSrcPath,
112 const char *pcszDstPath, const char *pcszDstBase, size_t cchDstBase,
113 SHAREDCLIPBOARDURILISTFLAGS fFlags)
114{
115 AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER);
116 AssertPtrReturn(pcszDstBase, VERR_INVALID_POINTER);
117 AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER);
118
119 LogFlowFunc(("pcszSrcPath=%s, pcszDstPath=%s, pcszDstBase=%s, cchDstBase=%zu, fFlags=0x%x\n",
120 pcszSrcPath, pcszDstPath, pcszDstBase, cchDstBase, fFlags));
121
122 RTFSOBJINFO objInfo;
123 int rc = RTPathQueryInfo(pcszSrcPath, &objInfo, RTFSOBJATTRADD_NOTHING);
124 if (RT_SUCCESS(rc))
125 {
126 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
127 {
128 rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags);
129 if (RT_SUCCESS(rc))
130 {
131 RTDIR hDir;
132 rc = RTDirOpen(&hDir, pcszSrcPath);
133 if (RT_SUCCESS(rc))
134 {
135 size_t cbDirEntry = 0;
136 PRTDIRENTRYEX pDirEntry = NULL;
137 do
138 {
139 /* Retrieve the next directory entry. */
140 rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
141 if (RT_FAILURE(rc))
142 {
143 if (rc == VERR_NO_MORE_FILES)
144 rc = VINF_SUCCESS;
145 break;
146 }
147
148 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
149 {
150 case RTFS_TYPE_DIRECTORY:
151 {
152 /* Skip "." and ".." entries. */
153 if (RTDirEntryExIsStdDotLink(pDirEntry))
154 break;
155
156 char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName);
157 if (pszSrc)
158 {
159 char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName);
160 if (pszDst)
161 {
162 rc = appendPathRecursive(pszSrc, pszDst, pcszDstBase, cchDstBase, fFlags);
163 RTStrFree(pszDst);
164 }
165 else
166 rc = VERR_NO_MEMORY;
167
168 RTStrFree(pszSrc);
169 }
170 else
171 rc = VERR_NO_MEMORY;
172 break;
173 }
174
175 case RTFS_TYPE_FILE:
176 {
177 char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName);
178 if (pszSrc)
179 {
180 char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName);
181 if (pszDst)
182 {
183 rc = addEntry(pszSrc, &pszDst[cchDstBase], fFlags);
184 RTStrFree(pszDst);
185 }
186 else
187 rc = VERR_NO_MEMORY;
188 RTStrFree(pszSrc);
189 }
190 else
191 rc = VERR_NO_MEMORY;
192 break;
193 }
194 case RTFS_TYPE_SYMLINK:
195 {
196 if (fFlags & SHAREDCLIPBOARDURILIST_FLAGS_RESOLVE_SYMLINKS)
197 {
198 char *pszSrc = RTPathRealDup(pcszDstBase);
199 if (pszSrc)
200 {
201 rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING);
202 if (RT_SUCCESS(rc))
203 {
204 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
205 {
206 LogFlowFunc(("Directory entry is symlink to directory\n"));
207 rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags);
208 }
209 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
210 {
211 LogFlowFunc(("Directory entry is symlink to file\n"));
212 rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags);
213 }
214 else
215 rc = VERR_NOT_SUPPORTED;
216 }
217
218 RTStrFree(pszSrc);
219 }
220 else
221 rc = VERR_NO_MEMORY;
222 }
223 break;
224 }
225
226 default:
227 break;
228 }
229
230 } while (RT_SUCCESS(rc));
231
232 RTDirReadExAFree(&pDirEntry, &cbDirEntry);
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 & SHAREDCLIPBOARDURILIST_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 SharedClipboardURIList::AppendNativePath(const char *pszPath, SHAREDCLIPBOARDURILISTFLAGS 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 SharedClipboardURIList::AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths,
308 SHAREDCLIPBOARDURILISTFLAGS 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 SharedClipboardURIList::AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths,
319 SHAREDCLIPBOARDURILISTFLAGS 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 SharedClipboardURIList::AppendURIPath(const char *pszURI, SHAREDCLIPBOARDURILISTFLAGS fFlags)
336{
337 AssertPtrReturn(pszURI, VERR_INVALID_POINTER);
338 AssertReturn(!(fFlags & ~SHAREDCLIPBOARDURILIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
339 /** @todo Check for string termination? */
340
341 RTURIPARSED Parsed;
342 int rc = RTUriParse(pszURI, &Parsed);
343 if (RT_FAILURE(rc))
344 return rc;
345
346 char *pszSrcPath = NULL;
347
348 /* file://host.example.com/path/to/file.txt */
349 const char *pszParsedAuthority = RTUriParsedAuthority(pszURI, &Parsed);
350 if ( pszParsedAuthority
351 && pszParsedAuthority[0] != '\0') /* Authority present? */
352 {
353 const char *pszParsedPath = RTUriParsedPath(pszURI, &Parsed);
354 if (pszParsedPath)
355 {
356 /* Always use UNIXy paths internally. */
357 if (RTStrAPrintf(&pszSrcPath, "//%s%s", pszParsedAuthority, pszParsedPath) == -1)
358 rc = VERR_NO_MEMORY;
359 }
360 else
361 rc = VERR_INVALID_PARAMETER;
362 }
363 else
364 {
365 pszSrcPath = RTUriFilePath(pszURI);
366 if (!pszSrcPath)
367 rc = VERR_INVALID_PARAMETER;
368 }
369
370 LogFlowFunc(("pszURI=%s, fFlags=0x%x -> pszParsedAuthority=%s, pszSrcPath=%s, rc=%Rrc\n",
371 pszURI, fFlags, pszParsedAuthority ? pszParsedAuthority : "<None>", pszSrcPath, rc));
372
373 if (RT_SUCCESS(rc))
374 {
375 /* Add the path to our internal file list (recursive in
376 * the case of a directory). */
377 size_t cbPathLen = RTPathStripTrailingSlash(pszSrcPath);
378 if (cbPathLen)
379 {
380 char *pszFileName = RTPathFilename(pszSrcPath);
381 if (pszFileName)
382 {
383 Assert(pszFileName >= pszSrcPath);
384 size_t cchDstBase = (fFlags & SHAREDCLIPBOARDURILIST_FLAGS_ABSOLUTE_PATHS)
385 ? 0 /* Use start of path as root. */
386 : pszFileName - pszSrcPath;
387 char *pszDstPath = &pszSrcPath[cchDstBase];
388 m_lstRoot.append(pszDstPath);
389
390 LogFlowFunc(("pszSrcPath=%s, pszFileName=%s, pszRoot=%s\n",
391 pszSrcPath, pszFileName, pszDstPath));
392
393 rc = appendPathRecursive(pszSrcPath, pszSrcPath, pszSrcPath, cchDstBase, fFlags);
394 }
395 else
396 rc = VERR_PATH_NOT_FOUND;
397 }
398 else
399 rc = VERR_INVALID_PARAMETER;
400 }
401
402 RTStrFree(pszSrcPath);
403
404 LogFlowFuncLeaveRC(rc);
405 return rc;
406}
407
408int SharedClipboardURIList::AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths,
409 SHAREDCLIPBOARDURILISTFLAGS fFlags)
410{
411 AssertPtrReturn(pszURIPaths, VERR_INVALID_POINTER);
412 AssertReturn(cbURIPaths, VERR_INVALID_PARAMETER);
413
414 RTCList<RTCString> lstPaths
415 = RTCString(pszURIPaths, cbURIPaths - 1).split("\r\n");
416 return AppendURIPathsFromList(lstPaths, fFlags);
417}
418
419int SharedClipboardURIList::AppendURIPathsFromList(const RTCList<RTCString> &lstURI,
420 SHAREDCLIPBOARDURILISTFLAGS fFlags)
421{
422 int rc = VINF_SUCCESS;
423
424 for (size_t i = 0; i < lstURI.size(); i++)
425 {
426 RTCString strURI = lstURI.at(i);
427 rc = AppendURIPath(strURI.c_str(), fFlags);
428
429 if (RT_FAILURE(rc))
430 break;
431 }
432
433 LogFlowFuncLeaveRC(rc);
434 return rc;
435}
436
437void SharedClipboardURIList::Clear(void)
438{
439 m_lstRoot.clear();
440
441 for (size_t i = 0; i < m_lstTree.size(); i++)
442 {
443 SharedClipboardURIObject *pCurObj = m_lstTree.at(i);
444 AssertPtr(pCurObj);
445 RTMemFree(pCurObj);
446 }
447 m_lstTree.clear();
448
449 m_cTotal = 0;
450 m_cbTotal = 0;
451}
452
453void SharedClipboardURIList::RemoveFirst(void)
454{
455 if (m_lstTree.isEmpty())
456 return;
457
458 SharedClipboardURIObject *pCurObj = m_lstTree.first();
459 AssertPtr(pCurObj);
460
461 uint64_t cbSize = pCurObj->GetSize();
462 Assert(m_cbTotal >= cbSize);
463 m_cbTotal -= cbSize; /* Adjust total size. */
464
465 pCurObj->Close();
466 RTMemFree(pCurObj);
467
468 m_lstTree.removeFirst();
469}
470
471int SharedClipboardURIList::SetFromURIData(const void *pvData, size_t cbData, SHAREDCLIPBOARDURILISTFLAGS fFlags)
472{
473 Assert(fFlags == 0); RT_NOREF1(fFlags);
474 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
475 AssertReturn(cbData, VERR_INVALID_PARAMETER);
476
477 if (!RTStrIsValidEncoding(static_cast<const char *>(pvData)))
478 return VERR_INVALID_PARAMETER;
479
480 RTCList<RTCString> lstURI =
481 RTCString(static_cast<const char *>(pvData), cbData - 1).split("\r\n");
482 if (lstURI.isEmpty())
483 return VINF_SUCCESS;
484
485 int rc = VINF_SUCCESS;
486
487 for (size_t i = 0; i < lstURI.size(); ++i)
488 {
489 /* Query the path component of a file URI. If this hasn't a
490 * file scheme, NULL is returned. */
491 const char *pszURI = lstURI.at(i).c_str();
492 char *pszFilePath = RTUriFilePath(pszURI);
493#ifdef DEBUG_andy
494 LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath));
495#endif
496 if (pszFilePath)
497 {
498 rc = SharedClipboardPathSanitize(pszFilePath, strlen(pszFilePath));
499 if (RT_SUCCESS(rc))
500 {
501 m_lstRoot.append(pszFilePath);
502 m_cTotal++;
503 }
504
505 RTStrFree(pszFilePath);
506 }
507 else
508 rc = VERR_INVALID_PARAMETER;
509
510 if (RT_FAILURE(rc))
511 break;
512 }
513
514 return rc;
515}
516
517RTCString SharedClipboardURIList::GetRootEntries(const RTCString &strPathBase /* = "" */,
518 const RTCString &strSeparator /* = "\r\n" */) const
519{
520 RTCString strRet;
521 for (size_t i = 0; i < m_lstRoot.size(); i++)
522 {
523 const char *pszCurRoot = m_lstRoot.at(i).c_str();
524#ifdef DEBUG_andy
525 LogFlowFunc(("pszCurRoot=%s\n", pszCurRoot));
526#endif
527 if (strPathBase.isNotEmpty())
528 {
529 char *pszPath = RTPathJoinA(strPathBase.c_str(), pszCurRoot);
530 if (pszPath)
531 {
532 char *pszPathURI = RTUriFileCreate(pszPath);
533 if (pszPathURI)
534 {
535 strRet += RTCString(pszPathURI) + strSeparator;
536 LogFlowFunc(("URI (Base): %s\n", strRet.c_str()));
537 RTStrFree(pszPathURI);
538 }
539
540 RTStrFree(pszPath);
541
542 if (!pszPathURI)
543 break;
544 }
545 else
546 break;
547 }
548 else
549 {
550 char *pszPathURI = RTUriFileCreate(pszCurRoot);
551 if (pszPathURI)
552 {
553 strRet += RTCString(pszPathURI) + strSeparator;
554 LogFlowFunc(("URI: %s\n", strRet.c_str()));
555 RTStrFree(pszPathURI);
556 }
557 else
558 break;
559 }
560 }
561
562 return strRet;
563}
564
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