VirtualBox

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

Last change on this file since 79107 was 78942, 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: 20.1 KB
Line 
1/* $Id: ClipboardURIList.cpp 78942 2019-06-03 19:10:19Z 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::appendEntry(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->OpenFile(SharedClipboardURIObject::View_Source,
70 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
71 if (RT_SUCCESS(rc))
72 {
73 rc = appendObject(pObjFile);
74 if (!(fFlags & SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN)) /* Shall we keep the file open while being added to this list? */
75 pObjFile->Close();
76 }
77 else
78 delete pObjFile;
79 }
80 else
81 rc = VERR_NO_MEMORY;
82 }
83 else if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
84 {
85 LogFlowFunc(("Directory '%s' -> '%s' (file mode 0x%x)\n", pcszSource, pcszTarget, objInfo.Attr.fMode));
86
87 SharedClipboardURIObject *pObjDir = new SharedClipboardURIObject(SharedClipboardURIObject::Type_Directory,
88 pcszSource, pcszTarget);
89 if (pObjDir)
90 {
91 m_lstTree.append(pObjDir);
92
93 /** @todo Add SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN handling? */
94 m_cTotal++;
95 }
96 else
97 rc = VERR_NO_MEMORY;
98 }
99 /* Note: Symlinks already should have been resolved at this point. */
100 else
101 rc = VERR_NOT_SUPPORTED;
102 }
103
104 LogFlowFuncLeaveRC(rc);
105 return rc;
106}
107
108int SharedClipboardURIList::appendPathRecursive(const char *pcszSrcPath,
109 const char *pcszDstPath, const char *pcszDstBase, size_t cchDstBase,
110 SHAREDCLIPBOARDURILISTFLAGS fFlags)
111{
112 AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER);
113 AssertPtrReturn(pcszDstBase, VERR_INVALID_POINTER);
114 AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER);
115
116 LogFlowFunc(("pcszSrcPath=%s, pcszDstPath=%s, pcszDstBase=%s, cchDstBase=%zu, fFlags=0x%x\n",
117 pcszSrcPath, pcszDstPath, pcszDstBase, cchDstBase, fFlags));
118
119 RTFSOBJINFO objInfo;
120 int rc = RTPathQueryInfo(pcszSrcPath, &objInfo, RTFSOBJATTRADD_NOTHING);
121 if (RT_SUCCESS(rc))
122 {
123 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
124 {
125 rc = appendEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags);
126 if (RT_SUCCESS(rc))
127 {
128 RTDIR hDir;
129 rc = RTDirOpen(&hDir, pcszSrcPath);
130 if (RT_SUCCESS(rc))
131 {
132 size_t cbDirEntry = 0;
133 PRTDIRENTRYEX pDirEntry = NULL;
134 do
135 {
136 /* Retrieve the next directory entry. */
137 rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
138 if (RT_FAILURE(rc))
139 {
140 if (rc == VERR_NO_MORE_FILES)
141 rc = VINF_SUCCESS;
142 break;
143 }
144
145 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
146 {
147 case RTFS_TYPE_DIRECTORY:
148 {
149 /* Skip "." and ".." entries. */
150 if (RTDirEntryExIsStdDotLink(pDirEntry))
151 break;
152
153 char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName);
154 if (pszSrc)
155 {
156 char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName);
157 if (pszDst)
158 {
159 rc = appendPathRecursive(pszSrc, pszDst, pcszDstBase, cchDstBase, fFlags);
160 RTStrFree(pszDst);
161 }
162 else
163 rc = VERR_NO_MEMORY;
164
165 RTStrFree(pszSrc);
166 }
167 else
168 rc = VERR_NO_MEMORY;
169 break;
170 }
171
172 case RTFS_TYPE_FILE:
173 {
174 char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName);
175 if (pszSrc)
176 {
177 char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName);
178 if (pszDst)
179 {
180 rc = appendEntry(pszSrc, &pszDst[cchDstBase], fFlags);
181 RTStrFree(pszDst);
182 }
183 else
184 rc = VERR_NO_MEMORY;
185 RTStrFree(pszSrc);
186 }
187 else
188 rc = VERR_NO_MEMORY;
189 break;
190 }
191 case RTFS_TYPE_SYMLINK:
192 {
193 if (fFlags & SHAREDCLIPBOARDURILIST_FLAGS_RESOLVE_SYMLINKS)
194 {
195 char *pszSrc = RTPathRealDup(pcszDstBase);
196 if (pszSrc)
197 {
198 rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING);
199 if (RT_SUCCESS(rc))
200 {
201 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
202 {
203 LogFlowFunc(("Directory entry is symlink to directory\n"));
204 rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags);
205 }
206 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
207 {
208 LogFlowFunc(("Directory entry is symlink to file\n"));
209 rc = appendEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags);
210 }
211 else
212 rc = VERR_NOT_SUPPORTED;
213 }
214
215 RTStrFree(pszSrc);
216 }
217 else
218 rc = VERR_NO_MEMORY;
219 }
220 break;
221 }
222
223 default:
224 break;
225 }
226
227 } while (RT_SUCCESS(rc));
228
229 RTDirReadExAFree(&pDirEntry, &cbDirEntry);
230 RTDirClose(hDir);
231 }
232 }
233 }
234 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
235 {
236 rc = appendEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags);
237 }
238 else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))
239 {
240 if (fFlags & SHAREDCLIPBOARDURILIST_FLAGS_RESOLVE_SYMLINKS)
241 {
242 char *pszSrc = RTPathRealDup(pcszSrcPath);
243 if (pszSrc)
244 {
245 rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING);
246 if (RT_SUCCESS(rc))
247 {
248 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
249 {
250 LogFlowFunc(("Symlink to directory\n"));
251 rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags);
252 }
253 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
254 {
255 LogFlowFunc(("Symlink to file\n"));
256 rc = appendEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags);
257 }
258 else
259 rc = VERR_NOT_SUPPORTED;
260 }
261
262 RTStrFree(pszSrc);
263 }
264 else
265 rc = VERR_NO_MEMORY;
266 }
267 }
268 else
269 rc = VERR_NOT_SUPPORTED;
270 }
271
272 LogFlowFuncLeaveRC(rc);
273 return rc;
274}
275
276int SharedClipboardURIList::appendObject(SharedClipboardURIObject *pObject)
277{
278 int rc = VINF_SUCCESS;
279
280 m_lstTree.append(pObject);
281 m_lstRoot.append(pObject->GetSourcePathAbs());;
282
283 m_cTotal++;
284 m_cbTotal += pObject->GetSize();
285
286 LogFlowFuncLeaveRC(rc);
287 return rc;
288}
289
290int SharedClipboardURIList::AppendNativePath(const char *pszPath, SHAREDCLIPBOARDURILISTFLAGS fFlags)
291{
292 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
293
294 int rc;
295 char *pszPathNative = RTStrDup(pszPath);
296 if (pszPathNative)
297 {
298 RTPathChangeToUnixSlashes(pszPathNative, true /* fForce */);
299
300 char *pszPathURI = RTUriCreate("file" /* pszScheme */, NULL /* pszAuthority */,
301 pszPathNative, NULL /* pszQuery */, NULL /* pszFragment */);
302 if (pszPathURI)
303 {
304 rc = AppendURIPath(pszPathURI, fFlags);
305 RTStrFree(pszPathURI);
306 }
307 else
308 rc = VERR_INVALID_PARAMETER;
309
310 RTStrFree(pszPathNative);
311 }
312 else
313 rc = VERR_NO_MEMORY;
314
315 return rc;
316}
317
318int SharedClipboardURIList::AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths,
319 SHAREDCLIPBOARDURILISTFLAGS fFlags)
320{
321 AssertPtrReturn(pszNativePaths, VERR_INVALID_POINTER);
322 AssertReturn(cbNativePaths, VERR_INVALID_PARAMETER);
323
324 RTCList<RTCString> lstPaths
325 = RTCString(pszNativePaths, cbNativePaths - 1).split("\r\n");
326 return AppendNativePathsFromList(lstPaths, fFlags);
327}
328
329int SharedClipboardURIList::AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths,
330 SHAREDCLIPBOARDURILISTFLAGS fFlags)
331{
332 int rc = VINF_SUCCESS;
333
334 for (size_t i = 0; i < lstNativePaths.size(); i++)
335 {
336 const RTCString &strPath = lstNativePaths.at(i);
337 rc = AppendNativePath(strPath.c_str(), fFlags);
338 if (RT_FAILURE(rc))
339 break;
340 }
341
342 LogFlowFuncLeaveRC(rc);
343 return rc;
344}
345
346int SharedClipboardURIList::AppendURIObject(SharedClipboardURIObject *pObject)
347{
348 AssertPtrReturn(pObject, VERR_INVALID_POINTER);
349
350 return appendObject(pObject);
351}
352
353int SharedClipboardURIList::AppendURIPath(const char *pszURI, SHAREDCLIPBOARDURILISTFLAGS fFlags)
354{
355 AssertPtrReturn(pszURI, VERR_INVALID_POINTER);
356 AssertReturn(!(fFlags & ~SHAREDCLIPBOARDURILIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
357 /** @todo Check for string termination? */
358
359 RTURIPARSED Parsed;
360 int rc = RTUriParse(pszURI, &Parsed);
361 if (RT_FAILURE(rc))
362 return rc;
363
364 char *pszSrcPath = NULL;
365
366 /* file://host.example.com/path/to/file.txt */
367 const char *pszParsedAuthority = RTUriParsedAuthority(pszURI, &Parsed);
368 if ( pszParsedAuthority
369 && pszParsedAuthority[0] != '\0') /* Authority present? */
370 {
371 const char *pszParsedPath = RTUriParsedPath(pszURI, &Parsed);
372 if (pszParsedPath)
373 {
374 /* Always use UNIXy paths internally. */
375 if (RTStrAPrintf(&pszSrcPath, "//%s%s", pszParsedAuthority, pszParsedPath) == -1)
376 rc = VERR_NO_MEMORY;
377 }
378 else
379 rc = VERR_INVALID_PARAMETER;
380 }
381 else
382 {
383 pszSrcPath = RTUriFilePath(pszURI);
384 if (!pszSrcPath)
385 rc = VERR_INVALID_PARAMETER;
386 }
387
388 LogFlowFunc(("pszURI=%s, fFlags=0x%x -> pszParsedAuthority=%s, pszSrcPath=%s, rc=%Rrc\n",
389 pszURI, fFlags, pszParsedAuthority ? pszParsedAuthority : "<None>", pszSrcPath, rc));
390
391 if (RT_SUCCESS(rc))
392 {
393 /* Add the path to our internal file list (recursive in
394 * the case of a directory). */
395 size_t cbPathLen = RTPathStripTrailingSlash(pszSrcPath);
396 if (cbPathLen)
397 {
398 char *pszFileName = RTPathFilename(pszSrcPath);
399 if (pszFileName)
400 {
401 Assert(pszFileName >= pszSrcPath);
402 size_t cchDstBase = (fFlags & SHAREDCLIPBOARDURILIST_FLAGS_ABSOLUTE_PATHS)
403 ? 0 /* Use start of path as root. */
404 : pszFileName - pszSrcPath;
405 char *pszDstPath = &pszSrcPath[cchDstBase];
406
407 m_lstRoot.append(pszDstPath);
408
409 LogFlowFunc(("pszSrcPath=%s, pszFileName=%s, pszRoot=%s\n", pszSrcPath, pszFileName, pszDstPath));
410 rc = appendPathRecursive(pszSrcPath, pszSrcPath, pszSrcPath, cchDstBase, fFlags);
411 }
412 else
413 rc = VERR_PATH_NOT_FOUND;
414 }
415 else
416 rc = VERR_INVALID_PARAMETER;
417 }
418
419 RTStrFree(pszSrcPath);
420
421 LogFlowFuncLeaveRC(rc);
422 return rc;
423}
424
425int SharedClipboardURIList::AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths,
426 SHAREDCLIPBOARDURILISTFLAGS fFlags)
427{
428 AssertPtrReturn(pszURIPaths, VERR_INVALID_POINTER);
429 AssertReturn(cbURIPaths, VERR_INVALID_PARAMETER);
430
431 RTCList<RTCString> lstPaths
432 = RTCString(pszURIPaths, cbURIPaths - 1).split("\r\n");
433 return AppendURIPathsFromList(lstPaths, fFlags);
434}
435
436int SharedClipboardURIList::AppendURIPathsFromList(const RTCList<RTCString> &lstURI,
437 SHAREDCLIPBOARDURILISTFLAGS fFlags)
438{
439 int rc = VINF_SUCCESS;
440
441 for (size_t i = 0; i < lstURI.size(); i++)
442 {
443 RTCString strURI = lstURI.at(i);
444 rc = AppendURIPath(strURI.c_str(), fFlags);
445
446 if (RT_FAILURE(rc))
447 break;
448 }
449
450 LogFlowFuncLeaveRC(rc);
451 return rc;
452}
453
454void SharedClipboardURIList::Clear(void)
455{
456 LogFlowThisFuncEnter();
457
458 m_lstRoot.clear();
459
460 for (size_t i = 0; i < m_lstTree.size(); i++)
461 {
462 SharedClipboardURIObject *pCurObj = m_lstTree.at(i);
463 AssertPtr(pCurObj);
464 delete pCurObj;
465 }
466
467 m_lstTree.clear();
468
469 m_cTotal = 0;
470 m_cbTotal = 0;
471
472 LogFlowThisFuncLeave();
473}
474
475void SharedClipboardURIList::RemoveFirst(void)
476{
477 if (m_lstTree.isEmpty())
478 return;
479
480 SharedClipboardURIObject *pCurObj = m_lstTree.first();
481 AssertPtr(pCurObj);
482
483 uint64_t cbSize = pCurObj->GetSize();
484 Assert(m_cbTotal >= cbSize);
485 m_cbTotal -= cbSize; /* Adjust total size. */
486
487 pCurObj->Close();
488 delete pCurObj;
489
490 m_lstTree.removeFirst();
491}
492
493int SharedClipboardURIList::SetFromURIData(const void *pvData, size_t cbData, SHAREDCLIPBOARDURILISTFLAGS fFlags)
494{
495 Assert(fFlags == 0); RT_NOREF1(fFlags);
496 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
497 AssertReturn(cbData, VERR_INVALID_PARAMETER);
498
499 if (!RTStrIsValidEncoding(static_cast<const char *>(pvData)))
500 return VERR_INVALID_PARAMETER;
501
502 RTCList<RTCString> lstURI =
503 RTCString(static_cast<const char *>(pvData), cbData - 1).split("\r\n");
504 if (lstURI.isEmpty())
505 return VINF_SUCCESS;
506
507 int rc = VINF_SUCCESS;
508
509 for (size_t i = 0; i < lstURI.size(); ++i)
510 {
511 /* Query the path component of a file URI. If this hasn't a
512 * file scheme, NULL is returned. */
513 const char *pszURI = lstURI.at(i).c_str();
514 char *pszFilePath = RTUriFilePath(pszURI);
515#ifdef DEBUG_andy
516 LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath));
517#endif
518 if (pszFilePath)
519 {
520 rc = SharedClipboardPathSanitize(pszFilePath, strlen(pszFilePath));
521 if (RT_SUCCESS(rc))
522 {
523 m_lstRoot.append(pszFilePath);
524 m_cTotal++;
525 }
526
527 RTStrFree(pszFilePath);
528 }
529 else
530 rc = VERR_INVALID_PARAMETER;
531
532 if (RT_FAILURE(rc))
533 break;
534 }
535
536 return rc;
537}
538
539RTCString SharedClipboardURIList::GetRootEntries(const RTCString &strPathBase /* = "" */,
540 const RTCString &strSeparator /* = "\r\n" */) const
541{
542 RTCString strRet;
543 for (size_t i = 0; i < m_lstRoot.size(); i++)
544 {
545 const char *pszCurRoot = m_lstRoot.at(i).c_str();
546#ifdef DEBUG_andy
547 LogFlowFunc(("pszCurRoot=%s\n", pszCurRoot));
548#endif
549 if (strPathBase.isNotEmpty())
550 {
551 char *pszPath = RTPathJoinA(strPathBase.c_str(), pszCurRoot);
552 if (pszPath)
553 {
554 char *pszPathURI = RTUriFileCreate(pszPath);
555 if (pszPathURI)
556 {
557 strRet += RTCString(pszPathURI) + strSeparator;
558 LogFlowFunc(("URI (Base): %s\n", strRet.c_str()));
559 RTStrFree(pszPathURI);
560 }
561
562 RTStrFree(pszPath);
563
564 if (!pszPathURI)
565 break;
566 }
567 else
568 break;
569 }
570 else
571 {
572 char *pszPathURI = RTUriFileCreate(pszCurRoot);
573 if (pszPathURI)
574 {
575 strRet += RTCString(pszPathURI) + strSeparator;
576 LogFlowFunc(("URI: %s\n", strRet.c_str()));
577 RTStrFree(pszPathURI);
578 }
579 else
580 break;
581 }
582 }
583
584 return strRet;
585}
586
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