VirtualBox

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

最後變更 在這個檔案從99965是 99955,由 vboxsync 提交於 22 月 前

Shared Clipboard: Docs [build fix]. bugref:9437

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 71.5 KB
 
1/* $Id: clipboard-transfers.cpp 99955 2023-05-24 11:11:36Z vboxsync $ */
2/** @file
3 * Shared Clipboard: Common clipboard transfer handling code.
4 */
5
6/*
7 * Copyright (C) 2019-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
29#include <VBox/log.h>
30
31#include <iprt/dir.h>
32#include <iprt/file.h>
33#include <iprt/list.h>
34#include <iprt/path.h>
35#include <iprt/rand.h>
36#include <iprt/semaphore.h>
37
38#include <VBox/err.h>
39#include <VBox/HostServices/VBoxClipboardSvc.h>
40#include <VBox/GuestHost/SharedClipboard-transfers.h>
41
42
43static int shClTransferThreadCreate(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser);
44static int shClTransferThreadDestroy(PSHCLTRANSFER pTransfer, RTMSINTERVAL uTimeoutMs);
45
46static void shclTransferCtxTransferRemoveAndUnregister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer);
47static PSHCLTRANSFER shClTransferCtxGetTransferByIdInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uId);
48static PSHCLTRANSFER shClTransferCtxGetTransferByIndexInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx);
49
50
51/**
52 * Allocates a new transfer root list.
53 *
54 * @returns Allocated transfer root list on success, or NULL on failure.
55 */
56PSHCLROOTLIST ShClTransferRootListAlloc(void)
57{
58 PSHCLROOTLIST pRootList = (PSHCLROOTLIST)RTMemAllocZ(sizeof(SHCLROOTLIST));
59
60 return pRootList;
61}
62
63/**
64 * Frees a transfer root list.
65 *
66 * @param pRootList Transfer root list to free. The pointer will be
67 * invalid after returning from this function.
68 */
69void ShClTransferRootListFree(PSHCLROOTLIST pRootList)
70{
71 if (!pRootList)
72 return;
73
74 for (uint32_t i = 0; i < pRootList->Hdr.cRoots; i++)
75 ShClTransferListEntryDestroy(&pRootList->paEntries[i]);
76
77 RTMemFree(pRootList);
78 pRootList = NULL;
79}
80
81/**
82 * Initializes a transfer root list header.
83 *
84 * @returns VBox status code.
85 * @param pRootLstHdr Root list header to initialize.
86 */
87int ShClTransferRootListHdrInit(PSHCLROOTLISTHDR pRootLstHdr)
88{
89 AssertPtrReturn(pRootLstHdr, VERR_INVALID_POINTER);
90
91 RT_BZERO(pRootLstHdr, sizeof(SHCLROOTLISTHDR));
92
93 return VINF_SUCCESS;
94}
95
96/**
97 * Destroys a transfer root list header.
98 *
99 * @param pRootLstHdr Root list header to destroy.
100 */
101void ShClTransferRootListHdrDestroy(PSHCLROOTLISTHDR pRootLstHdr)
102{
103 if (!pRootLstHdr)
104 return;
105
106 pRootLstHdr->cRoots = 0;
107}
108
109/**
110 * Duplicates a transfer list header.
111 *
112 * @returns Duplicated transfer list header on success, or NULL on failure.
113 * @param pRootLstHdr Root list header to duplicate.
114 */
115PSHCLROOTLISTHDR ShClTransferRootListHdrDup(PSHCLROOTLISTHDR pRootLstHdr)
116{
117 AssertPtrReturn(pRootLstHdr, NULL);
118
119 int rc = VINF_SUCCESS;
120
121 PSHCLROOTLISTHDR pRootsDup = (PSHCLROOTLISTHDR)RTMemAllocZ(sizeof(SHCLROOTLISTHDR));
122 if (pRootsDup)
123 {
124 *pRootsDup = *pRootLstHdr;
125 }
126 else
127 rc = VERR_NO_MEMORY;
128
129 if (RT_FAILURE(rc))
130 {
131 ShClTransferRootListHdrDestroy(pRootsDup);
132 pRootsDup = NULL;
133 }
134
135 return pRootsDup;
136}
137
138/**
139 * (Deep) Copies a clipboard root list entry structure.
140 *
141 * @returns VBox status code.
142 * @param pDst Where to copy the source root list entry to.
143 * @param pSrc Source root list entry to copy.
144 */
145int ShClTransferRootListEntryCopy(PSHCLROOTLISTENTRY pDst, PSHCLROOTLISTENTRY pSrc)
146{
147 return ShClTransferListEntryCopy(pDst, pSrc);
148}
149
150/**
151 * Initializes a clipboard root list entry structure.
152 *
153 * @param pRootListEntry Clipboard root list entry structure to destroy.
154 */
155int ShClTransferRootListEntryInit(PSHCLROOTLISTENTRY pRootListEntry)
156{
157 return ShClTransferListEntryInit(pRootListEntry);
158}
159
160/**
161 * Destroys a clipboard root list entry structure.
162 *
163 * @param pRootListEntry Clipboard root list entry structure to destroy.
164 */
165void ShClTransferRootListEntryDestroy(PSHCLROOTLISTENTRY pRootListEntry)
166{
167 return ShClTransferListEntryDestroy(pRootListEntry);
168}
169
170/**
171 * Duplicates (allocates) a clipboard root list entry structure.
172 *
173 * @returns Duplicated clipboard root list entry structure on success.
174 * @param pRootListEntry Clipboard root list entry to duplicate.
175 */
176PSHCLROOTLISTENTRY ShClTransferRootListEntryDup(PSHCLROOTLISTENTRY pRootListEntry)
177{
178 return ShClTransferListEntryDup(pRootListEntry);
179}
180
181/**
182 * Initializes an list handle info structure.
183 *
184 * @returns VBox status code.
185 * @param pInfo List handle info structure to initialize.
186 */
187int ShClTransferListHandleInfoInit(PSHCLLISTHANDLEINFO pInfo)
188{
189 AssertPtrReturn(pInfo, VERR_INVALID_POINTER);
190
191 pInfo->hList = NIL_SHCLLISTHANDLE;
192 pInfo->enmType = SHCLOBJTYPE_INVALID;
193
194 pInfo->pszPathLocalAbs = NULL;
195
196 RT_ZERO(pInfo->u);
197
198 return VINF_SUCCESS;
199}
200
201/**
202 * Destroys a list handle info structure.
203 *
204 * @param pInfo List handle info structure to destroy.
205 */
206void ShClTransferListHandleInfoDestroy(PSHCLLISTHANDLEINFO pInfo)
207{
208 if (!pInfo)
209 return;
210
211 if (pInfo->pszPathLocalAbs)
212 {
213 RTStrFree(pInfo->pszPathLocalAbs);
214 pInfo->pszPathLocalAbs = NULL;
215 }
216}
217
218/**
219 * Allocates a transfer list header structure.
220 *
221 * @returns VBox status code.
222 * @param ppListHdr Where to store the allocated transfer list header structure on success.
223 */
224int ShClTransferListHdrAlloc(PSHCLLISTHDR *ppListHdr)
225{
226 int rc;
227
228 PSHCLLISTHDR pListHdr = (PSHCLLISTHDR)RTMemAllocZ(sizeof(SHCLLISTHDR));
229 if (pListHdr)
230 {
231 *ppListHdr = pListHdr;
232 rc = VINF_SUCCESS;
233 }
234 else
235 rc = VERR_NO_MEMORY;
236
237 LogFlowFuncLeaveRC(rc);
238 return rc;
239}
240
241/**
242 * Frees a transfer list header structure.
243 *
244 * @param pListEntry Transfer list header structure to free.
245 * The pointer will be invalid on return.
246 */
247void ShClTransferListHdrFree(PSHCLLISTHDR pListHdr)
248{
249 if (!pListHdr)
250 return;
251
252 LogFlowFuncEnter();
253
254 ShClTransferListHdrDestroy(pListHdr);
255
256 RTMemFree(pListHdr);
257 pListHdr = NULL;
258}
259
260/**
261 * Duplicates (allocates) a transfer list header structure.
262 *
263 * @returns Duplicated transfer list header structure on success.
264 * @param pListHdr Transfer list header to duplicate.
265 */
266PSHCLLISTHDR ShClTransferListHdrDup(PSHCLLISTHDR pListHdr)
267{
268 AssertPtrReturn(pListHdr, NULL);
269
270 PSHCLLISTHDR pListHdrDup = (PSHCLLISTHDR)RTMemAlloc(sizeof(SHCLLISTHDR));
271 if (pListHdrDup)
272 *pListHdrDup = *pListHdr;
273
274 return pListHdrDup;
275}
276
277/**
278 * Initializes a transfer list header structure.
279 *
280 * @returns VBox status code.
281 * @param pListHdr Transfer list header struct to initialize.
282 */
283int ShClTransferListHdrInit(PSHCLLISTHDR pListHdr)
284{
285 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
286
287 LogFlowFuncEnter();
288
289 ShClTransferListHdrReset(pListHdr);
290
291 return VINF_SUCCESS;
292}
293
294/**
295 * Destroys a transfer list header structure.
296 *
297 * @param pListHdr Transfer list header struct to destroy.
298 */
299void ShClTransferListHdrDestroy(PSHCLLISTHDR pListHdr)
300{
301 if (!pListHdr)
302 return;
303
304 LogFlowFuncEnter();
305}
306
307/**
308 * Resets a transfer list header structure.
309 *
310 * @returns VBox status code.
311 * @param pListHdr Transfer list header struct to reset.
312 */
313void ShClTransferListHdrReset(PSHCLLISTHDR pListHdr)
314{
315 AssertPtrReturnVoid(pListHdr);
316
317 LogFlowFuncEnter();
318
319 RT_BZERO(pListHdr, sizeof(SHCLLISTHDR));
320}
321
322/**
323 * Returns whether a given transfer list header is valid or not.
324 *
325 * @returns \c true if valid, \c false if not.
326 * @param pListHdr Transfer list header to validate.
327 */
328bool ShClTransferListHdrIsValid(PSHCLLISTHDR pListHdr)
329{
330 RT_NOREF(pListHdr);
331 return true; /** @todo Implement this. */
332}
333
334/**
335 * (Deep-)Copies a transfer list open parameters structure from one into another.
336 *
337 * @returns VBox status code.
338 * @param pDst Destination parameters to copy to.
339 * @param pSrc Source parameters to copy from.
340 */
341int ShClTransferListOpenParmsCopy(PSHCLLISTOPENPARMS pDst, PSHCLLISTOPENPARMS pSrc)
342{
343 AssertPtrReturn(pDst, VERR_INVALID_POINTER);
344 AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
345
346 int rc = VINF_SUCCESS;
347
348 if (pSrc->pszFilter)
349 {
350 pDst->pszFilter = RTStrDup(pSrc->pszFilter);
351 if (!pDst->pszFilter)
352 rc = VERR_NO_MEMORY;
353 }
354
355 if ( RT_SUCCESS(rc)
356 && pSrc->pszPath)
357 {
358 pDst->pszPath = RTStrDup(pSrc->pszPath);
359 if (!pDst->pszPath)
360 rc = VERR_NO_MEMORY;
361 }
362
363 if (RT_SUCCESS(rc))
364 {
365 pDst->fList = pDst->fList;
366 pDst->cbFilter = pSrc->cbFilter;
367 pDst->cbPath = pSrc->cbPath;
368 }
369
370 return rc;
371}
372
373/**
374 * Duplicates a transfer list open parameters structure.
375 *
376 * @returns Duplicated transfer list open parameters structure on success, or NULL on failure.
377 * @param pParms Transfer list open parameters structure to duplicate.
378 */
379PSHCLLISTOPENPARMS ShClTransferListOpenParmsDup(PSHCLLISTOPENPARMS pParms)
380{
381 AssertPtrReturn(pParms, NULL);
382
383 PSHCLLISTOPENPARMS pParmsDup = (PSHCLLISTOPENPARMS)RTMemAllocZ(sizeof(SHCLLISTOPENPARMS));
384 if (!pParmsDup)
385 return NULL;
386
387 int rc = ShClTransferListOpenParmsCopy(pParmsDup, pParms);
388 if (RT_FAILURE(rc))
389 {
390 ShClTransferListOpenParmsDestroy(pParmsDup);
391
392 RTMemFree(pParmsDup);
393 pParmsDup = NULL;
394 }
395
396 return pParmsDup;
397}
398
399/**
400 * Initializes a transfer list open parameters structure.
401 *
402 * @returns VBox status code.
403 * @param pParms Transfer list open parameters structure to initialize.
404 */
405int ShClTransferListOpenParmsInit(PSHCLLISTOPENPARMS pParms)
406{
407 AssertPtrReturn(pParms, VERR_INVALID_POINTER);
408
409 RT_BZERO(pParms, sizeof(SHCLLISTOPENPARMS));
410
411 pParms->cbFilter = SHCL_TRANSFER_PATH_MAX; /** @todo Make this dynamic. */
412 pParms->pszFilter = RTStrAlloc(pParms->cbFilter);
413
414 pParms->cbPath = SHCL_TRANSFER_PATH_MAX; /** @todo Make this dynamic. */
415 pParms->pszPath = RTStrAlloc(pParms->cbPath);
416
417 LogFlowFuncLeave();
418 return VINF_SUCCESS;
419}
420
421/**
422 * Destroys a transfer list open parameters structure.
423 *
424 * @param pParms Transfer list open parameters structure to destroy.
425 */
426void ShClTransferListOpenParmsDestroy(PSHCLLISTOPENPARMS pParms)
427{
428 if (!pParms)
429 return;
430
431 if (pParms->pszFilter)
432 {
433 RTStrFree(pParms->pszFilter);
434 pParms->pszFilter = NULL;
435 }
436
437 if (pParms->pszPath)
438 {
439 RTStrFree(pParms->pszPath);
440 pParms->pszPath = NULL;
441 }
442}
443
444/**
445 * Creates (allocates) and initializes a clipboard list entry structure.
446 *
447 * @returns VBox status code.
448 * @param ppDirData Where to return the created clipboard list entry structure on success.
449 */
450int ShClTransferListEntryAlloc(PSHCLLISTENTRY *ppListEntry)
451{
452 PSHCLLISTENTRY pListEntry = (PSHCLLISTENTRY)RTMemAlloc(sizeof(SHCLLISTENTRY));
453 if (!pListEntry)
454 return VERR_NO_MEMORY;
455
456 int rc = ShClTransferListEntryInit(pListEntry);
457 if (RT_SUCCESS(rc))
458 *ppListEntry = pListEntry;
459
460 return rc;
461}
462
463/**
464 * Frees a clipboard list entry structure.
465 *
466 * @param pListEntry Clipboard list entry structure to free.
467 * The pointer will be invalid on return.
468 */
469void ShClTransferListEntryFree(PSHCLLISTENTRY pListEntry)
470{
471 if (!pListEntry)
472 return;
473
474 ShClTransferListEntryDestroy(pListEntry);
475 RTMemFree(pListEntry);
476}
477
478/**
479 * (Deep-)Copies a clipboard list entry structure.
480 *
481 * @returns VBox status code.
482 * @param pDst Destination list entry to copy to.
483 * @param pSrc Source list entry to copy from.
484 */
485int ShClTransferListEntryCopy(PSHCLLISTENTRY pDst, PSHCLLISTENTRY pSrc)
486{
487 AssertPtrReturn(pDst, VERR_INVALID_POINTER);
488 AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
489
490 int rc = VINF_SUCCESS;
491
492 *pDst = *pSrc;
493
494 if (pSrc->pszName)
495 {
496 pDst->pszName = RTStrDup(pSrc->pszName);
497 if (!pDst->pszName)
498 rc = VERR_NO_MEMORY;
499 }
500
501 if ( RT_SUCCESS(rc)
502 && pSrc->pvInfo)
503 {
504 pDst->pvInfo = RTMemDup(pSrc->pvInfo, pSrc->cbInfo);
505 if (pDst->pvInfo)
506 {
507 pDst->cbInfo = pSrc->cbInfo;
508 }
509 else
510 rc = VERR_NO_MEMORY;
511 }
512
513 if (RT_FAILURE(rc))
514 {
515 if (pDst->pvInfo)
516 {
517 RTMemFree(pDst->pvInfo);
518 pDst->pvInfo = NULL;
519 pDst->cbInfo = 0;
520 }
521 }
522
523 return rc;
524}
525
526/**
527 * Duplicates (allocates) a clipboard list entry structure.
528 *
529 * @returns Duplicated clipboard list entry structure on success.
530 * @param pListEntry Clipboard list entry to duplicate.
531 */
532PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pListEntry)
533{
534 AssertPtrReturn(pListEntry, NULL);
535
536 int rc = VINF_SUCCESS;
537
538 PSHCLLISTENTRY pListEntryDup = (PSHCLLISTENTRY)RTMemAllocZ(sizeof(SHCLLISTENTRY));
539 if (pListEntryDup)
540 rc = ShClTransferListEntryCopy(pListEntryDup, pListEntry);
541
542 if (RT_FAILURE(rc))
543 {
544 ShClTransferListEntryDestroy(pListEntryDup);
545
546 RTMemFree(pListEntryDup);
547 pListEntryDup = NULL;
548 }
549
550 return pListEntryDup;
551}
552
553/**
554 * Returns whether a given list entry name is valid or not.
555 *
556 * @returns \c true if valid, or \c false if not.
557 * @param pszName Name to check.
558 * @param cbName Size (in bytes) of \a pszName to check.
559 * Includes terminator.
560 */
561static bool shclTransferListEntryNameIsValid(const char *pszName, size_t cbName)
562{
563 if (!pszName)
564 return false;
565
566 size_t const cchLen = strlen(pszName);
567
568 if ( !cbName
569 || cchLen == 0
570 || cchLen > cbName /* Includes zero termination */ - 1
571 || cchLen > SHCLLISTENTRY_MAX_NAME /* Ditto */ - 1)
572 {
573 return false;
574 }
575
576 int rc = ShClTransferValidatePath(pszName, false /* fMustExist */);
577 if (RT_FAILURE(rc))
578 return false;
579
580 return true;
581}
582
583/**
584 * Initializes a clipboard list entry structure, extended version.
585 *
586 * @returns VBox status code.
587 * @param pListEntry Clipboard list entry structure to initialize.
588 * @param pszName Name (e.g. filename) to use. Can be NULL if not being used.
589 * Up to SHCLLISTENTRY_MAX_NAME characters.
590 */
591int ShClTransferListEntryInitEx(PSHCLLISTENTRY pListEntry, const char *pszName)
592{
593 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
594 AssertReturn ( pszName == NULL
595 || shclTransferListEntryNameIsValid(pszName, strlen(pszName) + 1), VERR_INVALID_PARAMETER);
596
597 RT_BZERO(pListEntry, sizeof(SHCLLISTENTRY));
598
599 if (pszName)
600 {
601 pListEntry->pszName = RTStrDup(pszName);
602 if (!pListEntry->pszName)
603 return VERR_NO_MEMORY;
604 pListEntry->cbName = strlen(pszName) + 1 /* Include terminator */;
605 }
606
607 pListEntry->pvInfo = (PSHCLFSOBJINFO)RTMemAlloc(sizeof(SHCLFSOBJINFO));
608 if (pListEntry->pvInfo)
609 {
610 pListEntry->cbInfo = sizeof(SHCLFSOBJINFO);
611 pListEntry->fInfo = VBOX_SHCL_INFO_FLAG_FSOBJINFO;
612
613 return VINF_SUCCESS;
614 }
615
616 return VERR_NO_MEMORY;
617}
618
619/**
620 * Initializes a clipboard list entry structure (as empty / invalid).
621 *
622 * @returns VBox status code.
623 * @param pListEntry Clipboard list entry structure to initialize.
624 */
625int ShClTransferListEntryInit(PSHCLLISTENTRY pListEntry)
626{
627 return ShClTransferListEntryInitEx(pListEntry, NULL);
628}
629
630/**
631 * Destroys a clipboard list entry structure.
632 *
633 * @param pListEntry Clipboard list entry structure to destroy.
634 */
635void ShClTransferListEntryDestroy(PSHCLLISTENTRY pListEntry)
636{
637 if (!pListEntry)
638 return;
639
640 if (pListEntry->pszName)
641 {
642 RTStrFree(pListEntry->pszName);
643
644 pListEntry->pszName = NULL;
645 pListEntry->cbName = 0;
646 }
647
648 if (pListEntry->pvInfo)
649 {
650 RTMemFree(pListEntry->pvInfo);
651 pListEntry->pvInfo = NULL;
652 pListEntry->cbInfo = 0;
653 }
654}
655
656/**
657 * Returns whether a given clipboard list entry is valid or not.
658 *
659 * @returns \c true if valid, \c false if not.
660 * @param pListEntry Clipboard list entry to validate.
661 */
662bool ShClTransferListEntryIsValid(PSHCLLISTENTRY pListEntry)
663{
664 AssertPtrReturn(pListEntry, false);
665
666 if (!shclTransferListEntryNameIsValid(pListEntry->pszName, pListEntry->cbName))
667 return false;
668
669 if (pListEntry->cbInfo) /* cbInfo / pvInfo is optional. */
670 {
671 if (!pListEntry->pvInfo)
672 return false;
673 }
674
675 return true;
676}
677
678/**
679 * Initializes a transfer object context.
680 *
681 * @returns VBox status code.
682 * @param pObjCtx Transfer object context to initialize.
683 */
684int ShClTransferObjCtxInit(PSHCLCLIENTTRANSFEROBJCTX pObjCtx)
685{
686 AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
687
688 LogFlowFuncEnter();
689
690 pObjCtx->uHandle = NIL_SHCLOBJHANDLE;
691
692 return VINF_SUCCESS;
693}
694
695/**
696 * Destroys a transfer object context.
697 *
698 * @param pObjCtx Transfer object context to destroy.
699 */
700void ShClTransferObjCtxDestroy(PSHCLCLIENTTRANSFEROBJCTX pObjCtx)
701{
702 AssertPtrReturnVoid(pObjCtx);
703
704 LogFlowFuncEnter();
705}
706
707/**
708 * Returns if a transfer object context is valid or not.
709 *
710 * @returns \c true if valid, \c false if not.
711 * @param pObjCtx Transfer object context to check.
712 */
713bool ShClTransferObjCtxIsValid(PSHCLCLIENTTRANSFEROBJCTX pObjCtx)
714{
715 return ( pObjCtx
716 && pObjCtx->uHandle != NIL_SHCLOBJHANDLE);
717}
718
719/**
720 * Initializes an object handle info structure.
721 *
722 * @returns VBox status code.
723 * @param pInfo Object handle info structure to initialize.
724 */
725int ShClTransferObjHandleInfoInit(PSHCLOBJHANDLEINFO pInfo)
726{
727 AssertPtrReturn(pInfo, VERR_INVALID_POINTER);
728
729 pInfo->hObj = NIL_SHCLOBJHANDLE;
730 pInfo->enmType = SHCLOBJTYPE_INVALID;
731
732 pInfo->pszPathLocalAbs = NULL;
733
734 RT_ZERO(pInfo->u);
735
736 return VINF_SUCCESS;
737}
738
739/**
740 * Destroys an object handle info structure.
741 *
742 * @param pInfo Object handle info structure to destroy.
743 */
744void ShClTransferObjHandleInfoDestroy(PSHCLOBJHANDLEINFO pInfo)
745{
746 if (!pInfo)
747 return;
748
749 if (pInfo->pszPathLocalAbs)
750 {
751 RTStrFree(pInfo->pszPathLocalAbs);
752 pInfo->pszPathLocalAbs = NULL;
753 }
754}
755
756/**
757 * Initializes a transfer object open parameters structure.
758 *
759 * @returns VBox status code.
760 * @param pParms Transfer object open parameters structure to initialize.
761 */
762int ShClTransferObjOpenParmsInit(PSHCLOBJOPENCREATEPARMS pParms)
763{
764 AssertPtrReturn(pParms, VERR_INVALID_POINTER);
765
766 int rc;
767
768 RT_BZERO(pParms, sizeof(SHCLOBJOPENCREATEPARMS));
769
770 pParms->cbPath = RTPATH_MAX; /** @todo Make this dynamic. */
771 pParms->pszPath = RTStrAlloc(pParms->cbPath);
772 if (pParms->pszPath)
773 {
774 rc = VINF_SUCCESS;
775 }
776 else
777 rc = VERR_NO_MEMORY;
778
779 LogFlowFuncLeaveRC(rc);
780 return rc;
781}
782
783/**
784 * Copies a transfer object open parameters structure from source to destination.
785 *
786 * @returns VBox status code.
787 * @param pParmsDst Where to copy the source transfer object open parameters to.
788 * @param pParmsSrc Which source transfer object open parameters to copy.
789 */
790int ShClTransferObjOpenParmsCopy(PSHCLOBJOPENCREATEPARMS pParmsDst, PSHCLOBJOPENCREATEPARMS pParmsSrc)
791{
792 int rc;
793
794 *pParmsDst = *pParmsSrc;
795
796 if (pParmsSrc->pszPath)
797 {
798 Assert(pParmsSrc->cbPath);
799 pParmsDst->pszPath = RTStrDup(pParmsSrc->pszPath);
800 if (pParmsDst->pszPath)
801 {
802 rc = VINF_SUCCESS;
803 }
804 else
805 rc = VERR_NO_MEMORY;
806 }
807 else
808 rc = VINF_SUCCESS;
809
810 LogFlowFuncLeaveRC(rc);
811 return rc;
812}
813
814/**
815 * Destroys a transfer object open parameters structure.
816 *
817 * @param pParms Transfer object open parameters structure to destroy.
818 */
819void ShClTransferObjOpenParmsDestroy(PSHCLOBJOPENCREATEPARMS pParms)
820{
821 if (!pParms)
822 return;
823
824 if (pParms->pszPath)
825 {
826 RTStrFree(pParms->pszPath);
827 pParms->pszPath = NULL;
828 }
829}
830
831/**
832 * Returns a specific object handle info of a transfer.
833 *
834 * @returns Pointer to object handle info if found, or NULL if not found.
835 * @param pTransfer Clipboard transfer to get object handle info from.
836 * @param hObj Object handle of the object to get handle info for.
837 */
838PSHCLOBJHANDLEINFO ShClTransferObjGet(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj)
839{
840 PSHCLOBJHANDLEINFO pIt;
841 RTListForEach(&pTransfer->lstObj, pIt, SHCLOBJHANDLEINFO, Node) /** @todo Slooow ...but works for now. */
842 {
843 if (pIt->hObj == hObj)
844 return pIt;
845 }
846
847 return NULL;
848}
849
850/**
851 * Opens a transfer object.
852 *
853 * @returns VBox status code.
854 * @param pTransfer Clipboard transfer to open the object for.
855 * @param pOpenCreateParms Open / create parameters of transfer object to open / create.
856 * @param phObj Where to store the handle of transfer object opened on success.
857 */
858int ShClTransferObjOpen(PSHCLTRANSFER pTransfer, PSHCLOBJOPENCREATEPARMS pOpenCreateParms, PSHCLOBJHANDLE phObj)
859{
860 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
861 AssertPtrReturn(pOpenCreateParms, VERR_INVALID_POINTER);
862 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
863 AssertMsgReturn(pTransfer->pszPathRootAbs, ("Transfer has no root path set\n"), VERR_INVALID_PARAMETER);
864 AssertMsgReturn(pOpenCreateParms->pszPath, ("No path in open/create params set\n"), VERR_INVALID_PARAMETER);
865
866 if (pTransfer->cObjHandles >= pTransfer->cMaxObjHandles)
867 return VERR_SHCLPB_MAX_OBJECTS_REACHED;
868
869 LogFlowFunc(("pszPath=%s, fCreate=0x%x\n", pOpenCreateParms->pszPath, pOpenCreateParms->fCreate));
870
871 int rc;
872 if (pTransfer->ProviderIface.pfnObjOpen)
873 rc = pTransfer->ProviderIface.pfnObjOpen(&pTransfer->ProviderCtx, pOpenCreateParms, phObj);
874 else
875 rc = VERR_NOT_SUPPORTED;
876
877 LogFlowFuncLeaveRC(rc);
878 return rc;
879}
880
881/**
882 * Closes a transfer object.
883 *
884 * @returns VBox status code.
885 * @param pTransfer Clipboard transfer that contains the object to close.
886 * @param hObj Handle of transfer object to close.
887 */
888int ShClTransferObjClose(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj)
889{
890 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
891
892 int rc;
893 if (pTransfer->ProviderIface.pfnObjClose)
894 rc = pTransfer->ProviderIface.pfnObjClose(&pTransfer->ProviderCtx, hObj);
895 else
896 rc = VERR_NOT_SUPPORTED;
897
898 LogFlowFuncLeaveRC(rc);
899 return rc;
900}
901
902/**
903 * Reads from a transfer object.
904 *
905 * @returns VBox status code.
906 * @param pTransfer Clipboard transfer that contains the object to read from.
907 * @param hObj Handle of transfer object to read from.
908 * @param pvBuf Buffer for where to store the read data.
909 * @param cbBuf Size (in bytes) of buffer.
910 * @param fFlags Read flags. Optional.
911 * @param pcbRead Where to return how much bytes were read on success. Optional.
912 */
913int ShClTransferObjRead(PSHCLTRANSFER pTransfer,
914 SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t fFlags, uint32_t *pcbRead)
915{
916 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
917 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
918 AssertReturn (cbBuf, VERR_INVALID_PARAMETER);
919 /* pcbRead is optional. */
920 /** @todo Validate fFlags. */
921
922 int rc;
923 if (pTransfer->ProviderIface.pfnObjRead)
924 rc = pTransfer->ProviderIface.pfnObjRead(&pTransfer->ProviderCtx, hObj, pvBuf, cbBuf, fFlags, pcbRead);
925 else
926 rc = VERR_NOT_SUPPORTED;
927
928 LogFlowFuncLeaveRC(rc);
929 return rc;
930}
931
932/**
933 * Writes to a transfer object.
934 *
935 * @returns VBox status code.
936 * @param pTransfer Clipboard transfer that contains the object to write to.
937 * @param hObj Handle of transfer object to write to.
938 * @param pvBuf Buffer of data to write.
939 * @param cbBuf Size (in bytes) of buffer to write.
940 * @param fFlags Write flags. Optional.
941 * @param pcbWritten How much bytes were writtenon success. Optional.
942 */
943int ShClTransferObjWrite(PSHCLTRANSFER pTransfer,
944 SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t fFlags, uint32_t *pcbWritten)
945{
946 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
947 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
948 AssertReturn (cbBuf, VERR_INVALID_PARAMETER);
949 /* pcbWritten is optional. */
950
951 int rc;
952 if (pTransfer->ProviderIface.pfnObjWrite)
953 rc = pTransfer->ProviderIface.pfnObjWrite(&pTransfer->ProviderCtx, hObj, pvBuf, cbBuf, fFlags, pcbWritten);
954 else
955 rc = VERR_NOT_SUPPORTED;
956
957 LogFlowFuncLeaveRC(rc);
958 return rc;
959}
960
961/**
962 * Duplicates a transfer object data chunk.
963 *
964 * @returns Duplicated object data chunk on success, or NULL on failure.
965 * @param pDataChunk Transfer object data chunk to duplicate.
966 */
967PSHCLOBJDATACHUNK ShClTransferObjDataChunkDup(PSHCLOBJDATACHUNK pDataChunk)
968{
969 AssertPtrReturn(pDataChunk, NULL);
970
971 PSHCLOBJDATACHUNK pDataChunkDup = (PSHCLOBJDATACHUNK)RTMemAllocZ(sizeof(SHCLOBJDATACHUNK));
972 if (!pDataChunkDup)
973 return NULL;
974
975 if (pDataChunk->pvData)
976 {
977 Assert(pDataChunk->cbData);
978
979 pDataChunkDup->uHandle = pDataChunk->uHandle;
980 pDataChunkDup->pvData = RTMemDup(pDataChunk->pvData, pDataChunk->cbData);
981 AssertPtrReturn(pDataChunkDup->pvData, NULL);
982 pDataChunkDup->cbData = pDataChunk->cbData;
983 }
984
985 return pDataChunkDup;
986}
987
988/**
989 * Destroys a transfer object data chunk.
990 *
991 * @param pDataChunk Transfer object data chunk to destroy.
992 */
993void ShClTransferObjDataChunkDestroy(PSHCLOBJDATACHUNK pDataChunk)
994{
995 if (!pDataChunk)
996 return;
997
998 if (pDataChunk->pvData)
999 {
1000 Assert(pDataChunk->cbData);
1001
1002 RTMemFree(pDataChunk->pvData);
1003
1004 pDataChunk->pvData = NULL;
1005 pDataChunk->cbData = 0;
1006 }
1007
1008 pDataChunk->uHandle = 0;
1009}
1010
1011/**
1012 * Frees a transfer object data chunk.
1013 *
1014 * @param pDataChunk Transfer object data chunk to free.
1015 * The pointer will be invalid on return.
1016 */
1017void ShClTransferObjDataChunkFree(PSHCLOBJDATACHUNK pDataChunk)
1018{
1019 if (!pDataChunk)
1020 return;
1021
1022 ShClTransferObjDataChunkDestroy(pDataChunk);
1023
1024 RTMemFree(pDataChunk);
1025 pDataChunk = NULL;
1026}
1027
1028/**
1029 * Creates a clipboard transfer, extended version.
1030 *
1031 * @returns VBox status code.
1032 * @param cbMaxChunkSize Maximum transfer chunk size (in bytes) to use.
1033 * @param cMaxListHandles Maximum list entries the transfer can have.
1034 * @param cMaxObjHandles Maximum transfer objects the transfer can have.
1035 * @param ppTransfer Where to return the created clipboard transfer struct.
1036 * Must be destroyed by ShClTransferDestroy().
1037 */
1038int ShClTransferCreateEx(uint32_t cbMaxChunkSize, uint32_t cMaxListHandles, uint32_t cMaxObjHandles,
1039 PSHCLTRANSFER *ppTransfer)
1040{
1041
1042
1043 AssertPtrReturn(ppTransfer, VERR_INVALID_POINTER);
1044
1045 LogFlowFuncEnter();
1046
1047 PSHCLTRANSFER pTransfer = (PSHCLTRANSFER)RTMemAllocZ(sizeof(SHCLTRANSFER));
1048 AssertPtrReturn(pTransfer, VERR_NO_MEMORY);
1049
1050 pTransfer->State.uID = 0;
1051 pTransfer->State.enmStatus = SHCLTRANSFERSTATUS_NONE;
1052 pTransfer->State.enmDir = SHCLTRANSFERDIR_UNKNOWN;
1053 pTransfer->State.enmSource = SHCLSOURCE_INVALID;
1054
1055 pTransfer->Thread.hThread = NIL_RTTHREAD;
1056 pTransfer->Thread.fCancelled = false;
1057 pTransfer->Thread.fStarted = false;
1058 pTransfer->Thread.fStop = false;
1059
1060 pTransfer->pszPathRootAbs = NULL;
1061
1062#ifdef DEBUG_andy
1063 pTransfer->uTimeoutMs = RT_MS_5SEC;
1064#else
1065 pTransfer->uTimeoutMs = RT_MS_30SEC;
1066#endif
1067 pTransfer->cbMaxChunkSize = cbMaxChunkSize;
1068 pTransfer->cMaxListHandles = cMaxListHandles;
1069 pTransfer->cMaxObjHandles = cMaxObjHandles;
1070
1071 pTransfer->pvUser = NULL;
1072 pTransfer->cbUser = 0;
1073
1074 RTListInit(&pTransfer->lstList);
1075 RTListInit(&pTransfer->lstObj);
1076
1077 pTransfer->cRoots = 0;
1078 RTListInit(&pTransfer->lstRoots);
1079
1080 int rc = ShClEventSourceCreate(&pTransfer->Events, 0 /* uID */);
1081 if (RT_SUCCESS(rc))
1082 {
1083 *ppTransfer = pTransfer;
1084 }
1085 else
1086 {
1087 if (pTransfer)
1088 {
1089 ShClTransferDestroy(pTransfer);
1090 RTMemFree(pTransfer);
1091 }
1092 }
1093
1094 LogFlowFuncLeaveRC(rc);
1095 return rc;
1096}
1097
1098/**
1099 * Creates a clipboard transfer with default settings.
1100 *
1101 * @returns VBox status code.
1102 * @param ppTransfer Where to return the created clipboard transfer struct.
1103 * Must be destroyed by ShClTransferDestroy().
1104 */
1105int ShClTransferCreate(PSHCLTRANSFER *ppTransfer)
1106{
1107 return ShClTransferCreateEx(SHCL_TRANSFER_DEFAULT_MAX_CHUNK_SIZE,
1108 SHCL_TRANSFER_DEFAULT_MAX_LIST_HANDLES,
1109 SHCL_TRANSFER_DEFAULT_MAX_OBJ_HANDLES,
1110 ppTransfer);
1111}
1112
1113/**
1114 * Destroys a clipboard transfer.
1115 *
1116 * @returns VBox status code.
1117 * @param pTransferCtx Clipboard transfer to destroy.
1118 */
1119int ShClTransferDestroy(PSHCLTRANSFER pTransfer)
1120{
1121 if (!pTransfer)
1122 return VINF_SUCCESS;
1123
1124 AssertMsgReturn(pTransfer->cRefs == 0, ("Number of references > 0 (%RU32)\n", pTransfer->cRefs), VERR_WRONG_ORDER);
1125
1126 LogFlowFuncEnter();
1127
1128 int rc = shClTransferThreadDestroy(pTransfer, 30 * 1000 /* Timeout in ms */);
1129 if (RT_FAILURE(rc))
1130 return rc;
1131
1132 ShClTransferReset(pTransfer);
1133
1134 ShClEventSourceDestroy(&pTransfer->Events);
1135
1136 LogFlowFuncLeave();
1137 return VINF_SUCCESS;
1138}
1139
1140/**
1141 * Initializes a clipboard transfer.
1142 *
1143 * @returns VBox status code.
1144 * @param pTransfer Transfer to initialize.
1145 * @param enmDir Specifies the transfer direction of this transfer.
1146 * @param enmSource Specifies the data source of the transfer.
1147 */
1148int ShClTransferInit(PSHCLTRANSFER pTransfer, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource)
1149{
1150 pTransfer->cRefs = 0;
1151
1152 pTransfer->State.enmDir = enmDir;
1153 pTransfer->State.enmSource = enmSource;
1154
1155 LogFlowFunc(("uID=%RU32, enmDir=%RU32, enmSource=%RU32\n",
1156 pTransfer->State.uID, pTransfer->State.enmDir, pTransfer->State.enmSource));
1157
1158 pTransfer->State.enmStatus = SHCLTRANSFERSTATUS_INITIALIZED; /* Now we're ready to run. */
1159
1160 pTransfer->cListHandles = 0;
1161 pTransfer->uListHandleNext = 1;
1162
1163 pTransfer->cObjHandles = 0;
1164 pTransfer->uObjHandleNext = 1;
1165
1166 int rc = VINF_SUCCESS;
1167
1168 if (pTransfer->Callbacks.pfnOnInitialize)
1169 rc = pTransfer->Callbacks.pfnOnInitialize(&pTransfer->CallbackCtx);
1170
1171 LogFlowFuncLeaveRC(rc);
1172 return rc;
1173}
1174
1175/**
1176 * Acquires a reference to this transfer.
1177 *
1178 * @returns New reference count.
1179 * @param pTransfer Transfer to acquire reference for.
1180 */
1181uint32_t ShClTransferAcquire(PSHCLTRANSFER pTransfer)
1182{
1183 return ASMAtomicIncU32(&pTransfer->cRefs);
1184}
1185
1186/**
1187 * Releases a reference to this transfer.
1188 *
1189 * @returns New reference count.
1190 * @param pTransfer Transfer to release reference for.
1191 */
1192uint32_t ShClTransferRelease(PSHCLTRANSFER pTransfer)
1193{
1194 return ASMAtomicDecU32(&pTransfer->cRefs);
1195}
1196
1197/**
1198 * Opens a transfer list.
1199 *
1200 * @returns VBox status code.
1201 * @param pTransfer Clipboard transfer to handle.
1202 * @param pOpenParms List open parameters to use for opening.
1203 * @param phList Where to store the List handle of opened list on success.
1204 */
1205int ShClTransferListOpen(PSHCLTRANSFER pTransfer, PSHCLLISTOPENPARMS pOpenParms,
1206 PSHCLLISTHANDLE phList)
1207{
1208 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1209 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1210 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1211
1212 if (pTransfer->cListHandles == pTransfer->cMaxListHandles)
1213 return VERR_SHCLPB_MAX_LISTS_REACHED;
1214
1215 int rc;
1216 if (pTransfer->ProviderIface.pfnListOpen)
1217 rc = pTransfer->ProviderIface.pfnListOpen(&pTransfer->ProviderCtx, pOpenParms, phList);
1218 else
1219 rc = VERR_NOT_SUPPORTED;
1220
1221 LogFlowFuncLeaveRC(rc);
1222 return rc;
1223}
1224
1225/**
1226 * Closes a transfer list.
1227 *
1228 * @returns VBox status code.
1229 * @param pTransfer Clipboard transfer to handle.
1230 * @param hList Handle of list to close.
1231 */
1232int ShClTransferListClose(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList)
1233{
1234 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1235
1236 if (hList == NIL_SHCLLISTHANDLE)
1237 return VINF_SUCCESS;
1238
1239 int rc;
1240 if (pTransfer->ProviderIface.pfnListClose)
1241 rc = pTransfer->ProviderIface.pfnListClose(&pTransfer->ProviderCtx, hList);
1242 else
1243 rc = VERR_NOT_SUPPORTED;
1244
1245 LogFlowFuncLeaveRC(rc);
1246 return rc;
1247}
1248
1249/**
1250 * Retrieves the header of a transfer list.
1251 *
1252 * @returns VBox status code.
1253 * @param pTransfer Clipboard transfer to handle.
1254 * @param hList Handle of list to get header for.
1255 * @param pHdr Where to store the returned list header information.
1256 */
1257int ShClTransferListGetHeader(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList,
1258 PSHCLLISTHDR pHdr)
1259{
1260 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1261 AssertPtrReturn(pHdr, VERR_INVALID_POINTER);
1262
1263 LogFlowFunc(("hList=%RU64\n", hList));
1264
1265 int rc;
1266 if (pTransfer->ProviderIface.pfnListHdrRead)
1267 rc = pTransfer->ProviderIface.pfnListHdrRead(&pTransfer->ProviderCtx, hList, pHdr);
1268 else
1269 rc = VERR_NOT_SUPPORTED;
1270
1271 LogFlowFuncLeaveRC(rc);
1272 return rc;
1273}
1274
1275/**
1276 * Returns a specific list handle info of a clipboard transfer.
1277 *
1278 * @returns Pointer to list handle info if found, or NULL if not found.
1279 * @param pTransfer Clipboard transfer to get list handle info from.
1280 * @param hList List handle of the list to get handle info for.
1281 */
1282PSHCLLISTHANDLEINFO ShClTransferListGetByHandle(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList)
1283{
1284 PSHCLLISTHANDLEINFO pIt;
1285 RTListForEach(&pTransfer->lstList, pIt, SHCLLISTHANDLEINFO, Node) /** @todo Sloooow ... improve this. */
1286 {
1287 if (pIt->hList == hList)
1288 return pIt;
1289 }
1290
1291 return NULL;
1292}
1293
1294/**
1295 * Returns the current transfer object of a transfer list.
1296 *
1297 * Currently not implemented and wil return NULL.
1298 *
1299 * @returns Pointer to transfer object, or NULL if not found / invalid.
1300 * @param pTransfer Clipboard transfer to return transfer object for.
1301 * @param hList Handle of clipboard transfer list to get object for.
1302 * @param uIdx Index of object to get.
1303 */
1304PSHCLTRANSFEROBJ ShClTransferListGetObj(PSHCLTRANSFER pTransfer,
1305 SHCLLISTHANDLE hList, uint64_t uIdx)
1306{
1307 AssertPtrReturn(pTransfer, NULL);
1308
1309 RT_NOREF(hList, uIdx);
1310
1311 LogFlowFunc(("hList=%RU64\n", hList));
1312
1313 return NULL;
1314}
1315
1316/**
1317 * Reads a single transfer list entry.
1318 *
1319 * @returns VBox status code or VERR_NO_MORE_FILES if the end of the list has been reached.
1320 * @param pTransfer Clipboard transfer to handle.
1321 * @param hList List handle of list to read from.
1322 * @param pEntry Where to store the read information.
1323 */
1324int ShClTransferListRead(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList,
1325 PSHCLLISTENTRY pEntry)
1326{
1327 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1328 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
1329
1330 LogFlowFunc(("hList=%RU64\n", hList));
1331
1332 int rc;
1333 if (pTransfer->ProviderIface.pfnListEntryRead)
1334 rc = pTransfer->ProviderIface.pfnListEntryRead(&pTransfer->ProviderCtx, hList, pEntry);
1335 else
1336 rc = VERR_NOT_SUPPORTED;
1337
1338 LogFlowFuncLeaveRC(rc);
1339 return rc;
1340}
1341
1342/**
1343 * Writes a single transfer list entry.
1344 *
1345 * @returns VBox status code.
1346 * @param pTransfer Clipboard transfer to handle.
1347 * @param hList List handle of list to write to.
1348 * @param pEntry Entry information to write.
1349 */
1350int ShClTransferListWrite(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList,
1351 PSHCLLISTENTRY pEntry)
1352{
1353 RT_NOREF(pTransfer, hList, pEntry);
1354
1355 int rc = VINF_SUCCESS;
1356
1357#if 0
1358 if (pTransfer->ProviderIface.pfnListEntryWrite)
1359 rc = pTransfer->ProviderIface.pfnListEntryWrite(&pTransfer->ProviderCtx, hList, pEntry);
1360#endif
1361
1362 LogFlowFuncLeaveRC(rc);
1363 return rc;
1364}
1365
1366/**
1367 * Returns whether a given transfer list handle is valid or not.
1368 *
1369 * @returns \c true if list handle is valid, \c false if not.
1370 * @param pTransfer Clipboard transfer to handle.
1371 * @param hList List handle to check.
1372 */
1373bool ShClTransferListHandleIsValid(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList)
1374{
1375 bool fIsValid = false;
1376
1377 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)
1378 {
1379 fIsValid = ShClTransferListGetByHandle(pTransfer, hList) != NULL;
1380 }
1381 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)
1382 {
1383 AssertFailed(); /** @todo Implement. */
1384 }
1385 else
1386 AssertFailedStmt(fIsValid = false);
1387
1388 return fIsValid;
1389}
1390
1391/**
1392 * Copies a transfer callback table from source to destination.
1393 *
1394 * @param pCallbacksDst Callback destination.
1395 * @param pCallbacksSrc Callback source. If set to NULL, the
1396 * destination callback table will be unset.
1397 */
1398void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacksDst,
1399 PSHCLTRANSFERCALLBACKTABLE pCallbacksSrc)
1400{
1401 AssertPtrReturnVoid(pCallbacksDst);
1402
1403 if (pCallbacksSrc) /* Set */
1404 {
1405#define SET_CALLBACK(a_pfnCallback) \
1406 if (pCallbacksSrc->a_pfnCallback) \
1407 pCallbacksDst->a_pfnCallback = pCallbacksSrc->a_pfnCallback
1408
1409 SET_CALLBACK(pfnOnInitialize);
1410 SET_CALLBACK(pfnOnStart);
1411 SET_CALLBACK(pfnOnCompleted);
1412 SET_CALLBACK(pfnOnError);
1413 SET_CALLBACK(pfnOnRegistered);
1414 SET_CALLBACK(pfnOnUnregistered);
1415
1416#undef SET_CALLBACK
1417
1418 pCallbacksDst->pvUser = pCallbacksSrc->pvUser;
1419 pCallbacksDst->cbUser = pCallbacksSrc->cbUser;
1420 }
1421 else /* Unset */
1422 RT_BZERO(pCallbacksDst, sizeof(SHCLTRANSFERCALLBACKTABLE));
1423}
1424
1425/**
1426 * Sets or unsets the callback table to be used for a clipboard transfer.
1427 *
1428 * @returns VBox status code.
1429 * @param pTransfer Clipboard transfer to set callbacks for.
1430 * @param pCallbacks Pointer to callback table to set. If set to NULL,
1431 * existing callbacks for this transfer will be unset.
1432 */
1433void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer,
1434 PSHCLTRANSFERCALLBACKTABLE pCallbacks)
1435{
1436 AssertPtrReturnVoid(pTransfer);
1437 /* pCallbacks can be NULL. */
1438
1439 ShClTransferCopyCallbacks(&pTransfer->Callbacks, pCallbacks);
1440}
1441
1442/**
1443 * Sets the transfer provider interface for a given transfer.
1444 *
1445 * @returns VBox status code.
1446 * @param pTransfer Transfer to create transfer provider for.
1447 * @param pCreationCtx Provider creation context to use for provider creation.
1448 */
1449int ShClTransferSetProviderIface(PSHCLTRANSFER pTransfer,
1450 PSHCLTXPROVIDERCREATIONCTX pCreationCtx)
1451{
1452 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1453 AssertPtrReturn(pCreationCtx, VERR_INVALID_POINTER);
1454
1455 LogFlowFuncEnter();
1456
1457 int rc = VINF_SUCCESS;
1458
1459 pTransfer->ProviderIface = pCreationCtx->Interface;
1460 pTransfer->ProviderCtx.pTransfer = pTransfer;
1461 pTransfer->ProviderCtx.pvUser = pCreationCtx->pvUser;
1462
1463 LogFlowFuncLeaveRC(rc);
1464 return rc;
1465}
1466
1467/**
1468 * Clears (resets) the root list of a clipboard transfer.
1469 *
1470 * @param pTransfer Transfer to clear transfer root list for.
1471 */
1472static void shClTransferListRootsClear(PSHCLTRANSFER pTransfer)
1473{
1474 AssertPtrReturnVoid(pTransfer);
1475
1476 if (pTransfer->pszPathRootAbs)
1477 {
1478 RTStrFree(pTransfer->pszPathRootAbs);
1479 pTransfer->pszPathRootAbs = NULL;
1480 }
1481
1482 PSHCLLISTROOT pListRoot, pListRootNext;
1483 RTListForEachSafe(&pTransfer->lstRoots, pListRoot, pListRootNext, SHCLLISTROOT, Node)
1484 {
1485 RTStrFree(pListRoot->pszPathAbs);
1486
1487 RTListNodeRemove(&pListRoot->Node);
1488
1489 RTMemFree(pListRoot);
1490 pListRoot = NULL;
1491 }
1492
1493 pTransfer->cRoots = 0;
1494}
1495
1496/**
1497 * Resets a clipboard transfer.
1498 *
1499 * @param pTransfer Clipboard transfer to reset.
1500 */
1501void ShClTransferReset(PSHCLTRANSFER pTransfer)
1502{
1503 AssertPtrReturnVoid(pTransfer);
1504
1505 LogFlowFuncEnter();
1506
1507 shClTransferListRootsClear(pTransfer);
1508
1509 PSHCLLISTHANDLEINFO pItList, pItListNext;
1510 RTListForEachSafe(&pTransfer->lstList, pItList, pItListNext, SHCLLISTHANDLEINFO, Node)
1511 {
1512 ShClTransferListHandleInfoDestroy(pItList);
1513
1514 RTListNodeRemove(&pItList->Node);
1515
1516 RTMemFree(pItList);
1517 }
1518
1519 PSHCLOBJHANDLEINFO pItObj, pItObjNext;
1520 RTListForEachSafe(&pTransfer->lstObj, pItObj, pItObjNext, SHCLOBJHANDLEINFO, Node)
1521 {
1522 ShClTransferObjHandleInfoDestroy(pItObj);
1523
1524 RTListNodeRemove(&pItObj->Node);
1525
1526 RTMemFree(pItObj);
1527 }
1528}
1529
1530/**
1531 * Returns the number of transfer root list entries.
1532 *
1533 * @returns Root list entry count.
1534 * @param pTransfer Clipboard transfer to return root entry count for.
1535 */
1536uint32_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer)
1537{
1538 AssertPtrReturn(pTransfer, 0);
1539
1540 LogFlowFunc(("[Transfer %RU32] cRoots=%RU64\n", pTransfer->State.uID, pTransfer->cRoots));
1541 return (uint32_t)pTransfer->cRoots;
1542}
1543
1544/**
1545 * Returns a specific root list entry of a transfer.
1546 *
1547 * @returns Pointer to root list entry if found, or NULL if not found.
1548 * @param pTransfer Clipboard transfer to get root list entry from.
1549 * @param uIdx Index of root list entry to return.
1550 */
1551DECLINLINE(PSHCLLISTROOT) shClTransferRootsGetInternal(PSHCLTRANSFER pTransfer, uint32_t uIdx)
1552{
1553 if (uIdx >= pTransfer->cRoots)
1554 return NULL;
1555
1556 PSHCLLISTROOT pIt = RTListGetFirst(&pTransfer->lstRoots, SHCLLISTROOT, Node);
1557 while (uIdx--) /** @todo Slow, but works for now. */
1558 pIt = RTListGetNext(&pTransfer->lstRoots, pIt, SHCLLISTROOT, Node);
1559
1560 return pIt;
1561}
1562
1563/**
1564 * Get a specific root list entry.
1565 *
1566 * @returns VBox status code.
1567 * @param pTransfer Clipboard transfer to get root list entry of.
1568 * @param uIndex Index (zero-based) of entry to get.
1569 * @param pEntry Where to store the returned entry on success.
1570 */
1571int ShClTransferRootsEntry(PSHCLTRANSFER pTransfer,
1572 uint64_t uIndex, PSHCLROOTLISTENTRY pEntry)
1573{
1574 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1575 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
1576
1577 if (uIndex >= pTransfer->cRoots)
1578 return VERR_INVALID_PARAMETER;
1579
1580 int rc;
1581
1582 PSHCLLISTROOT pRoot = shClTransferRootsGetInternal(pTransfer, uIndex);
1583 AssertPtrReturn(pRoot, VERR_INVALID_PARAMETER);
1584
1585 const char *pcszSrcPathAbs = pRoot->pszPathAbs;
1586
1587 /* Make sure that we only advertise relative source paths, not absolute ones. */
1588 char *pszFileName = RTPathFilename(pcszSrcPathAbs);
1589 if (pszFileName)
1590 {
1591 Assert(pszFileName >= pcszSrcPathAbs);
1592 size_t cchDstBase = pszFileName - pcszSrcPathAbs;
1593 const char *pszDstPath = &pcszSrcPathAbs[cchDstBase];
1594
1595 LogFlowFunc(("pcszSrcPathAbs=%s, pszDstPath=%s\n", pcszSrcPathAbs, pszDstPath));
1596
1597 rc = ShClTransferListEntryInitEx(pEntry, pszFileName);
1598 if (RT_SUCCESS(rc))
1599 {
1600 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pszDstPath);
1601 if (RT_SUCCESS(rc))
1602 {
1603 pEntry->cbInfo = sizeof(SHCLFSOBJINFO);
1604 pEntry->pvInfo = (PSHCLFSOBJINFO)RTMemAlloc(pEntry->cbInfo);
1605 if (pEntry->pvInfo)
1606 {
1607 RTFSOBJINFO fsObjInfo;
1608 rc = RTPathQueryInfo(pcszSrcPathAbs, &fsObjInfo, RTFSOBJATTRADD_NOTHING);
1609 if (RT_SUCCESS(rc))
1610 {
1611 ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &fsObjInfo);
1612
1613 pEntry->fInfo = VBOX_SHCL_INFO_FLAG_FSOBJINFO;
1614 }
1615 }
1616 else
1617 rc = VERR_NO_MEMORY;
1618 }
1619 }
1620 }
1621 else
1622 rc = VERR_INVALID_POINTER;
1623
1624 LogFlowFuncLeaveRC(rc);
1625 return rc;
1626}
1627
1628/**
1629 * Returns the root entries of a clipboard transfer.
1630 *
1631 * @returns VBox status code.
1632 * @param pTransfer Clipboard transfer to return root entries for.
1633 * @param ppRootList Where to store the root list on success.
1634 */
1635int ShClTransferRootsGet(PSHCLTRANSFER pTransfer, PSHCLROOTLIST *ppRootList)
1636{
1637 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1638 AssertPtrReturn(ppRootList, VERR_INVALID_POINTER);
1639
1640 LogFlowFuncEnter();
1641
1642 int rc;
1643 if (pTransfer->ProviderIface.pfnRootsGet)
1644 rc = pTransfer->ProviderIface.pfnRootsGet(&pTransfer->ProviderCtx, ppRootList);
1645 else
1646 rc = VERR_NOT_SUPPORTED;
1647
1648 LogFlowFuncLeaveRC(rc);
1649 return rc;
1650}
1651
1652/**
1653 * Sets root list entries for a given clipboard transfer.
1654 *
1655 * @returns VBox status code.
1656 * @param pTransfer Transfer to set transfer list entries for.
1657 * @param pszRoots String list (separated by CRLF) of root entries to set.
1658 * All entries must have the same root path.
1659 * @param cbRoots Size (in bytes) of string list.
1660 */
1661int ShClTransferRootsSet(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots)
1662{
1663 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1664 AssertPtrReturn(pszRoots, VERR_INVALID_POINTER);
1665 AssertReturn(cbRoots, VERR_INVALID_PARAMETER);
1666
1667 if (!RTStrIsValidEncoding(pszRoots))
1668 return VERR_INVALID_UTF8_ENCODING;
1669
1670 int rc = VINF_SUCCESS;
1671
1672 shClTransferListRootsClear(pTransfer);
1673
1674 char *pszPathRootAbs = NULL;
1675
1676 RTCList<RTCString> lstRootEntries = RTCString(pszRoots, cbRoots - 1).split("\r\n");
1677 for (size_t i = 0; i < lstRootEntries.size(); ++i)
1678 {
1679 PSHCLLISTROOT pListRoot = (PSHCLLISTROOT)RTMemAlloc(sizeof(SHCLLISTROOT));
1680 AssertPtrBreakStmt(pListRoot, rc = VERR_NO_MEMORY);
1681
1682 const char *pszPathCur = RTStrDup(lstRootEntries.at(i).c_str());
1683
1684 LogFlowFunc(("pszPathCur=%s\n", pszPathCur));
1685
1686 /* No root path determined yet? */
1687 if (!pszPathRootAbs)
1688 {
1689 pszPathRootAbs = RTStrDup(pszPathCur);
1690 if (pszPathRootAbs)
1691 {
1692 RTPathStripFilename(pszPathRootAbs);
1693
1694 LogFlowFunc(("pszPathRootAbs=%s\n", pszPathRootAbs));
1695
1696 /* We don't want to have a relative directory here. */
1697 if (RTPathStartsWithRoot(pszPathRootAbs))
1698 {
1699 rc = ShClTransferValidatePath(pszPathRootAbs, true /* Path must exist */);
1700 }
1701 else
1702 rc = VERR_INVALID_PARAMETER;
1703 }
1704 else
1705 rc = VERR_NO_MEMORY;
1706 }
1707
1708 if (RT_FAILURE(rc))
1709 break;
1710
1711 pListRoot->pszPathAbs = RTStrDup(pszPathCur);
1712 if (!pListRoot->pszPathAbs)
1713 {
1714 rc = VERR_NO_MEMORY;
1715 break;
1716 }
1717
1718 RTListAppend(&pTransfer->lstRoots, &pListRoot->Node);
1719
1720 pTransfer->cRoots++;
1721 }
1722
1723 /* No (valid) root directory found? Bail out early. */
1724 if (!pszPathRootAbs)
1725 rc = VERR_PATH_NOT_FOUND;
1726
1727 if (RT_SUCCESS(rc))
1728 {
1729 /*
1730 * Step 2:
1731 * Go through the created list and make sure all entries have the same root path.
1732 */
1733 PSHCLLISTROOT pListRoot;
1734 RTListForEach(&pTransfer->lstRoots, pListRoot, SHCLLISTROOT, Node)
1735 {
1736 if (!RTStrStartsWith(pListRoot->pszPathAbs, pszPathRootAbs))
1737 {
1738 rc = VERR_INVALID_PARAMETER;
1739 break;
1740 }
1741
1742 rc = ShClTransferValidatePath(pListRoot->pszPathAbs, true /* Path must exist */);
1743 if (RT_FAILURE(rc))
1744 break;
1745 }
1746 }
1747
1748 /** @todo Entry rollback on failure? */
1749
1750 if (RT_SUCCESS(rc))
1751 {
1752 pTransfer->pszPathRootAbs = pszPathRootAbs;
1753 LogFlowFunc(("pszPathRootAbs=%s, cRoots=%zu\n", pTransfer->pszPathRootAbs, pTransfer->cRoots));
1754
1755 LogRel2(("Shared Clipboard: Transfer uses root '%s'\n", pTransfer->pszPathRootAbs));
1756 }
1757 else
1758 {
1759 LogRel(("Shared Clipboard: Unable to set roots for transfer, rc=%Rrc\n", rc));
1760 RTStrFree(pszPathRootAbs);
1761 }
1762
1763 LogFlowFuncLeaveRC(rc);
1764 return rc;
1765}
1766
1767/**
1768 * Sets a single file as a transfer root.
1769 *
1770 * @returns VBox status code.
1771 * @param pTransfer Transfer to set transfer list entries for.
1772 * @param pszFile File to use as transfer root.
1773 *
1774 * @note Convenience function, uses ShClTransferRootsSet() internally.
1775 */
1776int ShClTransferRootsSetAsFile(PSHCLTRANSFER pTransfer, const char *pszFile)
1777{
1778 char *pszRoots = NULL;
1779
1780 int rc = RTStrAAppend(&pszRoots, pszFile);
1781 AssertRCReturn(rc, rc);
1782 rc = RTStrAAppend(&pszRoots, "\r\n");
1783 AssertRCReturn(rc, rc);
1784 rc = ShClTransferRootsSet(pTransfer, pszRoots, strlen(pszRoots) + 1);
1785 RTStrFree(pszRoots);
1786 return rc;
1787}
1788
1789/**
1790 * Returns the clipboard transfer's ID.
1791 *
1792 * @returns The transfer's ID.
1793 * @param pTransfer Clipboard transfer to return ID for.
1794 */
1795SHCLTRANSFERID ShClTransferGetID(PSHCLTRANSFER pTransfer)
1796{
1797 AssertPtrReturn(pTransfer, 0);
1798
1799 return pTransfer->State.uID;
1800}
1801
1802/**
1803 * Returns the clipboard transfer's direction.
1804 *
1805 * @returns The transfer's direction.
1806 * @param pTransfer Clipboard transfer to return direction for.
1807 */
1808SHCLTRANSFERDIR ShClTransferGetDir(PSHCLTRANSFER pTransfer)
1809{
1810 AssertPtrReturn(pTransfer, SHCLTRANSFERDIR_UNKNOWN);
1811
1812 LogFlowFunc(("[Transfer %RU32] enmDir=%RU32\n", pTransfer->State.uID, pTransfer->State.enmDir));
1813 return pTransfer->State.enmDir;
1814}
1815
1816/**
1817 * Returns the absolute root path of a transfer.
1818 *
1819 * @returns VBox status code.
1820 * @param pTransfer Clipboard transfer to return absolute root path for.
1821 * @param pszPath Where to store the returned path.
1822 * @param cbPath Size (in bytes) of \a pszPath.
1823 */
1824int ShClTransferGetRootPathAbs(PSHCLTRANSFER pTransfer, char *pszPath, size_t cbPath)
1825{
1826 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1827
1828 return RTStrCopy(pszPath, cbPath, pTransfer->pszPathRootAbs);
1829}
1830
1831/**
1832 * Returns the transfer's source.
1833 *
1834 * @returns The transfer's source.
1835 * @param pTransfer Clipboard transfer to return source for.
1836 */
1837SHCLSOURCE ShClTransferGetSource(PSHCLTRANSFER pTransfer)
1838{
1839 AssertPtrReturn(pTransfer, SHCLSOURCE_INVALID);
1840
1841 LogFlowFunc(("[Transfer %RU32] enmSource=%RU32\n", pTransfer->State.uID, pTransfer->State.enmSource));
1842 return pTransfer->State.enmSource;
1843}
1844
1845/**
1846 * Returns the current transfer status.
1847 *
1848 * @returns Current transfer status.
1849 * @param pTransfer Clipboard transfer to return status for.
1850 */
1851SHCLTRANSFERSTATUS ShClTransferGetStatus(PSHCLTRANSFER pTransfer)
1852{
1853 AssertPtrReturn(pTransfer, SHCLTRANSFERSTATUS_NONE);
1854
1855 LogFlowFunc(("[Transfer %RU32] enmStatus=%RU32\n", pTransfer->State.uID, pTransfer->State.enmStatus));
1856 return pTransfer->State.enmStatus;
1857}
1858
1859/**
1860 * Runs a started clipboard transfer in a dedicated thread.
1861 *
1862 * @returns VBox status code.
1863 * @param pTransfer Clipboard transfer to run.
1864 * @param pfnThreadFunc Pointer to thread function to use.
1865 * @param pvUser Pointer to user-provided data. Optional.
1866 */
1867int ShClTransferRun(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser)
1868{
1869 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1870 AssertPtrReturn(pfnThreadFunc, VERR_INVALID_POINTER);
1871 /* pvUser is optional. */
1872
1873 AssertMsgReturn(pTransfer->State.enmStatus == SHCLTRANSFERSTATUS_STARTED,
1874 ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)),
1875 VERR_WRONG_ORDER);
1876
1877 int rc = shClTransferThreadCreate(pTransfer, pfnThreadFunc, pvUser);
1878
1879 LogFlowFuncLeaveRC(rc);
1880 return rc;
1881}
1882
1883/**
1884 * Starts an initialized transfer.
1885 *
1886 * @returns VBox status code.
1887 * @param pTransfer Clipboard transfer to start.
1888 */
1889int ShClTransferStart(PSHCLTRANSFER pTransfer)
1890{
1891 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1892
1893 LogFlowFuncEnter();
1894
1895 /* Ready to start? */
1896 AssertMsgReturn(pTransfer->State.enmStatus == SHCLTRANSFERSTATUS_INITIALIZED,
1897 ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)),
1898 VERR_WRONG_ORDER);
1899
1900 int rc;
1901
1902 if (pTransfer->Callbacks.pfnOnStart)
1903 {
1904 rc = pTransfer->Callbacks.pfnOnStart(&pTransfer->CallbackCtx);
1905 }
1906 else
1907 rc = VINF_SUCCESS;
1908
1909 if (RT_SUCCESS(rc))
1910 {
1911 pTransfer->State.enmStatus = SHCLTRANSFERSTATUS_STARTED;
1912 }
1913
1914 LogFlowFuncLeaveRC(rc);
1915 return rc;
1916}
1917
1918/**
1919 * Creates a thread for a clipboard transfer.
1920 *
1921 * @returns VBox status code.
1922 * @param pTransfer Clipboard transfer to create thread for.
1923 * @param pfnThreadFunc Thread function to use for this transfer.
1924 * @param pvUser Pointer to user-provided data.
1925 */
1926static int shClTransferThreadCreate(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser)
1927
1928{
1929 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1930
1931 /* Already marked for stopping? */
1932 AssertMsgReturn(pTransfer->Thread.fStop == false,
1933 ("Transfer thread already marked for stopping"), VERR_WRONG_ORDER);
1934 /* Already started? */
1935 AssertMsgReturn(pTransfer->Thread.fStarted == false,
1936 ("Transfer thread already started"), VERR_WRONG_ORDER);
1937
1938 /* Spawn a worker thread, so that we don't block the window thread for too long. */
1939 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnThreadFunc,
1940 pvUser, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
1941 "shclp");
1942 if (RT_SUCCESS(rc))
1943 {
1944 int rc2 = RTThreadUserWait(pTransfer->Thread.hThread, 30 * 1000 /* Timeout in ms */);
1945 AssertRC(rc2);
1946
1947 if (pTransfer->Thread.fStarted) /* Did the thread indicate that it started correctly? */
1948 {
1949 /* Nothing to do in here. */
1950 }
1951 else
1952 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
1953 }
1954
1955 LogFlowFuncLeaveRC(rc);
1956 return rc;
1957}
1958
1959/**
1960 * Destroys the thread of a clipboard transfer.
1961 *
1962 * @returns VBox status code.
1963 * @param pTransfer Clipboard transfer to destroy thread for.
1964 * @param uTimeoutMs Timeout (in ms) to wait for thread creation.
1965 */
1966static int shClTransferThreadDestroy(PSHCLTRANSFER pTransfer, RTMSINTERVAL uTimeoutMs)
1967{
1968 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1969
1970 if (pTransfer->Thread.hThread == NIL_RTTHREAD)
1971 return VINF_SUCCESS;
1972
1973 LogFlowFuncEnter();
1974
1975 /* Set stop indicator. */
1976 pTransfer->Thread.fStop = true;
1977
1978 int rcThread = VERR_WRONG_ORDER;
1979 int rc = RTThreadWait(pTransfer->Thread.hThread, uTimeoutMs, &rcThread);
1980
1981 LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n", rc, rcThread));
1982
1983 return rc;
1984}
1985
1986/**
1987 * Initializes a clipboard transfer context.
1988 *
1989 * @returns VBox status code.
1990 * @param pTransferCtx Transfer context to initialize.
1991 */
1992int ShClTransferCtxInit(PSHCLTRANSFERCTX pTransferCtx)
1993{
1994 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
1995
1996 LogFlowFunc(("pTransferCtx=%p\n", pTransferCtx));
1997
1998 int rc = RTCritSectInit(&pTransferCtx->CritSect);
1999 if (RT_SUCCESS(rc))
2000 {
2001 RTListInit(&pTransferCtx->List);
2002
2003 pTransferCtx->cTransfers = 0;
2004 pTransferCtx->cRunning = 0;
2005 pTransferCtx->cMaxRunning = 64; /** @todo Make this configurable? */
2006
2007 RT_ZERO(pTransferCtx->bmTransferIds);
2008
2009 ShClTransferCtxReset(pTransferCtx);
2010 }
2011
2012 return VINF_SUCCESS;
2013}
2014
2015/**
2016 * Destroys a clipboard transfer context.
2017 *
2018 * @param pTransferCtx Transfer context to destroy.
2019 */
2020void ShClTransferCtxDestroy(PSHCLTRANSFERCTX pTransferCtx)
2021{
2022 if (!pTransferCtx)
2023 return;
2024
2025 LogFlowFunc(("pTransferCtx=%p\n", pTransferCtx));
2026
2027 if (RTCritSectIsInitialized(&pTransferCtx->CritSect))
2028 RTCritSectDelete(&pTransferCtx->CritSect);
2029
2030 PSHCLTRANSFER pTransfer, pTransferNext;
2031 RTListForEachSafe(&pTransferCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node)
2032 {
2033 ShClTransferDestroy(pTransfer);
2034
2035 shclTransferCtxTransferRemoveAndUnregister(pTransferCtx, pTransfer);
2036
2037 RTMemFree(pTransfer);
2038 pTransfer = NULL;
2039 }
2040
2041 pTransferCtx->cRunning = 0;
2042 pTransferCtx->cTransfers = 0;
2043}
2044
2045/**
2046 * Resets a clipboard transfer context.
2047 *
2048 * @param pTransferCtx Transfer context to reset.
2049 */
2050void ShClTransferCtxReset(PSHCLTRANSFERCTX pTransferCtx)
2051{
2052 AssertPtrReturnVoid(pTransferCtx);
2053
2054 LogFlowFuncEnter();
2055
2056 PSHCLTRANSFER pTransfer;
2057 RTListForEach(&pTransferCtx->List, pTransfer, SHCLTRANSFER, Node)
2058 ShClTransferReset(pTransfer);
2059
2060#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
2061 /** @todo Anything to do here? */
2062#endif
2063}
2064
2065/**
2066 * Returns a specific clipboard transfer, internal version.
2067 *
2068 * @returns Clipboard transfer found, or NULL if not found.
2069 * @param pTransferCtx Transfer context to return transfer for.
2070 * @param uID ID of the transfer to return.
2071 */
2072static PSHCLTRANSFER shClTransferCtxGetTransferByIdInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID)
2073{
2074 PSHCLTRANSFER pTransfer;
2075 RTListForEach(&pTransferCtx->List, pTransfer, SHCLTRANSFER, Node) /** @todo Slow, but works for now. */
2076 {
2077 if (pTransfer->State.uID == uID)
2078 return pTransfer;
2079 }
2080
2081 return NULL;
2082}
2083
2084/**
2085 * Returns a specific clipboard transfer by index, internal version.
2086 *
2087 * @returns Clipboard transfer found, or NULL if not found.
2088 * @param pTransferCtx Transfer context to return transfer for.
2089 * @param uIdx Index of the transfer to return.
2090 */
2091static PSHCLTRANSFER shClTransferCtxGetTransferByIndexInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx)
2092{
2093 uint32_t idx = 0;
2094
2095 PSHCLTRANSFER pTransfer;
2096 RTListForEach(&pTransferCtx->List, pTransfer, SHCLTRANSFER, Node) /** @todo Slow, but works for now. */
2097 {
2098 if (uIdx == idx)
2099 return pTransfer;
2100 idx++;
2101 }
2102
2103 return NULL;
2104}
2105
2106/**
2107 * Returns a clipboard transfer for a specific transfer ID.
2108 *
2109 * @returns Clipboard transfer found, or NULL if not found.
2110 * @param pTransferCtx Transfer context to return transfer for.
2111 * @param uID ID of the transfer to return.
2112 */
2113PSHCLTRANSFER ShClTransferCtxGetTransferById(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID)
2114{
2115 return shClTransferCtxGetTransferByIdInternal(pTransferCtx, uID);
2116}
2117
2118/**
2119 * Returns a clipboard transfer for a specific list index.
2120 *
2121 * @returns Clipboard transfer found, or NULL if not found.
2122 * @param pTransferCtx Transfer context to return transfer for.
2123 * @param uIdx List index of the transfer to return.
2124 */
2125PSHCLTRANSFER ShClTransferCtxGetTransferByIndex(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx)
2126{
2127 return shClTransferCtxGetTransferByIndexInternal(pTransferCtx, uIdx);
2128}
2129
2130/**
2131 * Returns the number of running clipboard transfers for a given transfer context.
2132 *
2133 * @returns Number of running transfers.
2134 * @param pTransferCtx Transfer context to return number for.
2135 */
2136uint32_t ShClTransferCtxGetRunningTransfers(PSHCLTRANSFERCTX pTransferCtx)
2137{
2138 AssertPtrReturn(pTransferCtx, 0);
2139 return pTransferCtx->cRunning;
2140}
2141
2142/**
2143 * Returns the number of total clipboard transfers for a given transfer context.
2144 *
2145 * @returns Number of total transfers.
2146 * @param pTransferCtx Transfer context to return number for.
2147 */
2148uint32_t ShClTransferCtxGetTotalTransfers(PSHCLTRANSFERCTX pTransferCtx)
2149{
2150 AssertPtrReturn(pTransferCtx, 0);
2151 return pTransferCtx->cTransfers;
2152}
2153
2154/**
2155 * Registers a clipboard transfer with a transfer context, i.e. allocates a transfer ID.
2156 *
2157 * @return VBox status code.
2158 * @retval VERR_SHCLPB_MAX_TRANSFERS_REACHED if the maximum of concurrent transfers
2159 * is reached.
2160 * @param pTransferCtx Transfer context to register transfer to.
2161 * @param pTransfer Transfer to register. The context takes ownership of the transfer on success.
2162 * @param pidTransfer Where to return the transfer ID on success. Optional.
2163 */
2164int ShClTransferCtxTransferRegister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID *pidTransfer)
2165{
2166 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
2167 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2168 /* pidTransfer is optional. */
2169
2170 /*
2171 * Pick a random bit as starting point. If it's in use, search forward
2172 * for a free one, wrapping around. We've reserved both the zero'th and
2173 * max-1 IDs.
2174 */
2175 SHCLTRANSFERID idTransfer = RTRandU32Ex(1, VBOX_SHCL_MAX_TRANSFERS - 2);
2176
2177 if (!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer))
2178 { /* likely */ }
2179 else if (pTransferCtx->cTransfers < VBOX_SHCL_MAX_TRANSFERS - 2 /* First and last are not used */)
2180 {
2181 /* Forward search. */
2182 int iHit = ASMBitNextClear(&pTransferCtx->bmTransferIds[0], VBOX_SHCL_MAX_TRANSFERS, idTransfer);
2183 if (iHit < 0)
2184 iHit = ASMBitFirstClear(&pTransferCtx->bmTransferIds[0], VBOX_SHCL_MAX_TRANSFERS);
2185 AssertLogRelMsgReturn(iHit >= 0, ("Transfer count: %RU16\n", pTransferCtx->cTransfers), VERR_SHCLPB_MAX_TRANSFERS_REACHED);
2186 idTransfer = iHit;
2187 AssertLogRelMsgReturn(!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer), ("idObject=%#x\n", idTransfer), VERR_INTERNAL_ERROR_2);
2188 }
2189 else
2190 {
2191 LogFunc(("Maximum number of transfers reached (%RU16 transfers)\n", pTransferCtx->cTransfers));
2192 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2193 }
2194
2195 Log2Func(("pTransfer=%p, idTransfer=%RU32 (%RU16 transfers)\n", pTransfer, idTransfer, pTransferCtx->cTransfers));
2196
2197 pTransfer->State.uID = idTransfer;
2198
2199 RTListAppend(&pTransferCtx->List, &pTransfer->Node);
2200
2201 pTransferCtx->cTransfers++;
2202
2203 if (pTransfer->Callbacks.pfnOnRegistered)
2204 pTransfer->Callbacks.pfnOnRegistered(&pTransfer->CallbackCtx, pTransferCtx);
2205
2206 if (pidTransfer)
2207 *pidTransfer = idTransfer;
2208
2209 LogFlowFuncLeaveRC(VINF_SUCCESS);
2210 return VINF_SUCCESS;
2211}
2212
2213/**
2214 * Registers a clipboard transfer with a transfer context by specifying an ID for the transfer.
2215 *
2216 * @return VBox status code.
2217 * @retval VERR_ALREADY_EXISTS if a transfer with the given ID already exists.
2218 * @retval VERR_SHCLPB_MAX_TRANSFERS_REACHED if the maximum of concurrent transfers for this context has been reached.
2219 * @param pTransferCtx Transfer context to register transfer to.
2220 * @param pTransfer Transfer to register.
2221 * @param idTransfer Transfer ID to use for registration.
2222 */
2223int ShClTransferCtxTransferRegisterById(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID idTransfer)
2224{
2225 LogFlowFunc(("cTransfers=%RU16, idTransfer=%RU32\n", pTransferCtx->cTransfers, idTransfer));
2226
2227 if (pTransferCtx->cTransfers < VBOX_SHCL_MAX_TRANSFERS - 2 /* First and last are not used */)
2228 {
2229 if (!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer))
2230 {
2231 RTListAppend(&pTransferCtx->List, &pTransfer->Node);
2232
2233 pTransfer->State.uID = idTransfer;
2234
2235 if (pTransfer->Callbacks.pfnOnRegistered)
2236 pTransfer->Callbacks.pfnOnRegistered(&pTransfer->CallbackCtx, pTransferCtx);
2237
2238 pTransferCtx->cTransfers++;
2239 return VINF_SUCCESS;
2240 }
2241
2242 return VERR_ALREADY_EXISTS;
2243 }
2244
2245 LogFunc(("Maximum number of transfers reached (%RU16 transfers)\n", pTransferCtx->cTransfers));
2246 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2247}
2248
2249/**
2250 * Removes and unregisters a transfer from a transfer context.
2251 *
2252 * @param pTransferCtx Transfer context to remove transfer from.
2253 * @param pTransfer Transfer to remove.
2254 */
2255static void shclTransferCtxTransferRemoveAndUnregister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer)
2256{
2257 RTListNodeRemove(&pTransfer->Node);
2258
2259 Assert(pTransferCtx->cTransfers);
2260 pTransferCtx->cTransfers--;
2261
2262 Assert(pTransferCtx->cTransfers >= pTransferCtx->cRunning);
2263
2264 if (pTransfer->Callbacks.pfnOnUnregistered)
2265 pTransfer->Callbacks.pfnOnUnregistered(&pTransfer->CallbackCtx, pTransferCtx);
2266
2267 LogFlowFunc(("Now %RU32 transfers left\n", pTransferCtx->cTransfers));
2268}
2269
2270/**
2271 * Unregisters a transfer from an transfer context.
2272 *
2273 * @retval VINF_SUCCESS on success.
2274 * @retval VERR_NOT_FOUND if the transfer ID was not found.
2275 * @param pTransferCtx Transfer context to unregister transfer from.
2276 * @param idTransfer Transfer ID to unregister.
2277 */
2278int ShClTransferCtxTransferUnregister(PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer)
2279{
2280 int rc = VINF_SUCCESS;
2281 AssertMsgStmt(ASMBitTestAndClear(&pTransferCtx->bmTransferIds, idTransfer), ("idTransfer=%#x\n", idTransfer), rc = VERR_NOT_FOUND);
2282
2283 LogFlowFunc(("idTransfer=%RU32\n", idTransfer));
2284
2285 PSHCLTRANSFER pTransfer = shClTransferCtxGetTransferByIdInternal(pTransferCtx, idTransfer);
2286 if (pTransfer)
2287 {
2288 shclTransferCtxTransferRemoveAndUnregister(pTransferCtx, pTransfer);
2289 }
2290 else
2291 rc = VERR_NOT_FOUND;
2292
2293 LogFlowFuncLeaveRC(rc);
2294 return rc;
2295}
2296
2297/**
2298 * Cleans up all associated transfers which are not needed (anymore).
2299 * This can be due to transfers which only have been announced but not / never being run.
2300 *
2301 * @param pTransferCtx Transfer context to cleanup transfers for.
2302 */
2303void ShClTransferCtxCleanup(PSHCLTRANSFERCTX pTransferCtx)
2304{
2305 AssertPtrReturnVoid(pTransferCtx);
2306
2307 LogFlowFunc(("pTransferCtx=%p, cTransfers=%RU16 cRunning=%RU16\n",
2308 pTransferCtx, pTransferCtx->cTransfers, pTransferCtx->cRunning));
2309
2310 if (pTransferCtx->cTransfers == 0)
2311 return;
2312
2313 /* Remove all transfers which are not in a running state (e.g. only announced). */
2314 PSHCLTRANSFER pTransfer, pTransferNext;
2315 RTListForEachSafe(&pTransferCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node)
2316 {
2317 if (ShClTransferGetStatus(pTransfer) != SHCLTRANSFERSTATUS_STARTED)
2318 {
2319 shclTransferCtxTransferRemoveAndUnregister(pTransferCtx, pTransfer);
2320
2321 ShClTransferDestroy(pTransfer);
2322
2323 RTMemFree(pTransfer);
2324 pTransfer = NULL;
2325 }
2326 }
2327}
2328
2329/**
2330 * Returns whether the maximum of concurrent transfers of a specific transfer contexthas been reached or not.
2331 *
2332 * @returns \c if maximum has been reached, \c false if not.
2333 * @param pTransferCtx Transfer context to determine value for.
2334 */
2335bool ShClTransferCtxTransfersMaximumReached(PSHCLTRANSFERCTX pTransferCtx)
2336{
2337 AssertPtrReturn(pTransferCtx, true);
2338
2339 LogFlowFunc(("cRunning=%RU32, cMaxRunning=%RU32\n", pTransferCtx->cRunning, pTransferCtx->cMaxRunning));
2340
2341 Assert(pTransferCtx->cRunning <= pTransferCtx->cMaxRunning);
2342 return pTransferCtx->cRunning == pTransferCtx->cMaxRunning;
2343}
2344
2345/**
2346 * Copies file system objinfo from IPRT to Shared Clipboard format.
2347 *
2348 * @param pDst The Shared Clipboard structure to convert data to.
2349 * @param pSrc The IPRT structure to convert data from.
2350 */
2351void ShClFsObjFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc)
2352{
2353 pDst->cbObject = pSrc->cbObject;
2354 pDst->cbAllocated = pSrc->cbAllocated;
2355 pDst->AccessTime = pSrc->AccessTime;
2356 pDst->ModificationTime = pSrc->ModificationTime;
2357 pDst->ChangeTime = pSrc->ChangeTime;
2358 pDst->BirthTime = pSrc->BirthTime;
2359 pDst->Attr.fMode = pSrc->Attr.fMode;
2360 /* Clear bits which we don't pass through for security reasons. */
2361 pDst->Attr.fMode &= ~(RTFS_UNIX_ISUID | RTFS_UNIX_ISGID | RTFS_UNIX_ISTXT);
2362 RT_ZERO(pDst->Attr.u);
2363 switch (pSrc->Attr.enmAdditional)
2364 {
2365 default:
2366 case RTFSOBJATTRADD_NOTHING:
2367 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_NOTHING;
2368 break;
2369
2370 case RTFSOBJATTRADD_UNIX:
2371 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_UNIX;
2372 pDst->Attr.u.Unix.uid = pSrc->Attr.u.Unix.uid;
2373 pDst->Attr.u.Unix.gid = pSrc->Attr.u.Unix.gid;
2374 pDst->Attr.u.Unix.cHardlinks = pSrc->Attr.u.Unix.cHardlinks;
2375 pDst->Attr.u.Unix.INodeIdDevice = pSrc->Attr.u.Unix.INodeIdDevice;
2376 pDst->Attr.u.Unix.INodeId = pSrc->Attr.u.Unix.INodeId;
2377 pDst->Attr.u.Unix.fFlags = pSrc->Attr.u.Unix.fFlags;
2378 pDst->Attr.u.Unix.GenerationId = pSrc->Attr.u.Unix.GenerationId;
2379 pDst->Attr.u.Unix.Device = pSrc->Attr.u.Unix.Device;
2380 break;
2381
2382 case RTFSOBJATTRADD_EASIZE:
2383 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_EASIZE;
2384 pDst->Attr.u.EASize.cb = pSrc->Attr.u.EASize.cb;
2385 break;
2386 }
2387}
2388
2389/**
2390 * Translates a clipboard transfer status (SHCLTRANSFERSTATUS_XXX) into a string.
2391 *
2392 * @returns Transfer status string name.
2393 * @param enmStatus The transfer status to translate.
2394 */
2395const char *ShClTransferStatusToStr(SHCLTRANSFERSTATUS enmStatus)
2396{
2397 switch (enmStatus)
2398 {
2399 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_NONE);
2400 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_INITIALIZED);
2401 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STARTED);
2402 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STOPPED);
2403 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_CANCELED);
2404 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_KILLED);
2405 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_ERROR);
2406 }
2407 return "Unknown";
2408}
2409
2410/**
2411 * Validates whether a given path matches our set of rules or not.
2412 *
2413 * @returns VBox status code.
2414 * @param pcszPath Path to validate.
2415 * @param fMustExist Whether the path to validate also must exist.
2416 */
2417int ShClTransferValidatePath(const char *pcszPath, bool fMustExist)
2418{
2419 int rc = VINF_SUCCESS;
2420
2421 if (!strlen(pcszPath))
2422 rc = VERR_INVALID_PARAMETER;
2423
2424 if ( RT_SUCCESS(rc)
2425 && !RTStrIsValidEncoding(pcszPath))
2426 {
2427 rc = VERR_INVALID_UTF8_ENCODING;
2428 }
2429
2430 if ( RT_SUCCESS(rc)
2431 && RTStrStr(pcszPath, ".."))
2432 {
2433 rc = VERR_INVALID_PARAMETER;
2434 }
2435
2436 if ( RT_SUCCESS(rc)
2437 && fMustExist)
2438 {
2439 RTFSOBJINFO objInfo;
2440 rc = RTPathQueryInfo(pcszPath, &objInfo, RTFSOBJATTRADD_NOTHING);
2441 if (RT_SUCCESS(rc))
2442 {
2443 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
2444 {
2445 if (!RTDirExists(pcszPath)) /* Path must exist. */
2446 rc = VERR_PATH_NOT_FOUND;
2447 }
2448 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
2449 {
2450 if (!RTFileExists(pcszPath)) /* File must exist. */
2451 rc = VERR_FILE_NOT_FOUND;
2452 }
2453 else /* Everything else (e.g. symbolic links) are not supported. */
2454 {
2455 LogRel2(("Shared Clipboard: Path '%s' contains a symbolic link or junktion, which are not supported\n", pcszPath));
2456 rc = VERR_NOT_SUPPORTED;
2457 }
2458 }
2459 }
2460
2461 if (RT_FAILURE(rc))
2462 LogRel2(("Shared Clipboard: Validating path '%s' failed: %Rrc\n", pcszPath, rc));
2463
2464 LogFlowFuncLeaveRC(rc);
2465 return rc;
2466}
2467
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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