VirtualBox

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

Last change on this file since 79366 was 79366, 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: 20.0 KB
Line 
1/* $Id: ClipboardURIList.cpp 79366 2019-06-26 15:59:30Z 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 char *pszPathURI;
297 int rc = SharedClipboardMetaDataConvertToFormat(pszPath, strlen(pszPath), SHAREDCLIPBOARDMETADATAFMT_URI_LIST,
298 (void **)&pszPathURI, NULL /* cbData */);
299 if (RT_SUCCESS(rc))
300 {
301 rc = AppendURIPath(pszPathURI, fFlags);
302 RTStrFree(pszPathURI);
303 }
304
305 return rc;
306}
307
308int SharedClipboardURIList::AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths,
309 SHAREDCLIPBOARDURILISTFLAGS fFlags)
310{
311 AssertPtrReturn(pszNativePaths, VERR_INVALID_POINTER);
312 AssertReturn(cbNativePaths, VERR_INVALID_PARAMETER);
313
314 RTCList<RTCString> lstPaths
315 = RTCString(pszNativePaths, cbNativePaths - 1).split("\r\n");
316 return AppendNativePathsFromList(lstPaths, fFlags);
317}
318
319int SharedClipboardURIList::AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths,
320 SHAREDCLIPBOARDURILISTFLAGS fFlags)
321{
322 int rc = VINF_SUCCESS;
323
324 for (size_t i = 0; i < lstNativePaths.size(); i++)
325 {
326 const RTCString &strPath = lstNativePaths.at(i);
327 rc = AppendNativePath(strPath.c_str(), fFlags);
328 if (RT_FAILURE(rc))
329 break;
330 }
331
332 LogFlowFuncLeaveRC(rc);
333 return rc;
334}
335
336int SharedClipboardURIList::AppendURIObject(SharedClipboardURIObject *pObject)
337{
338 AssertPtrReturn(pObject, VERR_INVALID_POINTER);
339
340 return appendObject(pObject);
341}
342
343int SharedClipboardURIList::AppendURIPath(const char *pszURI, SHAREDCLIPBOARDURILISTFLAGS fFlags)
344{
345 AssertPtrReturn(pszURI, VERR_INVALID_POINTER);
346 AssertReturn(!(fFlags & ~SHAREDCLIPBOARDURILIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
347 /** @todo Check for string termination? */
348
349 RTURIPARSED Parsed;
350 int rc = RTUriParse(pszURI, &Parsed);
351 if (RT_FAILURE(rc))
352 return rc;
353
354 char *pszSrcPath = NULL;
355
356 /* file://host.example.com/path/to/file.txt */
357 const char *pszParsedAuthority = RTUriParsedAuthority(pszURI, &Parsed);
358 if ( pszParsedAuthority
359 && pszParsedAuthority[0] != '\0') /* Authority present? */
360 {
361 const char *pszParsedPath = RTUriParsedPath(pszURI, &Parsed);
362 if (pszParsedPath)
363 {
364 /* Always use UNIXy paths internally. */
365 if (RTStrAPrintf(&pszSrcPath, "//%s%s", pszParsedAuthority, pszParsedPath) == -1)
366 rc = VERR_NO_MEMORY;
367 }
368 else
369 rc = VERR_INVALID_PARAMETER;
370 }
371 else
372 {
373 pszSrcPath = RTUriFilePath(pszURI);
374 if (!pszSrcPath)
375 rc = VERR_INVALID_PARAMETER;
376 }
377
378 LogFlowFunc(("pszURI=%s, fFlags=0x%x -> pszParsedAuthority=%s, pszSrcPath=%s, rc=%Rrc\n",
379 pszURI, fFlags, pszParsedAuthority ? pszParsedAuthority : "<None>", pszSrcPath, rc));
380
381 if (RT_SUCCESS(rc))
382 {
383 /* Add the path to our internal file list (recursive in
384 * the case of a directory). */
385 size_t cbPathLen = RTPathStripTrailingSlash(pszSrcPath);
386 if (cbPathLen)
387 {
388 char *pszFileName = RTPathFilename(pszSrcPath);
389 if (pszFileName)
390 {
391 Assert(pszFileName >= pszSrcPath);
392 size_t cchDstBase = (fFlags & SHAREDCLIPBOARDURILIST_FLAGS_ABSOLUTE_PATHS)
393 ? 0 /* Use start of path as root. */
394 : pszFileName - pszSrcPath;
395 char *pszDstPath = &pszSrcPath[cchDstBase];
396
397 m_lstRoot.append(pszDstPath);
398
399 LogFlowFunc(("pszSrcPath=%s, pszFileName=%s, pszRoot=%s\n", pszSrcPath, pszFileName, pszDstPath));
400 rc = appendPathRecursive(pszSrcPath, pszSrcPath, pszSrcPath, cchDstBase, fFlags);
401 }
402 else
403 rc = VERR_PATH_NOT_FOUND;
404 }
405 else
406 rc = VERR_INVALID_PARAMETER;
407 }
408
409 RTStrFree(pszSrcPath);
410
411 LogFlowFuncLeaveRC(rc);
412 return rc;
413}
414
415int SharedClipboardURIList::AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths,
416 SHAREDCLIPBOARDURILISTFLAGS fFlags)
417{
418 AssertPtrReturn(pszURIPaths, VERR_INVALID_POINTER);
419 AssertReturn(cbURIPaths, VERR_INVALID_PARAMETER);
420
421 RTCList<RTCString> lstPaths
422 = RTCString(pszURIPaths, cbURIPaths - 1).split("\r\n");
423 return AppendURIPathsFromList(lstPaths, fFlags);
424}
425
426int SharedClipboardURIList::AppendURIPathsFromList(const RTCList<RTCString> &lstURI,
427 SHAREDCLIPBOARDURILISTFLAGS fFlags)
428{
429 int rc = VINF_SUCCESS;
430
431 for (size_t i = 0; i < lstURI.size(); i++)
432 {
433 RTCString strURI = lstURI.at(i);
434 rc = AppendURIPath(strURI.c_str(), fFlags);
435
436 if (RT_FAILURE(rc))
437 break;
438 }
439
440 LogFlowFuncLeaveRC(rc);
441 return rc;
442}
443
444void SharedClipboardURIList::Clear(void)
445{
446 LogFlowThisFuncEnter();
447
448 m_lstRoot.clear();
449
450 for (size_t i = 0; i < m_lstTree.size(); i++)
451 {
452 SharedClipboardURIObject *pCurObj = m_lstTree.at(i);
453 AssertPtr(pCurObj);
454 delete pCurObj;
455 }
456
457 m_lstTree.clear();
458
459 m_cTotal = 0;
460 m_cbTotal = 0;
461
462 LogFlowThisFuncLeave();
463}
464
465void SharedClipboardURIList::RemoveFirst(void)
466{
467 if (m_lstTree.isEmpty())
468 return;
469
470 SharedClipboardURIObject *pCurObj = m_lstTree.first();
471 AssertPtr(pCurObj);
472
473 uint64_t cbSize = pCurObj->GetSize();
474 Assert(m_cbTotal >= cbSize);
475 m_cbTotal -= cbSize; /* Adjust total size. */
476
477 pCurObj->Close();
478 delete pCurObj;
479
480 m_lstTree.removeFirst();
481}
482
483int SharedClipboardURIList::SetFromURIData(const void *pvData, size_t cbData, SHAREDCLIPBOARDURILISTFLAGS fFlags)
484{
485 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
486 AssertReturn(cbData, VERR_INVALID_PARAMETER);
487 AssertReturn(!(fFlags & ~SHAREDCLIPBOARDURILIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
488
489 RTCList<RTCString> lstURI =
490 RTCString(static_cast<const char *>(pvData), cbData - 1).split("\r\n");
491 if (lstURI.isEmpty())
492 return VINF_SUCCESS;
493
494 int rc = VINF_SUCCESS;
495
496 for (size_t i = 0; i < lstURI.size(); ++i)
497 {
498 /* Query the path component of a file URI. If this hasn't a
499 * file scheme, NULL is returned. */
500 const char *pszURI = lstURI.at(i).c_str();
501 char *pszFilePath = RTUriFilePath(pszURI);
502#ifdef DEBUG_andy
503 LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath));
504#endif
505 if (pszFilePath)
506 {
507 rc = SharedClipboardPathSanitize(pszFilePath, strlen(pszFilePath));
508 if (RT_SUCCESS(rc))
509 {
510 m_lstRoot.append(pszFilePath);
511 m_cTotal++;
512 }
513
514 RTStrFree(pszFilePath);
515 }
516 else
517 rc = VERR_INVALID_PARAMETER;
518
519 if (RT_FAILURE(rc))
520 break;
521 }
522
523 LogFlowFuncLeaveRC(rc);
524 return rc;
525}
526
527RTCString SharedClipboardURIList::GetRootEntries(const RTCString &strPathBase /* = "" */,
528 const RTCString &strSeparator /* = "\r\n" */) const
529{
530 RTCString strRet;
531 for (size_t i = 0; i < m_lstRoot.size(); i++)
532 {
533 const char *pszCurRoot = m_lstRoot.at(i).c_str();
534#ifdef DEBUG_andy
535 LogFlowFunc(("pszCurRoot=%s\n", pszCurRoot));
536#endif
537 if (strPathBase.isNotEmpty())
538 {
539 char *pszPath = RTPathJoinA(strPathBase.c_str(), pszCurRoot);
540 if (pszPath)
541 {
542 char *pszPathURI = RTUriFileCreate(pszPath);
543 if (pszPathURI)
544 {
545 strRet += RTCString(pszPathURI) + strSeparator;
546 LogFlowFunc(("URI (Base): %s\n", strRet.c_str()));
547 RTStrFree(pszPathURI);
548 }
549
550 RTStrFree(pszPath);
551
552 if (!pszPathURI)
553 break;
554 }
555 else
556 break;
557 }
558 else
559 {
560 char *pszPathURI = RTUriFileCreate(pszCurRoot);
561 if (pszPathURI)
562 {
563 strRet += RTCString(pszPathURI) + strSeparator;
564 LogFlowFunc(("URI: %s\n", strRet.c_str()));
565 RTStrFree(pszPathURI);
566 }
567 else
568 break;
569 }
570 }
571
572 return strRet;
573}
574
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