VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp@ 81223

最後變更 在這個檔案從81223是 81223,由 vboxsync 提交於 5 年 前

Shared Clipboard/Transfers: Renaming.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette