VirtualBox

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

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