VirtualBox

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

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

Shared Clipboard/Transfers: Update.

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

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