VirtualBox

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

Last change on this file since 80444 was 80444, checked in by vboxsync, 5 years ago

Shared Clipboard/URI: Added protocol versioning support plus enhanced versions of existing commands (to also provide context IDs, among other stuff). So far only the host service(s) and the Windows guest is using the new(er) protocol.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 87.6 KB
Line 
1/* $Id: clipboard-uri.cpp 80444 2019-08-27 17:47:44Z 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/list.h>
24#include <iprt/path.h>
25#include <iprt/semaphore.h>
26
27#include <VBox/err.h>
28#include <VBox/HostServices/VBoxClipboardSvc.h>
29#include <VBox/GuestHost/SharedClipboard-uri.h>
30
31
32static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser);
33static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs);
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 * Returns a specific object handle info of a transfer.
701 *
702 * @returns Pointer to object handle info if found, or NULL if not found.
703 * @param pTransfer URI clipboard transfer to get object handle info from.
704 * @param hObj Object handle of the object to get handle info for.
705 */
706inline PSHAREDCLIPBOARDURIOBJHANDLEINFO sharedClipboardURIObjectGet(PSHAREDCLIPBOARDURITRANSFER pTransfer,
707 SHAREDCLIPBOARDOBJHANDLE hObj)
708{
709 PSHAREDCLIPBOARDURIOBJHANDLEINFO pIt;
710 RTListForEach(&pTransfer->lstObj, pIt, SHAREDCLIPBOARDURIOBJHANDLEINFO, Node)
711 {
712 if (pIt->hObj == hObj)
713 return pIt;
714 }
715
716 return NULL;
717}
718
719/**
720 * Opens an URI object.
721 *
722 * @returns VBox status code.
723 * @param pTransfer URI clipboard transfer to open the object for.
724 * @param pOpenCreateParms Open / create parameters of URI object to open / create.
725 * @param phObj Where to store the handle of URI object opened on success.
726 */
727int SharedClipboardURIObjectOpen(PSHAREDCLIPBOARDURITRANSFER pTransfer, PVBOXCLIPBOARDOBJOPENCREATEPARMS pOpenCreateParms,
728 PSHAREDCLIPBOARDOBJHANDLE phObj)
729{
730 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
731 AssertPtrReturn(pOpenCreateParms, VERR_INVALID_POINTER);
732 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
733
734 int rc = VINF_SUCCESS;
735
736 LogFlowFunc(("pszPath=%s, fCreate=0x%x\n", pOpenCreateParms->pszPath, pOpenCreateParms->fCreate));
737
738 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
739 {
740 PSHAREDCLIPBOARDURIOBJHANDLEINFO pInfo
741 = (PSHAREDCLIPBOARDURIOBJHANDLEINFO)RTMemAlloc(sizeof(SHAREDCLIPBOARDURIOBJHANDLEINFO));
742 if (pInfo)
743 {
744 const bool fWritable = true; /** @todo Fix this. */
745
746 uint64_t fOpen;
747 rc = sharedClipboardConvertFileCreateFlags(fWritable,
748 pOpenCreateParms->fCreate, pOpenCreateParms->ObjInfo.Attr.fMode,
749 SHAREDCLIPBOARDOBJHANDLE_INVALID, &fOpen);
750 if (RT_SUCCESS(rc))
751 {
752 char *pszPathAbs = RTStrAPrintf2("%s/%s", pTransfer->pszPathRootAbs, pOpenCreateParms->pszPath);
753 if (pszPathAbs)
754 {
755 LogFlowFunc(("%s\n", pszPathAbs));
756
757 rc = RTFileOpen(&pInfo->u.Local.hFile, pszPathAbs, fOpen);
758 RTStrFree(pszPathAbs);
759 }
760 else
761 rc = VERR_NO_MEMORY;
762 }
763
764 if (RT_SUCCESS(rc))
765 {
766 pInfo->hObj = pTransfer->uObjHandleNext++;
767 pInfo->enmType = SHAREDCLIPBOARDURIOBJTYPE_FILE;
768
769 RTListAppend(&pTransfer->lstObj, &pInfo->Node);
770
771 *phObj = pInfo->hObj;
772 }
773
774 if (RT_FAILURE(rc))
775 RTMemFree(pInfo);
776 }
777 else
778 rc = VERR_NO_MEMORY;
779 }
780 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
781 {
782 if (pTransfer->ProviderIface.pfnObjOpen)
783 {
784 rc = pTransfer->ProviderIface.pfnObjOpen(&pTransfer->ProviderCtx, pOpenCreateParms, phObj);
785 }
786 else
787 rc = VERR_NOT_SUPPORTED;
788 }
789
790 LogFlowFuncLeaveRC(rc);
791 return rc;
792}
793
794/**
795 * Closes an URI object.
796 *
797 * @returns VBox status code.
798 * @param pTransfer URI clipboard transfer that contains the object to close.
799 * @param hObj Handle of URI object to close.
800 */
801int SharedClipboardURIObjectClose(PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDOBJHANDLE hObj)
802{
803 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
804
805 int rc = VINF_SUCCESS;
806
807 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
808 {
809 PSHAREDCLIPBOARDURIOBJHANDLEINFO pInfo = sharedClipboardURIObjectGet(pTransfer, hObj);
810 if (pInfo)
811 {
812 switch (pInfo->enmType)
813 {
814 case SHAREDCLIPBOARDURIOBJTYPE_DIRECTORY:
815 {
816 rc = RTDirClose(pInfo->u.Local.hDir);
817 if (RT_SUCCESS(rc))
818 pInfo->u.Local.hDir = NIL_RTDIR;
819 break;
820 }
821
822 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
823 {
824 rc = RTFileClose(pInfo->u.Local.hFile);
825 if (RT_SUCCESS(rc))
826 pInfo->u.Local.hFile = NIL_RTFILE;
827 break;
828 }
829
830 default:
831 rc = VERR_NOT_IMPLEMENTED;
832 break;
833 }
834
835 RTMemFree(pInfo);
836
837 RTListNodeRemove(&pInfo->Node);
838 }
839 else
840 rc = VERR_NOT_FOUND;
841 }
842 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
843 {
844 if (pTransfer->ProviderIface.pfnObjClose)
845 {
846 rc = pTransfer->ProviderIface.pfnObjClose(&pTransfer->ProviderCtx, hObj);
847 }
848 else
849 rc = VERR_NOT_SUPPORTED;
850 }
851
852 LogFlowFuncLeaveRC(rc);
853 return rc;
854}
855
856/**
857 * Reads from an URI object.
858 *
859 * @returns VBox status code.
860 * @param pTransfer URI clipboard transfer that contains the object to read from.
861 * @param hObj Handle of URI object to read from.
862 * @param pvBuf Buffer for where to store the read data.
863 * @param cbBuf Size (in bytes) of buffer.
864 * @param pcbRead How much bytes were read on success. Optional.
865 */
866int SharedClipboardURIObjectRead(PSHAREDCLIPBOARDURITRANSFER pTransfer,
867 SHAREDCLIPBOARDOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead, uint32_t fFlags)
868{
869 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
870 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
871 AssertReturn (cbBuf, VERR_INVALID_PARAMETER);
872 /* pcbRead is optional. */
873 /** @todo Validate fFlags. */
874
875 int rc = VINF_SUCCESS;
876
877 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
878 {
879 PSHAREDCLIPBOARDURIOBJHANDLEINFO pInfo = sharedClipboardURIObjectGet(pTransfer, hObj);
880 if (pInfo)
881 {
882 switch (pInfo->enmType)
883 {
884 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
885 {
886 size_t cbRead;
887 rc = RTFileRead(pInfo->u.Local.hFile, pvBuf, cbBuf, &cbRead);
888 if (RT_SUCCESS(rc))
889 {
890 if (pcbRead)
891 *pcbRead = (uint32_t)cbRead;
892 }
893 break;
894 }
895
896 default:
897 rc = VERR_NOT_SUPPORTED;
898 break;
899 }
900 }
901 else
902 rc = VERR_NOT_FOUND;
903 }
904 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
905 {
906 if (pTransfer->ProviderIface.pfnObjRead)
907 {
908 rc = pTransfer->ProviderIface.pfnObjRead(&pTransfer->ProviderCtx, hObj, pvBuf, cbBuf, fFlags, pcbRead);
909 }
910 else
911 rc = VERR_NOT_SUPPORTED;
912 }
913
914 LogFlowFuncLeaveRC(rc);
915 return rc;
916}
917
918/**
919 * Writes to an URI object.
920 *
921 * @returns VBox status code.
922 * @param pTransfer URI clipboard transfer that contains the object to write to.
923 * @param hObj Handle of URI object to write to.
924 * @param pvBuf Buffer of data to write.
925 * @param cbBuf Size (in bytes) of buffer to write.
926 * @param pcbWritten How much bytes were writtenon success. Optional.
927 */
928int SharedClipboardURIObjectWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer,
929 SHAREDCLIPBOARDOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten,
930 uint32_t fFlags)
931{
932 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
933 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
934 AssertReturn (cbBuf, VERR_INVALID_PARAMETER);
935 /* pcbWritten is optional. */
936
937 int rc = VINF_SUCCESS;
938
939 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
940 {
941 PSHAREDCLIPBOARDURIOBJHANDLEINFO pInfo = sharedClipboardURIObjectGet(pTransfer, hObj);
942 if (pInfo)
943 {
944 switch (pInfo->enmType)
945 {
946 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
947 {
948 rc = RTFileWrite(pInfo->u.Local.hFile, pvBuf, cbBuf, (size_t *)pcbWritten);
949 break;
950 }
951
952 default:
953 rc = VERR_NOT_SUPPORTED;
954 break;
955 }
956 }
957 else
958 rc = VERR_NOT_FOUND;
959 }
960 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
961 {
962 if (pTransfer->ProviderIface.pfnObjWrite)
963 {
964 rc = pTransfer->ProviderIface.pfnObjWrite(&pTransfer->ProviderCtx, hObj, pvBuf, cbBuf, fFlags, pcbWritten);
965 }
966 else
967 rc = VERR_NOT_SUPPORTED;
968 }
969
970 LogFlowFuncLeaveRC(rc);
971 return rc;
972}
973
974/**
975 * Duplicaates an URI object data chunk.
976 *
977 * @returns Duplicated object data chunk on success, or NULL on failure.
978 * @param pDataChunk URI object data chunk to duplicate.
979 */
980PVBOXCLIPBOARDOBJDATACHUNK SharedClipboardURIObjectDataChunkDup(PVBOXCLIPBOARDOBJDATACHUNK pDataChunk)
981{
982 if (!pDataChunk)
983 return NULL;
984
985 PVBOXCLIPBOARDOBJDATACHUNK pDataChunkDup = (PVBOXCLIPBOARDOBJDATACHUNK)RTMemAllocZ(sizeof(VBOXCLIPBOARDOBJDATACHUNK));
986 if (!pDataChunkDup)
987 return NULL;
988
989 if (pDataChunk->pvData)
990 {
991 Assert(pDataChunk->cbData);
992
993 pDataChunkDup->uHandle = pDataChunk->uHandle;
994 pDataChunkDup->pvData = RTMemDup(pDataChunk->pvData, pDataChunk->cbData);
995 pDataChunkDup->cbData = pDataChunk->cbData;
996 }
997
998 return pDataChunkDup;
999}
1000
1001/**
1002 * Destroys an URI object data chunk.
1003 *
1004 * @param pDataChunk URI object data chunk to destroy.
1005 */
1006void SharedClipboardURIObjectDataChunkDestroy(PVBOXCLIPBOARDOBJDATACHUNK pDataChunk)
1007{
1008 if (!pDataChunk)
1009 return;
1010
1011 if (pDataChunk->pvData)
1012 {
1013 Assert(pDataChunk->cbData);
1014
1015 RTMemFree(pDataChunk->pvData);
1016
1017 pDataChunk->pvData = NULL;
1018 pDataChunk->cbData = 0;
1019 }
1020
1021 pDataChunk->uHandle = 0;
1022}
1023
1024/**
1025 * Frees an URI object data chunk.
1026 *
1027 * @param pDataChunk URI object data chunk to free. The handed-in pointer will
1028 * be invalid after calling this function.
1029 */
1030void SharedClipboardURIObjectDataChunkFree(PVBOXCLIPBOARDOBJDATACHUNK pDataChunk)
1031{
1032 if (!pDataChunk)
1033 return;
1034
1035 SharedClipboardURIObjectDataChunkDestroy(pDataChunk);
1036
1037 RTMemFree(pDataChunk);
1038 pDataChunk = NULL;
1039}
1040
1041/**
1042 * Initializes an URI clipboard transfer struct.
1043 *
1044 * @returns VBox status code.
1045 * @param enmDir Specifies the transfer direction of this transfer.
1046 * @param enmSource Specifies the data source of the transfer.
1047 * @param ppTransfer Where to return the created URI transfer struct.
1048 * Must be destroyed by SharedClipboardURITransferDestroy().
1049 */
1050int SharedClipboardURITransferCreate(SHAREDCLIPBOARDURITRANSFERDIR enmDir, SHAREDCLIPBOARDSOURCE enmSource,
1051 PSHAREDCLIPBOARDURITRANSFER *ppTransfer)
1052{
1053 AssertPtrReturn(ppTransfer, VERR_INVALID_POINTER);
1054
1055 LogFlowFuncEnter();
1056
1057 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)RTMemAlloc(sizeof(SHAREDCLIPBOARDURITRANSFER));
1058 if (!pTransfer)
1059 return VERR_NO_MEMORY;
1060
1061 int rc = VINF_SUCCESS;
1062
1063 pTransfer->State.uID = 0;
1064 pTransfer->State.enmStatus = SHAREDCLIPBOARDURITRANSFERSTATUS_NONE;
1065 pTransfer->State.enmDir = enmDir;
1066 pTransfer->State.enmSource = enmSource;
1067
1068 LogFlowFunc(("enmDir=%RU32, enmSource=%RU32\n", pTransfer->State.enmDir, pTransfer->State.enmSource));
1069
1070 pTransfer->pArea = NULL; /* Will be created later if needed. */
1071
1072 pTransfer->Thread.hThread = NIL_RTTHREAD;
1073 pTransfer->Thread.fCancelled = false;
1074 pTransfer->Thread.fStarted = false;
1075 pTransfer->Thread.fStop = false;
1076
1077 pTransfer->pszPathRootAbs = NULL;
1078
1079 pTransfer->uListHandleNext = 1;
1080 pTransfer->uObjHandleNext = 1;
1081
1082 pTransfer->uTimeoutMs = 30 * 1000; /* 30s timeout by default. */
1083 pTransfer->cbMaxChunkSize = _64K; /** @todo Make this configurable. */
1084
1085 pTransfer->pvUser = NULL;
1086 pTransfer->cbUser = 0;
1087
1088 RT_ZERO(pTransfer->Callbacks);
1089
1090 RTListInit(&pTransfer->lstList);
1091 RTListInit(&pTransfer->lstObj);
1092
1093 pTransfer->cRoots = 0;
1094 RTListInit(&pTransfer->lstRoots);
1095
1096 *ppTransfer = pTransfer;
1097
1098 if (RT_FAILURE(rc))
1099 {
1100 if (pTransfer)
1101 {
1102 SharedClipboardURITransferDestroy(pTransfer);
1103 RTMemFree(pTransfer);
1104 }
1105 }
1106
1107 LogFlowFuncLeaveRC(rc);
1108 return rc;
1109}
1110
1111/**
1112 * Destroys an URI clipboard transfer context struct.
1113 *
1114 * @returns VBox status code.
1115 * @param pURI URI clipboard transfer to destroy.
1116 */
1117int SharedClipboardURITransferDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1118{
1119 if (!pTransfer)
1120 return VINF_SUCCESS;
1121
1122 LogFlowFuncEnter();
1123
1124 int rc = sharedClipboardURITransferThreadDestroy(pTransfer, 30 * 1000 /* Timeout in ms */);
1125 if (RT_FAILURE(rc))
1126 return rc;
1127
1128 RTStrFree(pTransfer->pszPathRootAbs);
1129
1130 SharedClipboardEventSourceDestroy(&pTransfer->Events);
1131
1132 PSHAREDCLIPBOARDURILISTHANDLEINFO pItList, pItListNext;
1133 RTListForEachSafe(&pTransfer->lstList, pItList, pItListNext, SHAREDCLIPBOARDURILISTHANDLEINFO, Node)
1134 {
1135 SharedClipboardURIListHandleInfoDestroy(pItList);
1136
1137 RTListNodeRemove(&pItList->Node);
1138
1139 RTMemFree(pItList);
1140 }
1141
1142 PSHAREDCLIPBOARDURIOBJHANDLEINFO pItObj, pItObjNext;
1143 RTListForEachSafe(&pTransfer->lstObj, pItObj, pItObjNext, SHAREDCLIPBOARDURIOBJHANDLEINFO, Node)
1144 {
1145 SharedClipboardURIObjectHandleInfoDestroy(pItObj);
1146
1147 RTListNodeRemove(&pItObj->Node);
1148
1149 RTMemFree(pItObj);
1150 }
1151
1152 LogFlowFuncLeave();
1153 return VINF_SUCCESS;
1154}
1155
1156int SharedClipboardURITransferOpen(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1157{
1158 int rc = VINF_SUCCESS;
1159
1160 if (pTransfer->ProviderIface.pfnTransferOpen)
1161 rc = pTransfer->ProviderIface.pfnTransferOpen(&pTransfer->ProviderCtx);
1162
1163 LogFlowFuncLeaveRC(rc);
1164 return rc;
1165}
1166
1167int SharedClipboardURITransferClose(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1168{
1169 int rc = VINF_SUCCESS;
1170
1171 if (pTransfer->ProviderIface.pfnTransferClose)
1172 rc = pTransfer->ProviderIface.pfnTransferClose(&pTransfer->ProviderCtx);
1173
1174 LogFlowFuncLeaveRC(rc);
1175 return rc;
1176}
1177
1178/**
1179 * Returns a specific list handle info of a transfer.
1180 *
1181 * @returns Pointer to list handle info if found, or NULL if not found.
1182 * @param pTransfer URI clipboard transfer to get list handle info from.
1183 * @param hList List handle of the list to get handle info for.
1184 */
1185inline PSHAREDCLIPBOARDURILISTHANDLEINFO sharedClipboardURITransferListGet(PSHAREDCLIPBOARDURITRANSFER pTransfer,
1186 SHAREDCLIPBOARDLISTHANDLE hList)
1187{
1188 PSHAREDCLIPBOARDURILISTHANDLEINFO pIt;
1189 RTListForEach(&pTransfer->lstList, pIt, SHAREDCLIPBOARDURILISTHANDLEINFO, Node)
1190 {
1191 if (pIt->hList == hList)
1192 return pIt;
1193 }
1194
1195 return NULL;
1196}
1197
1198/**
1199 * Creates a new list handle (local only).
1200 *
1201 * @returns New List handle on success, or SHAREDCLIPBOARDLISTHANDLE_INVALID on error.
1202 * @param pTransfer URI clipboard transfer to create new list handle for.
1203 */
1204inline SHAREDCLIPBOARDLISTHANDLE sharedClipboardURITransferListHandleNew(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1205{
1206 return pTransfer->uListHandleNext++; /** @todo Good enough for now. Improve this later. */
1207}
1208
1209/**
1210 * Opens a list.
1211 *
1212 * @returns VBox status code.
1213 * @param pTransfer URI clipboard transfer to handle.
1214 * @param pOpenParms List open parameters to use for opening.
1215 * @param phList Where to store the List handle of opened list on success.
1216 */
1217int SharedClipboardURITransferListOpen(PSHAREDCLIPBOARDURITRANSFER pTransfer, PVBOXCLIPBOARDLISTOPENPARMS pOpenParms,
1218 PSHAREDCLIPBOARDLISTHANDLE phList)
1219{
1220 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1221 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1222 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1223
1224 int rc;
1225
1226 SHAREDCLIPBOARDLISTHANDLE hList = SHAREDCLIPBOARDLISTHANDLE_INVALID;
1227
1228 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
1229 {
1230 PSHAREDCLIPBOARDURILISTHANDLEINFO pInfo
1231 = (PSHAREDCLIPBOARDURILISTHANDLEINFO)RTMemAlloc(sizeof(SHAREDCLIPBOARDURILISTHANDLEINFO));
1232 if (pInfo)
1233 {
1234 LogFlowFunc(("pszPath=%s\n", pOpenParms->pszPath));
1235
1236 RTFSOBJINFO objInfo;
1237 rc = RTPathQueryInfo(pOpenParms->pszPath, &objInfo, RTFSOBJATTRADD_NOTHING);
1238 if (RT_SUCCESS(rc))
1239 {
1240 switch (pInfo->enmType)
1241 {
1242 case SHAREDCLIPBOARDURIOBJTYPE_DIRECTORY:
1243 {
1244 rc = RTDirOpen(&pInfo->u.Local.hDir, pOpenParms->pszPath);
1245 break;
1246 }
1247
1248 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
1249 {
1250 rc = RTFileOpen(&pInfo->u.Local.hFile, pOpenParms->pszPath,
1251 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
1252 break;
1253 }
1254
1255 default:
1256 rc = VERR_NOT_SUPPORTED;
1257 break;
1258 }
1259
1260 if (RT_SUCCESS(rc))
1261 {
1262 pInfo->hList = sharedClipboardURITransferListHandleNew(pTransfer);
1263
1264 RTListAppend(&pTransfer->lstList, &pInfo->Node);
1265 }
1266 else
1267 {
1268 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
1269 {
1270 if (RTDirIsValid(pInfo->u.Local.hDir))
1271 RTDirClose(pInfo->u.Local.hDir);
1272 }
1273 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
1274 {
1275 if (RTFileIsValid(pInfo->u.Local.hFile))
1276 RTFileClose(pInfo->u.Local.hFile);
1277 }
1278
1279 RTMemFree(pInfo);
1280 pInfo = NULL;
1281 }
1282 }
1283 }
1284 else
1285 rc = VERR_NO_MEMORY;
1286 }
1287 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
1288 {
1289 if (pTransfer->ProviderIface.pfnListOpen)
1290 {
1291 rc = pTransfer->ProviderIface.pfnListOpen(&pTransfer->ProviderCtx, pOpenParms, &hList);
1292 }
1293 else
1294 rc = VERR_NOT_SUPPORTED;
1295 }
1296 else
1297 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
1298
1299 if (RT_SUCCESS(rc))
1300 *phList = hList;
1301
1302 LogFlowFuncLeaveRC(rc);
1303 return rc;
1304}
1305
1306/**
1307 * Closes a list.
1308 *
1309 * @returns VBox status code.
1310 * @param pTransfer URI clipboard transfer to handle.
1311 * @param hList Handle of list to close.
1312 */
1313int SharedClipboardURITransferListClose(PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDLISTHANDLE hList)
1314{
1315 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1316
1317 if (hList == SHAREDCLIPBOARDLISTHANDLE_INVALID)
1318 return VINF_SUCCESS;
1319
1320 int rc = VINF_SUCCESS;
1321
1322 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
1323 {
1324 PSHAREDCLIPBOARDURILISTHANDLEINFO pInfo = sharedClipboardURITransferListGet(pTransfer, hList);
1325 if (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 RTListNodeRemove(&pInfo->Node);
1342
1343 RTMemFree(pInfo);
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 PSHAREDCLIPBOARDURILISTHANDLEINFO pInfo = sharedClipboardURITransferListGet(pTransfer, hList);
1558 if (pInfo)
1559 {
1560 rc = SharedClipboardURIListHdrInit(pHdr);
1561 if (RT_SUCCESS(rc))
1562 {
1563 switch (pInfo->enmType)
1564 {
1565 case SHAREDCLIPBOARDURIOBJTYPE_DIRECTORY:
1566 {
1567 char *pszPathRel = sharedClipboardPathTranslate(pInfo->pszPathLocalAbs);
1568 if (pszPathRel)
1569 {
1570 rc = sharedClipboardURITransferListHdrFromDir(pHdr,
1571 pszPathRel, pszPathRel, pszPathRel);
1572 RTStrFree(pszPathRel);
1573 }
1574 else
1575 rc = VERR_NO_MEMORY;
1576 break;
1577 }
1578
1579 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
1580 {
1581 pHdr->cTotalObjects = 1;
1582
1583 RTFSOBJINFO objInfo;
1584 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);
1585 if (RT_SUCCESS(rc))
1586 {
1587 pHdr->cbTotalSize = objInfo.cbObject;
1588 }
1589 break;
1590 }
1591
1592 default:
1593 rc = VERR_NOT_SUPPORTED;
1594 break;
1595 }
1596 }
1597
1598 LogFlowFunc(("cTotalObj=%RU64, cbTotalSize=%RU64\n", pHdr->cTotalObjects, pHdr->cbTotalSize));
1599 }
1600 else
1601 rc = VERR_NOT_FOUND;
1602 }
1603 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
1604 {
1605 if (pTransfer->ProviderIface.pfnListHdrRead)
1606 {
1607 rc = pTransfer->ProviderIface.pfnListHdrRead(&pTransfer->ProviderCtx, hList, pHdr);
1608 }
1609 else
1610 rc = VERR_NOT_SUPPORTED;
1611 }
1612 else
1613 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
1614
1615 LogFlowFuncLeaveRC(rc);
1616 return rc;
1617}
1618
1619/**
1620 * Returns the current URI object for a clipboard URI transfer list.
1621 *
1622 * Currently not implemented and wil return NULL.
1623 *
1624 * @returns Pointer to URI object, or NULL if not found / invalid.
1625 * @param pTransfer URI clipboard transfer to return URI object for.
1626 * @param hList Handle of URI transfer list to get object for.
1627 * @param uIdx Index of object to get.
1628 */
1629PSHAREDCLIPBOARDURITRANSFEROBJ SharedClipboardURITransferListGetObj(PSHAREDCLIPBOARDURITRANSFER pTransfer,
1630 SHAREDCLIPBOARDLISTHANDLE hList, uint64_t uIdx)
1631{
1632 AssertPtrReturn(pTransfer, NULL);
1633
1634 RT_NOREF(hList, uIdx);
1635
1636 LogFlowFunc(("hList=%RU64\n", hList));
1637
1638 return NULL;
1639}
1640
1641/**
1642 * Reads a single Shared Clipboard list entry.
1643 *
1644 * @returns VBox status code or VERR_NO_MORE_FILES if the end of the list has been reached.
1645 * @param pTransfer URI clipboard transfer to handle.
1646 * @param hList List handle of list to read from.
1647 * @param pEntry Where to store the read information.
1648 */
1649int SharedClipboardURITransferListRead(PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDLISTHANDLE hList,
1650 PVBOXCLIPBOARDLISTENTRY pEntry)
1651{
1652 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1653 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
1654
1655 int rc = VINF_SUCCESS;
1656
1657 LogFlowFunc(("hList=%RU64\n", hList));
1658
1659 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
1660 {
1661 PSHAREDCLIPBOARDURILISTHANDLEINFO pInfo = sharedClipboardURITransferListGet(pTransfer, hList);
1662 if (pInfo)
1663 {
1664 switch (pInfo->enmType)
1665 {
1666 case SHAREDCLIPBOARDURIOBJTYPE_DIRECTORY:
1667 {
1668 LogFlowFunc(("\tDirectory: %s\n", pInfo->pszPathLocalAbs));
1669
1670 for (;;)
1671 {
1672 bool fSkipEntry = false; /* Whether to skip an entry in the enumeration. */
1673
1674 size_t cbDirEntry = 0;
1675 PRTDIRENTRYEX pDirEntry = NULL;
1676 rc = RTDirReadExA(pInfo->u.Local.hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
1677 if (RT_SUCCESS(rc))
1678 {
1679 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
1680 {
1681 case RTFS_TYPE_DIRECTORY:
1682 {
1683 /* Skip "." and ".." entries. */
1684 if (RTDirEntryExIsStdDotLink(pDirEntry))
1685 {
1686 fSkipEntry = true;
1687 break;
1688 }
1689
1690 LogFlowFunc(("Directory: %s\n", pDirEntry->szName));
1691 break;
1692 }
1693
1694 case RTFS_TYPE_FILE:
1695 {
1696 LogFlowFunc(("File: %s\n", pDirEntry->szName));
1697 break;
1698 }
1699
1700 case RTFS_TYPE_SYMLINK:
1701 {
1702 rc = VERR_NOT_IMPLEMENTED; /** @todo Not implemented yet. */
1703 break;
1704 }
1705
1706 default:
1707 break;
1708 }
1709
1710 if ( RT_SUCCESS(rc)
1711 && !fSkipEntry)
1712 {
1713 pEntry->pvInfo = (PSHAREDCLIPBOARDFSOBJINFO)RTMemAlloc(sizeof(SHAREDCLIPBOARDFSOBJINFO));
1714 if (pEntry->pvInfo)
1715 {
1716 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pDirEntry->szName);
1717 if (RT_SUCCESS(rc))
1718 {
1719 SharedClipboardFsObjFromIPRT(PSHAREDCLIPBOARDFSOBJINFO(pEntry->pvInfo), &pDirEntry->Info);
1720
1721 pEntry->cbInfo = sizeof(SHAREDCLIPBOARDFSOBJINFO);
1722 pEntry->fInfo = VBOX_SHAREDCLIPBOARD_INFO_FLAG_FSOBJINFO;
1723 }
1724 }
1725 else
1726 rc = VERR_NO_MEMORY;
1727 }
1728
1729 RTDirReadExAFree(&pDirEntry, &cbDirEntry);
1730 }
1731
1732 if ( !fSkipEntry /* Do we have a valid entry? Bail out. */
1733 || RT_FAILURE(rc))
1734 {
1735 break;
1736 }
1737 }
1738
1739 break;
1740 }
1741
1742 case SHAREDCLIPBOARDURIOBJTYPE_FILE:
1743 {
1744 LogFlowFunc(("\tSingle file: %s\n", pInfo->pszPathLocalAbs));
1745
1746 RTFSOBJINFO objInfo;
1747 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);
1748 if (RT_SUCCESS(rc))
1749 {
1750 pEntry->pvInfo = (PSHAREDCLIPBOARDFSOBJINFO)RTMemAlloc(sizeof(SHAREDCLIPBOARDFSOBJINFO));
1751 if (pEntry->pvInfo)
1752 {
1753 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pInfo->pszPathLocalAbs);
1754 if (RT_SUCCESS(rc))
1755 {
1756 SharedClipboardFsObjFromIPRT(PSHAREDCLIPBOARDFSOBJINFO(pEntry->pvInfo), &objInfo);
1757
1758 pEntry->cbInfo = sizeof(SHAREDCLIPBOARDFSOBJINFO);
1759 pEntry->fInfo = VBOX_SHAREDCLIPBOARD_INFO_FLAG_FSOBJINFO;
1760 }
1761 }
1762 else
1763 rc = VERR_NO_MEMORY;
1764 }
1765
1766 break;
1767 }
1768
1769 default:
1770 rc = VERR_NOT_SUPPORTED;
1771 break;
1772 }
1773 }
1774 else
1775 rc = VERR_NOT_FOUND;
1776 }
1777 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
1778 {
1779 if (pTransfer->ProviderIface.pfnListEntryRead)
1780 rc = pTransfer->ProviderIface.pfnListEntryRead(&pTransfer->ProviderCtx, hList, pEntry);
1781 else
1782 rc = VERR_NOT_SUPPORTED;
1783 }
1784
1785 LogFlowFuncLeaveRC(rc);
1786 return rc;
1787}
1788
1789int SharedClipboardURITransferListWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDLISTHANDLE hList,
1790 PVBOXCLIPBOARDLISTENTRY pEntry)
1791{
1792 RT_NOREF(pTransfer, hList, pEntry);
1793
1794 int rc = VINF_SUCCESS;
1795
1796#if 0
1797 if (pTransfer->ProviderIface.pfnListEntryWrite)
1798 rc = pTransfer->ProviderIface.pfnListEntryWrite(&pTransfer->ProviderCtx, hList, pEntry);
1799#endif
1800
1801 LogFlowFuncLeaveRC(rc);
1802 return rc;
1803}
1804
1805/**
1806 * Returns whether a given list handle is valid or not.
1807 *
1808 * @returns \c true if list handle is valid, \c false if not.
1809 * @param pTransfer URI clipboard transfer to handle.
1810 * @param hList List handle to check.
1811 */
1812bool SharedClipboardURITransferListHandleIsValid(PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDLISTHANDLE hList)
1813{
1814 bool fIsValid = false;
1815
1816 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
1817 {
1818 fIsValid = sharedClipboardURITransferListGet(pTransfer, hList) != NULL;
1819 }
1820 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
1821 {
1822 AssertFailed(); /** @todo Implement. */
1823 }
1824
1825 return fIsValid;
1826}
1827
1828/**
1829 * Prepares everything needed for a read / write transfer to begin.
1830 *
1831 * @returns VBox status code.
1832 * @param pTransfer URI clipboard transfer to prepare.
1833 */
1834int SharedClipboardURITransferPrepare(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1835{
1836 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1837
1838 LogFlowFuncEnter();
1839
1840 int rc = VINF_SUCCESS;
1841
1842 AssertMsgReturn(pTransfer->State.enmStatus == SHAREDCLIPBOARDURITRANSFERSTATUS_NONE,
1843 ("Transfer has wrong state (%RU32)\n", pTransfer->State.enmStatus), VERR_WRONG_ORDER);
1844
1845 LogFlowFunc(("pTransfer=%p, enmDir=%RU32\n", pTransfer, pTransfer->State.enmDir));
1846
1847 if (pTransfer->Callbacks.pfnTransferPrepare)
1848 {
1849 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1850 pTransfer->Callbacks.pfnTransferPrepare(&callbackData);
1851 }
1852
1853 if (RT_SUCCESS(rc))
1854 {
1855 pTransfer->State.enmStatus = SHAREDCLIPBOARDURITRANSFERSTATUS_READY;
1856
1857 /** @todo Add checksum support. */
1858 }
1859
1860 LogFlowFuncLeaveRC(rc);
1861 return rc;
1862}
1863
1864/**
1865 * Sets the URI provider interface for a given transfer.
1866 *
1867 * @returns VBox status code.
1868 * @param pTransfer Transfer to create URI provider for.
1869 * @param pCreationCtx Provider creation context to use for provider creation.
1870 */
1871int SharedClipboardURITransferSetInterface(PSHAREDCLIPBOARDURITRANSFER pTransfer,
1872 PSHAREDCLIPBOARDPROVIDERCREATIONCTX pCreationCtx)
1873{
1874 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1875 AssertPtrReturn(pCreationCtx, VERR_INVALID_POINTER);
1876
1877 LogFlowFuncEnter();
1878
1879 int rc = VINF_SUCCESS;
1880
1881 pTransfer->ProviderIface = pCreationCtx->Interface;
1882
1883#ifdef DEBUG
1884# define LOG_IFACE_PTR(a_Name) \
1885 LogFlowFunc(( #a_Name "=%p\n", pTransfer->ProviderIface.a_Name));
1886
1887 LOG_IFACE_PTR(pfnTransferOpen);
1888 LOG_IFACE_PTR(pfnTransferClose);
1889 LOG_IFACE_PTR(pfnGetRoots);
1890 LOG_IFACE_PTR(pfnListOpen);
1891 LOG_IFACE_PTR(pfnListClose);
1892
1893# undef LOG_IFACE_PTR
1894#endif
1895
1896 pTransfer->ProviderCtx.pTransfer = pTransfer;
1897 pTransfer->ProviderCtx.pvUser = pCreationCtx->pvUser;
1898
1899 LogFlowFuncLeaveRC(rc);
1900 return rc;
1901}
1902
1903/**
1904 * Clears (resets) the root list of an URI transfer.
1905 *
1906 * @param pTransfer Transfer to clear URI root list for.
1907 */
1908static void sharedClipboardURIListTransferRootsClear(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1909{
1910 AssertPtrReturnVoid(pTransfer);
1911
1912 if (pTransfer->pszPathRootAbs)
1913 {
1914 RTStrFree(pTransfer->pszPathRootAbs);
1915 pTransfer->pszPathRootAbs = NULL;
1916 }
1917
1918 PSHAREDCLIPBOARDURILISTROOT pListRoot, pListRootNext;
1919 RTListForEachSafe(&pTransfer->lstRoots, pListRoot, pListRootNext, SHAREDCLIPBOARDURILISTROOT, Node)
1920 {
1921 RTStrFree(pListRoot->pszPathAbs);
1922
1923 RTListNodeRemove(&pListRoot->Node);
1924
1925 RTMemFree(pListRoot);
1926 pListRoot = NULL;
1927 }
1928
1929 pTransfer->cRoots = 0;
1930}
1931
1932/**
1933 * Sets URI root list entries for a given transfer.
1934 *
1935 * @returns VBox status code.
1936 * @param pTransfer Transfer to set URI list entries for.
1937 * @param pszRoots String list (separated by CRLF) of root entries to set.
1938 * All entries must have the same root path.
1939 * @param cbRoots Size (in bytes) of string list.
1940 */
1941int SharedClipboardURILTransferSetRoots(PSHAREDCLIPBOARDURITRANSFER pTransfer, const char *pszRoots, size_t cbRoots)
1942{
1943 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1944 AssertPtrReturn(pszRoots, VERR_INVALID_POINTER);
1945 AssertReturn(cbRoots, VERR_INVALID_PARAMETER);
1946
1947 if (!RTStrIsValidEncoding(pszRoots))
1948 return VERR_INVALID_PARAMETER;
1949
1950 int rc = VINF_SUCCESS;
1951
1952 sharedClipboardURIListTransferRootsClear(pTransfer);
1953
1954 char *pszPathRootAbs = NULL;
1955
1956 RTCList<RTCString> lstRootEntries = RTCString(pszRoots, cbRoots - 1).split("\r\n");
1957 for (size_t i = 0; i < lstRootEntries.size(); ++i)
1958 {
1959 PSHAREDCLIPBOARDURILISTROOT pListRoot = (PSHAREDCLIPBOARDURILISTROOT)RTMemAlloc(sizeof(SHAREDCLIPBOARDURILISTROOT));
1960 AssertPtrBreakStmt(pListRoot, rc = VERR_NO_MEMORY);
1961
1962 pListRoot->pszPathAbs = RTStrDup(lstRootEntries.at(i).c_str());
1963 AssertPtrBreakStmt(pListRoot->pszPathAbs, rc = VERR_NO_MEMORY);
1964
1965 if (!pszPathRootAbs)
1966 {
1967 pszPathRootAbs = RTStrDup(pListRoot->pszPathAbs);
1968 if (pszPathRootAbs)
1969 {
1970 RTPathStripFilename(pszPathRootAbs);
1971 LogFlowFunc(("pszPathRootAbs=%s\n", pszPathRootAbs));
1972 }
1973 else
1974 rc = VERR_NO_MEMORY;
1975 }
1976
1977 if (RT_FAILURE(rc))
1978 break;
1979
1980 /* Make sure all entries have the same root path. */
1981 if (!RTStrStartsWith(pListRoot->pszPathAbs, pszPathRootAbs))
1982 {
1983 rc = VERR_INVALID_PARAMETER;
1984 break;
1985 }
1986
1987 RTListAppend(&pTransfer->lstRoots, &pListRoot->Node);
1988
1989 pTransfer->cRoots++;
1990 }
1991
1992 /** @todo Entry rollback on failure? */
1993
1994 if (RT_SUCCESS(rc))
1995 {
1996 pTransfer->pszPathRootAbs = pszPathRootAbs;
1997 LogFlowFunc(("pszPathRootAbs=%s, cRoots=%zu\n", pTransfer->pszPathRootAbs, pTransfer->cRoots));
1998 }
1999
2000 LogFlowFuncLeaveRC(rc);
2001 return rc;
2002}
2003
2004/**
2005 * Resets an clipboard URI transfer.
2006 *
2007 * @param pTransfer URI clipboard transfer to reset.
2008 */
2009void SharedClipboardURITransferReset(PSHAREDCLIPBOARDURITRANSFER pTransfer)
2010{
2011 AssertPtrReturnVoid(pTransfer);
2012
2013 LogFlowFuncEnter();
2014
2015 sharedClipboardURIListTransferRootsClear(pTransfer);
2016}
2017
2018/**
2019 * Returns the clipboard area for a clipboard URI transfer.
2020 *
2021 * @returns Current clipboard area, or NULL if none.
2022 * @param pTransfer URI clipboard transfer to return clipboard area for.
2023 */
2024SharedClipboardArea *SharedClipboardURITransferGetArea(PSHAREDCLIPBOARDURITRANSFER pTransfer)
2025{
2026 AssertPtrReturn(pTransfer, NULL);
2027
2028 return pTransfer->pArea;
2029}
2030
2031/**
2032 * Returns the number of URI root list entries.
2033 *
2034 * @returns Root list entry count.
2035 * @param pTransfer URI clipboard transfer to return root entry count for.
2036 */
2037uint32_t SharedClipboardURILTransferRootsCount(PSHAREDCLIPBOARDURITRANSFER pTransfer)
2038{
2039 AssertPtrReturn(pTransfer, 0);
2040
2041 return (uint32_t)pTransfer->cRoots;
2042}
2043
2044/**
2045 * Returns a specific root list entry of a transfer.
2046 *
2047 * @returns Pointer to root list entry if found, or NULL if not found.
2048 * @param pTransfer URI clipboard transfer to get root list entry from.
2049 * @param uIdx Index of root list entry to return.
2050 */
2051inline PSHAREDCLIPBOARDURILISTROOT sharedClipboardURILTransferRootsGet(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t uIdx)
2052{
2053 if (uIdx >= pTransfer->cRoots)
2054 return NULL;
2055
2056 PSHAREDCLIPBOARDURILISTROOT pIt = RTListGetFirst(&pTransfer->lstRoots, SHAREDCLIPBOARDURILISTROOT, Node);
2057 while (uIdx--)
2058 pIt = RTListGetNext(&pTransfer->lstRoots, pIt, SHAREDCLIPBOARDURILISTROOT, Node);
2059
2060 return pIt;
2061}
2062
2063/**
2064 * Get a specific root list entry.
2065 *
2066 * @returns VBox status code.
2067 * @param pTransfer URI clipboard transfer to get root list entry of.
2068 * @param uIndex Index (zero-based) of entry to get.
2069 * @param pEntry Where to store the returned entry on success.
2070 */
2071int SharedClipboardURILTransferRootsEntry(PSHAREDCLIPBOARDURITRANSFER pTransfer,
2072 uint64_t uIndex, PVBOXCLIPBOARDROOTLISTENTRY pEntry)
2073{
2074 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2075 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
2076
2077 if (uIndex >= pTransfer->cRoots)
2078 return VERR_INVALID_PARAMETER;
2079
2080 int rc;
2081
2082 PSHAREDCLIPBOARDURILISTROOT pRoot = sharedClipboardURILTransferRootsGet(pTransfer, uIndex);
2083 AssertPtrReturn(pRoot, VERR_INVALID_PARAMETER);
2084
2085 /* Make sure that we only advertise relative source paths, not absolute ones. */
2086 const char *pcszSrcPath = pRoot->pszPathAbs;
2087
2088 char *pszFileName = RTPathFilename(pcszSrcPath);
2089 if (pszFileName)
2090 {
2091 Assert(pszFileName >= pcszSrcPath);
2092 size_t cchDstBase = pszFileName - pcszSrcPath;
2093 const char *pszDstPath = &pcszSrcPath[cchDstBase];
2094
2095 LogFlowFunc(("pcszSrcPath=%s, pszDstPath=%s\n", pcszSrcPath, pszDstPath));
2096
2097 rc = SharedClipboardURIListEntryInit(pEntry);
2098 if (RT_SUCCESS(rc))
2099 {
2100 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pszDstPath);
2101 if (RT_SUCCESS(rc))
2102 {
2103 pEntry->cbInfo = sizeof(SHAREDCLIPBOARDFSOBJINFO);
2104 pEntry->pvInfo = (PSHAREDCLIPBOARDFSOBJINFO)RTMemAlloc(pEntry->cbInfo);
2105 if (pEntry->pvInfo)
2106 {
2107 RTFSOBJINFO fsObjInfo;
2108 rc = RTPathQueryInfo(pcszSrcPath, & fsObjInfo, RTFSOBJATTRADD_NOTHING);
2109 if (RT_SUCCESS(rc))
2110 {
2111 SharedClipboardFsObjFromIPRT(PSHAREDCLIPBOARDFSOBJINFO(pEntry->pvInfo), &fsObjInfo);
2112
2113 pEntry->fInfo = VBOX_SHAREDCLIPBOARD_INFO_FLAG_FSOBJINFO;
2114 }
2115 }
2116 else
2117 rc = VERR_NO_MEMORY;
2118 }
2119 }
2120 }
2121 else
2122 rc = VERR_INVALID_POINTER;
2123
2124 LogFlowFuncLeaveRC(rc);
2125 return rc;
2126}
2127
2128/**
2129 * Returns the root entries of an URI transfer.
2130 *
2131 * @returns VBox status code.
2132 * @param pTransfer URI clipboard transfer to return root entries for.
2133 * @param ppRootList Where to store the root list on success.
2134 */
2135int SharedClipboardURILTransferRootsAsList(PSHAREDCLIPBOARDURITRANSFER pTransfer, PVBOXCLIPBOARDROOTLIST *ppRootList)
2136{
2137 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2138 AssertPtrReturn(ppRootList, VERR_INVALID_POINTER);
2139
2140 LogFlowFuncEnter();
2141
2142 int rc = VINF_SUCCESS;
2143
2144 if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_LOCAL)
2145 {
2146 PVBOXCLIPBOARDROOTLIST pRootList = SharedClipboardURIRootListAlloc();
2147 if (!pRootList)
2148 return VERR_NO_MEMORY;
2149
2150 const uint64_t cRoots = (uint32_t)pTransfer->cRoots;
2151
2152 LogFlowFunc(("cRoots=%RU64\n", cRoots));
2153
2154 if (cRoots)
2155 {
2156 PVBOXCLIPBOARDROOTLISTENTRY paRootListEntries
2157 = (PVBOXCLIPBOARDROOTLISTENTRY)RTMemAllocZ(cRoots * sizeof(VBOXCLIPBOARDROOTLISTENTRY));
2158 if (paRootListEntries)
2159 {
2160 for (uint64_t i = 0; i < cRoots; ++i)
2161 {
2162 rc = SharedClipboardURILTransferRootsEntry(pTransfer, i, &paRootListEntries[i]);
2163 if (RT_FAILURE(rc))
2164 break;
2165 }
2166
2167 if (RT_SUCCESS(rc))
2168 pRootList->paEntries = paRootListEntries;
2169 }
2170 else
2171 rc = VERR_NO_MEMORY;
2172 }
2173 else
2174 rc = VERR_NOT_FOUND;
2175
2176 if (RT_SUCCESS(rc))
2177 {
2178 pRootList->Hdr.cRoots = cRoots;
2179 pRootList->Hdr.fRoots = 0; /** @todo Implement this. */
2180
2181 *ppRootList = pRootList;
2182 }
2183 }
2184 else if (pTransfer->State.enmSource == SHAREDCLIPBOARDSOURCE_REMOTE)
2185 {
2186 if (pTransfer->ProviderIface.pfnGetRoots)
2187 rc = pTransfer->ProviderIface.pfnGetRoots(&pTransfer->ProviderCtx, ppRootList);
2188 else
2189 rc = VERR_NOT_SUPPORTED;
2190 }
2191
2192 LogFlowFuncLeaveRC(rc);
2193 return rc;
2194}
2195
2196/**
2197 * Returns the transfer's source.
2198 *
2199 * @returns The transfer's source.
2200 * @param pTransfer URI clipboard transfer to return source for.
2201 */
2202SHAREDCLIPBOARDSOURCE SharedClipboardURITransferGetSource(PSHAREDCLIPBOARDURITRANSFER pTransfer)
2203{
2204 AssertPtrReturn(pTransfer, SHAREDCLIPBOARDSOURCE_INVALID);
2205
2206 return pTransfer->State.enmSource;
2207}
2208
2209/**
2210 * Returns the current transfer status.
2211 *
2212 * @returns Current transfer status.
2213 * @param pTransfer URI clipboard transfer to return status for.
2214 */
2215SHAREDCLIPBOARDURITRANSFERSTATUS SharedClipboardURITransferGetStatus(PSHAREDCLIPBOARDURITRANSFER pTransfer)
2216{
2217 AssertPtrReturn(pTransfer, SHAREDCLIPBOARDURITRANSFERSTATUS_NONE);
2218
2219 return pTransfer->State.enmStatus;
2220}
2221
2222/**
2223 * Runs (starts) an URI transfer thread.
2224 *
2225 * @returns VBox status code.
2226 * @param pTransfer URI clipboard transfer to run.
2227 * @param pfnThreadFunc Pointer to thread function to use.
2228 * @param pvUser Pointer to user-provided data.
2229 */
2230int SharedClipboardURITransferRun(PSHAREDCLIPBOARDURITRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser)
2231{
2232 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2233
2234 AssertMsgReturn(pTransfer->State.enmStatus == SHAREDCLIPBOARDURITRANSFERSTATUS_READY,
2235 ("Wrong status (currently is %RU32)\n", pTransfer->State.enmStatus), VERR_WRONG_ORDER);
2236
2237 int rc = sharedClipboardURITransferThreadCreate(pTransfer, pfnThreadFunc, pvUser);
2238
2239 LogFlowFuncLeaveRC(rc);
2240 return rc;
2241}
2242
2243/**
2244 * Sets or unsets the callback table to be used for a clipboard URI transfer.
2245 *
2246 * @returns VBox status code.
2247 * @param pTransfer URI clipboard transfer to set callbacks for.
2248 * @param pCallbacks Pointer to callback table to set.
2249 */
2250void SharedClipboardURITransferSetCallbacks(PSHAREDCLIPBOARDURITRANSFER pTransfer,
2251 PSHAREDCLIPBOARDURITRANSFERCALLBACKS pCallbacks)
2252{
2253 AssertPtrReturnVoid(pTransfer);
2254 AssertPtrReturnVoid(pCallbacks);
2255
2256 LogFlowFunc(("pCallbacks=%p\n", pCallbacks));
2257
2258#define SET_CALLBACK(a_pfnCallback) \
2259 if (pCallbacks->a_pfnCallback) \
2260 pTransfer->Callbacks.a_pfnCallback = pCallbacks->a_pfnCallback
2261
2262 SET_CALLBACK(pfnTransferPrepare);
2263 SET_CALLBACK(pfnTransferStarted);
2264 SET_CALLBACK(pfnListHeaderComplete);
2265 SET_CALLBACK(pfnListEntryComplete);
2266 SET_CALLBACK(pfnTransferCanceled);
2267 SET_CALLBACK(pfnTransferError);
2268 SET_CALLBACK(pfnTransferStarted);
2269
2270#undef SET_CALLBACK
2271
2272 pTransfer->Callbacks.pvUser = pCallbacks->pvUser;
2273}
2274
2275/**
2276 * Creates a thread for a clipboard URI transfer.
2277 *
2278 * @returns VBox status code.
2279 * @param pTransfer URI clipboard transfer to create thread for.
2280 * @param pfnThreadFunc Thread function to use for this transfer.
2281 * @param pvUser Pointer to user-provided data.
2282 */
2283static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser)
2284
2285{
2286 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2287
2288 /* Spawn a worker thread, so that we don't block the window thread for too long. */
2289 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnThreadFunc,
2290 pvUser, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
2291 "shclp");
2292 if (RT_SUCCESS(rc))
2293 {
2294 int rc2 = RTThreadUserWait(pTransfer->Thread.hThread, 30 * 1000 /* Timeout in ms */);
2295 AssertRC(rc2);
2296
2297 if (pTransfer->Thread.fStarted) /* Did the thread indicate that it started correctly? */
2298 {
2299 pTransfer->State.enmStatus = SHAREDCLIPBOARDURITRANSFERSTATUS_RUNNING;
2300 }
2301 else
2302 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
2303 }
2304
2305 LogFlowFuncLeaveRC(rc);
2306 return rc;
2307}
2308
2309/**
2310 * Destroys a thread of a clipboard URI transfer.
2311 *
2312 * @returns VBox status code.
2313 * @param pTransfer URI clipboard transfer to destroy thread for.
2314 * @param uTimeoutMs Timeout (in ms) to wait for thread creation.
2315 */
2316static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs)
2317{
2318 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2319
2320 if (pTransfer->Thread.hThread == NIL_RTTHREAD)
2321 return VINF_SUCCESS;
2322
2323 LogFlowFuncEnter();
2324
2325 /* Set stop indicator. */
2326 pTransfer->Thread.fStop = true;
2327
2328 int rcThread = VERR_WRONG_ORDER;
2329 int rc = RTThreadWait(pTransfer->Thread.hThread, uTimeoutMs, &rcThread);
2330
2331 LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n", rc, rcThread));
2332
2333 return rc;
2334}
2335
2336/**
2337 * Initializes a clipboard URI transfer.
2338 *
2339 * @returns VBox status code.
2340 * @param pURI URI clipboard context to initialize.
2341 */
2342int SharedClipboardURICtxInit(PSHAREDCLIPBOARDURICTX pURI)
2343{
2344 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
2345
2346 LogFlowFunc(("%p\n", pURI));
2347
2348 int rc = RTCritSectInit(&pURI->CritSect);
2349 if (RT_SUCCESS(rc))
2350 {
2351 RTListInit(&pURI->List);
2352
2353 pURI->cRunning = 0;
2354 pURI->cMaxRunning = 1; /* For now we only support one transfer per client at a time. */
2355
2356#ifdef DEBUG_andy
2357 pURI->cMaxRunning = UINT32_MAX;
2358#endif
2359 SharedClipboardURICtxReset(pURI);
2360 }
2361
2362 return VINF_SUCCESS;
2363}
2364
2365/**
2366 * Destroys an URI clipboard information context struct.
2367 *
2368 * @param pURI URI clipboard context to destroy.
2369 */
2370void SharedClipboardURICtxDestroy(PSHAREDCLIPBOARDURICTX pURI)
2371{
2372 AssertPtrReturnVoid(pURI);
2373
2374 LogFlowFunc(("%p\n", pURI));
2375
2376 RTCritSectDelete(&pURI->CritSect);
2377
2378 PSHAREDCLIPBOARDURITRANSFER pTransfer, pTransferNext;
2379 RTListForEachSafe(&pURI->List, pTransfer, pTransferNext, SHAREDCLIPBOARDURITRANSFER, Node)
2380 {
2381 SharedClipboardURITransferDestroy(pTransfer);
2382
2383 RTListNodeRemove(&pTransfer->Node);
2384
2385 RTMemFree(pTransfer);
2386 pTransfer = NULL;
2387 }
2388
2389 pURI->cRunning = 0;
2390 pURI->cTransfers = 0;
2391}
2392
2393/**
2394 * Resets an clipboard URI transfer.
2395 *
2396 * @param pURI URI clipboard context to reset.
2397 */
2398void SharedClipboardURICtxReset(PSHAREDCLIPBOARDURICTX pURI)
2399{
2400 AssertPtrReturnVoid(pURI);
2401
2402 LogFlowFuncEnter();
2403
2404 PSHAREDCLIPBOARDURITRANSFER pTransfer;
2405 RTListForEach(&pURI->List, pTransfer, SHAREDCLIPBOARDURITRANSFER, Node)
2406 SharedClipboardURITransferReset(pTransfer);
2407}
2408
2409/**
2410 * Adds a new URI transfer to an clipboard URI transfer.
2411 *
2412 * @returns VBox status code.
2413 * @param pURI URI clipboard context to add transfer to.
2414 * @param pTransfer Pointer to URI clipboard transfer to add.
2415 */
2416int SharedClipboardURICtxTransferAdd(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
2417{
2418 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
2419 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2420
2421 LogFlowFuncEnter();
2422
2423 if (pURI->cRunning == pURI->cMaxRunning)
2424 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2425
2426 RTListAppend(&pURI->List, &pTransfer->Node);
2427
2428 pURI->cTransfers++;
2429 LogFlowFunc(("cTransfers=%RU32, cRunning=%RU32\n", pURI->cTransfers, pURI->cRunning));
2430
2431 return VINF_SUCCESS;
2432}
2433
2434/**
2435 * Removes an URI transfer from a clipboard URI transfer.
2436 *
2437 * @returns VBox status code.
2438 * @param pURI URI clipboard context to remove transfer from.
2439 * @param pTransfer Pointer to URI clipboard transfer to remove.
2440 */
2441int SharedClipboardURICtxTransferRemove(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
2442{
2443 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
2444 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2445
2446 LogFlowFuncEnter();
2447
2448
2449 int rc = SharedClipboardURITransferDestroy(pTransfer);
2450 if (RT_SUCCESS(rc))
2451 {
2452 RTListNodeRemove(&pTransfer->Node);
2453
2454 RTMemFree(pTransfer);
2455 pTransfer = NULL;
2456 }
2457
2458 LogFlowFuncLeaveRC(rc);
2459 return rc;
2460}
2461
2462/**
2463 * Returns a specific URI transfer, internal version.
2464 *
2465 * @returns URI transfer, or NULL if not found.
2466 * @param pURI URI clipboard context to return transfer for.
2467 * @param uIdx Index of the transfer to return.
2468 */
2469static PSHAREDCLIPBOARDURITRANSFER sharedClipboardURICtxGetTransferInternal(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
2470{
2471 AssertReturn(uIdx == 0, NULL); /* Only one transfer allowed at the moment. */
2472 return RTListGetFirst(&pURI->List, SHAREDCLIPBOARDURITRANSFER, Node);
2473}
2474
2475/**
2476 * Returns a specific URI transfer.
2477 *
2478 * @returns URI transfer, or NULL if not found.
2479 * @param pURI URI clipboard context to return transfer for.
2480 * @param uIdx Index of the transfer to return.
2481 */
2482PSHAREDCLIPBOARDURITRANSFER SharedClipboardURICtxGetTransfer(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
2483{
2484 return sharedClipboardURICtxGetTransferInternal(pURI, uIdx);
2485}
2486
2487/**
2488 * Returns the number of running URI transfers.
2489 *
2490 * @returns Number of running transfers.
2491 * @param pURI URI clipboard context to return number for.
2492 */
2493uint32_t SharedClipboardURICtxGetRunningTransfers(PSHAREDCLIPBOARDURICTX pURI)
2494{
2495 AssertPtrReturn(pURI, 0);
2496 return pURI->cRunning;
2497}
2498
2499/**
2500 * Returns the number of total URI transfers.
2501 *
2502 * @returns Number of total transfers.
2503 * @param pURI URI clipboard context to return number for.
2504 */
2505uint32_t SharedClipboardURICtxGetTotalTransfers(PSHAREDCLIPBOARDURICTX pURI)
2506{
2507 AssertPtrReturn(pURI, 0);
2508 return pURI->cTransfers;
2509}
2510
2511/**
2512 * Cleans up all associated transfers which are not needed (anymore).
2513 * This can be due to transfers which only have been announced but not / never being run.
2514 *
2515 * @param pURI URI clipboard context to cleanup transfers for.
2516 */
2517void SharedClipboardURICtxTransfersCleanup(PSHAREDCLIPBOARDURICTX pURI)
2518{
2519 AssertPtrReturnVoid(pURI);
2520
2521 LogFlowFunc(("cTransfers=%RU32, cRunning=%RU32\n", pURI->cTransfers, pURI->cRunning));
2522
2523 /* Remove all transfers which are not in a running state (e.g. only announced). */
2524 PSHAREDCLIPBOARDURITRANSFER pTransfer, pTransferNext;
2525 RTListForEachSafe(&pURI->List, pTransfer, pTransferNext, SHAREDCLIPBOARDURITRANSFER, Node)
2526 {
2527 if (SharedClipboardURITransferGetStatus(pTransfer) != SHAREDCLIPBOARDURITRANSFERSTATUS_RUNNING)
2528 {
2529 SharedClipboardURITransferDestroy(pTransfer);
2530 RTListNodeRemove(&pTransfer->Node);
2531
2532 RTMemFree(pTransfer);
2533 pTransfer = NULL;
2534
2535 Assert(pURI->cTransfers);
2536 pURI->cTransfers--;
2537 }
2538 }
2539}
2540
2541/**
2542 * Returns whether the maximum of concurrent transfers of a specific URI context has been reached or not.
2543 *
2544 * @returns \c if maximum has been reached, \c false if not.
2545 * @param pURI URI clipboard context to determine value for.
2546 */
2547bool SharedClipboardURICtxTransfersMaximumReached(PSHAREDCLIPBOARDURICTX pURI)
2548{
2549 AssertPtrReturn(pURI, true);
2550
2551 LogFlowFunc(("cRunning=%RU32, cMaxRunning=%RU32\n", pURI->cRunning, pURI->cMaxRunning));
2552
2553 Assert(pURI->cRunning <= pURI->cMaxRunning);
2554 return pURI->cRunning == pURI->cMaxRunning;
2555}
2556
2557/**
2558 * Copies file system objinfo from IPRT to Shared Clipboard format.
2559 *
2560 * @param pDst The Shared Clipboard structure to convert data to.
2561 * @param pSrc The IPRT structure to convert data from.
2562 */
2563void SharedClipboardFsObjFromIPRT(PSHAREDCLIPBOARDFSOBJINFO pDst, PCRTFSOBJINFO pSrc)
2564{
2565 pDst->cbObject = pSrc->cbObject;
2566 pDst->cbAllocated = pSrc->cbAllocated;
2567 pDst->AccessTime = pSrc->AccessTime;
2568 pDst->ModificationTime = pSrc->ModificationTime;
2569 pDst->ChangeTime = pSrc->ChangeTime;
2570 pDst->BirthTime = pSrc->BirthTime;
2571 pDst->Attr.fMode = pSrc->Attr.fMode;
2572 /* Clear bits which we don't pass through for security reasons. */
2573 pDst->Attr.fMode &= ~(RTFS_UNIX_ISUID | RTFS_UNIX_ISGID | RTFS_UNIX_ISTXT);
2574 RT_ZERO(pDst->Attr.u);
2575 switch (pSrc->Attr.enmAdditional)
2576 {
2577 default:
2578 case RTFSOBJATTRADD_NOTHING:
2579 pDst->Attr.enmAdditional = SHAREDCLIPBOARDFSOBJATTRADD_NOTHING;
2580 break;
2581
2582 case RTFSOBJATTRADD_UNIX:
2583 pDst->Attr.enmAdditional = SHAREDCLIPBOARDFSOBJATTRADD_UNIX;
2584 pDst->Attr.u.Unix.uid = pSrc->Attr.u.Unix.uid;
2585 pDst->Attr.u.Unix.gid = pSrc->Attr.u.Unix.gid;
2586 pDst->Attr.u.Unix.cHardlinks = pSrc->Attr.u.Unix.cHardlinks;
2587 pDst->Attr.u.Unix.INodeIdDevice = pSrc->Attr.u.Unix.INodeIdDevice;
2588 pDst->Attr.u.Unix.INodeId = pSrc->Attr.u.Unix.INodeId;
2589 pDst->Attr.u.Unix.fFlags = pSrc->Attr.u.Unix.fFlags;
2590 pDst->Attr.u.Unix.GenerationId = pSrc->Attr.u.Unix.GenerationId;
2591 pDst->Attr.u.Unix.Device = pSrc->Attr.u.Unix.Device;
2592 break;
2593
2594 case RTFSOBJATTRADD_EASIZE:
2595 pDst->Attr.enmAdditional = SHAREDCLIPBOARDFSOBJATTRADD_EASIZE;
2596 pDst->Attr.u.EASize.cb = pSrc->Attr.u.EASize.cb;
2597 break;
2598 }
2599}
2600
2601/**
2602 * Converts Shared Clipboard create flags (see SharedClipboard-uri.) into IPRT create flags.
2603 *
2604 * @returns IPRT status code.
2605 * @param fWritable Whether the shared folder is writable
2606 * @param fShClFlags Shared clipboard create flags.
2607 * @param fMode File attributes.
2608 * @param handleInitial Initial handle.
2609 * @retval pfOpen Where to store the IPRT creation / open flags.
2610 *
2611 * @sa Initially taken from vbsfConvertFileOpenFlags().
2612 */
2613static int sharedClipboardConvertFileCreateFlags(bool fWritable, unsigned fShClFlags, RTFMODE fMode,
2614 SHAREDCLIPBOARDOBJHANDLE handleInitial, uint64_t *pfOpen)
2615{
2616 uint64_t fOpen = 0;
2617 int rc = VINF_SUCCESS;
2618
2619 if ( (fMode & RTFS_DOS_MASK) != 0
2620 && (fMode & RTFS_UNIX_MASK) == 0)
2621 {
2622 /* A DOS/Windows guest, make RTFS_UNIX_* from RTFS_DOS_*.
2623 * @todo this is based on rtFsModeNormalize/rtFsModeFromDos.
2624 * May be better to use RTFsModeNormalize here.
2625 */
2626 fMode |= RTFS_UNIX_IRUSR | RTFS_UNIX_IRGRP | RTFS_UNIX_IROTH;
2627 /* x for directories. */
2628 if (fMode & RTFS_DOS_DIRECTORY)
2629 fMode |= RTFS_TYPE_DIRECTORY | RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;
2630 /* writable? */
2631 if (!(fMode & RTFS_DOS_READONLY))
2632 fMode |= RTFS_UNIX_IWUSR | RTFS_UNIX_IWGRP | RTFS_UNIX_IWOTH;
2633
2634 /* Set the requested mode using only allowed bits. */
2635 fOpen |= ((fMode & RTFS_UNIX_MASK) << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK;
2636 }
2637 else
2638 {
2639 /* Old linux and solaris additions did not initialize the Info.Attr.fMode field
2640 * and it contained random bits from stack. Detect this using the handle field value
2641 * passed from the guest: old additions set it (incorrectly) to 0, new additions
2642 * set it to SHAREDCLIPBOARDOBJHANDLE_INVALID(~0).
2643 */
2644 if (handleInitial == 0)
2645 {
2646 /* Old additions. Do nothing, use default mode. */
2647 }
2648 else
2649 {
2650 /* New additions or Windows additions. Set the requested mode using only allowed bits.
2651 * Note: Windows guest set RTFS_UNIX_MASK bits to 0, which means a default mode
2652 * will be set in fOpen.
2653 */
2654 fOpen |= ((fMode & RTFS_UNIX_MASK) << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK;
2655 }
2656 }
2657
2658 switch ((fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACCESS_MASK_RW))
2659 {
2660 default:
2661 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_NONE:
2662 {
2663#ifdef RT_OS_WINDOWS
2664 if ((fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACCESS_MASK_ATTR) != SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_NONE)
2665 fOpen |= RTFILE_O_ATTR_ONLY;
2666 else
2667#endif
2668 fOpen |= RTFILE_O_READ;
2669 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_NONE\n"));
2670 break;
2671 }
2672
2673 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_READ:
2674 {
2675 fOpen |= RTFILE_O_READ;
2676 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_READ\n"));
2677 break;
2678 }
2679
2680 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_WRITE:
2681 {
2682 fOpen |= RTFILE_O_WRITE;
2683 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_WRITE\n"));
2684 break;
2685 }
2686
2687 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_READWRITE:
2688 {
2689 fOpen |= RTFILE_O_READWRITE;
2690 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_READWRITE\n"));
2691 break;
2692 }
2693 }
2694
2695 if (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACCESS_APPEND)
2696 {
2697 fOpen |= RTFILE_O_APPEND;
2698 }
2699
2700 switch ((fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACCESS_MASK_ATTR))
2701 {
2702 default:
2703 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_NONE:
2704 {
2705 fOpen |= RTFILE_O_ACCESS_ATTR_DEFAULT;
2706 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_NONE\n"));
2707 break;
2708 }
2709
2710 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_READ:
2711 {
2712 fOpen |= RTFILE_O_ACCESS_ATTR_READ;
2713 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_READ\n"));
2714 break;
2715 }
2716
2717 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_WRITE:
2718 {
2719 fOpen |= RTFILE_O_ACCESS_ATTR_WRITE;
2720 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_WRITE\n"));
2721 break;
2722 }
2723
2724 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_READWRITE:
2725 {
2726 fOpen |= RTFILE_O_ACCESS_ATTR_READWRITE;
2727 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_ATTR_READWRITE\n"));
2728 break;
2729 }
2730 }
2731
2732 /* Sharing mask */
2733 switch ((fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACCESS_MASK_DENY))
2734 {
2735 default:
2736 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYNONE:
2737 fOpen |= RTFILE_O_DENY_NONE;
2738 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYNONE\n"));
2739 break;
2740
2741 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYREAD:
2742 fOpen |= RTFILE_O_DENY_READ;
2743 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYREAD\n"));
2744 break;
2745
2746 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYWRITE:
2747 fOpen |= RTFILE_O_DENY_WRITE;
2748 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYWRITE\n"));
2749 break;
2750
2751 case SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYALL:
2752 fOpen |= RTFILE_O_DENY_ALL;
2753 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACCESS_DENYALL\n"));
2754 break;
2755 }
2756
2757 /* Open/Create action mask */
2758 switch ((fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_EXISTS))
2759 {
2760 case SHAREDCLIPBOARD_OBJ_CF_ACT_OPEN_IF_EXISTS:
2761 if (SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2762 {
2763 fOpen |= RTFILE_O_OPEN_CREATE;
2764 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_OPEN_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW\n"));
2765 }
2766 else if (SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2767 {
2768 fOpen |= RTFILE_O_OPEN;
2769 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_OPEN_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW\n"));
2770 }
2771 else
2772 {
2773 LogFlowFunc(("invalid open/create action combination\n"));
2774 rc = VERR_INVALID_PARAMETER;
2775 }
2776 break;
2777 case SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_EXISTS:
2778 if (SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2779 {
2780 fOpen |= RTFILE_O_CREATE;
2781 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW\n"));
2782 }
2783 else
2784 {
2785 LogFlowFunc(("invalid open/create action combination\n"));
2786 rc = VERR_INVALID_PARAMETER;
2787 }
2788 break;
2789 case SHAREDCLIPBOARD_OBJ_CF_ACT_REPLACE_IF_EXISTS:
2790 if (SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2791 {
2792 fOpen |= RTFILE_O_CREATE_REPLACE;
2793 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_REPLACE_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW\n"));
2794 }
2795 else if (SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2796 {
2797 fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
2798 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_REPLACE_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW\n"));
2799 }
2800 else
2801 {
2802 LogFlowFunc(("invalid open/create action combination\n"));
2803 rc = VERR_INVALID_PARAMETER;
2804 }
2805 break;
2806 case SHAREDCLIPBOARD_OBJ_CF_ACT_OVERWRITE_IF_EXISTS:
2807 if (SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2808 {
2809 fOpen |= RTFILE_O_CREATE_REPLACE;
2810 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_OVERWRITE_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_CREATE_IF_NEW\n"));
2811 }
2812 else if (SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW == (fShClFlags & SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_NEW))
2813 {
2814 fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
2815 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_OVERWRITE_IF_EXISTS and SHAREDCLIPBOARD_OBJ_CF_ACT_FAIL_IF_NEW\n"));
2816 }
2817 else
2818 {
2819 LogFlowFunc(("invalid open/create action combination\n"));
2820 rc = VERR_INVALID_PARAMETER;
2821 }
2822 break;
2823 default:
2824 {
2825 rc = VERR_INVALID_PARAMETER;
2826 LogFlowFunc(("SHAREDCLIPBOARD_OBJ_CF_ACT_MASK_IF_EXISTS - invalid parameter\n"));
2827 break;
2828 }
2829 }
2830
2831 if (RT_SUCCESS(rc))
2832 {
2833 if (!fWritable)
2834 fOpen &= ~RTFILE_O_WRITE;
2835
2836 *pfOpen = fOpen;
2837 }
2838
2839 LogFlowFuncLeaveRC(rc);
2840 return rc;
2841}
2842
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