VirtualBox

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

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

Shared Clipboard/Transfers: Renamed SHCLTRANSFERDIR_[READ|WRITE] -> SHCLTRANSFERDIR_[FROM|TO]_REMOTE.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 99.9 KB
Line 
1/* $Id: clipboard-transfers.cpp 82462 2019-12-06 14:22:03Z 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_FROM_REMOTE)
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_TO_REMOTE)
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_FROM_REMOTE;
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 * Validates whether a given path matches our set of rules or not.
1378 *
1379 * @returns VBox status code.
1380 * @param pcszPath Path to validate.
1381 * @param fMustExist Whether the path to validate also must exist.
1382 */
1383static int shClTransferValidatePath(const char *pcszPath, bool fMustExist)
1384{
1385 int rc = VINF_SUCCESS;
1386
1387 if (!strlen(pcszPath))
1388 rc = VERR_INVALID_PARAMETER;
1389
1390 if ( RT_SUCCESS(rc)
1391 && !RTStrIsValidEncoding(pcszPath))
1392 {
1393 rc = VERR_INVALID_UTF8_ENCODING;
1394 }
1395
1396 if ( RT_SUCCESS(rc)
1397 && RTStrStr(pcszPath, ".."))
1398 {
1399 rc = VERR_INVALID_PARAMETER;
1400 }
1401
1402 if ( RT_SUCCESS(rc)
1403 && fMustExist)
1404 {
1405 RTFSOBJINFO objInfo;
1406 rc = RTPathQueryInfo(pcszPath, &objInfo, RTFSOBJATTRADD_NOTHING);
1407 if (RT_SUCCESS(rc))
1408 {
1409 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
1410 {
1411 if (!RTDirExists(pcszPath)) /* Path must exist. */
1412 rc = VERR_PATH_NOT_FOUND;
1413 }
1414 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
1415 {
1416 if (!RTFileExists(pcszPath)) /* File must exist. */
1417 rc = VERR_FILE_NOT_FOUND;
1418 }
1419 else /* Everything else (e.g. symbolic links) are not supported. */
1420 {
1421 LogRel2(("Shared Clipboard: Path '%s' contains a symbolic link or junktion, which are not supported\n", pcszPath));
1422 rc = VERR_NOT_SUPPORTED;
1423 }
1424 }
1425 }
1426
1427 if (RT_FAILURE(rc))
1428 LogRel2(("Shared Clipboard: Validating path '%s' failed: %Rrc\n", pcszPath, rc));
1429
1430 LogFlowFuncLeaveRC(rc);
1431 return rc;
1432}
1433
1434/**
1435 * Resolves a relative path of a specific transfer to its absolute path.
1436 *
1437 * @returns VBox status code.
1438 * @param pTransfer Clipboard transfer to resolve path for.
1439 * @param pszPath Path to resolve.
1440 * @param fFlags Resolve flags. Currently not used and must be 0.
1441 * @param ppszResolved Where to store the allocated resolved path. Must be free'd by the called using RTStrFree().
1442 */
1443static int shClTransferResolvePathAbs(PSHCLTRANSFER pTransfer, const char *pszPath, uint32_t fFlags,
1444 char **ppszResolved)
1445{
1446 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1447 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
1448 AssertReturn (fFlags == 0, VERR_INVALID_PARAMETER);
1449
1450 LogFlowFunc(("pszPathRootAbs=%s, pszPath=%s\n", pTransfer->pszPathRootAbs, pszPath));
1451
1452 int rc = shClTransferValidatePath(pszPath, false /* fMustExist */);
1453 if (RT_SUCCESS(rc))
1454 {
1455 char *pszPathAbs = RTPathJoinA(pTransfer->pszPathRootAbs, pszPath);
1456 if (pszPathAbs)
1457 {
1458 char szResolved[RTPATH_MAX];
1459 size_t cbResolved = sizeof(szResolved);
1460 rc = RTPathAbsEx(pTransfer->pszPathRootAbs, pszPathAbs, RTPATH_STR_F_STYLE_HOST, szResolved, &cbResolved);
1461
1462 RTStrFree(pszPathAbs);
1463
1464 if (RT_SUCCESS(rc))
1465 {
1466 LogFlowFunc(("pszResolved=%s\n", szResolved));
1467
1468 rc = VERR_PATH_NOT_FOUND; /* Play safe by default. */
1469
1470 /* Make sure the resolved path is part of the set of root entries. */
1471 PSHCLLISTROOT pListRoot;
1472 RTListForEach(&pTransfer->lstRoots, pListRoot, SHCLLISTROOT, Node)
1473 {
1474 if (RTPathStartsWith(szResolved, pListRoot->pszPathAbs))
1475 {
1476 rc = VINF_SUCCESS;
1477 break;
1478 }
1479 }
1480
1481 if (RT_SUCCESS(rc))
1482 *ppszResolved = RTStrDup(szResolved);
1483 }
1484 }
1485 else
1486 rc = VERR_NO_MEMORY;
1487 }
1488
1489 if (RT_FAILURE(rc))
1490 LogRel(("Shared Clipboard: Resolving absolute path '%s' failed, rc=%Rrc\n", pszPath, rc));
1491
1492 LogFlowFuncLeaveRC(rc);
1493 return rc;
1494}
1495
1496/**
1497 * Opens a list.
1498 *
1499 * @returns VBox status code.
1500 * @param pTransfer Clipboard transfer to handle.
1501 * @param pOpenParms List open parameters to use for opening.
1502 * @param phList Where to store the List handle of opened list on success.
1503 */
1504int ShClTransferListOpen(PSHCLTRANSFER pTransfer, PSHCLLISTOPENPARMS pOpenParms,
1505 PSHCLLISTHANDLE phList)
1506{
1507 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1508 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1509 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1510
1511 int rc;
1512
1513 if (pTransfer->cListHandles == pTransfer->cMaxListHandles)
1514 return VERR_SHCLPB_MAX_LISTS_REACHED;
1515
1516 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)
1517 {
1518 LogFlowFunc(("pszPath=%s\n", pOpenParms->pszPath));
1519
1520 PSHCLLISTHANDLEINFO pInfo
1521 = (PSHCLLISTHANDLEINFO)RTMemAllocZ(sizeof(SHCLLISTHANDLEINFO));
1522 if (pInfo)
1523 {
1524 rc = ShClTransferListHandleInfoInit(pInfo);
1525 if (RT_SUCCESS(rc))
1526 {
1527 rc = shClTransferResolvePathAbs(pTransfer, pOpenParms->pszPath, 0 /* fFlags */, &pInfo->pszPathLocalAbs);
1528 if (RT_SUCCESS(rc))
1529 {
1530 RTFSOBJINFO objInfo;
1531 rc = RTPathQueryInfo(pInfo->pszPathLocalAbs, &objInfo, RTFSOBJATTRADD_NOTHING);
1532 if (RT_SUCCESS(rc))
1533 {
1534 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
1535 {
1536 rc = RTDirOpen(&pInfo->u.Local.hDir, pInfo->pszPathLocalAbs);
1537 if (RT_SUCCESS(rc))
1538 {
1539 pInfo->enmType = SHCLOBJTYPE_DIRECTORY;
1540
1541 LogRel2(("Shared Clipboard: Opening directory '%s'\n", pInfo->pszPathLocalAbs));
1542 }
1543 else
1544 LogRel(("Shared Clipboard: Opening directory '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));
1545
1546 }
1547 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
1548 {
1549 rc = RTFileOpen(&pInfo->u.Local.hFile, pInfo->pszPathLocalAbs,
1550 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
1551 if (RT_SUCCESS(rc))
1552 {
1553 pInfo->enmType = SHCLOBJTYPE_FILE;
1554
1555 LogRel2(("Shared Clipboard: Opening file '%s'\n", pInfo->pszPathLocalAbs));
1556 }
1557 else
1558 LogRel(("Shared Clipboard: Opening file '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));
1559 }
1560 else
1561 rc = VERR_NOT_SUPPORTED;
1562
1563 if (RT_SUCCESS(rc))
1564 {
1565 pInfo->hList = shClTransferListHandleNew(pTransfer);
1566
1567 RTListAppend(&pTransfer->lstList, &pInfo->Node);
1568 pTransfer->cListHandles++;
1569
1570 if (phList)
1571 *phList = pInfo->hList;
1572
1573 LogFlowFunc(("pszPathLocalAbs=%s, hList=%RU64, cListHandles=%RU32\n",
1574 pInfo->pszPathLocalAbs, pInfo->hList, pTransfer->cListHandles));
1575 }
1576 else
1577 {
1578 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
1579 {
1580 if (RTDirIsValid(pInfo->u.Local.hDir))
1581 RTDirClose(pInfo->u.Local.hDir);
1582 }
1583 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
1584 {
1585 if (RTFileIsValid(pInfo->u.Local.hFile))
1586 RTFileClose(pInfo->u.Local.hFile);
1587 }
1588 }
1589 }
1590 }
1591 }
1592
1593 if (RT_FAILURE(rc))
1594 {
1595 ShClTransferListHandleInfoDestroy(pInfo);
1596
1597 RTMemFree(pInfo);
1598 pInfo = NULL;
1599 }
1600 }
1601 else
1602 rc = VERR_NO_MEMORY;
1603 }
1604 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)
1605 {
1606 if (pTransfer->ProviderIface.pfnListOpen)
1607 {
1608 rc = pTransfer->ProviderIface.pfnListOpen(&pTransfer->ProviderCtx, pOpenParms, phList);
1609 }
1610 else
1611 rc = VERR_NOT_SUPPORTED;
1612 }
1613 else
1614 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
1615
1616 LogFlowFuncLeaveRC(rc);
1617 return rc;
1618}
1619
1620/**
1621 * Closes a list.
1622 *
1623 * @returns VBox status code.
1624 * @param pTransfer Clipboard transfer to handle.
1625 * @param hList Handle of list to close.
1626 */
1627int ShClTransferListClose(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList)
1628{
1629 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1630
1631 if (hList == SHCLLISTHANDLE_INVALID)
1632 return VINF_SUCCESS;
1633
1634 int rc = VINF_SUCCESS;
1635
1636 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)
1637 {
1638 PSHCLLISTHANDLEINFO pInfo = shClTransferListGetByHandle(pTransfer, hList);
1639 if (pInfo)
1640 {
1641 switch (pInfo->enmType)
1642 {
1643 case SHCLOBJTYPE_DIRECTORY:
1644 {
1645 if (RTDirIsValid(pInfo->u.Local.hDir))
1646 {
1647 RTDirClose(pInfo->u.Local.hDir);
1648 pInfo->u.Local.hDir = NIL_RTDIR;
1649 }
1650 break;
1651 }
1652
1653 default:
1654 rc = VERR_NOT_SUPPORTED;
1655 break;
1656 }
1657
1658 RTListNodeRemove(&pInfo->Node);
1659
1660 Assert(pTransfer->cListHandles);
1661 pTransfer->cListHandles--;
1662
1663 RTMemFree(pInfo);
1664 }
1665 else
1666 rc = VERR_NOT_FOUND;
1667 }
1668 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)
1669 {
1670 if (pTransfer->ProviderIface.pfnListClose)
1671 {
1672 rc = pTransfer->ProviderIface.pfnListClose(&pTransfer->ProviderCtx, hList);
1673 }
1674 else
1675 rc = VERR_NOT_SUPPORTED;
1676 }
1677
1678 LogFlowFuncLeaveRC(rc);
1679 return rc;
1680}
1681
1682/**
1683 * Adds a file to a list heaer.
1684 *
1685 * @returns VBox status code.
1686 * @param pHdr List header to add file to.
1687 * @param pszPath Path of file to add.
1688 */
1689static int shclTransferListHdrAddFile(PSHCLLISTHDR pHdr, const char *pszPath)
1690{
1691 uint64_t cbSize = 0;
1692 int rc = RTFileQuerySizeByPath(pszPath, &cbSize);
1693 if (RT_SUCCESS(rc))
1694 {
1695 pHdr->cbTotalSize += cbSize;
1696 pHdr->cTotalObjects++;
1697 }
1698
1699 LogFlowFuncLeaveRC(rc);
1700 return rc;
1701}
1702
1703/**
1704 * Builds a list header, internal version.
1705 *
1706 * @returns VBox status code.
1707 * @param pHdr Where to store the build list header.
1708 * @param pcszSrcPath Source path of list.
1709 * @param pcszDstPath Destination path of list.
1710 * @param pcszDstBase Destination base path.
1711 * @param cchDstBase Number of charaters of destination base path.
1712 */
1713static int shclTransferListHdrFromDir(PSHCLLISTHDR pHdr, const char *pcszPathAbs)
1714{
1715 AssertPtrReturn(pcszPathAbs, VERR_INVALID_POINTER);
1716
1717 LogFlowFunc(("pcszPathAbs=%s\n", pcszPathAbs));
1718
1719 RTFSOBJINFO objInfo;
1720 int rc = RTPathQueryInfo(pcszPathAbs, &objInfo, RTFSOBJATTRADD_NOTHING);
1721 if (RT_SUCCESS(rc))
1722 {
1723 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
1724 {
1725 RTDIR hDir;
1726 rc = RTDirOpen(&hDir, pcszPathAbs);
1727 if (RT_SUCCESS(rc))
1728 {
1729 size_t cbDirEntry = 0;
1730 PRTDIRENTRYEX pDirEntry = NULL;
1731 do
1732 {
1733 /* Retrieve the next directory entry. */
1734 rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
1735 if (RT_FAILURE(rc))
1736 {
1737 if (rc == VERR_NO_MORE_FILES)
1738 rc = VINF_SUCCESS;
1739 break;
1740 }
1741
1742 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
1743 {
1744 case RTFS_TYPE_DIRECTORY:
1745 {
1746 /* Skip "." and ".." entries. */
1747 if (RTDirEntryExIsStdDotLink(pDirEntry))
1748 break;
1749
1750 pHdr->cTotalObjects++;
1751 break;
1752 }
1753 case RTFS_TYPE_FILE:
1754 {
1755 char *pszSrc = RTPathJoinA(pcszPathAbs, pDirEntry->szName);
1756 if (pszSrc)
1757 {
1758 rc = shclTransferListHdrAddFile(pHdr, pszSrc);
1759 RTStrFree(pszSrc);
1760 }
1761 else
1762 rc = VERR_NO_MEMORY;
1763 break;
1764 }
1765 case RTFS_TYPE_SYMLINK:
1766 {
1767 /** @todo Not implemented yet. */
1768 }
1769
1770 default:
1771 break;
1772 }
1773
1774 } while (RT_SUCCESS(rc));
1775
1776 RTDirReadExAFree(&pDirEntry, &cbDirEntry);
1777 RTDirClose(hDir);
1778 }
1779 }
1780 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
1781 {
1782 rc = shclTransferListHdrAddFile(pHdr, pcszPathAbs);
1783 }
1784 else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))
1785 {
1786 /** @todo Not implemented yet. */
1787 }
1788 else
1789 rc = VERR_NOT_SUPPORTED;
1790 }
1791
1792 LogFlowFuncLeaveRC(rc);
1793 return rc;
1794}
1795
1796/**
1797 * Retrieves the header of a Shared Clipboard list.
1798 *
1799 * @returns VBox status code.
1800 * @param pTransfer Clipboard transfer to handle.
1801 * @param hList Handle of list to get header for.
1802 * @param pHdr Where to store the returned list header information.
1803 */
1804int ShClTransferListGetHeader(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList,
1805 PSHCLLISTHDR pHdr)
1806{
1807 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1808 AssertPtrReturn(pHdr, VERR_INVALID_POINTER);
1809
1810 int rc;
1811
1812 LogFlowFunc(("hList=%RU64\n", hList));
1813
1814 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)
1815 {
1816 PSHCLLISTHANDLEINFO pInfo = shClTransferListGetByHandle(pTransfer, hList);
1817 if (pInfo)
1818 {
1819 rc = ShClTransferListHdrInit(pHdr);
1820 if (RT_SUCCESS(rc))
1821 {
1822 switch (pInfo->enmType)
1823 {
1824 case SHCLOBJTYPE_DIRECTORY:
1825 {
1826 LogFlowFunc(("DirAbs: %s\n", pInfo->pszPathLocalAbs));
1827
1828 rc = shclTransferListHdrFromDir(pHdr, pInfo->pszPathLocalAbs);
1829 break;
1830 }
1831
1832 case SHCLOBJTYPE_FILE:
1833 {
1834 LogFlowFunc(("FileAbs: %s\n", pInfo->pszPathLocalAbs));
1835
1836 pHdr->cTotalObjects = 1;
1837
1838 RTFSOBJINFO objInfo;
1839 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);
1840 if (RT_SUCCESS(rc))
1841 {
1842 pHdr->cbTotalSize = objInfo.cbObject;
1843 }
1844 break;
1845 }
1846
1847 default:
1848 rc = VERR_NOT_SUPPORTED;
1849 break;
1850 }
1851 }
1852
1853 LogFlowFunc(("cTotalObj=%RU64, cbTotalSize=%RU64\n", pHdr->cTotalObjects, pHdr->cbTotalSize));
1854 }
1855 else
1856 rc = VERR_NOT_FOUND;
1857 }
1858 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)
1859 {
1860 if (pTransfer->ProviderIface.pfnListHdrRead)
1861 {
1862 rc = pTransfer->ProviderIface.pfnListHdrRead(&pTransfer->ProviderCtx, hList, pHdr);
1863 }
1864 else
1865 rc = VERR_NOT_SUPPORTED;
1866 }
1867 else
1868 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
1869
1870 LogFlowFuncLeaveRC(rc);
1871 return rc;
1872}
1873
1874/**
1875 * Returns the current transfer object for a Shared Clipboard transfer list.
1876 *
1877 * Currently not implemented and wil return NULL.
1878 *
1879 * @returns Pointer to transfer object, or NULL if not found / invalid.
1880 * @param pTransfer Clipboard transfer to return transfer object for.
1881 * @param hList Handle of Shared Clipboard transfer list to get object for.
1882 * @param uIdx Index of object to get.
1883 */
1884PSHCLTRANSFEROBJ ShClTransferListGetObj(PSHCLTRANSFER pTransfer,
1885 SHCLLISTHANDLE hList, uint64_t uIdx)
1886{
1887 AssertPtrReturn(pTransfer, NULL);
1888
1889 RT_NOREF(hList, uIdx);
1890
1891 LogFlowFunc(("hList=%RU64\n", hList));
1892
1893 return NULL;
1894}
1895
1896/**
1897 * Reads a single Shared Clipboard list entry.
1898 *
1899 * @returns VBox status code or VERR_NO_MORE_FILES if the end of the list has been reached.
1900 * @param pTransfer Clipboard transfer to handle.
1901 * @param hList List handle of list to read from.
1902 * @param pEntry Where to store the read information.
1903 */
1904int ShClTransferListRead(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList,
1905 PSHCLLISTENTRY pEntry)
1906{
1907 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1908 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
1909
1910 int rc = VINF_SUCCESS;
1911
1912 LogFlowFunc(("hList=%RU64\n", hList));
1913
1914 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)
1915 {
1916 PSHCLLISTHANDLEINFO pInfo = shClTransferListGetByHandle(pTransfer, hList);
1917 if (pInfo)
1918 {
1919 switch (pInfo->enmType)
1920 {
1921 case SHCLOBJTYPE_DIRECTORY:
1922 {
1923 LogFlowFunc(("\tDirectory: %s\n", pInfo->pszPathLocalAbs));
1924
1925 for (;;)
1926 {
1927 bool fSkipEntry = false; /* Whether to skip an entry in the enumeration. */
1928
1929 size_t cbDirEntry = 0;
1930 PRTDIRENTRYEX pDirEntry = NULL;
1931 rc = RTDirReadExA(pInfo->u.Local.hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
1932 if (RT_SUCCESS(rc))
1933 {
1934 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
1935 {
1936 case RTFS_TYPE_DIRECTORY:
1937 {
1938 /* Skip "." and ".." entries. */
1939 if (RTDirEntryExIsStdDotLink(pDirEntry))
1940 {
1941 fSkipEntry = true;
1942 break;
1943 }
1944
1945 LogFlowFunc(("Directory: %s\n", pDirEntry->szName));
1946 break;
1947 }
1948
1949 case RTFS_TYPE_FILE:
1950 {
1951 LogFlowFunc(("File: %s\n", pDirEntry->szName));
1952 break;
1953 }
1954
1955 case RTFS_TYPE_SYMLINK:
1956 {
1957 rc = VERR_NOT_IMPLEMENTED; /** @todo Not implemented yet. */
1958 break;
1959 }
1960
1961 default:
1962 break;
1963 }
1964
1965 if ( RT_SUCCESS(rc)
1966 && !fSkipEntry)
1967 {
1968 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pDirEntry->szName);
1969 if (RT_SUCCESS(rc))
1970 {
1971 pEntry->cbName = (uint32_t)strlen(pEntry->pszName) + 1; /* Include termination. */
1972
1973 AssertPtr(pEntry->pvInfo);
1974 Assert (pEntry->cbInfo == sizeof(SHCLFSOBJINFO));
1975
1976 ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &pDirEntry->Info);
1977
1978 LogFlowFunc(("Entry pszName=%s, pvInfo=%p, cbInfo=%RU32\n",
1979 pEntry->pszName, pEntry->pvInfo, pEntry->cbInfo));
1980 }
1981 }
1982
1983 RTDirReadExAFree(&pDirEntry, &cbDirEntry);
1984 }
1985
1986 if ( !fSkipEntry /* Do we have a valid entry? Bail out. */
1987 || RT_FAILURE(rc))
1988 {
1989 break;
1990 }
1991 }
1992
1993 break;
1994 }
1995
1996 case SHCLOBJTYPE_FILE:
1997 {
1998 LogFlowFunc(("\tSingle file: %s\n", pInfo->pszPathLocalAbs));
1999
2000 RTFSOBJINFO objInfo;
2001 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);
2002 if (RT_SUCCESS(rc))
2003 {
2004 pEntry->pvInfo = (PSHCLFSOBJINFO)RTMemAlloc(sizeof(SHCLFSOBJINFO));
2005 if (pEntry->pvInfo)
2006 {
2007 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pInfo->pszPathLocalAbs);
2008 if (RT_SUCCESS(rc))
2009 {
2010 ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &objInfo);
2011
2012 pEntry->cbInfo = sizeof(SHCLFSOBJINFO);
2013 pEntry->fInfo = VBOX_SHCL_INFO_FLAG_FSOBJINFO;
2014 }
2015 }
2016 else
2017 rc = VERR_NO_MEMORY;
2018 }
2019
2020 break;
2021 }
2022
2023 default:
2024 rc = VERR_NOT_SUPPORTED;
2025 break;
2026 }
2027 }
2028 else
2029 rc = VERR_NOT_FOUND;
2030 }
2031 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)
2032 {
2033 if (pTransfer->ProviderIface.pfnListEntryRead)
2034 rc = pTransfer->ProviderIface.pfnListEntryRead(&pTransfer->ProviderCtx, hList, pEntry);
2035 else
2036 rc = VERR_NOT_SUPPORTED;
2037 }
2038 else
2039 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
2040
2041 LogFlowFuncLeaveRC(rc);
2042 return rc;
2043}
2044
2045int ShClTransferListWrite(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList,
2046 PSHCLLISTENTRY pEntry)
2047{
2048 RT_NOREF(pTransfer, hList, pEntry);
2049
2050 int rc = VINF_SUCCESS;
2051
2052#if 0
2053 if (pTransfer->ProviderIface.pfnListEntryWrite)
2054 rc = pTransfer->ProviderIface.pfnListEntryWrite(&pTransfer->ProviderCtx, hList, pEntry);
2055#endif
2056
2057 LogFlowFuncLeaveRC(rc);
2058 return rc;
2059}
2060
2061/**
2062 * Returns whether a given list handle is valid or not.
2063 *
2064 * @returns \c true if list handle is valid, \c false if not.
2065 * @param pTransfer Clipboard transfer to handle.
2066 * @param hList List handle to check.
2067 */
2068bool ShClTransferListHandleIsValid(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList)
2069{
2070 bool fIsValid = false;
2071
2072 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)
2073 {
2074 fIsValid = shClTransferListGetByHandle(pTransfer, hList) != NULL;
2075 }
2076 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)
2077 {
2078 AssertFailed(); /** @todo Implement. */
2079 }
2080 else
2081 AssertFailedStmt(fIsValid = false);
2082
2083 return fIsValid;
2084}
2085
2086/**
2087 * Sets the transfer provider interface for a given transfer.
2088 *
2089 * @returns VBox status code.
2090 * @param pTransfer Transfer to create transfer provider for.
2091 * @param pCreationCtx Provider creation context to use for provider creation.
2092 */
2093int ShClTransferSetInterface(PSHCLTRANSFER pTransfer,
2094 PSHCLPROVIDERCREATIONCTX pCreationCtx)
2095{
2096 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2097 AssertPtrReturn(pCreationCtx, VERR_INVALID_POINTER);
2098
2099 LogFlowFuncEnter();
2100
2101 int rc = VINF_SUCCESS;
2102
2103 pTransfer->ProviderIface = pCreationCtx->Interface;
2104
2105#ifdef DEBUG
2106# define LOG_IFACE_PTR(a_Name) \
2107 LogFlowFunc(( #a_Name "=%p\n", pTransfer->ProviderIface.a_Name));
2108
2109 LOG_IFACE_PTR(pfnTransferOpen);
2110 LOG_IFACE_PTR(pfnTransferClose);
2111 LOG_IFACE_PTR(pfnRootsGet);
2112 LOG_IFACE_PTR(pfnListOpen);
2113 LOG_IFACE_PTR(pfnListClose);
2114
2115# undef LOG_IFACE_PTR
2116#endif
2117
2118 pTransfer->ProviderCtx.pTransfer = pTransfer;
2119 pTransfer->ProviderCtx.pvUser = pCreationCtx->pvUser;
2120
2121 LogFlowFuncLeaveRC(rc);
2122 return rc;
2123}
2124
2125/**
2126 * Clears (resets) the root list of a Shared Clipboard transfer.
2127 *
2128 * @param pTransfer Transfer to clear transfer root list for.
2129 */
2130static void shClTransferListRootsClear(PSHCLTRANSFER pTransfer)
2131{
2132 AssertPtrReturnVoid(pTransfer);
2133
2134 if (pTransfer->pszPathRootAbs)
2135 {
2136 RTStrFree(pTransfer->pszPathRootAbs);
2137 pTransfer->pszPathRootAbs = NULL;
2138 }
2139
2140 PSHCLLISTROOT pListRoot, pListRootNext;
2141 RTListForEachSafe(&pTransfer->lstRoots, pListRoot, pListRootNext, SHCLLISTROOT, Node)
2142 {
2143 RTStrFree(pListRoot->pszPathAbs);
2144
2145 RTListNodeRemove(&pListRoot->Node);
2146
2147 RTMemFree(pListRoot);
2148 pListRoot = NULL;
2149 }
2150
2151 pTransfer->cRoots = 0;
2152}
2153
2154/**
2155 * Resets a Shared Clipboard transfer.
2156 *
2157 * @param pTransfer Clipboard transfer to reset.
2158 */
2159void ShClTransferReset(PSHCLTRANSFER pTransfer)
2160{
2161 AssertPtrReturnVoid(pTransfer);
2162
2163 LogFlowFuncEnter();
2164
2165 shClTransferListRootsClear(pTransfer);
2166
2167 PSHCLLISTHANDLEINFO pItList, pItListNext;
2168 RTListForEachSafe(&pTransfer->lstList, pItList, pItListNext, SHCLLISTHANDLEINFO, Node)
2169 {
2170 ShClTransferListHandleInfoDestroy(pItList);
2171
2172 RTListNodeRemove(&pItList->Node);
2173
2174 RTMemFree(pItList);
2175 }
2176
2177 PSHCLOBJHANDLEINFO pItObj, pItObjNext;
2178 RTListForEachSafe(&pTransfer->lstObj, pItObj, pItObjNext, SHCLOBJHANDLEINFO, Node)
2179 {
2180 ShClTransferObjHandleInfoDestroy(pItObj);
2181
2182 RTListNodeRemove(&pItObj->Node);
2183
2184 RTMemFree(pItObj);
2185 }
2186}
2187
2188/**
2189 * Returns the clipboard area for a Shared Clipboard transfer.
2190 *
2191 * @returns Current clipboard area, or NULL if none.
2192 * @param pTransfer Clipboard transfer to return clipboard area for.
2193 */
2194SharedClipboardArea *ShClTransferGetArea(PSHCLTRANSFER pTransfer)
2195{
2196 AssertPtrReturn(pTransfer, NULL);
2197
2198 return pTransfer->pArea;
2199}
2200
2201/**
2202 * Returns the number of transfer root list entries.
2203 *
2204 * @returns Root list entry count.
2205 * @param pTransfer Clipboard transfer to return root entry count for.
2206 */
2207uint32_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer)
2208{
2209 AssertPtrReturn(pTransfer, 0);
2210
2211 LogFlowFunc(("[Transfer %RU16] cRoots=%RU64\n", pTransfer->State.uID, pTransfer->cRoots));
2212 return (uint32_t)pTransfer->cRoots;
2213}
2214
2215/**
2216 * Returns a specific root list entry of a transfer.
2217 *
2218 * @returns Pointer to root list entry if found, or NULL if not found.
2219 * @param pTransfer Clipboard transfer to get root list entry from.
2220 * @param uIdx Index of root list entry to return.
2221 */
2222DECLINLINE(PSHCLLISTROOT) shClTransferRootsGetInternal(PSHCLTRANSFER pTransfer, uint32_t uIdx)
2223{
2224 if (uIdx >= pTransfer->cRoots)
2225 return NULL;
2226
2227 PSHCLLISTROOT pIt = RTListGetFirst(&pTransfer->lstRoots, SHCLLISTROOT, Node);
2228 while (uIdx--) /** @todo Slow, but works for now. */
2229 pIt = RTListGetNext(&pTransfer->lstRoots, pIt, SHCLLISTROOT, Node);
2230
2231 return pIt;
2232}
2233
2234/**
2235 * Get a specific root list entry.
2236 *
2237 * @returns VBox status code.
2238 * @param pTransfer Clipboard transfer to get root list entry of.
2239 * @param uIndex Index (zero-based) of entry to get.
2240 * @param pEntry Where to store the returned entry on success.
2241 */
2242int ShClTransferRootsEntry(PSHCLTRANSFER pTransfer,
2243 uint64_t uIndex, PSHCLROOTLISTENTRY pEntry)
2244{
2245 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2246 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
2247
2248 if (uIndex >= pTransfer->cRoots)
2249 return VERR_INVALID_PARAMETER;
2250
2251 int rc;
2252
2253 PSHCLLISTROOT pRoot = shClTransferRootsGetInternal(pTransfer, uIndex);
2254 AssertPtrReturn(pRoot, VERR_INVALID_PARAMETER);
2255
2256 /* Make sure that we only advertise relative source paths, not absolute ones. */
2257 const char *pcszSrcPath = pRoot->pszPathAbs;
2258
2259 char *pszFileName = RTPathFilename(pcszSrcPath);
2260 if (pszFileName)
2261 {
2262 Assert(pszFileName >= pcszSrcPath);
2263 size_t cchDstBase = pszFileName - pcszSrcPath;
2264 const char *pszDstPath = &pcszSrcPath[cchDstBase];
2265
2266 LogFlowFunc(("pcszSrcPath=%s, pszDstPath=%s\n", pcszSrcPath, pszDstPath));
2267
2268 rc = ShClTransferListEntryInit(pEntry);
2269 if (RT_SUCCESS(rc))
2270 {
2271 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pszDstPath);
2272 if (RT_SUCCESS(rc))
2273 {
2274 pEntry->cbInfo = sizeof(SHCLFSOBJINFO);
2275 pEntry->pvInfo = (PSHCLFSOBJINFO)RTMemAlloc(pEntry->cbInfo);
2276 if (pEntry->pvInfo)
2277 {
2278 RTFSOBJINFO fsObjInfo;
2279 rc = RTPathQueryInfo(pcszSrcPath, &fsObjInfo, RTFSOBJATTRADD_NOTHING);
2280 if (RT_SUCCESS(rc))
2281 {
2282 ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &fsObjInfo);
2283
2284 pEntry->fInfo = VBOX_SHCL_INFO_FLAG_FSOBJINFO;
2285 }
2286 }
2287 else
2288 rc = VERR_NO_MEMORY;
2289 }
2290 }
2291 }
2292 else
2293 rc = VERR_INVALID_POINTER;
2294
2295 LogFlowFuncLeaveRC(rc);
2296 return rc;
2297}
2298
2299/**
2300 * Returns the root entries of a Shared Clipboard transfer.
2301 *
2302 * @returns VBox status code.
2303 * @param pTransfer Clipboard transfer to return root entries for.
2304 * @param ppRootList Where to store the root list on success.
2305 */
2306int ShClTransferRootsGet(PSHCLTRANSFER pTransfer, PSHCLROOTLIST *ppRootList)
2307{
2308 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2309 AssertPtrReturn(ppRootList, VERR_INVALID_POINTER);
2310
2311 LogFlowFuncEnter();
2312
2313 int rc = VINF_SUCCESS;
2314
2315 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)
2316 {
2317 PSHCLROOTLIST pRootList = ShClTransferRootListAlloc();
2318 if (!pRootList)
2319 return VERR_NO_MEMORY;
2320
2321 const uint64_t cRoots = (uint32_t)pTransfer->cRoots;
2322
2323 LogFlowFunc(("cRoots=%RU64\n", cRoots));
2324
2325 if (cRoots)
2326 {
2327 PSHCLROOTLISTENTRY paRootListEntries
2328 = (PSHCLROOTLISTENTRY)RTMemAllocZ(cRoots * sizeof(SHCLROOTLISTENTRY));
2329 if (paRootListEntries)
2330 {
2331 for (uint64_t i = 0; i < cRoots; ++i)
2332 {
2333 rc = ShClTransferRootsEntry(pTransfer, i, &paRootListEntries[i]);
2334 if (RT_FAILURE(rc))
2335 break;
2336 }
2337
2338 if (RT_SUCCESS(rc))
2339 pRootList->paEntries = paRootListEntries;
2340 }
2341 else
2342 rc = VERR_NO_MEMORY;
2343 }
2344 else
2345 rc = VERR_NOT_FOUND;
2346
2347 if (RT_SUCCESS(rc))
2348 {
2349 pRootList->Hdr.cRoots = cRoots;
2350 pRootList->Hdr.fRoots = 0; /** @todo Implement this. */
2351
2352 *ppRootList = pRootList;
2353 }
2354 }
2355 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)
2356 {
2357 if (pTransfer->ProviderIface.pfnRootsGet)
2358 rc = pTransfer->ProviderIface.pfnRootsGet(&pTransfer->ProviderCtx, ppRootList);
2359 else
2360 rc = VERR_NOT_SUPPORTED;
2361 }
2362 else
2363 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
2364
2365 LogFlowFuncLeaveRC(rc);
2366 return rc;
2367}
2368
2369/**
2370 * Sets transfer root list entries for a given transfer.
2371 *
2372 * @returns VBox status code.
2373 * @param pTransfer Transfer to set transfer list entries for.
2374 * @param pszRoots String list (separated by CRLF) of root entries to set.
2375 * All entries must have the same root path.
2376 * @param cbRoots Size (in bytes) of string list.
2377 */
2378int ShClTransferRootsSet(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots)
2379{
2380 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2381 AssertPtrReturn(pszRoots, VERR_INVALID_POINTER);
2382 AssertReturn(cbRoots, VERR_INVALID_PARAMETER);
2383
2384 if (!RTStrIsValidEncoding(pszRoots))
2385 return VERR_INVALID_UTF8_ENCODING;
2386
2387 int rc = VINF_SUCCESS;
2388
2389 shClTransferListRootsClear(pTransfer);
2390
2391 char *pszPathRootAbs = NULL;
2392
2393 RTCList<RTCString> lstRootEntries = RTCString(pszRoots, cbRoots - 1).split("\r\n");
2394 for (size_t i = 0; i < lstRootEntries.size(); ++i)
2395 {
2396 PSHCLLISTROOT pListRoot = (PSHCLLISTROOT)RTMemAlloc(sizeof(SHCLLISTROOT));
2397 AssertPtrBreakStmt(pListRoot, rc = VERR_NO_MEMORY);
2398
2399 const char *pszPathCur = RTStrDup(lstRootEntries.at(i).c_str());
2400
2401 LogFlowFunc(("pszPathCur=%s\n", pszPathCur));
2402
2403 /* No root path determined yet? */
2404 if (!pszPathRootAbs)
2405 {
2406 pszPathRootAbs = RTStrDup(pszPathCur);
2407 if (pszPathRootAbs)
2408 {
2409 RTPathStripFilename(pszPathRootAbs);
2410
2411 LogFlowFunc(("pszPathRootAbs=%s\n", pszPathRootAbs));
2412
2413 /* We don't want to have a relative directory here. */
2414 if (RTPathStartsWithRoot(pszPathRootAbs))
2415 {
2416 rc = shClTransferValidatePath(pszPathRootAbs, true /* Path must exist */);
2417 }
2418 else
2419 rc = VERR_INVALID_PARAMETER;
2420 }
2421 else
2422 rc = VERR_NO_MEMORY;
2423 }
2424
2425 if (RT_FAILURE(rc))
2426 break;
2427
2428 pListRoot->pszPathAbs = RTStrDup(pszPathCur);
2429 if (!pListRoot->pszPathAbs)
2430 {
2431 rc = VERR_NO_MEMORY;
2432 break;
2433 }
2434
2435 RTListAppend(&pTransfer->lstRoots, &pListRoot->Node);
2436
2437 pTransfer->cRoots++;
2438 }
2439
2440 /* No (valid) root directory found? Bail out early. */
2441 if (!pszPathRootAbs)
2442 rc = VERR_PATH_NOT_FOUND;
2443
2444 if (RT_SUCCESS(rc))
2445 {
2446 /*
2447 * Step 2:
2448 * Go through the created list and make sure all entries have the same root path.
2449 */
2450 PSHCLLISTROOT pListRoot;
2451 RTListForEach(&pTransfer->lstRoots, pListRoot, SHCLLISTROOT, Node)
2452 {
2453 if (!RTStrStartsWith(pListRoot->pszPathAbs, pszPathRootAbs))
2454 {
2455 rc = VERR_INVALID_PARAMETER;
2456 break;
2457 }
2458
2459 rc = shClTransferValidatePath(pListRoot->pszPathAbs, true /* Path must exist */);
2460 if (RT_FAILURE(rc))
2461 break;
2462 }
2463 }
2464
2465 /** @todo Entry rollback on failure? */
2466
2467 if (RT_SUCCESS(rc))
2468 {
2469 pTransfer->pszPathRootAbs = pszPathRootAbs;
2470 LogFlowFunc(("pszPathRootAbs=%s, cRoots=%zu\n", pTransfer->pszPathRootAbs, pTransfer->cRoots));
2471
2472 LogRel2(("Shared Clipboard: Transfer uses root '%s'\n", pTransfer->pszPathRootAbs));
2473 }
2474 else
2475 {
2476 LogRel(("Shared Clipboard: Unable to set roots for transfer, rc=%Rrc\n", rc));
2477 RTStrFree(pszPathRootAbs);
2478 }
2479
2480 LogFlowFuncLeaveRC(rc);
2481 return rc;
2482}
2483
2484/**
2485 * Returns the transfer's ID.
2486 *
2487 * @returns The transfer's ID.
2488 * @param pTransfer Clipboard transfer to return ID for.
2489 */
2490SHCLTRANSFERID ShClTransferGetID(PSHCLTRANSFER pTransfer)
2491{
2492 AssertPtrReturn(pTransfer, 0);
2493
2494 return pTransfer->State.uID;
2495}
2496
2497/**
2498 * Returns the transfer's direction.
2499 *
2500 * @returns The transfer's direction.
2501 * @param pTransfer Clipboard transfer to return direction for.
2502 */
2503SHCLTRANSFERDIR ShClTransferGetDir(PSHCLTRANSFER pTransfer)
2504{
2505 AssertPtrReturn(pTransfer, SHCLTRANSFERDIR_UNKNOWN);
2506
2507 LogFlowFunc(("[Transfer %RU16] enmDir=%RU32\n", pTransfer->State.uID, pTransfer->State.enmDir));
2508 return pTransfer->State.enmDir;
2509}
2510
2511/**
2512 * Returns the transfer's source.
2513 *
2514 * @returns The transfer's source.
2515 * @param pTransfer Clipboard transfer to return source for.
2516 */
2517SHCLSOURCE ShClTransferGetSource(PSHCLTRANSFER pTransfer)
2518{
2519 AssertPtrReturn(pTransfer, SHCLSOURCE_INVALID);
2520
2521 LogFlowFunc(("[Transfer %RU16] enmSource=%RU32\n", pTransfer->State.uID, pTransfer->State.enmSource));
2522 return pTransfer->State.enmSource;
2523}
2524
2525/**
2526 * Returns the current transfer status.
2527 *
2528 * @returns Current transfer status.
2529 * @param pTransfer Clipboard transfer to return status for.
2530 */
2531SHCLTRANSFERSTATUS ShClTransferGetStatus(PSHCLTRANSFER pTransfer)
2532{
2533 AssertPtrReturn(pTransfer, SHCLTRANSFERSTATUS_NONE);
2534
2535 LogFlowFunc(("[Transfer %RU16] enmStatus=%RU32\n", pTransfer->State.uID, pTransfer->State.enmStatus));
2536 return pTransfer->State.enmStatus;
2537}
2538
2539/**
2540 * Runs a started Shared Clipboard transfer in a dedicated thread.
2541 *
2542 * @returns VBox status code.
2543 * @param pTransfer Clipboard transfer to run.
2544 * @param pfnThreadFunc Pointer to thread function to use.
2545 * @param pvUser Pointer to user-provided data. Optional.
2546 */
2547int ShClTransferRun(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser)
2548{
2549 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2550 AssertPtrReturn(pfnThreadFunc, VERR_INVALID_POINTER);
2551 /* pvUser is optional. */
2552
2553 AssertMsgReturn(pTransfer->State.enmStatus == SHCLTRANSFERSTATUS_STARTED,
2554 ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)),
2555 VERR_WRONG_ORDER);
2556
2557 int rc = shClTransferThreadCreate(pTransfer, pfnThreadFunc, pvUser);
2558
2559 LogFlowFuncLeaveRC(rc);
2560 return rc;
2561}
2562
2563/**
2564 * Starts an initialized transfer.
2565 *
2566 * @returns VBox status code.
2567 * @param pTransfer Clipboard transfer to start.
2568 */
2569int ShClTransferStart(PSHCLTRANSFER pTransfer)
2570{
2571 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2572
2573 LogFlowFuncEnter();
2574
2575 /* Ready to start? */
2576 AssertMsgReturn(pTransfer->State.enmStatus == SHCLTRANSFERSTATUS_INITIALIZED,
2577 ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)),
2578 VERR_WRONG_ORDER);
2579
2580 int rc;
2581
2582 if (pTransfer->Callbacks.pfnTransferStart)
2583 {
2584 SHCLTRANSFERCALLBACKDATA Data = { pTransfer, pTransfer->Callbacks.pvUser, pTransfer->Callbacks.cbUser };
2585 rc = pTransfer->Callbacks.pfnTransferStart(&Data);
2586 }
2587 else
2588 rc = VINF_SUCCESS;
2589
2590 if (RT_SUCCESS(rc))
2591 {
2592 pTransfer->State.enmStatus = SHCLTRANSFERSTATUS_STARTED;
2593 }
2594
2595 LogFlowFuncLeaveRC(rc);
2596 return rc;
2597}
2598
2599/**
2600 * Sets or unsets the callback table to be used for a Shared Clipboard transfer.
2601 *
2602 * @returns VBox status code.
2603 * @param pTransfer Clipboard transfer to set callbacks for.
2604 * @param pCallbacks Pointer to callback table to set.
2605 */
2606void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer,
2607 PSHCLTRANSFERCALLBACKS pCallbacks)
2608{
2609 AssertPtrReturnVoid(pTransfer);
2610 AssertPtrReturnVoid(pCallbacks);
2611
2612 LogFlowFunc(("pCallbacks=%p\n", pCallbacks));
2613
2614#define SET_CALLBACK(a_pfnCallback) \
2615 if (pCallbacks->a_pfnCallback) \
2616 pTransfer->Callbacks.a_pfnCallback = pCallbacks->a_pfnCallback
2617
2618 SET_CALLBACK(pfnTransferInitialize);
2619 SET_CALLBACK(pfnTransferStart);
2620 SET_CALLBACK(pfnListHeaderComplete);
2621 SET_CALLBACK(pfnListEntryComplete);
2622 SET_CALLBACK(pfnTransferCanceled);
2623 SET_CALLBACK(pfnTransferError);
2624
2625#undef SET_CALLBACK
2626
2627 pTransfer->Callbacks.pvUser = pCallbacks->pvUser;
2628 pTransfer->Callbacks.cbUser = pCallbacks->cbUser;
2629}
2630
2631/**
2632 * Creates a thread for a Shared Clipboard transfer.
2633 *
2634 * @returns VBox status code.
2635 * @param pTransfer Clipboard transfer to create thread for.
2636 * @param pfnThreadFunc Thread function to use for this transfer.
2637 * @param pvUser Pointer to user-provided data.
2638 */
2639static int shClTransferThreadCreate(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser)
2640
2641{
2642 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2643
2644 /* Already marked for stopping? */
2645 AssertMsgReturn(pTransfer->Thread.fStop == false,
2646 ("Thransfer thread already marked for stopping"), VERR_WRONG_ORDER);
2647 /* Already started? */
2648 AssertMsgReturn(pTransfer->Thread.fStarted == false,
2649 ("Thransfer thread already started"), VERR_WRONG_ORDER);
2650
2651 /* Spawn a worker thread, so that we don't block the window thread for too long. */
2652 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnThreadFunc,
2653 pvUser, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
2654 "shclp");
2655 if (RT_SUCCESS(rc))
2656 {
2657 int rc2 = RTThreadUserWait(pTransfer->Thread.hThread, 30 * 1000 /* Timeout in ms */);
2658 AssertRC(rc2);
2659
2660 if (pTransfer->Thread.fStarted) /* Did the thread indicate that it started correctly? */
2661 {
2662 /* Nothing to do in here. */
2663 }
2664 else
2665 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
2666 }
2667
2668 LogFlowFuncLeaveRC(rc);
2669 return rc;
2670}
2671
2672/**
2673 * Destroys a thread of a Shared Clipboard transfer.
2674 *
2675 * @returns VBox status code.
2676 * @param pTransfer Clipboard transfer to destroy thread for.
2677 * @param uTimeoutMs Timeout (in ms) to wait for thread creation.
2678 */
2679static int shClTransferThreadDestroy(PSHCLTRANSFER pTransfer, RTMSINTERVAL uTimeoutMs)
2680{
2681 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2682
2683 if (pTransfer->Thread.hThread == NIL_RTTHREAD)
2684 return VINF_SUCCESS;
2685
2686 LogFlowFuncEnter();
2687
2688 /* Set stop indicator. */
2689 pTransfer->Thread.fStop = true;
2690
2691 int rcThread = VERR_WRONG_ORDER;
2692 int rc = RTThreadWait(pTransfer->Thread.hThread, uTimeoutMs, &rcThread);
2693
2694 LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n", rc, rcThread));
2695
2696 return rc;
2697}
2698
2699/**
2700 * Initializes a Shared Clipboard transfer context.
2701 *
2702 * @returns VBox status code.
2703 * @param pTransferCtx Transfer context to initialize.
2704 */
2705int ShClTransferCtxInit(PSHCLTRANSFERCTX pTransferCtx)
2706{
2707 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
2708
2709 LogFlowFunc(("pTransferCtx=%p\n", pTransferCtx));
2710
2711 int rc = RTCritSectInit(&pTransferCtx->CritSect);
2712 if (RT_SUCCESS(rc))
2713 {
2714 RTListInit(&pTransferCtx->List);
2715
2716 pTransferCtx->cTransfers = 0;
2717 pTransferCtx->cRunning = 0;
2718 pTransferCtx->cMaxRunning = UINT16_MAX; /** @todo Make this configurable? */
2719
2720 RT_ZERO(pTransferCtx->bmTransferIds);
2721
2722 ShClTransferCtxReset(pTransferCtx);
2723 }
2724
2725 return VINF_SUCCESS;
2726}
2727
2728/**
2729 * Destroys a Shared Clipboard transfer context struct.
2730 *
2731 * @param pTransferCtx Transfer context to destroy.
2732 */
2733void ShClTransferCtxDestroy(PSHCLTRANSFERCTX pTransferCtx)
2734{
2735 AssertPtrReturnVoid(pTransferCtx);
2736
2737 LogFlowFunc(("pTransferCtx=%p\n", pTransferCtx));
2738
2739 if (RTCritSectIsInitialized(&pTransferCtx->CritSect))
2740 RTCritSectDelete(&pTransferCtx->CritSect);
2741
2742 PSHCLTRANSFER pTransfer, pTransferNext;
2743 RTListForEachSafe(&pTransferCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node)
2744 {
2745 ShClTransferDestroy(pTransfer);
2746
2747 RTListNodeRemove(&pTransfer->Node);
2748
2749 RTMemFree(pTransfer);
2750 pTransfer = NULL;
2751 }
2752
2753 pTransferCtx->cRunning = 0;
2754 pTransferCtx->cTransfers = 0;
2755}
2756
2757/**
2758 * Resets a Shared Clipboard transfer.
2759 *
2760 * @param pTransferCtx Transfer context to reset.
2761 */
2762void ShClTransferCtxReset(PSHCLTRANSFERCTX pTransferCtx)
2763{
2764 AssertPtrReturnVoid(pTransferCtx);
2765
2766 LogFlowFuncEnter();
2767
2768 PSHCLTRANSFER pTransfer;
2769 RTListForEach(&pTransferCtx->List, pTransfer, SHCLTRANSFER, Node)
2770 ShClTransferReset(pTransfer);
2771}
2772
2773/**
2774 * Returns a specific Shared Clipboard transfer, internal version.
2775 *
2776 * @returns Shared Clipboard transfer, or NULL if not found.
2777 * @param pTransferCtx Transfer context to return transfer for.
2778 * @param uID ID of the transfer to return.
2779 */
2780static PSHCLTRANSFER shClTransferCtxGetTransferInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID)
2781{
2782 PSHCLTRANSFER pTransfer;
2783 RTListForEach(&pTransferCtx->List, pTransfer, SHCLTRANSFER, Node) /** @todo Slow, but works for now. */
2784 {
2785 if (pTransfer->State.uID == uID)
2786 return pTransfer;
2787 }
2788
2789 return NULL;
2790}
2791
2792/**
2793 * Returns a specific Shared Clipboard transfer.
2794 *
2795 * @returns Shared Clipboard transfer, or NULL if not found.
2796 * @param pTransferCtx Transfer context to return transfer for.
2797 * @param uID ID of the transfer to return.
2798 */
2799PSHCLTRANSFER ShClTransferCtxGetTransfer(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID)
2800{
2801 return shClTransferCtxGetTransferInternal(pTransferCtx, uID);
2802}
2803
2804/**
2805 * Returns the number of running Shared Clipboard transfers.
2806 *
2807 * @returns Number of running transfers.
2808 * @param pTransferCtx Transfer context to return number for.
2809 */
2810uint32_t ShClTransferCtxGetRunningTransfers(PSHCLTRANSFERCTX pTransferCtx)
2811{
2812 AssertPtrReturn(pTransferCtx, 0);
2813 return pTransferCtx->cRunning;
2814}
2815
2816/**
2817 * Returns the number of total Shared Clipboard transfers.
2818 *
2819 * @returns Number of total transfers.
2820 * @param pTransferCtx Transfer context to return number for.
2821 */
2822uint32_t ShClTransferCtxGetTotalTransfers(PSHCLTRANSFERCTX pTransferCtx)
2823{
2824 AssertPtrReturn(pTransferCtx, 0);
2825 return pTransferCtx->cTransfers;
2826}
2827
2828/**
2829 * Registers a Shared Clipboard transfer with a transfer context, i.e. allocates a transfer ID.
2830 *
2831 * @return VBox status code.
2832 * @retval VERR_SHCLPB_MAX_TRANSFERS_REACHED if the maximum of concurrent transfers
2833 * is reached.
2834 * @param pTransferCtx Transfer context to register transfer to.
2835 * @param pTransfer Transfer to register.
2836 * @param pidTransfer Where to return the transfer ID on success. Optional.
2837 */
2838int ShClTransferCtxTransferRegister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, uint32_t *pidTransfer)
2839{
2840 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
2841 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2842 /* pidTransfer is optional. */
2843
2844 /*
2845 * Pick a random bit as starting point. If it's in use, search forward
2846 * for a free one, wrapping around. We've reserved both the zero'th and
2847 * max-1 IDs.
2848 */
2849 uint32_t idTransfer = RTRandU32Ex(1, VBOX_SHCL_MAX_TRANSFERS - 2);
2850
2851 if (!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer))
2852 { /* likely */ }
2853 else if (pTransferCtx->cTransfers < VBOX_SHCL_MAX_TRANSFERS - 2 /* First and last are not used */)
2854 {
2855 /* Forward search. */
2856 int iHit = ASMBitNextClear(&pTransferCtx->bmTransferIds[0], VBOX_SHCL_MAX_TRANSFERS, idTransfer);
2857 if (iHit < 0)
2858 iHit = ASMBitFirstClear(&pTransferCtx->bmTransferIds[0], VBOX_SHCL_MAX_TRANSFERS);
2859 AssertLogRelMsgReturn(iHit >= 0, ("Transfer count: %RU16\n", pTransferCtx->cTransfers), VERR_SHCLPB_MAX_TRANSFERS_REACHED);
2860 idTransfer = iHit;
2861 AssertLogRelMsgReturn(!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer), ("idObject=%#x\n", idTransfer), VERR_INTERNAL_ERROR_2);
2862 }
2863 else
2864 {
2865 LogFunc(("Maximum number of transfers reached (%RU16 transfers)\n", pTransferCtx->cTransfers));
2866 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2867 }
2868
2869 Log2Func(("pTransfer=%p, idTransfer=%RU32 (%RU16 transfers)\n", pTransfer, idTransfer, pTransferCtx->cTransfers));
2870
2871 RTListAppend(&pTransferCtx->List, &pTransfer->Node);
2872
2873 pTransferCtx->cTransfers++;
2874
2875 if (pidTransfer)
2876 *pidTransfer = idTransfer;
2877
2878 return VINF_SUCCESS;
2879}
2880
2881/**
2882 * Registers a Shared Clipboard transfer with a transfer contextby specifying an ID for the transfer.
2883 *
2884 * @return VBox status code.
2885 * @retval VERR_ALREADY_EXISTS if a transfer with the given ID already exists.
2886 * @retval VERR_SHCLPB_MAX_TRANSFERS_REACHED if the maximum of concurrent transfers for this context has been reached.
2887 * @param pTransferCtx Transfer context to register transfer to.
2888 * @param pTransfer Transfer to register.
2889 * @param idTransfer Transfer ID to use for registration.
2890 */
2891int ShClTransferCtxTransferRegisterByIndex(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, uint32_t idTransfer)
2892{
2893 LogFlowFunc(("cTransfers=%RU16, idTransfer=%RU32\n", pTransferCtx->cTransfers, idTransfer));
2894
2895 if (pTransferCtx->cTransfers < VBOX_SHCL_MAX_TRANSFERS - 2 /* First and last are not used */)
2896 {
2897 if (!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer))
2898 {
2899 RTListAppend(&pTransferCtx->List, &pTransfer->Node);
2900
2901 pTransferCtx->cTransfers++;
2902 return VINF_SUCCESS;
2903 }
2904
2905 return VERR_ALREADY_EXISTS;
2906 }
2907
2908 LogFunc(("Maximum number of transfers reached (%RU16 transfers)\n", pTransferCtx->cTransfers));
2909 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2910}
2911
2912/**
2913 * Unregisters a transfer from an Transfer context.
2914 *
2915 * @retval VINF_SUCCESS on success.
2916 * @retval VERR_NOT_FOUND if the transfer ID was not found.
2917 * @param pTransferCtx Transfer context to unregister transfer from.
2918 * @param idTransfer Transfer ID to unregister.
2919 */
2920int ShClTransferCtxTransferUnregister(PSHCLTRANSFERCTX pTransferCtx, uint32_t idTransfer)
2921{
2922 int rc = VINF_SUCCESS;
2923 AssertMsgStmt(ASMBitTestAndClear(&pTransferCtx->bmTransferIds, idTransfer), ("idTransfer=%#x\n", idTransfer), rc = VERR_NOT_FOUND);
2924
2925 LogFlowFunc(("idTransfer=%RU32\n", idTransfer));
2926
2927 PSHCLTRANSFER pTransfer = shClTransferCtxGetTransferInternal(pTransferCtx, idTransfer);
2928 if (pTransfer)
2929 {
2930 RTListNodeRemove(&pTransfer->Node);
2931
2932 Assert(pTransferCtx->cTransfers);
2933 pTransferCtx->cTransfers--;
2934
2935 Assert(pTransferCtx->cTransfers >= pTransferCtx->cRunning);
2936
2937 LogFlowFunc(("Now %RU32 transfers left\n", pTransferCtx->cTransfers));
2938 }
2939 else
2940 rc = VERR_NOT_FOUND;
2941
2942 LogFlowFuncLeaveRC(rc);
2943 return rc;
2944}
2945
2946/**
2947 * Cleans up all associated transfers which are not needed (anymore).
2948 * This can be due to transfers which only have been announced but not / never being run.
2949 *
2950 * @param pTransferCtx Transfer context to cleanup transfers for.
2951 */
2952void ShClTransferCtxCleanup(PSHCLTRANSFERCTX pTransferCtx)
2953{
2954 AssertPtrReturnVoid(pTransferCtx);
2955
2956 LogFlowFunc(("pTransferCtx=%p, cTransfers=%RU16 cRunning=%RU16\n",
2957 pTransferCtx, pTransferCtx->cTransfers, pTransferCtx->cRunning));
2958
2959 if (pTransferCtx->cTransfers == 0)
2960 return;
2961
2962 /* Remove all transfers which are not in a running state (e.g. only announced). */
2963 PSHCLTRANSFER pTransfer, pTransferNext;
2964 RTListForEachSafe(&pTransferCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node)
2965 {
2966 if (ShClTransferGetStatus(pTransfer) != SHCLTRANSFERSTATUS_STARTED)
2967 {
2968 ShClTransferDestroy(pTransfer);
2969 RTListNodeRemove(&pTransfer->Node);
2970
2971 RTMemFree(pTransfer);
2972 pTransfer = NULL;
2973
2974 Assert(pTransferCtx->cTransfers);
2975 pTransferCtx->cTransfers--;
2976 }
2977 }
2978}
2979
2980/**
2981 * Returns whether the maximum of concurrent transfers of a specific transfer contexthas been reached or not.
2982 *
2983 * @returns \c if maximum has been reached, \c false if not.
2984 * @param pTransferCtx Transfer context to determine value for.
2985 */
2986bool ShClTransferCtxTransfersMaximumReached(PSHCLTRANSFERCTX pTransferCtx)
2987{
2988 AssertPtrReturn(pTransferCtx, true);
2989
2990 LogFlowFunc(("cRunning=%RU32, cMaxRunning=%RU32\n", pTransferCtx->cRunning, pTransferCtx->cMaxRunning));
2991
2992 Assert(pTransferCtx->cRunning <= pTransferCtx->cMaxRunning);
2993 return pTransferCtx->cRunning == pTransferCtx->cMaxRunning;
2994}
2995
2996/**
2997 * Copies file system objinfo from IPRT to Shared Clipboard format.
2998 *
2999 * @param pDst The Shared Clipboard structure to convert data to.
3000 * @param pSrc The IPRT structure to convert data from.
3001 */
3002void ShClFsObjFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc)
3003{
3004 pDst->cbObject = pSrc->cbObject;
3005 pDst->cbAllocated = pSrc->cbAllocated;
3006 pDst->AccessTime = pSrc->AccessTime;
3007 pDst->ModificationTime = pSrc->ModificationTime;
3008 pDst->ChangeTime = pSrc->ChangeTime;
3009 pDst->BirthTime = pSrc->BirthTime;
3010 pDst->Attr.fMode = pSrc->Attr.fMode;
3011 /* Clear bits which we don't pass through for security reasons. */
3012 pDst->Attr.fMode &= ~(RTFS_UNIX_ISUID | RTFS_UNIX_ISGID | RTFS_UNIX_ISTXT);
3013 RT_ZERO(pDst->Attr.u);
3014 switch (pSrc->Attr.enmAdditional)
3015 {
3016 default:
3017 case RTFSOBJATTRADD_NOTHING:
3018 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_NOTHING;
3019 break;
3020
3021 case RTFSOBJATTRADD_UNIX:
3022 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_UNIX;
3023 pDst->Attr.u.Unix.uid = pSrc->Attr.u.Unix.uid;
3024 pDst->Attr.u.Unix.gid = pSrc->Attr.u.Unix.gid;
3025 pDst->Attr.u.Unix.cHardlinks = pSrc->Attr.u.Unix.cHardlinks;
3026 pDst->Attr.u.Unix.INodeIdDevice = pSrc->Attr.u.Unix.INodeIdDevice;
3027 pDst->Attr.u.Unix.INodeId = pSrc->Attr.u.Unix.INodeId;
3028 pDst->Attr.u.Unix.fFlags = pSrc->Attr.u.Unix.fFlags;
3029 pDst->Attr.u.Unix.GenerationId = pSrc->Attr.u.Unix.GenerationId;
3030 pDst->Attr.u.Unix.Device = pSrc->Attr.u.Unix.Device;
3031 break;
3032
3033 case RTFSOBJATTRADD_EASIZE:
3034 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_EASIZE;
3035 pDst->Attr.u.EASize.cb = pSrc->Attr.u.EASize.cb;
3036 break;
3037 }
3038}
3039
3040/**
3041 * Converts Shared Clipboard create flags (see SharedClipboard-transfers.h) into IPRT create flags.
3042 *
3043 * @returns IPRT status code.
3044 * @param fWritable Whether the object is writable.
3045 * @param fShClFlags Shared clipboard create flags.
3046 * @param fMode File attributes.
3047 * @param handleInitial Initial handle.
3048 * @retval pfOpen Where to store the IPRT creation / open flags.
3049 *
3050 * @sa Initially taken from vbsfConvertFileOpenFlags().
3051 */
3052static int shClConvertFileCreateFlags(bool fWritable, unsigned fShClFlags, RTFMODE fMode,
3053 SHCLOBJHANDLE handleInitial, uint64_t *pfOpen)
3054{
3055 uint64_t fOpen = 0;
3056 int rc = VINF_SUCCESS;
3057
3058 if ( (fMode & RTFS_DOS_MASK) != 0
3059 && (fMode & RTFS_UNIX_MASK) == 0)
3060 {
3061 /* A DOS/Windows guest, make RTFS_UNIX_* from RTFS_DOS_*.
3062 * @todo this is based on rtFsModeNormalize/rtFsModeFromDos.
3063 * May be better to use RTFsModeNormalize here.
3064 */
3065 fMode |= RTFS_UNIX_IRUSR | RTFS_UNIX_IRGRP | RTFS_UNIX_IROTH;
3066 /* x for directories. */
3067 if (fMode & RTFS_DOS_DIRECTORY)
3068 fMode |= RTFS_TYPE_DIRECTORY | RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;
3069 /* writable? */
3070 if (!(fMode & RTFS_DOS_READONLY))
3071 fMode |= RTFS_UNIX_IWUSR | RTFS_UNIX_IWGRP | RTFS_UNIX_IWOTH;
3072
3073 /* Set the requested mode using only allowed bits. */
3074 fOpen |= ((fMode & RTFS_UNIX_MASK) << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK;
3075 }
3076 else
3077 {
3078 /* Old linux and solaris additions did not initialize the Info.Attr.fMode field
3079 * and it contained random bits from stack. Detect this using the handle field value
3080 * passed from the guest: old additions set it (incorrectly) to 0, new additions
3081 * set it to SHCLOBJHANDLE_INVALID(~0).
3082 */
3083 if (handleInitial == 0)
3084 {
3085 /* Old additions. Do nothing, use default mode. */
3086 }
3087 else
3088 {
3089 /* New additions or Windows additions. Set the requested mode using only allowed bits.
3090 * Note: Windows guest set RTFS_UNIX_MASK bits to 0, which means a default mode
3091 * will be set in fOpen.
3092 */
3093 fOpen |= ((fMode & RTFS_UNIX_MASK) << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK;
3094 }
3095 }
3096
3097 switch ((fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_RW))
3098 {
3099 default:
3100 case SHCL_OBJ_CF_ACCESS_NONE:
3101 {
3102#ifdef RT_OS_WINDOWS
3103 if ((fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_ATTR) != SHCL_OBJ_CF_ACCESS_ATTR_NONE)
3104 fOpen |= RTFILE_O_ATTR_ONLY;
3105 else
3106#endif
3107 fOpen |= RTFILE_O_READ;
3108 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_NONE\n"));
3109 break;
3110 }
3111
3112 case SHCL_OBJ_CF_ACCESS_READ:
3113 {
3114 fOpen |= RTFILE_O_READ;
3115 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_READ\n"));
3116 break;
3117 }
3118
3119 case SHCL_OBJ_CF_ACCESS_WRITE:
3120 {
3121 fOpen |= RTFILE_O_WRITE;
3122 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_WRITE\n"));
3123 break;
3124 }
3125
3126 case SHCL_OBJ_CF_ACCESS_READWRITE:
3127 {
3128 fOpen |= RTFILE_O_READWRITE;
3129 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_READWRITE\n"));
3130 break;
3131 }
3132 }
3133
3134 if (fShClFlags & SHCL_OBJ_CF_ACCESS_APPEND)
3135 {
3136 fOpen |= RTFILE_O_APPEND;
3137 }
3138
3139 switch ((fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_ATTR))
3140 {
3141 default:
3142 case SHCL_OBJ_CF_ACCESS_ATTR_NONE:
3143 {
3144 fOpen |= RTFILE_O_ACCESS_ATTR_DEFAULT;
3145 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_ATTR_NONE\n"));
3146 break;
3147 }
3148
3149 case SHCL_OBJ_CF_ACCESS_ATTR_READ:
3150 {
3151 fOpen |= RTFILE_O_ACCESS_ATTR_READ;
3152 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_ATTR_READ\n"));
3153 break;
3154 }
3155
3156 case SHCL_OBJ_CF_ACCESS_ATTR_WRITE:
3157 {
3158 fOpen |= RTFILE_O_ACCESS_ATTR_WRITE;
3159 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_ATTR_WRITE\n"));
3160 break;
3161 }
3162
3163 case SHCL_OBJ_CF_ACCESS_ATTR_READWRITE:
3164 {
3165 fOpen |= RTFILE_O_ACCESS_ATTR_READWRITE;
3166 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_ATTR_READWRITE\n"));
3167 break;
3168 }
3169 }
3170
3171 /* Sharing mask */
3172 switch ((fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_DENY))
3173 {
3174 default:
3175 case SHCL_OBJ_CF_ACCESS_DENYNONE:
3176 fOpen |= RTFILE_O_DENY_NONE;
3177 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_DENYNONE\n"));
3178 break;
3179
3180 case SHCL_OBJ_CF_ACCESS_DENYREAD:
3181 fOpen |= RTFILE_O_DENY_READ;
3182 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_DENYREAD\n"));
3183 break;
3184
3185 case SHCL_OBJ_CF_ACCESS_DENYWRITE:
3186 fOpen |= RTFILE_O_DENY_WRITE;
3187 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_DENYWRITE\n"));
3188 break;
3189
3190 case SHCL_OBJ_CF_ACCESS_DENYALL:
3191 fOpen |= RTFILE_O_DENY_ALL;
3192 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_DENYALL\n"));
3193 break;
3194 }
3195
3196 /* Open/Create action mask */
3197 switch ((fShClFlags & SHCL_OBJ_CF_ACT_MASK_IF_EXISTS))
3198 {
3199 case SHCL_OBJ_CF_ACT_OPEN_IF_EXISTS:
3200 if (SHCL_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHCL_OBJ_CF_ACT_MASK_IF_NEW))
3201 {
3202 fOpen |= RTFILE_O_OPEN_CREATE;
3203 LogFlowFunc(("SHCL_OBJ_CF_ACT_OPEN_IF_EXISTS and SHCL_OBJ_CF_ACT_CREATE_IF_NEW\n"));
3204 }
3205 else if (SHCL_OBJ_CF_ACT_FAIL_IF_NEW == (fShClFlags & SHCL_OBJ_CF_ACT_MASK_IF_NEW))
3206 {
3207 fOpen |= RTFILE_O_OPEN;
3208 LogFlowFunc(("SHCL_OBJ_CF_ACT_OPEN_IF_EXISTS and SHCL_OBJ_CF_ACT_FAIL_IF_NEW\n"));
3209 }
3210 else
3211 {
3212 LogFlowFunc(("invalid open/create action combination\n"));
3213 rc = VERR_INVALID_PARAMETER;
3214 }
3215 break;
3216 case SHCL_OBJ_CF_ACT_FAIL_IF_EXISTS:
3217 if (SHCL_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHCL_OBJ_CF_ACT_MASK_IF_NEW))
3218 {
3219 fOpen |= RTFILE_O_CREATE;
3220 LogFlowFunc(("SHCL_OBJ_CF_ACT_FAIL_IF_EXISTS and SHCL_OBJ_CF_ACT_CREATE_IF_NEW\n"));
3221 }
3222 else
3223 {
3224 LogFlowFunc(("invalid open/create action combination\n"));
3225 rc = VERR_INVALID_PARAMETER;
3226 }
3227 break;
3228 case SHCL_OBJ_CF_ACT_REPLACE_IF_EXISTS:
3229 if (SHCL_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHCL_OBJ_CF_ACT_MASK_IF_NEW))
3230 {
3231 fOpen |= RTFILE_O_CREATE_REPLACE;
3232 LogFlowFunc(("SHCL_OBJ_CF_ACT_REPLACE_IF_EXISTS and SHCL_OBJ_CF_ACT_CREATE_IF_NEW\n"));
3233 }
3234 else if (SHCL_OBJ_CF_ACT_FAIL_IF_NEW == (fShClFlags & SHCL_OBJ_CF_ACT_MASK_IF_NEW))
3235 {
3236 fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
3237 LogFlowFunc(("SHCL_OBJ_CF_ACT_REPLACE_IF_EXISTS and SHCL_OBJ_CF_ACT_FAIL_IF_NEW\n"));
3238 }
3239 else
3240 {
3241 LogFlowFunc(("invalid open/create action combination\n"));
3242 rc = VERR_INVALID_PARAMETER;
3243 }
3244 break;
3245 case SHCL_OBJ_CF_ACT_OVERWRITE_IF_EXISTS:
3246 if (SHCL_OBJ_CF_ACT_CREATE_IF_NEW == (fShClFlags & SHCL_OBJ_CF_ACT_MASK_IF_NEW))
3247 {
3248 fOpen |= RTFILE_O_CREATE_REPLACE;
3249 LogFlowFunc(("SHCL_OBJ_CF_ACT_OVERWRITE_IF_EXISTS and SHCL_OBJ_CF_ACT_CREATE_IF_NEW\n"));
3250 }
3251 else if (SHCL_OBJ_CF_ACT_FAIL_IF_NEW == (fShClFlags & SHCL_OBJ_CF_ACT_MASK_IF_NEW))
3252 {
3253 fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
3254 LogFlowFunc(("SHCL_OBJ_CF_ACT_OVERWRITE_IF_EXISTS and SHCL_OBJ_CF_ACT_FAIL_IF_NEW\n"));
3255 }
3256 else
3257 {
3258 LogFlowFunc(("invalid open/create action combination\n"));
3259 rc = VERR_INVALID_PARAMETER;
3260 }
3261 break;
3262 default:
3263 {
3264 rc = VERR_INVALID_PARAMETER;
3265 LogFlowFunc(("SHCL_OBJ_CF_ACT_MASK_IF_EXISTS - invalid parameter\n"));
3266 break;
3267 }
3268 }
3269
3270 if (RT_SUCCESS(rc))
3271 {
3272 if (!fWritable)
3273 fOpen &= ~RTFILE_O_WRITE;
3274
3275 *pfOpen = fOpen;
3276 }
3277
3278 LogFlowFuncLeaveRC(rc);
3279 return rc;
3280}
3281
3282/**
3283 * Translates a Shared Clipboard transfer status (SHCLTRANSFERSTATUS_XXX) into a string.
3284 *
3285 * @returns Transfer status string name.
3286 * @param enmStatus The transfer status to translate.
3287 */
3288const char *ShClTransferStatusToStr(SHCLTRANSFERSTATUS enmStatus)
3289{
3290 switch (enmStatus)
3291 {
3292 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_NONE);
3293 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_INITIALIZED);
3294 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STARTED);
3295 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STOPPED);
3296 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_CANCELED);
3297 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_KILLED);
3298 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_ERROR);
3299 }
3300 return "Unknown";
3301}
Note: See TracBrowser for help on using the repository browser.

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