VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/clipboard-uri.cpp@ 80662

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

Shared Clipboard: Renaming (SHAREDCLIPBOARD -> SHCL and VBOXCLIPBOARD -> SHCL).

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