VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/clipboard-uri.cpp@ 80359

Last change on this file since 80359 was 80359, 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: 92.5 KB
Line 
1/* $Id: clipboard-uri.cpp 80359 2019-08-21 08:37:54Z vboxsync $ */
2/** @file
3 * Shared Clipboard: Common URI transfer handling code.
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#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
19#include <VBox/log.h>
20
21#include <iprt/dir.h>
22#include <iprt/file.h>
23#include <iprt/path.h>
24#include <iprt/semaphore.h>
25
26#include <VBox/err.h>
27#include <VBox/HostServices/VBoxClipboardSvc.h>
28#include <VBox/GuestHost/SharedClipboard-uri.h>
29
30
31static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser);
32static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs);
33static int sharedClipboardURITransferWriteThread(RTTHREAD hThread, void *pvUser);
34static PSHAREDCLIPBOARDURITRANSFER sharedClipboardURICtxGetTransferInternal(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx);
35static int sharedClipboardConvertFileCreateFlags(bool fWritable, unsigned fShClFlags, RTFMODE fMode,
36 SHAREDCLIPBOARDOBJHANDLE handleInitial, uint64_t *pfOpen);
37
38/** @todo Split this file up in different modules. */
39
40/**
41 * Allocates a new URI root list.
42 *
43 * @returns Allocated URI root list on success, or NULL on failure.
44 */
45PVBOXCLIPBOARDROOTLIST SharedClipboardURIRootListAlloc(void)
46{
47 PVBOXCLIPBOARDROOTLIST pRootList = (PVBOXCLIPBOARDROOTLIST)RTMemAllocZ(sizeof(VBOXCLIPBOARDROOTLIST));
48
49 return pRootList;
50}
51
52/**
53 * Frees an URI root list.
54 *
55 * @param pRootList URI root list to free. The pointer will be
56 * invalid after returning from this function.
57 */
58void SharedClipboardURIRootListFree(PVBOXCLIPBOARDROOTLIST pRootList)
59{
60 if (!pRootList)
61 return;
62
63 for (uint32_t i = 0; i < pRootList->Hdr.cRoots; i++)
64 SharedClipboardURIListEntryDestroy(&pRootList->paEntries[i]);
65
66 RTMemFree(pRootList);
67 pRootList = NULL;
68}
69
70/**
71 * Initializes an URI root list header.
72 *
73 * @returns VBox status code.
74 * @param pRootLstHdr Root list header to initialize.
75 */
76int SharedClipboardURIRootListHdrInit(PVBOXCLIPBOARDROOTLISTHDR pRootLstHdr)
77{
78 AssertPtrReturn(pRootLstHdr, VERR_INVALID_POINTER);
79
80 RT_BZERO(pRootLstHdr, sizeof(VBOXCLIPBOARDROOTLISTHDR));
81
82 return VINF_SUCCESS;
83}
84
85/**
86 * Destroys an URI root list header.
87 *
88 * @param pRootLstHdr Root list header to destroy.
89 */
90void SharedClipboardURIRootListHdrDestroy(PVBOXCLIPBOARDROOTLISTHDR pRootLstHdr)
91{
92 if (!pRootLstHdr)
93 return;
94
95 pRootLstHdr->fRoots = 0;
96 pRootLstHdr->cRoots = 0;
97}
98
99/**
100 * Duplicates an URI list header.
101 *
102 * @returns Duplicated URI list header on success, or NULL on failure.
103 * @param pRootLstHdr Root list header to duplicate.
104 */
105PVBOXCLIPBOARDROOTLISTHDR SharedClipboardURIRootListHdrDup(PVBOXCLIPBOARDROOTLISTHDR pRootLstHdr)
106{
107 AssertPtrReturn(pRootLstHdr, NULL);
108
109 int rc = VINF_SUCCESS;
110
111 PVBOXCLIPBOARDROOTLISTHDR pRootsDup = (PVBOXCLIPBOARDROOTLISTHDR)RTMemAllocZ(sizeof(VBOXCLIPBOARDROOTLISTHDR));
112 if (pRootsDup)
113 {
114 *pRootsDup = *pRootLstHdr;
115 }
116 else
117 rc = VERR_NO_MEMORY;
118
119 if (RT_FAILURE(rc))
120 {
121 SharedClipboardURIRootListHdrDestroy(pRootsDup);
122 pRootsDup = NULL;
123 }
124
125 return pRootsDup;
126}
127
128/**
129 * (Deep) Copies a clipboard root list entry structure.
130 *
131 * @returns VBox status code.
132 * @param pListEntry Clipboard root list entry to copy.
133 */
134int SharedClipboardURIRootListEntryCopy(PVBOXCLIPBOARDROOTLISTENTRY pDst, PVBOXCLIPBOARDROOTLISTENTRY pSrc)
135{
136 return SharedClipboardURIListEntryCopy(pDst, pSrc);
137}
138
139/**
140 * Duplicates (allocates) a clipboard root list entry structure.
141 *
142 * @returns Duplicated clipboard root list entry structure on success.
143 * @param pListEntry Clipboard root list entry to duplicate.
144 */
145PVBOXCLIPBOARDROOTLISTENTRY SharedClipboardURIRootListEntryDup(PVBOXCLIPBOARDROOTLISTENTRY pRootListEntry)
146{
147 return SharedClipboardURIListEntryDup(pRootListEntry);
148}
149
150/**
151 * Destroys a clipboard root list entry structure.
152 *
153 * @param pListEntry Clipboard root list entry structure to destroy.
154 */
155void SharedClipboardURIRootListEntryDestroy(PVBOXCLIPBOARDROOTLISTENTRY pRootListEntry)
156{
157 return SharedClipboardURIListEntryDestroy(pRootListEntry);
158}
159
160/**
161 * Destroys a list handle info structure.
162 *
163 * @param pInfo List handle info structure to destroy.
164 */
165void SharedClipboardURIListHandleInfoDestroy(PSHAREDCLIPBOARDURILISTHANDLEINFO pInfo)
166{
167 if (!pInfo)
168 return;
169
170 if (pInfo->pszPathLocalAbs)
171 {
172 RTStrFree(pInfo->pszPathLocalAbs);
173 pInfo->pszPathLocalAbs = NULL;
174 }
175}
176
177/**
178 * Allocates a URI list header structure.
179 *
180 * @returns VBox status code.
181 * @param ppListHdr Where to store the allocated URI list header structure on success.
182 */
183int SharedClipboardURIListHdrAlloc(PVBOXCLIPBOARDLISTHDR *ppListHdr)
184{
185 int rc;
186
187 PVBOXCLIPBOARDLISTHDR pListHdr = (PVBOXCLIPBOARDLISTHDR)RTMemAllocZ(sizeof(VBOXCLIPBOARDLISTHDR));
188 if (pListHdr)
189 {
190 *ppListHdr = pListHdr;
191 rc = VINF_SUCCESS;
192 }
193 else
194 rc = VERR_NO_MEMORY;
195
196 LogFlowFuncLeaveRC(rc);
197 return rc;
198}
199
200/**
201 * Frees an URI list header structure.
202 *
203 * @param pListEntry URI list header structure to free.
204 */
205void SharedClipboardURIListHdrFree(PVBOXCLIPBOARDLISTHDR pListHdr)
206{
207 if (!pListHdr)
208 return;
209
210 LogFlowFuncEnter();
211
212 SharedClipboardURIListHdrDestroy(pListHdr);
213
214 RTMemFree(pListHdr);
215 pListHdr = NULL;
216}
217
218/**
219 * Duplicates (allocates) an URI list header structure.
220 *
221 * @returns Duplicated URI list header structure on success.
222 * @param pListHdr URI list header to duplicate.
223 */
224PVBOXCLIPBOARDLISTHDR SharedClipboardURIListHdrDup(PVBOXCLIPBOARDLISTHDR pListHdr)
225{
226 AssertPtrReturn(pListHdr, NULL);
227
228 PVBOXCLIPBOARDLISTHDR pListHdrDup = (PVBOXCLIPBOARDLISTHDR)RTMemAlloc(sizeof(VBOXCLIPBOARDLISTHDR));
229 if (pListHdrDup)
230 {
231 *pListHdrDup = *pListHdr;
232 }
233
234 return pListHdrDup;
235}
236
237/**
238 * Initializes an URI data header struct.
239 *
240 * @returns VBox status code.
241 * @param pListHdr Data header struct to initialize.
242 */
243int SharedClipboardURIListHdrInit(PVBOXCLIPBOARDLISTHDR pListHdr)
244{
245 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
246
247 LogFlowFuncEnter();
248
249 SharedClipboardURIListHdrReset(pListHdr);
250
251 return VINF_SUCCESS;
252}
253
254/**
255 * Destroys an URI data header struct.
256 *
257 * @param pListHdr Data header struct to destroy.
258 */
259void SharedClipboardURIListHdrDestroy(PVBOXCLIPBOARDLISTHDR pListHdr)
260{
261 if (!pListHdr)
262 return;
263
264 LogFlowFuncEnter();
265}
266
267/**
268 * Resets a VBOXCLIPBOARDListHdr structture.
269 *
270 * @returns VBox status code.
271 * @param pListHdr VBOXCLIPBOARDListHdr structture to reset.
272 */
273void SharedClipboardURIListHdrReset(PVBOXCLIPBOARDLISTHDR pListHdr)
274{
275 AssertPtrReturnVoid(pListHdr);
276
277 LogFlowFuncEnter();
278
279 RT_BZERO(pListHdr, sizeof(VBOXCLIPBOARDLISTHDR));
280}
281
282/**
283 * Returns whether a given clipboard data header is valid or not.
284 *
285 * @returns \c true if valid, \c false if not.
286 * @param pListHdr Clipboard data header to validate.
287 */
288bool SharedClipboardURIListHdrIsValid(PVBOXCLIPBOARDLISTHDR pListHdr)
289{
290 RT_NOREF(pListHdr);
291 return true; /** @todo Implement this. */
292}
293
294int SharedClipboardURIListOpenParmsCopy(PVBOXCLIPBOARDLISTOPENPARMS pDst, PVBOXCLIPBOARDLISTOPENPARMS pSrc)
295{
296 AssertPtrReturn(pDst, VERR_INVALID_POINTER);
297 AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
298
299 int rc = VINF_SUCCESS;
300
301 if (pSrc->pszFilter)
302 {
303 pDst->pszFilter = RTStrDup(pSrc->pszFilter);
304 if (!pDst->pszFilter)
305 rc = VERR_NO_MEMORY;
306 }
307
308 if ( RT_SUCCESS(rc)
309 && pSrc->pszPath)
310 {
311 pDst->pszPath = RTStrDup(pSrc->pszPath);
312 if (!pDst->pszPath)
313 rc = VERR_NO_MEMORY;
314 }
315
316 if (RT_SUCCESS(rc))
317 {
318 pDst->fList = pDst->fList;
319 pDst->cbFilter = pSrc->cbFilter;
320 pDst->cbPath = pSrc->cbPath;
321 }
322
323 return rc;
324}
325
326/**
327 * Duplicates an URI list open parameters structure.
328 *
329 * @returns Duplicated URI list open parameters structure on success, or NULL on failure.
330 * @param pParms URI list open parameters structure to duplicate.
331 */
332PVBOXCLIPBOARDLISTOPENPARMS SharedClipboardURIListOpenParmsDup(PVBOXCLIPBOARDLISTOPENPARMS pParms)
333{
334 AssertPtrReturn(pParms, NULL);
335
336 PVBOXCLIPBOARDLISTOPENPARMS pParmsDup = (PVBOXCLIPBOARDLISTOPENPARMS)RTMemAllocZ(sizeof(VBOXCLIPBOARDLISTOPENPARMS));
337 if (!pParmsDup)
338 return NULL;
339
340 int rc = SharedClipboardURIListOpenParmsCopy(pParmsDup, pParms);
341 if (RT_FAILURE(rc))
342 {
343 SharedClipboardURIListOpenParmsDestroy(pParmsDup);
344
345 RTMemFree(pParmsDup);
346 pParmsDup = NULL;
347 }
348
349 return pParmsDup;
350}
351
352/**
353 * Initializes an URI list open parameters structure.
354 *
355 * @returns VBox status code.
356 * @param pParms URI list open parameters structure to initialize.
357 */
358int SharedClipboardURIListOpenParmsInit(PVBOXCLIPBOARDLISTOPENPARMS pParms)
359{
360 AssertPtrReturn(pParms, VERR_INVALID_POINTER);
361
362 RT_BZERO(pParms, sizeof(VBOXCLIPBOARDLISTOPENPARMS));
363
364 pParms->cbFilter = 64; /** @todo Make this dynamic. */
365 pParms->pszFilter = RTStrAlloc(pParms->cbFilter);
366
367 pParms->cbPath = RTPATH_MAX;
368 pParms->pszPath = RTStrAlloc(pParms->cbPath);
369
370 LogFlowFuncLeave();
371 return VINF_SUCCESS;
372}
373
374/**
375 * Destroys an URI list open parameters structure.
376 *
377 * @param pParms URI list open parameters structure to destroy.
378 */
379void SharedClipboardURIListOpenParmsDestroy(PVBOXCLIPBOARDLISTOPENPARMS pParms)
380{
381 if (!pParms)
382 return;
383
384 if (pParms->pszFilter)
385 {
386 RTStrFree(pParms->pszFilter);
387 pParms->pszFilter = NULL;
388 }
389
390 if (pParms->pszPath)
391 {
392 RTStrFree(pParms->pszPath);
393 pParms->pszPath = NULL;
394 }
395}
396
397/**
398 * Creates (allocates) and initializes a clipboard list entry structure.
399 *
400 * @param ppDirData Where to return the created clipboard list entry structure on success.
401 */
402int SharedClipboardURIListEntryAlloc(PVBOXCLIPBOARDLISTENTRY *ppListEntry)
403{
404 PVBOXCLIPBOARDLISTENTRY pListEntry = (PVBOXCLIPBOARDLISTENTRY)RTMemAlloc(sizeof(VBOXCLIPBOARDLISTENTRY));
405 if (!pListEntry)
406 return VERR_NO_MEMORY;
407
408 int rc = SharedClipboardURIListEntryInit(pListEntry);
409 if (RT_SUCCESS(rc))
410 *ppListEntry = pListEntry;
411
412 return rc;
413}
414
415/**
416 * Frees a clipboard list entry structure.
417 *
418 * @param pListEntry Clipboard list entry structure to free.
419 */
420void SharedClipboardURIListEntryFree(PVBOXCLIPBOARDLISTENTRY pListEntry)
421{
422 if (!pListEntry)
423 return;
424
425 SharedClipboardURIListEntryDestroy(pListEntry);
426 RTMemFree(pListEntry);
427}
428
429/**
430 * (Deep) Copies a clipboard list entry structure.
431 *
432 * @returns VBox status code.
433 * @param pListEntry Clipboard list entry to copy.
434 */
435int SharedClipboardURIListEntryCopy(PVBOXCLIPBOARDLISTENTRY pDst, PVBOXCLIPBOARDLISTENTRY pSrc)
436{
437 AssertPtrReturn(pDst, VERR_INVALID_POINTER);
438 AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
439
440 int rc = VINF_SUCCESS;
441
442 *pDst = *pSrc;
443
444 if (pSrc->pszName)
445 {
446 pDst->pszName = RTStrDup(pSrc->pszName);
447 if (!pDst->pszName)
448 rc = VERR_NO_MEMORY;
449 }
450
451 if ( RT_SUCCESS(rc)
452 && pSrc->pvInfo)
453 {
454 pDst->pvInfo = RTMemDup(pSrc->pvInfo, pSrc->cbInfo);
455 if (pDst->pvInfo)
456 {
457 pDst->cbInfo = pSrc->cbInfo;
458 }
459 else
460 rc = VERR_NO_MEMORY;
461 }
462
463 if (RT_FAILURE(rc))
464 {
465 if (pDst->pvInfo)
466 {
467 RTMemFree(pDst->pvInfo);
468 pDst->pvInfo = NULL;
469 pDst->cbInfo = 0;
470 }
471 }
472
473 return rc;
474}
475
476/**
477 * Duplicates (allocates) a clipboard list entry structure.
478 *
479 * @returns Duplicated clipboard list entry structure on success.
480 * @param pListEntry Clipboard list entry to duplicate.
481 */
482PVBOXCLIPBOARDLISTENTRY SharedClipboardURIListEntryDup(PVBOXCLIPBOARDLISTENTRY pListEntry)
483{
484 AssertPtrReturn(pListEntry, NULL);
485
486 int rc = VINF_SUCCESS;
487
488 PVBOXCLIPBOARDLISTENTRY pListEntryDup = (PVBOXCLIPBOARDLISTENTRY)RTMemAllocZ(sizeof(VBOXCLIPBOARDLISTENTRY));
489 if (pListEntryDup)
490 rc = SharedClipboardURIListEntryCopy(pListEntryDup, pListEntry);
491
492 if (RT_FAILURE(rc))
493 {
494 SharedClipboardURIListEntryDestroy(pListEntryDup);
495
496 RTMemFree(pListEntryDup);
497 pListEntryDup = NULL;
498 }
499
500 return pListEntryDup;
501}
502
503/**
504 * Initializes a clipboard list entry structure.
505 *
506 * @returns VBox status code.
507 * @param pListEntry Clipboard list entry structure to initialize.
508 */
509int SharedClipboardURIListEntryInit(PVBOXCLIPBOARDLISTENTRY pListEntry)
510{
511 RT_BZERO(pListEntry, sizeof(VBOXCLIPBOARDLISTENTRY));
512
513 pListEntry->pszName = RTStrAlloc(VBOXCLIPBOARDLISTENTRY_MAX_NAME);
514 if (!pListEntry->pszName)
515 return VERR_NO_MEMORY;
516
517 pListEntry->cbName = VBOXCLIPBOARDLISTENTRY_MAX_NAME;
518 pListEntry->pvInfo = NULL;
519 pListEntry->cbInfo = 0;
520 pListEntry->fInfo = 0;
521
522 return VINF_SUCCESS;
523}
524
525/**
526 * Destroys a clipboard list entry structure.
527 *
528 * @param pListEntry Clipboard list entry structure to destroy.
529 */
530void SharedClipboardURIListEntryDestroy(PVBOXCLIPBOARDLISTENTRY pListEntry)
531{
532 if (!pListEntry)
533 return;
534
535 if (pListEntry->pszName)
536 {
537 RTStrFree(pListEntry->pszName);
538
539 pListEntry->pszName = NULL;
540 pListEntry->cbName = 0;
541 }
542
543 if (pListEntry->pvInfo)
544 {
545 RTMemFree(pListEntry->pvInfo);
546 pListEntry->pvInfo = NULL;
547 pListEntry->cbInfo = 0;
548 }
549}
550
551/**
552 * Returns whether a given clipboard data chunk is valid or not.
553 *
554 * @returns \c true if valid, \c false if not.
555 * @param pListEntry Clipboard data chunk to validate.
556 */
557bool SharedClipboardURIListEntryIsValid(PVBOXCLIPBOARDLISTENTRY pListEntry)
558{
559 RT_NOREF(pListEntry);
560
561 /** @todo Verify checksum. */
562
563 return true; /** @todo Implement this. */
564}
565
566/**
567 * Initializes an URI object context.
568 *
569 * @returns VBox status code.
570 * @param pObjCtx URI object context to initialize.
571 */
572int SharedClipboardURIObjCtxInit(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
573{
574 AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
575
576 LogFlowFuncEnter();
577
578 pObjCtx->uHandle = SHAREDCLIPBOARDOBJHANDLE_INVALID;
579
580 return VINF_SUCCESS;
581}
582
583/**
584 * Destroys an URI object context.
585 *
586 * @param pObjCtx URI object context to destroy.
587 */
588void SharedClipboardURIObjCtxDestroy(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
589{
590 AssertPtrReturnVoid(pObjCtx);
591
592 LogFlowFuncEnter();
593}
594
595/**
596 * Returns if an URI object context is valid or not.
597 *
598 * @returns \c true if valid, \c false if not.
599 * @param pObjCtx URI object context to check.
600 */
601bool SharedClipboardURIObjCtxIsValid(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
602{
603 return ( pObjCtx
604 && pObjCtx->uHandle != SHAREDCLIPBOARDOBJHANDLE_INVALID);
605}
606
607/**
608 * Destroys an object handle info structure.
609 *
610 * @param pInfo Object handle info structure to destroy.
611 */
612void SharedClipboardURIObjectHandleInfoDestroy(PSHAREDCLIPBOARDURIOBJHANDLEINFO pInfo)
613{
614 if (!pInfo)
615 return;
616
617 if (pInfo->pszPathLocalAbs)
618 {
619 RTStrFree(pInfo->pszPathLocalAbs);
620 pInfo->pszPathLocalAbs = NULL;
621 }
622}
623
624/**
625 * Initializes an URI object open parameters structure.
626 *
627 * @returns VBox status code.
628 * @param pParms URI object open parameters structure to initialize.
629 */
630int SharedClipboardURIObjectOpenParmsInit(PVBOXCLIPBOARDOBJOPENCREATEPARMS pParms)
631{
632 AssertPtrReturn(pParms, VERR_INVALID_POINTER);
633
634 int rc;
635
636 RT_BZERO(pParms, sizeof(VBOXCLIPBOARDOBJOPENCREATEPARMS));
637
638 pParms->cbPath = RTPATH_MAX; /** @todo Make this dynamic. */
639 pParms->pszPath = RTStrAlloc(pParms->cbPath);
640 if (pParms->pszPath)
641 {
642 rc = VINF_SUCCESS;
643 }
644 else
645 rc = VERR_NO_MEMORY;
646
647 LogFlowFuncLeaveRC(rc);
648 return rc;
649}
650
651/**
652 * Copies an URI object open parameters structure from source to destination.
653 *
654 * @returns VBox status code.
655 * @param pParmsDst Where to copy the source URI object open parameters to.
656 * @param pParmsSrc Which source URI object open parameters to copy.
657 */
658int SharedClipboardURIObjectOpenParmsCopy(PVBOXCLIPBOARDOBJOPENCREATEPARMS pParmsDst, PVBOXCLIPBOARDOBJOPENCREATEPARMS pParmsSrc)
659{
660 int rc;
661
662 *pParmsDst = *pParmsSrc;
663
664 if (pParmsSrc->pszPath)
665 {
666 Assert(pParmsSrc->cbPath);
667 pParmsDst->pszPath = RTStrDup(pParmsSrc->pszPath);
668 if (pParmsDst->pszPath)
669 {
670 rc = VINF_SUCCESS;
671 }
672 else
673 rc = VERR_NO_MEMORY;
674 }
675 else
676 rc = VINF_SUCCESS;
677
678 LogFlowFuncLeaveRC(rc);
679 return rc;
680}
681
682/**
683 * Destroys an URI object open parameters structure.
684 *
685 * @param pParms URI object open parameters structure to destroy.
686 */
687void SharedClipboardURIObjectOpenParmsDestroy(PVBOXCLIPBOARDOBJOPENCREATEPARMS pParms)
688{
689 if (!pParms)
690 return;
691
692 if (pParms->pszPath)
693 {
694 RTStrFree(pParms->pszPath);
695 pParms->pszPath = NULL;
696 }
697}
698
699/**
700 * Opens an URI object.
701 *
702 * @returns VBox status code.
703 * @param pTransfer URI clipboard transfer to open the object for.
704 * @param pOpenCreateParms Open / create parameters of URI object to open / create.
705 * @param phObj Where to store the handle of URI object opened on success.
706 */
707int SharedClipboardURIObjectOpen(PSHAREDCLIPBOARDURITRANSFER pTransfer, PVBOXCLIPBOARDOBJOPENCREATEPARMS pOpenCreateParms,
708 PSHAREDCLIPBOARDOBJHANDLE phObj)
709{
710 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
711 AssertPtrReturn(pOpenCreateParms, VERR_INVALID_POINTER);
712 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
713
714 int rc = VINF_SUCCESS;
715
716 LogFlowFunc(("pszPath=%s, fCreate=0x%x\n", pOpenCreateParms->pszPath, pOpenCreateParms->fCreate));
717
718 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
719 {
720 PSHAREDCLIPBOARDURIOBJHANDLEINFO pInfo
721 = (PSHAREDCLIPBOARDURIOBJHANDLEINFO)RTMemAlloc(sizeof(SHAREDCLIPBOARDURIOBJHANDLEINFO));
722 if (pInfo)
723 {
724 const bool fWritable = true; /** @todo Fix this. */
725
726 uint64_t fOpen;
727 rc = sharedClipboardConvertFileCreateFlags(fWritable,
728 pOpenCreateParms->fCreate, pOpenCreateParms->ObjInfo.Attr.fMode,
729 SHAREDCLIPBOARDOBJHANDLE_INVALID, &fOpen);
730 if (RT_SUCCESS(rc))
731 {
732 char *pszPathAbs = RTStrAPrintf2("%s/%s", pTransfer->pszPathRootAbs, pOpenCreateParms->pszPath);
733 if (pszPathAbs)
734 {
735 LogFlowFunc(("%s\n", pszPathAbs));
736
737 rc = RTFileOpen(&pInfo->u.Local.hFile, pszPathAbs, fOpen);
738 RTStrFree(pszPathAbs);
739 }
740 else
741 rc = VERR_NO_MEMORY;
742 }
743
744 if (RT_SUCCESS(rc))
745 {
746 const SHAREDCLIPBOARDOBJHANDLE hObj = pTransfer->uObjHandleNext++;
747
748 pInfo->enmType = SHAREDCLIPBOARDURIOBJTYPE_FILE;
749
750 pTransfer->pMapObj->insert(
751 std::pair<SHAREDCLIPBOARDOBJHANDLE, PSHAREDCLIPBOARDURIOBJHANDLEINFO>(hObj, pInfo));
752
753 *phObj = hObj;
754 }
755
756 if (RT_FAILURE(rc))
757 RTMemFree(pInfo);
758 }
759 else
760 rc = VERR_NO_MEMORY;
761 }
762 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
763 {
764 if (pTransfer->ProviderIface.pfnObjOpen)
765 {
766 rc = pTransfer->ProviderIface.pfnObjOpen(&pTransfer->ProviderCtx, pOpenCreateParms, phObj);
767 }
768 else
769 rc = VERR_NOT_SUPPORTED;
770 }
771
772 LogFlowFuncLeaveRC(rc);
773 return rc;
774}
775
776/**
777 * Closes an URI object.
778 *
779 * @returns VBox status code.
780 * @param pTransfer URI clipboard transfer that contains the object to close.
781 * @param hObj Handle of URI object to close.
782 */
783int SharedClipboardURIObjectClose(PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDOBJHANDLE hObj)
784{
785 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
786
787 int rc = VINF_SUCCESS;
788
789 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
790 {
791 SharedClipboardURIObjMap::iterator itObj = pTransfer->pMapObj->find(hObj);
792 if (itObj != pTransfer->pMapObj->end())
793 {
794 PSHAREDCLIPBOARDURIOBJHANDLEINFO pInfo = itObj->second;
795 AssertPtr(pInfo);
796
797 switch (pInfo->enmType)
798 {
799 case SHAREDCLIPBOARDURIOBJTYPE_DIRECTORY:
800 {
801 rc = RTDirClose(pInfo->u.Local.hDir);
802 if (RT_SUCCESS(rc))
803 pInfo->u.Local.hDir = NIL_RTDIR;
804 break;
805 }
806
807 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
808 {
809 rc = RTFileClose(pInfo->u.Local.hFile);
810 if (RT_SUCCESS(rc))
811 pInfo->u.Local.hFile = NIL_RTFILE;
812 break;
813 }
814
815 default:
816 rc = VERR_NOT_IMPLEMENTED;
817 break;
818 }
819
820 RTMemFree(pInfo);
821
822 pTransfer->pMapObj->erase(itObj);
823 }
824 else
825 rc = VERR_NOT_FOUND;
826 }
827 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
828 {
829 if (pTransfer->ProviderIface.pfnObjClose)
830 {
831 rc = pTransfer->ProviderIface.pfnObjClose(&pTransfer->ProviderCtx, hObj);
832 }
833 else
834 rc = VERR_NOT_SUPPORTED;
835 }
836
837 LogFlowFuncLeaveRC(rc);
838 return rc;
839}
840
841/**
842 * Reads from an URI object.
843 *
844 * @returns VBox status code.
845 * @param pTransfer URI clipboard transfer that contains the object to read from.
846 * @param hObj Handle of URI object to read from.
847 * @param pvBuf Buffer for where to store the read data.
848 * @param cbBuf Size (in bytes) of buffer.
849 * @param pcbRead How much bytes were read on success. Optional.
850 */
851int SharedClipboardURIObjectRead(PSHAREDCLIPBOARDURITRANSFER pTransfer,
852 SHAREDCLIPBOARDOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead, uint32_t fFlags)
853{
854 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
855 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
856 AssertReturn (cbBuf, VERR_INVALID_PARAMETER);
857 /* pcbRead is optional. */
858 /** @todo Validate fFlags. */
859
860 int rc = VINF_SUCCESS;
861
862 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
863 {
864 SharedClipboardURIObjMap::iterator itObj = pTransfer->pMapObj->find(hObj);
865 if (itObj != pTransfer->pMapObj->end())
866 {
867 PSHAREDCLIPBOARDURIOBJHANDLEINFO pInfo = itObj->second;
868 AssertPtr(pInfo);
869
870 switch (pInfo->enmType)
871 {
872 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
873 {
874 size_t cbRead;
875 rc = RTFileRead(pInfo->u.Local.hFile, pvBuf, cbBuf, &cbRead);
876 if (RT_SUCCESS(rc))
877 {
878 if (pcbRead)
879 *pcbRead = (uint32_t)cbRead;
880 }
881 break;
882 }
883
884 default:
885 rc = VERR_NOT_SUPPORTED;
886 break;
887 }
888 }
889 else
890 rc = VERR_NOT_FOUND;
891 }
892 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
893 {
894 if (pTransfer->ProviderIface.pfnObjRead)
895 {
896 rc = pTransfer->ProviderIface.pfnObjRead(&pTransfer->ProviderCtx, hObj, pvBuf, cbBuf, fFlags, pcbRead);
897 }
898 else
899 rc = VERR_NOT_SUPPORTED;
900 }
901
902 LogFlowFuncLeaveRC(rc);
903 return rc;
904}
905
906/**
907 * Writes to an URI object.
908 *
909 * @returns VBox status code.
910 * @param pTransfer URI clipboard transfer that contains the object to write to.
911 * @param hObj Handle of URI object to write to.
912 * @param pvBuf Buffer of data to write.
913 * @param cbBuf Size (in bytes) of buffer to write.
914 * @param pcbWritten How much bytes were writtenon success. Optional.
915 */
916int SharedClipboardURIObjectWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer,
917 SHAREDCLIPBOARDOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten,
918 uint32_t fFlags)
919{
920 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
921 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
922 AssertReturn (cbBuf, VERR_INVALID_PARAMETER);
923 /* pcbWritten is optional. */
924
925 int rc = VINF_SUCCESS;
926
927 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
928 {
929 SharedClipboardURIObjMap::iterator itObj = pTransfer->pMapObj->find(hObj);
930 if (itObj != pTransfer->pMapObj->end())
931 {
932 PSHAREDCLIPBOARDURIOBJHANDLEINFO pInfo = itObj->second;
933 AssertPtr(pInfo);
934
935 switch (pInfo->enmType)
936 {
937 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
938 {
939 rc = RTFileWrite(pInfo->u.Local.hFile, pvBuf, cbBuf, (size_t *)pcbWritten);
940 break;
941 }
942
943 default:
944 rc = VERR_NOT_SUPPORTED;
945 break;
946 }
947 }
948 else
949 rc = VERR_NOT_FOUND;
950 }
951 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
952 {
953 if (pTransfer->ProviderIface.pfnObjWrite)
954 {
955 rc = pTransfer->ProviderIface.pfnObjWrite(&pTransfer->ProviderCtx, hObj, pvBuf, cbBuf, fFlags, pcbWritten);
956 }
957 else
958 rc = VERR_NOT_SUPPORTED;
959 }
960
961 LogFlowFuncLeaveRC(rc);
962 return rc;
963}
964
965/**
966 * Duplicaates an URI object data chunk.
967 *
968 * @returns Duplicated object data chunk on success, or NULL on failure.
969 * @param pDataChunk URI object data chunk to duplicate.
970 */
971PVBOXCLIPBOARDOBJDATACHUNK SharedClipboardURIObjectDataChunkDup(PVBOXCLIPBOARDOBJDATACHUNK pDataChunk)
972{
973 if (!pDataChunk)
974 return NULL;
975
976 PVBOXCLIPBOARDOBJDATACHUNK pDataChunkDup = (PVBOXCLIPBOARDOBJDATACHUNK)RTMemAllocZ(sizeof(VBOXCLIPBOARDOBJDATACHUNK));
977 if (!pDataChunkDup)
978 return NULL;
979
980 if (pDataChunk->pvData)
981 {
982 Assert(pDataChunk->cbData);
983
984 pDataChunkDup->uHandle = pDataChunk->uHandle;
985 pDataChunkDup->pvData = RTMemDup(pDataChunk->pvData, pDataChunk->cbData);
986 pDataChunkDup->cbData = pDataChunk->cbData;
987 }
988
989 return pDataChunkDup;
990}
991
992/**
993 * Destroys an URI object data chunk.
994 *
995 * @param pDataChunk URI object data chunk to destroy.
996 */
997void SharedClipboardURIObjectDataChunkDestroy(PVBOXCLIPBOARDOBJDATACHUNK pDataChunk)
998{
999 if (!pDataChunk)
1000 return;
1001
1002 if (pDataChunk->pvData)
1003 {
1004 Assert(pDataChunk->cbData);
1005
1006 RTMemFree(pDataChunk->pvData);
1007
1008 pDataChunk->pvData = NULL;
1009 pDataChunk->cbData = 0;
1010 }
1011
1012 pDataChunk->uHandle = 0;
1013}
1014
1015/**
1016 * Frees an URI object data chunk.
1017 *
1018 * @param pDataChunk URI object data chunk to free. The handed-in pointer will
1019 * be invalid after calling this function.
1020 */
1021void SharedClipboardURIObjectDataChunkFree(PVBOXCLIPBOARDOBJDATACHUNK pDataChunk)
1022{
1023 if (!pDataChunk)
1024 return;
1025
1026 SharedClipboardURIObjectDataChunkDestroy(pDataChunk);
1027
1028 RTMemFree(pDataChunk);
1029 pDataChunk = NULL;
1030}
1031
1032/**
1033 * Initializes an URI clipboard transfer struct.
1034 *
1035 * @returns VBox status code.
1036 * @param enmDir Specifies the transfer direction of this transfer.
1037 * @param enmSource Specifies the data source of the transfer.
1038 * @param ppTransfer Where to return the created URI transfer struct.
1039 * Must be destroyed by SharedClipboardURITransferDestroy().
1040 */
1041int SharedClipboardURITransferCreate(SHAREDCLIPBOARDURITRANSFERDIR enmDir, SHAREDCLIPBOARDSOURCE enmSource,
1042 PSHAREDCLIPBOARDURITRANSFER *ppTransfer)
1043{
1044 AssertPtrReturn(ppTransfer, VERR_INVALID_POINTER);
1045
1046 LogFlowFuncEnter();
1047
1048 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)RTMemAlloc(sizeof(SHAREDCLIPBOARDURITRANSFER));
1049 if (!pTransfer)
1050 return VERR_NO_MEMORY;
1051
1052 int rc = VINF_SUCCESS;
1053
1054 pTransfer->State.uID = 0;
1055 pTransfer->State.enmStatus = SHAREDCLIPBOARDURITRANSFERSTATUS_NONE;
1056 pTransfer->State.enmDir = enmDir;
1057 pTransfer->State.enmSource = enmSource;
1058
1059 LogFlowFunc(("enmDir=%RU32, enmSource=%RU32\n", pTransfer->State.enmDir, pTransfer->State.enmSource));
1060
1061 pTransfer->pArea = NULL; /* Will be created later if needed. */
1062
1063 pTransfer->Thread.hThread = NIL_RTTHREAD;
1064 pTransfer->Thread.fCancelled = false;
1065 pTransfer->Thread.fStarted = false;
1066 pTransfer->Thread.fStop = false;
1067
1068 pTransfer->pszPathRootAbs = NULL;
1069
1070 pTransfer->uListHandleNext = 1;
1071 pTransfer->uObjHandleNext = 1;
1072 pTransfer->uEventIDNext = 1;
1073
1074 pTransfer->uTimeoutMs = 30 * 1000; /* 30s timeout by default. */
1075 pTransfer->cbMaxChunkSize = _64K; /** @todo Make this configurable. */
1076
1077 pTransfer->pvUser = NULL;
1078 pTransfer->cbUser = 0;
1079
1080 RT_ZERO(pTransfer->Callbacks);
1081
1082 pTransfer->pMapEvents = new SharedClipboardURITransferEventMap();
1083 if (pTransfer->pMapEvents)
1084 {
1085 pTransfer->pMapLists = new SharedClipboardURIListMap();
1086 if (pTransfer->pMapLists)
1087 {
1088 pTransfer->pMapObj = new SharedClipboardURIObjMap();
1089 if (pTransfer->pMapObj)
1090 *ppTransfer = pTransfer;
1091 }
1092 }
1093 else
1094 rc = VERR_NO_MEMORY;
1095
1096 if (RT_FAILURE(rc))
1097 {
1098 RTMemFree(pTransfer);
1099 }
1100
1101 LogFlowFuncLeaveRC(rc);
1102 return rc;
1103}
1104
1105/**
1106 * Destroys an URI clipboard transfer context struct.
1107 *
1108 * @returns VBox status code.
1109 * @param pURI URI clipboard transfer to destroy.
1110 */
1111int SharedClipboardURITransferDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1112{
1113 if (!pTransfer)
1114 return VINF_SUCCESS;
1115
1116 LogFlowFuncEnter();
1117
1118 int rc = sharedClipboardURITransferThreadDestroy(pTransfer, 30 * 1000 /* Timeout in ms */);
1119 if (RT_FAILURE(rc))
1120 return rc;
1121
1122 RTStrFree(pTransfer->pszPathRootAbs);
1123
1124 if (pTransfer->pMapEvents)
1125 {
1126 SharedClipboardURITransferEventMap::iterator itEvent = pTransfer->pMapEvents->begin();
1127 while (itEvent != pTransfer->pMapEvents->end())
1128 {
1129
1130 itEvent = pTransfer->pMapEvents->begin();
1131 }
1132
1133 delete pTransfer->pMapEvents;
1134 pTransfer->pMapEvents = NULL;
1135 }
1136
1137 if (pTransfer->pMapLists)
1138 {
1139 SharedClipboardURIListMap::iterator itList = pTransfer->pMapLists->begin();
1140 while (itList != pTransfer->pMapLists->end())
1141 {
1142 SharedClipboardURIListHandleInfoDestroy(itList->second);
1143 pTransfer->pMapLists->erase(itList);
1144 itList = pTransfer->pMapLists->begin();
1145 }
1146
1147 Assert(pTransfer->pMapLists->size() == 0);
1148
1149 delete pTransfer->pMapLists;
1150 pTransfer->pMapLists = NULL;
1151 }
1152
1153 if (pTransfer->pMapObj)
1154 {
1155 SharedClipboardURIObjMap::iterator itObj = pTransfer->pMapObj->begin();
1156 while (itObj != pTransfer->pMapObj->end())
1157 {
1158 SharedClipboardURIObjectHandleInfoDestroy(itObj->second);
1159 pTransfer->pMapObj->erase(itObj);
1160 itObj = pTransfer->pMapObj->begin();
1161 }
1162
1163 Assert(pTransfer->pMapObj->size() == 0);
1164
1165 delete pTransfer->pMapObj;
1166 pTransfer->pMapObj = NULL;
1167 }
1168
1169 LogFlowFuncLeave();
1170 return VINF_SUCCESS;
1171}
1172
1173int SharedClipboardURITransferOpen(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1174{
1175 int rc = VINF_SUCCESS;
1176
1177 if (pTransfer->ProviderIface.pfnTransferOpen)
1178 rc = pTransfer->ProviderIface.pfnTransferOpen(&pTransfer->ProviderCtx);
1179
1180 LogFlowFuncLeaveRC(rc);
1181 return rc;
1182}
1183
1184int SharedClipboardURITransferClose(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1185{
1186 int rc = VINF_SUCCESS;
1187
1188 if (pTransfer->ProviderIface.pfnTransferClose)
1189 rc = pTransfer->ProviderIface.pfnTransferClose(&pTransfer->ProviderCtx);
1190
1191 LogFlowFuncLeaveRC(rc);
1192 return rc;
1193}
1194
1195/**
1196 * Creates a new list handle (local only).
1197 *
1198 * @returns New List handle on success, or SHAREDCLIPBOARDLISTHANDLE_INVALID on error.
1199 * @param pTransfer URI clipboard transfer to create new list handle for.
1200 */
1201static SHAREDCLIPBOARDLISTHANDLE sharedClipboardURITransferListHandleNew(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1202{
1203 return pTransfer->uListHandleNext++; /** @todo Good enough for now. Improve this later. */
1204}
1205
1206/**
1207 * Opens a list.
1208 *
1209 * @returns VBox status code.
1210 * @param pTransfer URI clipboard transfer to handle.
1211 * @param pOpenParms List open parameters to use for opening.
1212 * @param phList Where to store the List handle of opened list on success.
1213 */
1214int SharedClipboardURITransferListOpen(PSHAREDCLIPBOARDURITRANSFER pTransfer, PVBOXCLIPBOARDLISTOPENPARMS pOpenParms,
1215 PSHAREDCLIPBOARDLISTHANDLE phList)
1216{
1217 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1218 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1219 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1220
1221 int rc;
1222
1223 SHAREDCLIPBOARDLISTHANDLE hList = SHAREDCLIPBOARDLISTHANDLE_INVALID;
1224
1225 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
1226 {
1227 PSHAREDCLIPBOARDURILISTHANDLEINFO pInfo
1228 = (PSHAREDCLIPBOARDURILISTHANDLEINFO)RTMemAlloc(sizeof(SHAREDCLIPBOARDURILISTHANDLEINFO));
1229 if (pInfo)
1230 {
1231 LogFlowFunc(("pszPath=%s\n", pOpenParms->pszPath));
1232
1233 RTFSOBJINFO objInfo;
1234 rc = RTPathQueryInfo(pOpenParms->pszPath, &objInfo, RTFSOBJATTRADD_NOTHING);
1235 if (RT_SUCCESS(rc))
1236 {
1237 switch (pInfo->enmType)
1238 {
1239 case SHAREDCLIPBOARDURIOBJTYPE_DIRECTORY:
1240 {
1241 rc = RTDirOpen(&pInfo->u.Local.hDir, pOpenParms->pszPath);
1242 }
1243
1244 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
1245 {
1246 rc = RTFileOpen(&pInfo->u.Local.hFile, pOpenParms->pszPath,
1247 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
1248 break;
1249 }
1250
1251 default:
1252 rc = VERR_NOT_SUPPORTED;
1253 break;
1254 }
1255
1256 if (RT_SUCCESS(rc))
1257 {
1258 hList = sharedClipboardURITransferListHandleNew(pTransfer);
1259
1260 pTransfer->pMapLists->insert(
1261 std::pair<SHAREDCLIPBOARDLISTHANDLE, PSHAREDCLIPBOARDURILISTHANDLEINFO>(hList, pInfo)); /** @todo Can this throw? */
1262 }
1263 else
1264 {
1265 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
1266 {
1267 if (RTDirIsValid(pInfo->u.Local.hDir))
1268 RTDirClose(pInfo->u.Local.hDir);
1269 }
1270 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
1271 {
1272 if (RTFileIsValid(pInfo->u.Local.hFile))
1273 RTFileClose(pInfo->u.Local.hFile);
1274 }
1275
1276 RTMemFree(pInfo);
1277 pInfo = NULL;
1278 }
1279 }
1280 }
1281 else
1282 rc = VERR_NO_MEMORY;
1283 }
1284 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
1285 {
1286 if (pTransfer->ProviderIface.pfnListOpen)
1287 {
1288 rc = pTransfer->ProviderIface.pfnListOpen(&pTransfer->ProviderCtx, pOpenParms, &hList);
1289 }
1290 else
1291 rc = VERR_NOT_SUPPORTED;
1292 }
1293 else
1294 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
1295
1296 if (RT_SUCCESS(rc))
1297 *phList = hList;
1298
1299 LogFlowFuncLeaveRC(rc);
1300 return rc;
1301}
1302
1303/**
1304 * Closes a list.
1305 *
1306 * @returns VBox status code.
1307 * @param pTransfer URI clipboard transfer to handle.
1308 * @param hList Handle of list to close.
1309 */
1310int SharedClipboardURITransferListClose(PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDLISTHANDLE hList)
1311{
1312 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1313
1314 if (hList == SHAREDCLIPBOARDLISTHANDLE_INVALID)
1315 return VINF_SUCCESS;
1316
1317 int rc = VINF_SUCCESS;
1318
1319 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
1320 {
1321 SharedClipboardURIListMap::iterator itList = pTransfer->pMapLists->find(hList);
1322 if (itList != pTransfer->pMapLists->end())
1323 {
1324 PSHAREDCLIPBOARDURILISTHANDLEINFO pInfo = itList->second;
1325 AssertPtr(pInfo);
1326
1327 switch (pInfo->enmType)
1328 {
1329 case SHAREDCLIPBOARDURIOBJTYPE_DIRECTORY:
1330 {
1331 if (RTDirIsValid(pInfo->u.Local.hDir))
1332 RTDirClose(pInfo->u.Local.hDir);
1333 break;
1334 }
1335
1336 default:
1337 rc = VERR_NOT_SUPPORTED;
1338 break;
1339 }
1340
1341 RTMemFree(pInfo);
1342
1343 pTransfer->pMapLists->erase(itList);
1344 }
1345 else
1346 rc = VERR_NOT_FOUND;
1347 }
1348 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
1349 {
1350 if (pTransfer->ProviderIface.pfnListClose)
1351 {
1352 rc = pTransfer->ProviderIface.pfnListClose(&pTransfer->ProviderCtx, hList);
1353 }
1354 else
1355 rc = VERR_NOT_SUPPORTED;
1356 }
1357
1358 LogFlowFuncLeaveRC(rc);
1359 return rc;
1360}
1361
1362/**
1363 * Adds a file to a list heaer.
1364 *
1365 * @returns VBox status code.
1366 * @param pHdr List header to add file to.
1367 * @param pszPath Path of file to add.
1368 */
1369static int sharedClipboardURITransferListHdrAddFile(PVBOXCLIPBOARDLISTHDR pHdr, const char *pszPath)
1370{
1371 uint64_t cbSize = 0;
1372 int rc = RTFileQuerySize(pszPath, &cbSize);
1373 if (RT_SUCCESS(rc))
1374 {
1375 pHdr->cbTotalSize += cbSize;
1376 pHdr->cTotalObjects++;
1377 }
1378
1379 LogFlowFuncLeaveRC(rc);
1380 return rc;
1381}
1382
1383/**
1384 * Builds a list header, internal version.
1385 *
1386 * @returns VBox status code.
1387 * @param pHdr Where to store the build list header.
1388 * @param pcszSrcPath Source path of list.
1389 * @param pcszDstPath Destination path of list.
1390 * @param pcszDstBase Destination base path.
1391 * @param cchDstBase Number of charaters of destination base path.
1392 */
1393static int sharedClipboardURITransferListHdrFromDir(PVBOXCLIPBOARDLISTHDR pHdr,
1394 const char *pcszSrcPath, const char *pcszDstPath,
1395 const char *pcszDstBase)
1396{
1397 AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER);
1398 AssertPtrReturn(pcszDstBase, VERR_INVALID_POINTER);
1399 AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER);
1400
1401 LogFlowFunc(("pcszSrcPath=%s, pcszDstPath=%s, pcszDstBase=%s\n",
1402 pcszSrcPath, pcszDstPath, pcszDstBase));
1403
1404 RTFSOBJINFO objInfo;
1405 int rc = RTPathQueryInfo(pcszSrcPath, &objInfo, RTFSOBJATTRADD_NOTHING);
1406 if (RT_SUCCESS(rc))
1407 {
1408 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
1409 {
1410 pHdr->cTotalObjects++;
1411
1412 RTDIR hDir;
1413 rc = RTDirOpen(&hDir, pcszSrcPath);
1414 if (RT_SUCCESS(rc))
1415 {
1416 size_t cbDirEntry = 0;
1417 PRTDIRENTRYEX pDirEntry = NULL;
1418 do
1419 {
1420 /* Retrieve the next directory entry. */
1421 rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
1422 if (RT_FAILURE(rc))
1423 {
1424 if (rc == VERR_NO_MORE_FILES)
1425 rc = VINF_SUCCESS;
1426 break;
1427 }
1428
1429 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
1430 {
1431 #if 0 /* No recursion here (yet). */
1432 case RTFS_TYPE_DIRECTORY:
1433 {
1434 /* Skip "." and ".." entries. */
1435 if (RTDirEntryExIsStdDotLink(pDirEntry))
1436 break;
1437
1438 char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName);
1439 if (pszSrc)
1440 {
1441 char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName);
1442 if (pszDst)
1443 {
1444 rc = sharedClipboardURITransferListHdrFromDir(pHdr, pszSrc, pszDst,
1445 pcszDstBase, cchDstBase);
1446 RTStrFree(pszDst);
1447 }
1448 else
1449 rc = VERR_NO_MEMORY;
1450
1451 RTStrFree(pszSrc);
1452 }
1453 else
1454 rc = VERR_NO_MEMORY;
1455 break;
1456 }
1457 #endif
1458 case RTFS_TYPE_FILE:
1459 {
1460 char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName);
1461 if (pszSrc)
1462 {
1463 rc = sharedClipboardURITransferListHdrAddFile(pHdr, pszSrc);
1464 RTStrFree(pszSrc);
1465 }
1466 else
1467 rc = VERR_NO_MEMORY;
1468 break;
1469 }
1470 case RTFS_TYPE_SYMLINK:
1471 {
1472 /** @todo Not implemented yet. */
1473 }
1474
1475 default:
1476 break;
1477 }
1478
1479 } while (RT_SUCCESS(rc));
1480
1481 RTDirReadExAFree(&pDirEntry, &cbDirEntry);
1482 RTDirClose(hDir);
1483 }
1484 }
1485 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
1486 {
1487 rc = sharedClipboardURITransferListHdrAddFile(pHdr, pcszSrcPath);
1488 }
1489 else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))
1490 {
1491 /** @todo Not implemented yet. */
1492 }
1493 else
1494 rc = VERR_NOT_SUPPORTED;
1495 }
1496
1497 LogFlowFuncLeaveRC(rc);
1498 return rc;
1499}
1500
1501/**
1502 * Translates an absolute path to a relative one.
1503 *
1504 * @returns Translated, allocated path on success, or NULL on failure.
1505 * Must be free'd with RTStrFree().
1506 * @param pszPath Absolute path to translate.
1507 */
1508static char *sharedClipboardPathTranslate(const char *pszPath)
1509{
1510 char *pszPathTranslated = NULL;
1511
1512 char *pszSrcPath = RTStrDup(pszPath);
1513 if (pszSrcPath)
1514 {
1515 size_t cbSrcPathLen = RTPathStripTrailingSlash(pszSrcPath);
1516 if (cbSrcPathLen)
1517 {
1518 char *pszFileName = RTPathFilename(pszSrcPath);
1519 if (pszFileName)
1520 {
1521 Assert(pszFileName >= pszSrcPath);
1522 size_t cchDstBase = pszFileName - pszSrcPath;
1523
1524 pszPathTranslated = RTStrDup(&pszSrcPath[cchDstBase]);
1525
1526 LogFlowFunc(("pszSrcPath=%s, pszFileName=%s -> pszPathTranslated=%s\n",
1527 pszSrcPath, pszFileName, pszPathTranslated));
1528 }
1529 }
1530
1531 RTStrFree(pszSrcPath);
1532 }
1533
1534 return pszPathTranslated;
1535}
1536
1537/**
1538 * Retrieves the header of a Shared Clipboard list.
1539 *
1540 * @returns VBox status code.
1541 * @param pTransfer URI clipboard transfer to handle.
1542 * @param hList Handle of list to get header for.
1543 * @param pHdr Where to store the returned list header information.
1544 */
1545int SharedClipboardURITransferListGetHeader(PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDLISTHANDLE hList,
1546 PVBOXCLIPBOARDLISTHDR pHdr)
1547{
1548 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1549 AssertPtrReturn(pHdr, VERR_INVALID_POINTER);
1550
1551 int rc;
1552
1553 LogFlowFunc(("hList=%RU64\n", hList));
1554
1555 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
1556 {
1557 SharedClipboardURIListMap::iterator itList = pTransfer->pMapLists->find(hList);
1558 if (itList != pTransfer->pMapLists->end())
1559 {
1560 rc = SharedClipboardURIListHdrInit(pHdr);
1561 if (RT_SUCCESS(rc))
1562 {
1563 PSHAREDCLIPBOARDURILISTHANDLEINFO pInfo = itList->second;
1564 AssertPtr(pInfo);
1565
1566 switch (pInfo->enmType)
1567 {
1568 case SHAREDCLIPBOARDURIOBJTYPE_DIRECTORY:
1569 {
1570 char *pszPathRel = sharedClipboardPathTranslate(pInfo->pszPathLocalAbs);
1571 if (pszPathRel)
1572 {
1573 rc = sharedClipboardURITransferListHdrFromDir(pHdr,
1574 pszPathRel, pszPathRel, pszPathRel);
1575 RTStrFree(pszPathRel);
1576 }
1577 else
1578 rc = VERR_NO_MEMORY;
1579 break;
1580 }
1581
1582 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
1583 {
1584 pHdr->cTotalObjects = 1;
1585
1586 RTFSOBJINFO objInfo;
1587 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);
1588 if (RT_SUCCESS(rc))
1589 {
1590 pHdr->cbTotalSize = objInfo.cbObject;
1591 }
1592 break;
1593 }
1594
1595 default:
1596 rc = VERR_NOT_SUPPORTED;
1597 break;
1598 }
1599 }
1600
1601 LogFlowFunc(("cTotalObj=%RU64, cbTotalSize=%RU64\n", pHdr->cTotalObjects, pHdr->cbTotalSize));
1602 }
1603 else
1604 rc = VERR_NOT_FOUND;
1605 }
1606 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
1607 {
1608 if (pTransfer->ProviderIface.pfnListHdrRead)
1609 {
1610 rc = pTransfer->ProviderIface.pfnListHdrRead(&pTransfer->ProviderCtx, hList, pHdr);
1611 }
1612 else
1613 rc = VERR_NOT_SUPPORTED;
1614 }
1615 else
1616 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
1617
1618 LogFlowFuncLeaveRC(rc);
1619 return rc;
1620}
1621
1622/**
1623 * Returns the current URI object for a clipboard URI transfer list.
1624 *
1625 * Currently not implemented and wil return NULL.
1626 *
1627 * @returns Pointer to URI object, or NULL if not found / invalid.
1628 * @param pTransfer URI clipboard transfer to return URI object for.
1629 * @param hList Handle of URI transfer list to get object for.
1630 * @param uIdx Index of object to get.
1631 */
1632PSHAREDCLIPBOARDURITRANSFEROBJ SharedClipboardURITransferListGetObj(PSHAREDCLIPBOARDURITRANSFER pTransfer,
1633 SHAREDCLIPBOARDLISTHANDLE hList, uint64_t uIdx)
1634{
1635 AssertPtrReturn(pTransfer, NULL);
1636
1637 RT_NOREF(hList, uIdx);
1638
1639 LogFlowFunc(("hList=%RU64\n", hList));
1640
1641 return NULL;
1642}
1643
1644/**
1645 * Reads a single Shared Clipboard list entry.
1646 *
1647 * @returns VBox status code or VERR_NO_MORE_FILES if the end of the list has been reached.
1648 * @param pTransfer URI clipboard transfer to handle.
1649 * @param hList List handle of list to read from.
1650 * @param pEntry Where to store the read information.
1651 */
1652int SharedClipboardURITransferListRead(PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDLISTHANDLE hList,
1653 PVBOXCLIPBOARDLISTENTRY pEntry)
1654{
1655 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1656 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
1657
1658 int rc = VINF_SUCCESS;
1659
1660 LogFlowFunc(("hList=%RU64\n", hList));
1661
1662 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
1663 {
1664 SharedClipboardURIListMap::iterator itList = pTransfer->pMapLists->find(hList);
1665 if (itList != pTransfer->pMapLists->end())
1666 {
1667 PSHAREDCLIPBOARDURILISTHANDLEINFO pInfo = itList->second;
1668 AssertPtr(pInfo);
1669
1670 switch (pInfo->enmType)
1671 {
1672 case SHAREDCLIPBOARDURIOBJTYPE_DIRECTORY:
1673 {
1674 LogFlowFunc(("\tDirectory: %s\n", pInfo->pszPathLocalAbs));
1675
1676 for (;;)
1677 {
1678 bool fSkipEntry = false; /* Whether to skip an entry in the enumeration. */
1679
1680 size_t cbDirEntry = 0;
1681 PRTDIRENTRYEX pDirEntry = NULL;
1682 rc = RTDirReadExA(pInfo->u.Local.hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
1683 if (RT_SUCCESS(rc))
1684 {
1685 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
1686 {
1687 case RTFS_TYPE_DIRECTORY:
1688 {
1689 /* Skip "." and ".." entries. */
1690 if (RTDirEntryExIsStdDotLink(pDirEntry))
1691 {
1692 fSkipEntry = true;
1693 break;
1694 }
1695
1696 LogFlowFunc(("Directory: %s\n", pDirEntry->szName));
1697 break;
1698 }
1699
1700 case RTFS_TYPE_FILE:
1701 {
1702 LogFlowFunc(("File: %s\n", pDirEntry->szName));
1703 break;
1704 }
1705
1706 case RTFS_TYPE_SYMLINK:
1707 {
1708 rc = VERR_NOT_IMPLEMENTED; /** @todo Not implemented yet. */
1709 break;
1710 }
1711
1712 default:
1713 break;
1714 }
1715
1716 if ( RT_SUCCESS(rc)
1717 && !fSkipEntry)
1718 {
1719 pEntry->pvInfo = (PSHAREDCLIPBOARDFSOBJINFO)RTMemAlloc(sizeof(SHAREDCLIPBOARDFSOBJINFO));
1720 if (pEntry->pvInfo)
1721 {
1722 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pDirEntry->szName);
1723 if (RT_SUCCESS(rc))
1724 {
1725 SharedClipboardFsObjFromIPRT(PSHAREDCLIPBOARDFSOBJINFO(pEntry->pvInfo), &pDirEntry->Info);
1726
1727 pEntry->cbInfo = sizeof(SHAREDCLIPBOARDFSOBJINFO);
1728 pEntry->fInfo = VBOX_SHAREDCLIPBOARD_INFO_FLAG_FSOBJINFO;
1729 }
1730 }
1731 else
1732 rc = VERR_NO_MEMORY;
1733 }
1734
1735 RTDirReadExAFree(&pDirEntry, &cbDirEntry);
1736 }
1737
1738 if ( !fSkipEntry /* Do we have a valid entry? Bail out. */
1739 || RT_FAILURE(rc))
1740 {
1741 break;
1742 }
1743 }
1744
1745 break;
1746 }
1747
1748 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
1749 {
1750 LogFlowFunc(("\tSingle file: %s\n", pInfo->pszPathLocalAbs));
1751
1752 RTFSOBJINFO objInfo;
1753 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);
1754 if (RT_SUCCESS(rc))
1755 {
1756 pEntry->pvInfo = (PSHAREDCLIPBOARDFSOBJINFO)RTMemAlloc(sizeof(SHAREDCLIPBOARDFSOBJINFO));
1757 if (pEntry->pvInfo)
1758 {
1759 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pInfo->pszPathLocalAbs);
1760 if (RT_SUCCESS(rc))
1761 {
1762 SharedClipboardFsObjFromIPRT(PSHAREDCLIPBOARDFSOBJINFO(pEntry->pvInfo), &objInfo);
1763
1764 pEntry->cbInfo = sizeof(SHAREDCLIPBOARDFSOBJINFO);
1765 pEntry->fInfo = VBOX_SHAREDCLIPBOARD_INFO_FLAG_FSOBJINFO;
1766 }
1767 }
1768 else
1769 rc = VERR_NO_MEMORY;
1770 }
1771
1772 break;
1773 }
1774
1775 default:
1776 rc = VERR_NOT_SUPPORTED;
1777 break;
1778 }
1779 }
1780 else
1781 rc = VERR_NOT_FOUND;
1782 }
1783 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
1784 {
1785 if (pTransfer->ProviderIface.pfnListEntryRead)
1786 rc = pTransfer->ProviderIface.pfnListEntryRead(&pTransfer->ProviderCtx, hList, pEntry);
1787 else
1788 rc = VERR_NOT_SUPPORTED;
1789 }
1790
1791 LogFlowFuncLeaveRC(rc);
1792 return rc;
1793}
1794
1795int SharedClipboardURITransferListWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDLISTHANDLE hList,
1796 PVBOXCLIPBOARDLISTENTRY pEntry)
1797{
1798 RT_NOREF(pTransfer, hList, pEntry);
1799
1800 int rc = VINF_SUCCESS;
1801
1802#if 0
1803 if (pTransfer->ProviderIface.pfnListEntryWrite)
1804 rc = pTransfer->ProviderIface.pfnListEntryWrite(&pTransfer->ProviderCtx, hList, pEntry);
1805#endif
1806
1807 LogFlowFuncLeaveRC(rc);
1808 return rc;
1809}
1810
1811/**
1812 * Returns whether a given list handle is valid or not.
1813 *
1814 * @returns \c true if list handle is valid, \c false if not.
1815 * @param pTransfer URI clipboard transfer to handle.
1816 * @param hList List handle to check.
1817 */
1818bool SharedClipboardURITransferListHandleIsValid(PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDLISTHANDLE hList)
1819{
1820 bool fIsValid = false;
1821
1822 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
1823 {
1824 SharedClipboardURIListMap::iterator itList = pTransfer->pMapLists->find(hList);
1825 fIsValid = itList != pTransfer->pMapLists->end();
1826 }
1827 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
1828 {
1829 AssertFailed(); /** @todo Implement. */
1830 }
1831
1832 return fIsValid;
1833}
1834
1835/**
1836 * Prepares everything needed for a read / write transfer to begin.
1837 *
1838 * @returns VBox status code.
1839 * @param pTransfer URI clipboard transfer to prepare.
1840 */
1841int SharedClipboardURITransferPrepare(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1842{
1843 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1844
1845 LogFlowFuncEnter();
1846
1847 int rc = VINF_SUCCESS;
1848
1849 AssertMsgReturn(pTransfer->State.enmStatus == SHAREDCLIPBOARDURITRANSFERSTATUS_NONE,
1850 ("Transfer has wrong state (%RU32)\n", pTransfer->State.enmStatus), VERR_WRONG_ORDER);
1851
1852 LogFlowFunc(("pTransfer=%p, enmDir=%RU32\n", pTransfer, pTransfer->State.enmDir));
1853
1854 if (pTransfer->Callbacks.pfnTransferPrepare)
1855 {
1856 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1857 pTransfer->Callbacks.pfnTransferPrepare(&callbackData);
1858 }
1859
1860 if (RT_SUCCESS(rc))
1861 {
1862 pTransfer->State.enmStatus = SHAREDCLIPBOARDURITRANSFERSTATUS_READY;
1863
1864 /** @todo Add checksum support. */
1865 }
1866
1867 LogFlowFuncLeaveRC(rc);
1868 return rc;
1869}
1870
1871/**
1872 * Sets the URI provider interface for a given transfer.
1873 *
1874 * @returns VBox status code.
1875 * @param pTransfer Transfer to create URI provider for.
1876 * @param pCreationCtx Provider creation context to use for provider creation.
1877 */
1878int SharedClipboardURITransferSetInterface(PSHAREDCLIPBOARDURITRANSFER pTransfer,
1879 PSHAREDCLIPBOARDPROVIDERCREATIONCTX pCreationCtx)
1880{
1881 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1882 AssertPtrReturn(pCreationCtx, VERR_INVALID_POINTER);
1883
1884 LogFlowFuncEnter();
1885
1886 int rc = VINF_SUCCESS;
1887
1888 pTransfer->ProviderIface = pCreationCtx->Interface;
1889
1890 pTransfer->ProviderCtx.pTransfer = pTransfer;
1891 pTransfer->ProviderCtx.pvUser = pCreationCtx->pvUser;
1892
1893 LogFlowFuncLeaveRC(rc);
1894 return rc;
1895}
1896
1897/**
1898 * Clears (resets) the root list of an URI transfer.
1899 *
1900 * @param pTransfer Transfer to clear URI root list for.
1901 */
1902static void sharedClipboardURIListTransferRootsClear(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1903{
1904 AssertPtrReturnVoid(pTransfer);
1905
1906 if (pTransfer->pszPathRootAbs)
1907 {
1908 RTStrFree(pTransfer->pszPathRootAbs);
1909 pTransfer->pszPathRootAbs = NULL;
1910 }
1911
1912 pTransfer->lstRootEntries.clear();
1913}
1914
1915/**
1916 * Sets URI root list entries for a given transfer.
1917 *
1918 * @returns VBox status code.
1919 * @param pTransfer Transfer to set URI list entries for.
1920 * @param pszRoots String list (separated by CRLF) of root entries to set.
1921 * All entries must have the same root path.
1922 * @param cbRoots Size (in bytes) of string list.
1923 */
1924int SharedClipboardURILTransferSetRoots(PSHAREDCLIPBOARDURITRANSFER pTransfer, const char *pszRoots, size_t cbRoots)
1925{
1926 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1927 AssertPtrReturn(pszRoots, VERR_INVALID_POINTER);
1928 AssertReturn(cbRoots, VERR_INVALID_PARAMETER);
1929
1930 if (!RTStrIsValidEncoding(pszRoots))
1931 return VERR_INVALID_PARAMETER;
1932
1933 int rc = VINF_SUCCESS;
1934
1935 sharedClipboardURIListTransferRootsClear(pTransfer);
1936
1937 char *pszPathRootAbs = NULL;
1938
1939 RTCList<RTCString> lstRootEntries = RTCString(pszRoots, cbRoots - 1).split("\r\n");
1940 for (size_t i = 0; i < lstRootEntries.size(); ++i)
1941 {
1942 SHAREDCLIPBOARDURILISTROOT listRoot;
1943 listRoot.strPathAbs = lstRootEntries.at(i);
1944
1945 if (!pszPathRootAbs)
1946 {
1947 pszPathRootAbs = RTStrDup(listRoot.strPathAbs.c_str());
1948 if (pszPathRootAbs)
1949 {
1950 RTPathStripFilename(pszPathRootAbs);
1951 LogFlowFunc(("pszPathRootAbs=%s\n", pszPathRootAbs));
1952 }
1953 else
1954 rc = VERR_NO_MEMORY;
1955 }
1956
1957 if (RT_FAILURE(rc))
1958 break;
1959
1960 /* Make sure all entries have the same root path. */
1961 if (!RTStrStartsWith(listRoot.strPathAbs.c_str(), pszPathRootAbs))
1962 {
1963 rc = VERR_INVALID_PARAMETER;
1964 break;
1965 }
1966
1967 pTransfer->lstRootEntries.append(listRoot);
1968 }
1969
1970 /** @todo Entry rollback on failure? */
1971
1972 if (RT_SUCCESS(rc))
1973 {
1974 pTransfer->pszPathRootAbs = pszPathRootAbs;
1975 LogFlowFunc(("pszPathRootAbs=%s, cRoots=%zu\n", pTransfer->pszPathRootAbs, pTransfer->lstRootEntries.size()));
1976 }
1977
1978 LogFlowFuncLeaveRC(rc);
1979 return rc;
1980}
1981
1982/**
1983 * Resets an clipboard URI transfer.
1984 *
1985 * @param pTransfer URI clipboard transfer to reset.
1986 */
1987void SharedClipboardURITransferReset(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1988{
1989 AssertPtrReturnVoid(pTransfer);
1990
1991 LogFlowFuncEnter();
1992
1993 sharedClipboardURIListTransferRootsClear(pTransfer);
1994}
1995
1996/**
1997 * Returns the clipboard area for a clipboard URI transfer.
1998 *
1999 * @returns Current clipboard area, or NULL if none.
2000 * @param pTransfer URI clipboard transfer to return clipboard area for.
2001 */
2002SharedClipboardArea *SharedClipboardURITransferGetArea(PSHAREDCLIPBOARDURITRANSFER pTransfer)
2003{
2004 AssertPtrReturn(pTransfer, NULL);
2005
2006 return pTransfer->pArea;
2007}
2008
2009/**
2010 * Returns the number of URI root list entries.
2011 *
2012 * @returns Root list entry count.
2013 * @param pTransfer URI clipboard transfer to return root entry count for.
2014 */
2015uint32_t SharedClipboardURILTransferRootsCount(PSHAREDCLIPBOARDURITRANSFER pTransfer)
2016{
2017 AssertPtrReturn(pTransfer, 0);
2018
2019 return (uint32_t)pTransfer->lstRootEntries.size();
2020}
2021
2022/**
2023 * Get a specific root list entry.
2024 *
2025 * @returns VBox status code.
2026 * @param pTransfer URI clipboard transfer to get root list entry of.
2027 * @param uIndex Index (zero-based) of entry to get.
2028 * @param pEntry Where to store the returned entry on success.
2029 */
2030int SharedClipboardURILTransferRootsEntry(PSHAREDCLIPBOARDURITRANSFER pTransfer,
2031 uint32_t uIndex, PVBOXCLIPBOARDROOTLISTENTRY pEntry)
2032{
2033 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2034 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
2035
2036 if (uIndex >= pTransfer->lstRootEntries.size())
2037 return VERR_INVALID_PARAMETER;
2038
2039 int rc;
2040
2041 PSHAREDCLIPBOARDURILISTROOT pRoot = &pTransfer->lstRootEntries.at(uIndex);
2042 AssertPtrReturn(pRoot, VERR_INVALID_POINTER);
2043
2044 /* Make sure that we only advertise relative source paths, not absolute ones. */
2045 const char *pcszSrcPath = pRoot->strPathAbs.c_str();
2046
2047 char *pszFileName = RTPathFilename(pcszSrcPath);
2048 if (pszFileName)
2049 {
2050 Assert(pszFileName >= pcszSrcPath);
2051 size_t cchDstBase = pszFileName - pcszSrcPath;
2052 const char *pszDstPath = &pcszSrcPath[cchDstBase];
2053
2054 LogFlowFunc(("pcszSrcPath=%s, pszDstPath=%s\n", pcszSrcPath, pszDstPath));
2055
2056 rc = SharedClipboardURIListEntryInit(pEntry);
2057 if (RT_SUCCESS(rc))
2058 {
2059 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pszDstPath);
2060 if (RT_SUCCESS(rc))
2061 {
2062 pEntry->cbInfo = sizeof(SHAREDCLIPBOARDFSOBJINFO);
2063 pEntry->pvInfo = (PSHAREDCLIPBOARDFSOBJINFO)RTMemAlloc(pEntry->cbInfo);
2064 if (pEntry->pvInfo)
2065 {
2066 RTFSOBJINFO fsObjInfo;
2067 rc = RTPathQueryInfo(pcszSrcPath, & fsObjInfo, RTFSOBJATTRADD_NOTHING);
2068 if (RT_SUCCESS(rc))
2069 {
2070 SharedClipboardFsObjFromIPRT(PSHAREDCLIPBOARDFSOBJINFO(pEntry->pvInfo), &fsObjInfo);
2071
2072 pEntry->fInfo = VBOX_SHAREDCLIPBOARD_INFO_FLAG_FSOBJINFO;
2073 }
2074 }
2075 else
2076 rc = VERR_NO_MEMORY;
2077 }
2078 }
2079 }
2080 else
2081 rc = VERR_INVALID_POINTER;
2082
2083 LogFlowFuncLeaveRC(rc);
2084 return rc;
2085}
2086
2087/**
2088 * Returns the root entries of an URI transfer.
2089 *
2090 * @returns VBox status code.
2091 * @param pTransfer URI clipboard transfer to return root entries for.
2092 * @param ppRootList Where to store the root list on success.
2093 */
2094int SharedClipboardURILTransferRootsAsList(PSHAREDCLIPBOARDURITRANSFER pTransfer, PVBOXCLIPBOARDROOTLIST *ppRootList)
2095{
2096 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2097 AssertPtrReturn(ppRootList, VERR_INVALID_POINTER);
2098
2099 int rc = VINF_SUCCESS;
2100
2101 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
2102 {
2103 PVBOXCLIPBOARDROOTLIST pRootList = SharedClipboardURIRootListAlloc();
2104 if (!pRootList)
2105 return VERR_NO_MEMORY;
2106
2107 const uint32_t cRoots = (uint32_t)pTransfer->lstRootEntries.size();
2108
2109 LogFlowFunc(("cRoots=%RU32\n", cRoots));
2110
2111 if (cRoots)
2112 {
2113 PVBOXCLIPBOARDROOTLISTENTRY paRootListEntries
2114 = (PVBOXCLIPBOARDROOTLISTENTRY)RTMemAllocZ(cRoots * sizeof(VBOXCLIPBOARDROOTLISTENTRY));
2115 if (paRootListEntries)
2116 {
2117 for (uint32_t i = 0; i < cRoots; ++i)
2118 {
2119 rc = SharedClipboardURILTransferRootsEntry(pTransfer, i, &paRootListEntries[i]);
2120 if (RT_FAILURE(rc))
2121 break;
2122 }
2123
2124 if (RT_SUCCESS(rc))
2125 pRootList->paEntries = paRootListEntries;
2126 }
2127 else
2128 rc = VERR_NO_MEMORY;
2129 }
2130 else
2131 rc = VERR_NOT_FOUND;
2132
2133 if (RT_SUCCESS(rc))
2134 {
2135 pRootList->Hdr.cRoots = cRoots;
2136 pRootList->Hdr.fRoots = 0; /** @todo Implement this. */
2137
2138 *ppRootList = pRootList;
2139 }
2140 }
2141 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
2142 {
2143 if (pTransfer->ProviderIface.pfnGetRoots)
2144 rc = pTransfer->ProviderIface.pfnGetRoots(&pTransfer->ProviderCtx, ppRootList);
2145 else
2146 rc = VERR_NOT_SUPPORTED;
2147 }
2148
2149 LogFlowFuncLeaveRC(rc);
2150 return rc;
2151}
2152
2153/**
2154 * Returns the transfer's source.
2155 *
2156 * @returns The transfer's source.
2157 * @param pTransfer URI clipboard transfer to return source for.
2158 */
2159SHAREDCLIPBOARDSOURCE SharedClipboardURITransferGetSource(PSHAREDCLIPBOARDURITRANSFER pTransfer)
2160{
2161 AssertPtrReturn(pTransfer, SHAREDCLIPBOARDSOURCE_INVALID);
2162
2163 return pTransfer->State.enmSource;
2164}
2165
2166/**
2167 * Returns the current transfer status.
2168 *
2169 * @returns Current transfer status.
2170 * @param pTransfer URI clipboard transfer to return status for.
2171 */
2172SHAREDCLIPBOARDURITRANSFERSTATUS SharedClipboardURITransferGetStatus(PSHAREDCLIPBOARDURITRANSFER pTransfer)
2173{
2174 AssertPtrReturn(pTransfer, SHAREDCLIPBOARDURITRANSFERSTATUS_NONE);
2175
2176 return pTransfer->State.enmStatus;
2177}
2178
2179/**
2180 * Runs (starts) an URI transfer thread.
2181 *
2182 * @returns VBox status code.
2183 * @param pTransfer URI clipboard transfer to run.
2184 * @param pfnThreadFunc Pointer to thread function to use.
2185 * @param pvUser Pointer to user-provided data.
2186 */
2187int SharedClipboardURITransferRun(PSHAREDCLIPBOARDURITRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser)
2188{
2189 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2190
2191 AssertMsgReturn(pTransfer->State.enmStatus == SHAREDCLIPBOARDURITRANSFERSTATUS_READY,
2192 ("Wrong status (currently is %RU32)\n", pTransfer->State.enmStatus), VERR_WRONG_ORDER);
2193
2194 int rc = sharedClipboardURITransferThreadCreate(pTransfer, pfnThreadFunc, pvUser);
2195
2196 LogFlowFuncLeaveRC(rc);
2197 return rc;
2198}
2199
2200/**
2201 * Sets or unsets the callback table to be used for a clipboard URI transfer.
2202 *
2203 * @returns VBox status code.
2204 * @param pTransfer URI clipboard transfer to set callbacks for.
2205 * @param pCallbacks Pointer to callback table to set.
2206 */
2207void SharedClipboardURITransferSetCallbacks(PSHAREDCLIPBOARDURITRANSFER pTransfer,
2208 PSHAREDCLIPBOARDURITRANSFERCALLBACKS pCallbacks)
2209{
2210 AssertPtrReturnVoid(pTransfer);
2211 AssertPtrReturnVoid(pCallbacks);
2212
2213 LogFlowFunc(("pCallbacks=%p\n", pCallbacks));
2214
2215#define SET_CALLBACK(a_pfnCallback) \
2216 if (pCallbacks->a_pfnCallback) \
2217 pTransfer->Callbacks.a_pfnCallback = pCallbacks->a_pfnCallback
2218
2219 SET_CALLBACK(pfnTransferPrepare);
2220 SET_CALLBACK(pfnTransferStarted);
2221 SET_CALLBACK(pfnListHeaderComplete);
2222 SET_CALLBACK(pfnListEntryComplete);
2223 SET_CALLBACK(pfnTransferCanceled);
2224 SET_CALLBACK(pfnTransferError);
2225 SET_CALLBACK(pfnTransferStarted);
2226
2227#undef SET_CALLBACK
2228
2229 pTransfer->Callbacks.pvUser = pCallbacks->pvUser;
2230}
2231
2232/**
2233 * Allocates a new event payload.
2234 *
2235 * @returns VBox status code.
2236 * @param uID Event ID to associate payload to.
2237 * @param pvData Data block to associate to this payload.
2238 * @param cbData Size (in bytes) of data block to associate.
2239 * @param ppPayload Where to store the allocated event payload on success.
2240 */
2241int SharedClipboardURITransferPayloadAlloc(uint32_t uID, const void *pvData, uint32_t cbData,
2242 PSHAREDCLIPBOARDURITRANSFERPAYLOAD *ppPayload)
2243{
2244 PSHAREDCLIPBOARDURITRANSFERPAYLOAD pPayload =
2245 (PSHAREDCLIPBOARDURITRANSFERPAYLOAD)RTMemAlloc(sizeof(SHAREDCLIPBOARDURITRANSFERPAYLOAD));
2246 if (!pPayload)
2247 return VERR_NO_MEMORY;
2248
2249 pPayload->pvData = RTMemAlloc(cbData);
2250 if (pPayload->pvData)
2251 {
2252 memcpy(pPayload->pvData, pvData, cbData);
2253
2254 pPayload->cbData = cbData;
2255 pPayload->uID = uID;
2256
2257 *ppPayload = pPayload;
2258
2259 return VINF_SUCCESS;
2260 }
2261
2262 RTMemFree(pPayload);
2263 return VERR_NO_MEMORY;
2264}
2265
2266/**
2267 * Frees an event payload.
2268 *
2269 * @returns VBox status code.
2270 * @param pPayload URI clipboard transfer event payload to free.
2271 */
2272void SharedClipboardURITransferPayloadFree(PSHAREDCLIPBOARDURITRANSFERPAYLOAD pPayload)
2273{
2274 if (!pPayload)
2275 return;
2276
2277 if (pPayload->pvData)
2278 {
2279 Assert(pPayload->cbData);
2280 RTMemFree(pPayload->pvData);
2281 pPayload->pvData = NULL;
2282 }
2283
2284 pPayload->cbData = 0;
2285
2286 RTMemFree(pPayload);
2287 pPayload = NULL;
2288}
2289
2290/**
2291 * Generates a new event ID for a specific URI transfer.
2292 *
2293 * @returns New event ID generated, or 0 on error.
2294 * @param pTransfer URI clipboard transfer to generate event for.
2295 */
2296uint16_t SharedClipboardURITransferEventIDGenerate(PSHAREDCLIPBOARDURITRANSFER pTransfer)
2297{
2298 LogFlowFunc(("New event %RU16\n", pTransfer->uEventIDNext));
2299 return pTransfer->uEventIDNext++; /** @todo Improve this. */
2300}
2301
2302/**
2303 * Registers an URI transfer event.
2304 *
2305 * @returns VBox status code.
2306 * @param pTransfer URI clipboard transfer to register event for.
2307 * @param uID Event ID to register.
2308 */
2309int SharedClipboardURITransferEventRegister(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint16_t uID)
2310{
2311 int rc;
2312
2313 SharedClipboardURITransferEventMap::iterator itEvent = pTransfer->pMapEvents->find(uID);
2314 if (itEvent == pTransfer->pMapEvents->end())
2315 {
2316 PSHAREDCLIPBOARDURITRANSFEREVENT pEvent
2317 = (PSHAREDCLIPBOARDURITRANSFEREVENT)RTMemAllocZ(sizeof(SHAREDCLIPBOARDURITRANSFEREVENT));
2318 if (pEvent)
2319 {
2320 rc = RTSemEventCreate(&pEvent->hEventSem);
2321 if (RT_SUCCESS(rc))
2322 {
2323 pTransfer->pMapEvents->insert(std::pair<uint16_t, PSHAREDCLIPBOARDURITRANSFEREVENT>(uID, pEvent)); /** @todo Can this throw? */
2324
2325 LogFlowFunc(("Event %RU16\n", uID));
2326 }
2327 }
2328 else
2329 rc = VERR_NO_MEMORY;
2330 }
2331 else
2332 rc = VERR_ALREADY_EXISTS;
2333
2334#ifdef DEBUG_andy
2335 AssertRC(rc);
2336#endif
2337
2338 LogFlowFuncLeaveRC(rc);
2339 return rc;
2340}
2341
2342/**
2343 * Unregisters an URI transfer event.
2344 *
2345 * @returns VBox status code.
2346 * @param pTransfer URI clipboard transfer to unregister event for.
2347 * @param uID Event ID to unregister.
2348 */
2349int SharedClipboardURITransferEventUnregister(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint16_t uID)
2350{
2351 int rc;
2352
2353 SharedClipboardURITransferEventMap::const_iterator itEvent = pTransfer->pMapEvents->find(uID);
2354 if (itEvent != pTransfer->pMapEvents->end())
2355 {
2356 SharedClipboardURITransferPayloadFree(itEvent->second->pPayload);
2357
2358 RTSemEventDestroy(itEvent->second->hEventSem);
2359
2360 RTMemFree(itEvent->second);
2361
2362 pTransfer->pMapEvents->erase(itEvent);
2363
2364 LogFlowFunc(("Event %RU16\n", uID));
2365
2366 rc = VINF_SUCCESS;
2367 }
2368 else
2369 rc = VERR_NOT_FOUND;
2370
2371 AssertRC(rc);
2372
2373 LogFlowFuncLeaveRC(rc);
2374 return rc;
2375}
2376
2377/**
2378 * Waits for an URI transfer event to get signalled.
2379 *
2380 * @returns VBox status code.
2381 * @param pTransfer URI clipboard transfer that contains the event to wait for.
2382 * @param uID Event ID to wait for.
2383 * @param uTimeoutMs Timeout (in ms) to wait.
2384 * @param ppPayload Where to store the (allocated) event payload on success. Needs to be free'd with
2385 * SharedClipboardURITransferPayloadFree().
2386 */
2387int SharedClipboardURITransferEventWait(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint16_t uID, RTMSINTERVAL uTimeoutMs,
2388 PSHAREDCLIPBOARDURITRANSFERPAYLOAD *ppPayload)
2389{
2390 LogFlowFuncEnter();
2391
2392 int rc;
2393
2394 SharedClipboardURITransferEventMap::const_iterator itEvent = pTransfer->pMapEvents->find(uID);
2395 if (itEvent != pTransfer->pMapEvents->end())
2396 {
2397 rc = RTSemEventWait(itEvent->second->hEventSem, uTimeoutMs);
2398 if (RT_SUCCESS(rc))
2399 {
2400 *ppPayload = itEvent->second->pPayload;
2401
2402 itEvent->second->pPayload = NULL;
2403 }
2404 }
2405 else
2406 rc = VERR_NOT_FOUND;
2407
2408 LogFlowFuncLeaveRC(rc);
2409 return rc;
2410}
2411
2412/**
2413 * Signals an URI transfer event.
2414 *
2415 * @returns VBox status code.
2416 * @param pTransfer URI clipboard transfer of event to signal.
2417 * @param uID Event ID to signal.
2418 * @param pPayload Event payload to associate. Takes ownership. Optional.
2419 */
2420int SharedClipboardURITransferEventSignal(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint16_t uID,
2421 PSHAREDCLIPBOARDURITRANSFERPAYLOAD pPayload)
2422{
2423 int rc;
2424
2425 SharedClipboardURITransferEventMap::const_iterator itEvent = pTransfer->pMapEvents->find(uID);
2426 if (itEvent != pTransfer->pMapEvents->end())
2427 {
2428 Assert(itEvent->second->pPayload == NULL);
2429
2430 itEvent->second->pPayload = pPayload;
2431
2432 rc = RTSemEventSignal(itEvent->second->hEventSem);
2433 }
2434 else
2435 rc = VERR_NOT_FOUND;
2436
2437#ifdef DEBUG_andy
2438 AssertRC(rc);
2439#endif
2440
2441 LogFlowFuncLeaveRC(rc);
2442 return rc;
2443}
2444
2445/**
2446 * Creates a thread for a clipboard URI transfer.
2447 *
2448 * @returns VBox status code.
2449 * @param pTransfer URI clipboard transfer to create thread for.
2450 * @param pfnThreadFunc Thread function to use for this transfer.
2451 * @param pvUser Pointer to user-provided data.
2452 */
2453static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser)
2454
2455{
2456 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2457
2458 /* Spawn a worker thread, so that we don't block the window thread for too long. */
2459 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnThreadFunc,
2460 pvUser, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
2461 "shclp");
2462 if (RT_SUCCESS(rc))
2463 {
2464 int rc2 = RTThreadUserWait(pTransfer->Thread.hThread, 30 * 1000 /* Timeout in ms */);
2465 AssertRC(rc2);
2466
2467 if (pTransfer->Thread.fStarted) /* Did the thread indicate that it started correctly? */
2468 {
2469 pTransfer->State.enmStatus = SHAREDCLIPBOARDURITRANSFERSTATUS_RUNNING;
2470 }
2471 else
2472 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
2473 }
2474
2475 LogFlowFuncLeaveRC(rc);
2476 return rc;
2477}
2478
2479/**
2480 * Destroys a thread of a clipboard URI transfer.
2481 *
2482 * @returns VBox status code.
2483 * @param pTransfer URI clipboard transfer to destroy thread for.
2484 * @param uTimeoutMs Timeout (in ms) to wait for thread creation.
2485 */
2486static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs)
2487{
2488 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2489
2490 if (pTransfer->Thread.hThread == NIL_RTTHREAD)
2491 return VINF_SUCCESS;
2492
2493 LogFlowFuncEnter();
2494
2495 /* Set stop indicator. */
2496 pTransfer->Thread.fStop = true;
2497
2498 int rcThread = VERR_WRONG_ORDER;
2499 int rc = RTThreadWait(pTransfer->Thread.hThread, uTimeoutMs, &rcThread);
2500
2501 LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n", rc, rcThread));
2502
2503 return rc;
2504}
2505
2506/**
2507 * Initializes a clipboard URI transfer.
2508 *
2509 * @returns VBox status code.
2510 * @param pURI URI clipboard context to initialize.
2511 */
2512int SharedClipboardURICtxInit(PSHAREDCLIPBOARDURICTX pURI)
2513{
2514 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
2515
2516 LogFlowFunc(("%p\n", pURI));
2517
2518 int rc = RTCritSectInit(&pURI->CritSect);
2519 if (RT_SUCCESS(rc))
2520 {
2521 RTListInit(&pURI->List);
2522
2523 pURI->cRunning = 0;
2524 pURI->cMaxRunning = 1; /* For now we only support one transfer per client at a time. */
2525
2526#ifdef DEBUG_andy
2527 pURI->cMaxRunning = UINT32_MAX;
2528#endif
2529 SharedClipboardURICtxReset(pURI);
2530 }
2531
2532 return VINF_SUCCESS;
2533}
2534
2535/**
2536 * Destroys an URI clipboard information context struct.
2537 *
2538 * @param pURI URI clipboard context to destroy.
2539 */
2540void SharedClipboardURICtxDestroy(PSHAREDCLIPBOARDURICTX pURI)
2541{
2542 AssertPtrReturnVoid(pURI);
2543
2544 LogFlowFunc(("%p\n", pURI));
2545
2546 RTCritSectDelete(&pURI->CritSect);
2547
2548 PSHAREDCLIPBOARDURITRANSFER pTransfer, pTransferNext;
2549 RTListForEachSafe(&pURI->List, pTransfer, pTransferNext, SHAREDCLIPBOARDURITRANSFER, Node)
2550 {
2551 SharedClipboardURITransferDestroy(pTransfer);
2552
2553 RTListNodeRemove(&pTransfer->Node);
2554
2555 RTMemFree(pTransfer);
2556 pTransfer = NULL;
2557 }
2558
2559 pURI->cRunning = 0;
2560 pURI->cTransfers = 0;
2561}
2562
2563/**
2564 * Resets an clipboard URI transfer.
2565 *
2566 * @param pURI URI clipboard context to reset.
2567 */
2568void SharedClipboardURICtxReset(PSHAREDCLIPBOARDURICTX pURI)
2569{
2570 AssertPtrReturnVoid(pURI);
2571
2572 LogFlowFuncEnter();
2573
2574 PSHAREDCLIPBOARDURITRANSFER pTransfer;
2575 RTListForEach(&pURI->List, pTransfer, SHAREDCLIPBOARDURITRANSFER, Node)
2576 SharedClipboardURITransferReset(pTransfer);
2577}
2578
2579/**
2580 * Adds a new URI transfer to an clipboard URI transfer.
2581 *
2582 * @returns VBox status code.
2583 * @param pURI URI clipboard context to add transfer to.
2584 * @param pTransfer Pointer to URI clipboard transfer to add.
2585 */
2586int SharedClipboardURICtxTransferAdd(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
2587{
2588 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
2589 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2590
2591 LogFlowFuncEnter();
2592
2593 if (pURI->cRunning == pURI->cMaxRunning)
2594 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2595
2596 RTListAppend(&pURI->List, &pTransfer->Node);
2597
2598 pURI->cTransfers++;
2599 LogFlowFunc(("cTransfers=%RU32, cRunning=%RU32\n", pURI->cTransfers, pURI->cRunning));
2600
2601 return VINF_SUCCESS;
2602}
2603
2604/**
2605 * Removes an URI transfer from a clipboard URI transfer.
2606 *
2607 * @returns VBox status code.
2608 * @param pURI URI clipboard context to remove transfer from.
2609 * @param pTransfer Pointer to URI clipboard transfer to remove.
2610 */
2611int SharedClipboardURICtxTransferRemove(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
2612{
2613 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
2614 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2615
2616 LogFlowFuncEnter();
2617
2618
2619 int rc = SharedClipboardURITransferDestroy(pTransfer);
2620 if (RT_SUCCESS(rc))
2621 {
2622 RTListNodeRemove(&pTransfer->Node);
2623
2624 RTMemFree(pTransfer);
2625 pTransfer = NULL;
2626 }
2627
2628 LogFlowFuncLeaveRC(rc);
2629 return rc;
2630}
2631
2632/**
2633 * Returns a specific URI transfer, internal version.
2634 *
2635 * @returns URI transfer, or NULL if not found.
2636 * @param pURI URI clipboard context to return transfer for.
2637 * @param uIdx Index of the transfer to return.
2638 */
2639static PSHAREDCLIPBOARDURITRANSFER sharedClipboardURICtxGetTransferInternal(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
2640{
2641 AssertReturn(uIdx == 0, NULL); /* Only one transfer allowed at the moment. */
2642 return RTListGetFirst(&pURI->List, SHAREDCLIPBOARDURITRANSFER, Node);
2643}
2644
2645/**
2646 * Returns a specific URI transfer.
2647 *
2648 * @returns URI transfer, or NULL if not found.
2649 * @param pURI URI clipboard context to return transfer for.
2650 * @param uIdx Index of the transfer to return.
2651 */
2652PSHAREDCLIPBOARDURITRANSFER SharedClipboardURICtxGetTransfer(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
2653{
2654 return sharedClipboardURICtxGetTransferInternal(pURI, uIdx);
2655}
2656
2657/**
2658 * Returns the number of running URI transfers.
2659 *
2660 * @returns Number of running transfers.
2661 * @param pURI URI clipboard context to return number for.
2662 */
2663uint32_t SharedClipboardURICtxGetRunningTransfers(PSHAREDCLIPBOARDURICTX pURI)
2664{
2665 AssertPtrReturn(pURI, 0);
2666 return pURI->cRunning;
2667}
2668
2669/**
2670 * Returns the number of total URI transfers.
2671 *
2672 * @returns Number of total transfers.
2673 * @param pURI URI clipboard context to return number for.
2674 */
2675uint32_t SharedClipboardURICtxGetTotalTransfers(PSHAREDCLIPBOARDURICTX pURI)
2676{
2677 AssertPtrReturn(pURI, 0);
2678 return pURI->cTransfers;
2679}
2680
2681/**
2682 * Cleans up all associated transfers which are not needed (anymore).
2683 * This can be due to transfers which only have been announced but not / never being run.
2684 *
2685 * @param pURI URI clipboard context to cleanup transfers for.
2686 */
2687void SharedClipboardURICtxTransfersCleanup(PSHAREDCLIPBOARDURICTX pURI)
2688{
2689 AssertPtrReturnVoid(pURI);
2690
2691 LogFlowFunc(("cRunning=%RU32\n", pURI->cRunning));
2692
2693 /* Remove all transfers which are not in a running state (e.g. only announced). */
2694 PSHAREDCLIPBOARDURITRANSFER pTransfer, pTransferNext;
2695 RTListForEachSafe(&pURI->List, pTransfer, pTransferNext, SHAREDCLIPBOARDURITRANSFER, Node)
2696 {
2697 if (SharedClipboardURITransferGetStatus(pTransfer) != SHAREDCLIPBOARDURITRANSFERSTATUS_RUNNING)
2698 {
2699 SharedClipboardURITransferDestroy(pTransfer);
2700 RTListNodeRemove(&pTransfer->Node);
2701
2702 RTMemFree(pTransfer);
2703 pTransfer = NULL;
2704
2705 Assert(pURI->cTransfers);
2706 pURI->cTransfers--;
2707
2708 LogFlowFunc(("cTransfers=%RU32\n", pURI->cTransfers));
2709 }
2710 }
2711}
2712
2713/**
2714 * Returns whether the maximum of concurrent transfers of a specific URI context has been reached or not.
2715 *
2716 * @returns \c if maximum has been reached, \c false if not.
2717 * @param pURI URI clipboard context to determine value for.
2718 */
2719bool SharedClipboardURICtxTransfersMaximumReached(PSHAREDCLIPBOARDURICTX pURI)
2720{
2721 AssertPtrReturn(pURI, true);
2722
2723 LogFlowFunc(("cRunning=%RU32, cMaxRunning=%RU32\n", pURI->cRunning, pURI->cMaxRunning));
2724
2725 Assert(pURI->cRunning <= pURI->cMaxRunning);
2726 return pURI->cRunning == pURI->cMaxRunning;
2727}
2728
2729/**
2730 * Copies file system objinfo from IPRT to Shared Clipboard format.
2731 *
2732 * @param pDst The Shared Clipboard structure to convert data to.
2733 * @param pSrc The IPRT structure to convert data from.
2734 */
2735void SharedClipboardFsObjFromIPRT(PSHAREDCLIPBOARDFSOBJINFO pDst, PCRTFSOBJINFO pSrc)
2736{
2737 pDst->cbObject = pSrc->cbObject;
2738 pDst->cbAllocated = pSrc->cbAllocated;
2739 pDst->AccessTime = pSrc->AccessTime;
2740 pDst->ModificationTime = pSrc->ModificationTime;
2741 pDst->ChangeTime = pSrc->ChangeTime;
2742 pDst->BirthTime = pSrc->BirthTime;
2743 pDst->Attr.fMode = pSrc->Attr.fMode;
2744 /* Clear bits which we don't pass through for security reasons. */
2745 pDst->Attr.fMode &= ~(RTFS_UNIX_ISUID | RTFS_UNIX_ISGID | RTFS_UNIX_ISTXT);
2746 RT_ZERO(pDst->Attr.u);
2747 switch (pSrc->Attr.enmAdditional)
2748 {
2749 default:
2750 case RTFSOBJATTRADD_NOTHING:
2751 pDst->Attr.enmAdditional = SHAREDCLIPBOARDFSOBJATTRADD_NOTHING;
2752 break;
2753
2754 case RTFSOBJATTRADD_UNIX:
2755 pDst->Attr.enmAdditional = SHAREDCLIPBOARDFSOBJATTRADD_UNIX;
2756 pDst->Attr.u.Unix.uid = pSrc->Attr.u.Unix.uid;
2757 pDst->Attr.u.Unix.gid = pSrc->Attr.u.Unix.gid;
2758 pDst->Attr.u.Unix.cHardlinks = pSrc->Attr.u.Unix.cHardlinks;
2759 pDst->Attr.u.Unix.INodeIdDevice = pSrc->Attr.u.Unix.INodeIdDevice;
2760 pDst->Attr.u.Unix.INodeId = pSrc->Attr.u.Unix.INodeId;
2761 pDst->Attr.u.Unix.fFlags = pSrc->Attr.u.Unix.fFlags;
2762 pDst->Attr.u.Unix.GenerationId = pSrc->Attr.u.Unix.GenerationId;
2763 pDst->Attr.u.Unix.Device = pSrc->Attr.u.Unix.Device;
2764 break;
2765
2766 case RTFSOBJATTRADD_EASIZE:
2767 pDst->Attr.enmAdditional = SHAREDCLIPBOARDFSOBJATTRADD_EASIZE;
2768 pDst->Attr.u.EASize.cb = pSrc->Attr.u.EASize.cb;
2769 break;
2770 }
2771}
2772
2773/**
2774 * Converts Shared Clipboard create flags (see SharedClipboard-uri.) into IPRT create flags.
2775 *
2776 * @returns IPRT status code.
2777 * @param fWritable Whether the shared folder is writable
2778 * @param fShClFlags Shared clipboard create flags.
2779 * @param fMode File attributes.
2780 * @param handleInitial Initial handle.
2781 * @retval pfOpen Where to store the IPRT creation / open flags.
2782 *
2783 * @sa Initially taken from vbsfConvertFileOpenFlags().
2784 */
2785static int sharedClipboardConvertFileCreateFlags(bool fWritable, unsigned fShClFlags, RTFMODE fMode,
2786 SHAREDCLIPBOARDOBJHANDLE handleInitial, uint64_t *pfOpen)
2787{
2788 uint64_t fOpen = 0;
2789 int rc = VINF_SUCCESS;
2790
2791 if ( (fMode & RTFS_DOS_MASK) != 0
2792 && (fMode & RTFS_UNIX_MASK) == 0)
2793 {
2794 /* A DOS/Windows guest, make RTFS_UNIX_* from RTFS_DOS_*.
2795 * @todo this is based on rtFsModeNormalize/rtFsModeFromDos.
2796 * May be better to use RTFsModeNormalize here.
2797 */
2798 fMode |= RTFS_UNIX_IRUSR | RTFS_UNIX_IRGRP | RTFS_UNIX_IROTH;
2799 /* x for directories. */
2800 if (fMode & RTFS_DOS_DIRECTORY)
2801 fMode |= RTFS_TYPE_DIRECTORY | RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;
2802 /* writable? */
2803 if (!(fMode & RTFS_DOS_READONLY))
2804 fMode |= RTFS_UNIX_IWUSR | RTFS_UNIX_IWGRP | RTFS_UNIX_IWOTH;
2805
2806 /* Set the requested mode using only allowed bits. */
2807 fOpen |= ((fMode & RTFS_UNIX_MASK) << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK;
2808 }
2809 else
2810 {
2811 /* Old linux and solaris additions did not initialize the Info.Attr.fMode field
2812 * and it contained random bits from stack. Detect this using the handle field value
2813 * passed from the guest: old additions set it (incorrectly) to 0, new additions
2814 * set it to SHAREDCLIPBOARDOBJHANDLE_INVALID(~0).
2815 */
2816 if (handleInitial == 0)
2817 {
2818 /* Old additions. Do nothing, use default mode. */
2819 }
2820 else
2821 {
2822 /* New additions or Windows additions. Set the requested mode using only allowed bits.
2823 * Note: Windows guest set RTFS_UNIX_MASK bits to 0, which means a default mode
2824 * will be set in fOpen.
2825 */
2826 fOpen |= ((fMode & RTFS_UNIX_MASK) << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK;
2827 }
2828 }
2829
2830 switch ((fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACCESS_MASK_RW))
2831 {
2832 default:
2833 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_NONE:
2834 {
2835#ifdef RT_OS_WINDOWS
2836 if ((fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACCESS_MASK_ATTR) != SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_NONE)
2837 fOpen |= RTFILE_O_ATTR_ONLY;
2838 else
2839#endif
2840 fOpen |= RTFILE_O_READ;
2841 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_NONE\n"));
2842 break;
2843 }
2844
2845 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_READ:
2846 {
2847 fOpen |= RTFILE_O_READ;
2848 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_READ\n"));
2849 break;
2850 }
2851
2852 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_WRITE:
2853 {
2854 fOpen |= RTFILE_O_WRITE;
2855 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_WRITE\n"));
2856 break;
2857 }
2858
2859 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_READWRITE:
2860 {
2861 fOpen |= RTFILE_O_READWRITE;
2862 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_READWRITE\n"));
2863 break;
2864 }
2865 }
2866
2867 if (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACCESS_APPEND)
2868 {
2869 fOpen |= RTFILE_O_APPEND;
2870 }
2871
2872 switch ((fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACCESS_MASK_ATTR))
2873 {
2874 default:
2875 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_NONE:
2876 {
2877 fOpen |= RTFILE_O_ACCESS_ATTR_DEFAULT;
2878 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_NONE\n"));
2879 break;
2880 }
2881
2882 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_READ:
2883 {
2884 fOpen |= RTFILE_O_ACCESS_ATTR_READ;
2885 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_READ\n"));
2886 break;
2887 }
2888
2889 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_WRITE:
2890 {
2891 fOpen |= RTFILE_O_ACCESS_ATTR_WRITE;
2892 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_WRITE\n"));
2893 break;
2894 }
2895
2896 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_READWRITE:
2897 {
2898 fOpen |= RTFILE_O_ACCESS_ATTR_READWRITE;
2899 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_READWRITE\n"));
2900 break;
2901 }
2902 }
2903
2904 /* Sharing mask */
2905 switch ((fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACCESS_MASK_DENY))
2906 {
2907 default:
2908 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYNONE:
2909 fOpen |= RTFILE_O_DENY_NONE;
2910 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYNONE\n"));
2911 break;
2912
2913 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYREAD:
2914 fOpen |= RTFILE_O_DENY_READ;
2915 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYREAD\n"));
2916 break;
2917
2918 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYWRITE:
2919 fOpen |= RTFILE_O_DENY_WRITE;
2920 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYWRITE\n"));
2921 break;
2922
2923 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYALL:
2924 fOpen |= RTFILE_O_DENY_ALL;
2925 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYALL\n"));
2926 break;
2927 }
2928
2929 /* Open/Create action mask */
2930 switch ((fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_EXISTS))
2931 {
2932 case SHAREDCLIPBOARD_OBJ_CF_ACT_OPEN_IF_EXISTS:
2933 if (SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2934 {
2935 fOpen |= RTFILE_O_OPEN_CREATE;
2936 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_OPEN_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW\n"));
2937 }
2938 else if (SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2939 {
2940 fOpen |= RTFILE_O_OPEN;
2941 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_OPEN_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW\n"));
2942 }
2943 else
2944 {
2945 LogFlowFunc(("invalid open/create action combination\n"));
2946 rc = VERR_INVALID_PARAMETER;
2947 }
2948 break;
2949 case SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_EXISTS:
2950 if (SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2951 {
2952 fOpen |= RTFILE_O_CREATE;
2953 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW\n"));
2954 }
2955 else
2956 {
2957 LogFlowFunc(("invalid open/create action combination\n"));
2958 rc = VERR_INVALID_PARAMETER;
2959 }
2960 break;
2961 case SHAREDCLIPBOARD_OBJ_CF_ACT_REPLACE_IF_EXISTS:
2962 if (SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2963 {
2964 fOpen |= RTFILE_O_CREATE_REPLACE;
2965 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_REPLACE_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW\n"));
2966 }
2967 else if (SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2968 {
2969 fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
2970 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_REPLACE_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW\n"));
2971 }
2972 else
2973 {
2974 LogFlowFunc(("invalid open/create action combination\n"));
2975 rc = VERR_INVALID_PARAMETER;
2976 }
2977 break;
2978 case SHAREDCLIPBOARD_OBJ_CF_ACT_OVERWRITE_IF_EXISTS:
2979 if (SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2980 {
2981 fOpen |= RTFILE_O_CREATE_REPLACE;
2982 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_OVERWRITE_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW\n"));
2983 }
2984 else if (SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2985 {
2986 fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
2987 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_OVERWRITE_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW\n"));
2988 }
2989 else
2990 {
2991 LogFlowFunc(("invalid open/create action combination\n"));
2992 rc = VERR_INVALID_PARAMETER;
2993 }
2994 break;
2995 default:
2996 {
2997 rc = VERR_INVALID_PARAMETER;
2998 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_EXISTS - invalid parameter\n"));
2999 break;
3000 }
3001 }
3002
3003 if (RT_SUCCESS(rc))
3004 {
3005 if (!fWritable)
3006 fOpen &= ~RTFILE_O_WRITE;
3007
3008 *pfOpen = fOpen;
3009 }
3010
3011 LogFlowFuncLeaveRC(rc);
3012 return rc;
3013}
3014
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