VirtualBox

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

Last change on this file since 99937 was 99937, checked in by vboxsync, 21 months ago

Shared Clipboard: Added new testcase for the HTTP server in combination with the Shared Clipboard API, various updates and general improvements. bugref:9437

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

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