VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers-provider-local.cpp@ 99951

Last change on this file since 99951 was 99951, checked in by vboxsync, 22 months ago

Shared Clipboard: Moved code for handling local filesystems with transfers into an own provider interface implementation. This cleans up the generic code a lot. bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.6 KB
Line 
1/* $Id: clipboard-transfers-provider-local.cpp 99951 2023-05-24 10:37:12Z vboxsync $ */
2/** @file
3 * Shared Clipboard - Transfers interface implementation for local file systems.
4 */
5
6/*
7 * Copyright (C) 2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
33#include <VBox/GuestHost/SharedClipboard-transfers.h>
34
35#include <iprt/dir.h>
36#include <iprt/err.h>
37#include <iprt/file.h>
38#include <iprt/path.h>
39#include <iprt/string.h>
40
41
42/**
43 * Converts Shared Clipboard create flags (see SharedClipboard-transfers.h) into IPRT create flags.
44 *
45 * @returns IPRT status code.
46 * @param fShClFlags Shared clipboard create flags.
47 * @param[out] pfOpen Where to store the RTFILE_O_XXX flags for
48 * RTFileOpen.
49 *
50 * @sa Initially taken from vbsfConvertFileOpenFlags().
51 */
52static int shClConvertFileCreateFlags(uint32_t fShClFlags, uint64_t *pfOpen)
53{
54 AssertMsgReturnStmt(!(fShClFlags & ~SHCL_OBJ_CF_VALID_MASK), ("%#x4\n", fShClFlags), *pfOpen = 0, VERR_INVALID_FLAGS);
55
56 uint64_t fOpen = 0;
57
58 switch (fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_RW)
59 {
60 case SHCL_OBJ_CF_ACCESS_NONE:
61 {
62#ifdef RT_OS_WINDOWS
63 if ((fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_ATTR) != SHCL_OBJ_CF_ACCESS_ATTR_NONE)
64 fOpen |= RTFILE_O_OPEN | RTFILE_O_ATTR_ONLY;
65 else
66#endif
67 fOpen |= RTFILE_O_OPEN | RTFILE_O_READ;
68 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_NONE\n"));
69 break;
70 }
71
72 case SHCL_OBJ_CF_ACCESS_READ:
73 {
74 fOpen |= RTFILE_O_OPEN | RTFILE_O_READ;
75 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_READ\n"));
76 break;
77 }
78
79 default:
80 AssertFailedReturn(VERR_IPE_NOT_REACHED_DEFAULT_CASE);
81 }
82
83 switch (fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_ATTR)
84 {
85 case SHCL_OBJ_CF_ACCESS_ATTR_NONE:
86 {
87 fOpen |= RTFILE_O_ACCESS_ATTR_DEFAULT;
88 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_ATTR_NONE\n"));
89 break;
90 }
91
92 case SHCL_OBJ_CF_ACCESS_ATTR_READ:
93 {
94 fOpen |= RTFILE_O_ACCESS_ATTR_READ;
95 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_ATTR_READ\n"));
96 break;
97 }
98
99 default:
100 AssertFailedReturn(VERR_IPE_NOT_REACHED_DEFAULT_CASE);
101 }
102
103 /* Sharing mask */
104 switch (fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_DENY)
105 {
106 case SHCL_OBJ_CF_ACCESS_DENYNONE:
107 fOpen |= RTFILE_O_DENY_NONE;
108 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_DENYNONE\n"));
109 break;
110
111 case SHCL_OBJ_CF_ACCESS_DENYWRITE:
112 fOpen |= RTFILE_O_DENY_WRITE;
113 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_DENYWRITE\n"));
114 break;
115
116 default:
117 AssertFailedReturn(VERR_IPE_NOT_REACHED_DEFAULT_CASE);
118 }
119
120 *pfOpen = fOpen;
121
122 LogFlowFuncLeaveRC(VINF_SUCCESS);
123 return VINF_SUCCESS;
124}
125
126/**
127 * Resolves a relative path of a specific transfer to its absolute path.
128 *
129 * @returns VBox status code.
130 * @param pTransfer Clipboard transfer to resolve path for.
131 * @param pszPath Path to resolve.
132 * @param fFlags Resolve flags. Currently not used and must be 0.
133 * @param ppszResolved Where to store the allocated resolved path. Must be free'd by the called using RTStrFree().
134 */
135static int shClTransferResolvePathAbs(PSHCLTRANSFER pTransfer, const char *pszPath, uint32_t fFlags,
136 char **ppszResolved)
137{
138 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
139 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
140 AssertReturn (fFlags == 0, VERR_INVALID_PARAMETER);
141
142 LogFlowFunc(("pszPathRootAbs=%s, pszPath=%s\n", pTransfer->pszPathRootAbs, pszPath));
143
144 int rc = ShClTransferValidatePath(pszPath, false /* fMustExist */);
145 if (RT_SUCCESS(rc))
146 {
147 char *pszPathAbs = RTPathJoinA(pTransfer->pszPathRootAbs, pszPath);
148 if (pszPathAbs)
149 {
150 char szResolved[RTPATH_MAX];
151 size_t cbResolved = sizeof(szResolved);
152 rc = RTPathAbsEx(pTransfer->pszPathRootAbs, pszPathAbs, RTPATH_STR_F_STYLE_HOST, szResolved, &cbResolved);
153
154 RTStrFree(pszPathAbs);
155
156 if (RT_SUCCESS(rc))
157 {
158 LogFlowFunc(("pszResolved=%s\n", szResolved));
159
160 rc = VERR_PATH_NOT_FOUND; /* Play safe by default. */
161
162 /* Make sure the resolved path is part of the set of root entries. */
163 PSHCLLISTROOT pListRoot;
164 RTListForEach(&pTransfer->lstRoots, pListRoot, SHCLLISTROOT, Node)
165 {
166 if (RTPathStartsWith(szResolved, pListRoot->pszPathAbs))
167 {
168 rc = VINF_SUCCESS;
169 break;
170 }
171 }
172
173 if (RT_SUCCESS(rc))
174 *ppszResolved = RTStrDup(szResolved);
175 }
176 }
177 else
178 rc = VERR_NO_MEMORY;
179 }
180
181 if (RT_FAILURE(rc))
182 LogRel(("Shared Clipboard: Resolving absolute path '%s' failed, rc=%Rrc\n", pszPath, rc));
183
184 LogFlowFuncLeaveRC(rc);
185 return rc;
186}
187
188/**
189 * Adds a file to a transfer list header.
190 *
191 * @returns VBox status code.
192 * @param pHdr List header to add file to.
193 * @param pszPath Path of file to add.
194 */
195static int shclTransferListHdrAddFile(PSHCLLISTHDR pHdr, const char *pszPath)
196{
197 AssertPtrReturn(pHdr, VERR_INVALID_POINTER);
198 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
199
200 uint64_t cbSize = 0;
201 int rc = RTFileQuerySizeByPath(pszPath, &cbSize);
202 if (RT_SUCCESS(rc))
203 {
204 pHdr->cbTotalSize += cbSize;
205 pHdr->cTotalObjects++;
206 }
207
208 LogFlowFuncLeaveRC(rc);
209 return rc;
210}
211
212/**
213 * Builds a transfer list header, internal version.
214 *
215 * @returns VBox status code.
216 * @param pHdr Where to store the build list header.
217 * @param pcszPathAbs Absolute path to use for building the transfer list.
218 */
219static int shclTransferListHdrFromDir(PSHCLLISTHDR pHdr, const char *pcszPathAbs)
220{
221 AssertPtrReturn(pcszPathAbs, VERR_INVALID_POINTER);
222
223 LogFlowFunc(("pcszPathAbs=%s\n", pcszPathAbs));
224
225 RTFSOBJINFO objInfo;
226 int rc = RTPathQueryInfo(pcszPathAbs, &objInfo, RTFSOBJATTRADD_NOTHING);
227 if (RT_SUCCESS(rc))
228 {
229 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
230 {
231 RTDIR hDir;
232 rc = RTDirOpen(&hDir, pcszPathAbs);
233 if (RT_SUCCESS(rc))
234 {
235 size_t cbDirEntry = 0;
236 PRTDIRENTRYEX pDirEntry = NULL;
237 do
238 {
239 /* Retrieve the next directory entry. */
240 rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
241 if (RT_FAILURE(rc))
242 {
243 if (rc == VERR_NO_MORE_FILES)
244 rc = VINF_SUCCESS;
245 break;
246 }
247
248 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
249 {
250 case RTFS_TYPE_DIRECTORY:
251 {
252 /* Skip "." and ".." entries. */
253 if (RTDirEntryExIsStdDotLink(pDirEntry))
254 break;
255
256 pHdr->cTotalObjects++;
257 break;
258 }
259 case RTFS_TYPE_FILE:
260 {
261 char *pszSrc = RTPathJoinA(pcszPathAbs, pDirEntry->szName);
262 if (pszSrc)
263 {
264 rc = shclTransferListHdrAddFile(pHdr, pszSrc);
265 RTStrFree(pszSrc);
266 }
267 else
268 rc = VERR_NO_MEMORY;
269 break;
270 }
271 case RTFS_TYPE_SYMLINK:
272 {
273 /** @todo Not implemented yet. */
274 }
275
276 default:
277 break;
278 }
279
280 } while (RT_SUCCESS(rc));
281
282 RTDirReadExAFree(&pDirEntry, &cbDirEntry);
283 RTDirClose(hDir);
284 }
285 }
286 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
287 {
288 rc = shclTransferListHdrAddFile(pHdr, pcszPathAbs);
289 }
290 else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))
291 {
292 /** @todo Not implemented yet. */
293 }
294 else
295 rc = VERR_NOT_SUPPORTED;
296 }
297
298 LogFlowFuncLeaveRC(rc);
299 return rc;
300}
301
302/**
303 * Creates a new list handle (local only).
304 *
305 * @returns New List handle on success, or SHCLLISTHANDLE_INVALID on error.
306 * @param pTransfer Clipboard transfer to create new list handle for.
307 */
308DECLINLINE(SHCLLISTHANDLE) shClTransferListHandleNew(PSHCLTRANSFER pTransfer)
309{
310 return pTransfer->uListHandleNext++; /** @todo Good enough for now. Improve this later. */
311}
312
313static DECLCALLBACK(int) vbclTransferIfaceLocalRootsGet(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)
314{
315 LogFlowFuncEnter();
316
317 PSHCLROOTLIST pRootList = ShClTransferRootListAlloc();
318 if (!pRootList)
319 return VERR_NO_MEMORY;
320
321 AssertPtr(pCtx->pTransfer);
322 const uint64_t cRoots = (uint32_t)pCtx->pTransfer->cRoots;
323
324 LogFlowFunc(("cRoots=%RU64\n", cRoots));
325
326 int rc = VINF_SUCCESS;
327
328 if (cRoots)
329 {
330 PSHCLROOTLISTENTRY paRootListEntries
331 = (PSHCLROOTLISTENTRY)RTMemAllocZ(cRoots * sizeof(SHCLROOTLISTENTRY));
332 if (paRootListEntries)
333 {
334 for (uint64_t i = 0; i < cRoots; ++i)
335 {
336 rc = ShClTransferRootsEntry(pCtx->pTransfer, i, &paRootListEntries[i]);
337 if (RT_FAILURE(rc))
338 break;
339 }
340
341 if (RT_SUCCESS(rc))
342 pRootList->paEntries = paRootListEntries;
343 }
344 else
345 rc = VERR_NO_MEMORY;
346 }
347 else
348 rc = VERR_NOT_FOUND;
349
350 if (RT_SUCCESS(rc))
351 {
352 pRootList->Hdr.cRoots = cRoots;
353
354 *ppRootList = pRootList;
355 }
356
357 LogFlowFuncLeaveRC(rc);
358 return rc;
359}
360
361static DECLCALLBACK(int) vbclTransferIfaceLocalListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
362 PSHCLLISTHANDLE phList)
363{
364 LogFlowFunc(("pszPath=%s\n", pOpenParms->pszPath));
365
366 int rc;
367
368 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
369 AssertPtr(pTransfer);
370
371 PSHCLLISTHANDLEINFO pInfo
372 = (PSHCLLISTHANDLEINFO)RTMemAllocZ(sizeof(SHCLLISTHANDLEINFO));
373 if (pInfo)
374 {
375 rc = ShClTransferListHandleInfoInit(pInfo);
376 if (RT_SUCCESS(rc))
377 {
378 rc = shClTransferResolvePathAbs(pTransfer, pOpenParms->pszPath, 0 /* fFlags */, &pInfo->pszPathLocalAbs);
379 if (RT_SUCCESS(rc))
380 {
381 RTFSOBJINFO objInfo;
382 rc = RTPathQueryInfo(pInfo->pszPathLocalAbs, &objInfo, RTFSOBJATTRADD_NOTHING);
383 if (RT_SUCCESS(rc))
384 {
385 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
386 {
387 rc = RTDirOpen(&pInfo->u.Local.hDir, pInfo->pszPathLocalAbs);
388 if (RT_SUCCESS(rc))
389 {
390 pInfo->enmType = SHCLOBJTYPE_DIRECTORY;
391
392 LogRel2(("Shared Clipboard: Opening directory '%s'\n", pInfo->pszPathLocalAbs));
393 }
394 else
395 LogRel(("Shared Clipboard: Opening directory '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));
396
397 }
398 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
399 {
400 rc = RTFileOpen(&pInfo->u.Local.hFile, pInfo->pszPathLocalAbs,
401 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
402 if (RT_SUCCESS(rc))
403 {
404 pInfo->enmType = SHCLOBJTYPE_FILE;
405
406 LogRel2(("Shared Clipboard: Opening file '%s'\n", pInfo->pszPathLocalAbs));
407 }
408 else
409 LogRel(("Shared Clipboard: Opening file '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));
410 }
411 else
412 rc = VERR_NOT_SUPPORTED;
413
414 if (RT_SUCCESS(rc))
415 {
416 pInfo->hList = shClTransferListHandleNew(pTransfer);
417
418 RTListAppend(&pTransfer->lstList, &pInfo->Node);
419 pTransfer->cListHandles++;
420
421 if (phList)
422 *phList = pInfo->hList;
423
424 LogFlowFunc(("pszPathLocalAbs=%s, hList=%RU64, cListHandles=%RU32\n",
425 pInfo->pszPathLocalAbs, pInfo->hList, pTransfer->cListHandles));
426 }
427 else
428 {
429 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
430 {
431 if (RTDirIsValid(pInfo->u.Local.hDir))
432 RTDirClose(pInfo->u.Local.hDir);
433 }
434 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
435 {
436 if (RTFileIsValid(pInfo->u.Local.hFile))
437 RTFileClose(pInfo->u.Local.hFile);
438 }
439 }
440 }
441 }
442 }
443
444 if (RT_FAILURE(rc))
445 {
446 ShClTransferListHandleInfoDestroy(pInfo);
447
448 RTMemFree(pInfo);
449 pInfo = NULL;
450 }
451 }
452 else
453 rc = VERR_NO_MEMORY;
454
455 LogFlowFuncLeaveRC(rc);
456 return rc;
457}
458
459static DECLCALLBACK(int) vbclTransferIfaceLocalListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
460{
461 LogFlowFuncEnter();
462
463 int rc = VINF_SUCCESS;
464
465 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
466 AssertPtr(pTransfer);
467
468 PSHCLLISTHANDLEINFO pInfo = ShClTransferListGetByHandle(pTransfer, hList);
469 if (pInfo)
470 {
471 switch (pInfo->enmType)
472 {
473 case SHCLOBJTYPE_DIRECTORY:
474 {
475 if (RTDirIsValid(pInfo->u.Local.hDir))
476 {
477 RTDirClose(pInfo->u.Local.hDir);
478 pInfo->u.Local.hDir = NIL_RTDIR;
479 }
480 break;
481 }
482
483 default:
484 rc = VERR_NOT_SUPPORTED;
485 break;
486 }
487
488 RTListNodeRemove(&pInfo->Node);
489
490 Assert(pTransfer->cListHandles);
491 pTransfer->cListHandles--;
492
493 RTMemFree(pInfo);
494 }
495 else
496 rc = VERR_NOT_FOUND;
497
498 LogFlowFuncLeaveRC(rc);
499 return rc;
500}
501
502static DECLCALLBACK(int) vbclTransferIfaceLocalListHdrRead(PSHCLTXPROVIDERCTX pCtx,
503 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
504{
505 LogFlowFuncEnter();
506
507 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
508 AssertPtr(pTransfer);
509
510 int rc;
511
512 PSHCLLISTHANDLEINFO pInfo = ShClTransferListGetByHandle(pTransfer, hList);
513 if (pInfo)
514 {
515 rc = ShClTransferListHdrInit(pListHdr);
516 if (RT_SUCCESS(rc))
517 {
518 switch (pInfo->enmType)
519 {
520 case SHCLOBJTYPE_DIRECTORY:
521 {
522 LogFlowFunc(("DirAbs: %s\n", pInfo->pszPathLocalAbs));
523
524 rc = shclTransferListHdrFromDir(pListHdr, pInfo->pszPathLocalAbs);
525 break;
526 }
527
528 case SHCLOBJTYPE_FILE:
529 {
530 LogFlowFunc(("FileAbs: %s\n", pInfo->pszPathLocalAbs));
531
532 pListHdr->cTotalObjects = 1;
533
534 RTFSOBJINFO objInfo;
535 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);
536 if (RT_SUCCESS(rc))
537 {
538 pListHdr->cbTotalSize = objInfo.cbObject;
539 }
540 break;
541 }
542
543 /* We don't support symlinks (yet). */
544
545 default:
546 rc = VERR_NOT_SUPPORTED;
547 break;
548 }
549 }
550
551 LogFlowFunc(("cTotalObj=%RU64, cbTotalSize=%RU64\n", pListHdr->cTotalObjects, pListHdr->cbTotalSize));
552 }
553 else
554 rc = VERR_NOT_FOUND;
555
556 LogFlowFuncLeaveRC(rc);
557 return rc;
558}
559
560static DECLCALLBACK(int) vbclTransferIfaceLocalListEntryRead(PSHCLTXPROVIDERCTX pCtx,
561 SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)
562{
563 LogFlowFuncEnter();
564
565 int rc;
566
567 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
568 AssertPtr(pTransfer);
569
570 PSHCLLISTHANDLEINFO pInfo = ShClTransferListGetByHandle(pTransfer, hList);
571 if (pInfo)
572 {
573 switch (pInfo->enmType)
574 {
575 case SHCLOBJTYPE_DIRECTORY:
576 {
577 LogFlowFunc(("\tDirectory: %s\n", pInfo->pszPathLocalAbs));
578
579 for (;;)
580 {
581 bool fSkipEntry = false; /* Whether to skip an entry in the enumeration. */
582
583 size_t cbDirEntry = 0;
584 PRTDIRENTRYEX pDirEntry = NULL;
585 rc = RTDirReadExA(pInfo->u.Local.hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
586 if (RT_SUCCESS(rc))
587 {
588 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
589 {
590 case RTFS_TYPE_DIRECTORY:
591 {
592 /* Skip "." and ".." entries. */
593 if (RTDirEntryExIsStdDotLink(pDirEntry))
594 {
595 fSkipEntry = true;
596 break;
597 }
598
599 LogFlowFunc(("Directory: %s\n", pDirEntry->szName));
600 break;
601 }
602
603 case RTFS_TYPE_FILE:
604 {
605 LogFlowFunc(("File: %s\n", pDirEntry->szName));
606 break;
607 }
608
609 case RTFS_TYPE_SYMLINK:
610 {
611 rc = VERR_NOT_IMPLEMENTED; /** @todo Not implemented yet. */
612 break;
613 }
614
615 default:
616 break;
617 }
618
619 if ( RT_SUCCESS(rc)
620 && !fSkipEntry)
621 {
622 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pDirEntry->szName);
623 if (RT_SUCCESS(rc))
624 {
625 pEntry->cbName = (uint32_t)strlen(pEntry->pszName) + 1; /* Include termination. */
626
627 AssertPtr(pEntry->pvInfo);
628 Assert (pEntry->cbInfo == sizeof(SHCLFSOBJINFO));
629
630 ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &pDirEntry->Info);
631
632 LogFlowFunc(("Entry pszName=%s, pvInfo=%p, cbInfo=%RU32\n",
633 pEntry->pszName, pEntry->pvInfo, pEntry->cbInfo));
634 }
635 }
636
637 RTDirReadExAFree(&pDirEntry, &cbDirEntry);
638 }
639
640 if ( !fSkipEntry /* Do we have a valid entry? Bail out. */
641 || RT_FAILURE(rc))
642 {
643 break;
644 }
645 }
646
647 break;
648 }
649
650 case SHCLOBJTYPE_FILE:
651 {
652 LogFlowFunc(("\tSingle file: %s\n", pInfo->pszPathLocalAbs));
653
654 RTFSOBJINFO objInfo;
655 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);
656 if (RT_SUCCESS(rc))
657 {
658 pEntry->pvInfo = (PSHCLFSOBJINFO)RTMemAlloc(sizeof(SHCLFSOBJINFO));
659 if (pEntry->pvInfo)
660 {
661 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pInfo->pszPathLocalAbs);
662 if (RT_SUCCESS(rc))
663 {
664 ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &objInfo);
665
666 pEntry->cbInfo = sizeof(SHCLFSOBJINFO);
667 pEntry->fInfo = VBOX_SHCL_INFO_FLAG_FSOBJINFO;
668 }
669 }
670 else
671 rc = VERR_NO_MEMORY;
672 }
673
674 break;
675 }
676
677 default:
678 rc = VERR_NOT_SUPPORTED;
679 break;
680 }
681 }
682 else
683 rc = VERR_NOT_FOUND;
684
685 LogFlowFuncLeaveRC(rc);
686 return rc;
687}
688
689static DECLCALLBACK(int) vbclTransferIfaceLocalObjOpen(PSHCLTXPROVIDERCTX pCtx,
690 PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
691{
692 LogFlowFuncEnter();
693
694 int rc;
695
696 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
697 AssertPtr(pTransfer);
698
699 PSHCLOBJHANDLEINFO pInfo = (PSHCLOBJHANDLEINFO)RTMemAllocZ(sizeof(SHCLOBJHANDLEINFO));
700 if (pInfo)
701 {
702 rc = ShClTransferObjHandleInfoInit(pInfo);
703 if (RT_SUCCESS(rc))
704 {
705 uint64_t fOpen;
706 rc = shClConvertFileCreateFlags(pCreateParms->fCreate, &fOpen);
707 if (RT_SUCCESS(rc))
708 {
709 rc = shClTransferResolvePathAbs(pTransfer, pCreateParms->pszPath, 0 /* fFlags */,
710 &pInfo->pszPathLocalAbs);
711 if (RT_SUCCESS(rc))
712 {
713 rc = RTFileOpen(&pInfo->u.Local.hFile, pInfo->pszPathLocalAbs, fOpen);
714 if (RT_SUCCESS(rc))
715 LogRel2(("Shared Clipboard: Opened file '%s'\n", pInfo->pszPathLocalAbs));
716 else
717 LogRel(("Shared Clipboard: Error opening file '%s': rc=%Rrc\n", pInfo->pszPathLocalAbs, rc));
718 }
719 }
720 }
721
722 if (RT_SUCCESS(rc))
723 {
724 pInfo->hObj = pTransfer->uObjHandleNext++;
725 pInfo->enmType = SHCLOBJTYPE_FILE;
726
727 RTListAppend(&pTransfer->lstObj, &pInfo->Node);
728 pTransfer->cObjHandles++;
729
730 LogFlowFunc(("cObjHandles=%RU32\n", pTransfer->cObjHandles));
731
732 *phObj = pInfo->hObj;
733 }
734 else
735 {
736 ShClTransferObjHandleInfoDestroy(pInfo);
737 RTMemFree(pInfo);
738 }
739 }
740 else
741 rc = VERR_NO_MEMORY;
742
743 LogFlowFuncLeaveRC(rc);
744 return rc;
745}
746
747static DECLCALLBACK(int) vbclTransferIfaceLocalObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
748{
749 LogFlowFuncEnter();
750
751 int rc;
752
753 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
754 AssertPtr(pTransfer);
755
756 PSHCLOBJHANDLEINFO pInfo = ShClTransferObjGet(pTransfer, hObj);
757 if (pInfo)
758 {
759 switch (pInfo->enmType)
760 {
761 case SHCLOBJTYPE_DIRECTORY:
762 {
763 rc = RTDirClose(pInfo->u.Local.hDir);
764 if (RT_SUCCESS(rc))
765 {
766 pInfo->u.Local.hDir = NIL_RTDIR;
767
768 LogRel2(("Shared Clipboard: Closed directory '%s'\n", pInfo->pszPathLocalAbs));
769 }
770 else
771 LogRel(("Shared Clipboard: Closing directory '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));
772 break;
773 }
774
775 case SHCLOBJTYPE_FILE:
776 {
777 rc = RTFileClose(pInfo->u.Local.hFile);
778 if (RT_SUCCESS(rc))
779 {
780 pInfo->u.Local.hFile = NIL_RTFILE;
781
782 LogRel2(("Shared Clipboard: Closed file '%s'\n", pInfo->pszPathLocalAbs));
783 }
784 else
785 LogRel(("Shared Clipboard: Closing file '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));
786 break;
787 }
788
789 default:
790 rc = VERR_NOT_IMPLEMENTED;
791 break;
792 }
793
794 RTListNodeRemove(&pInfo->Node);
795
796 Assert(pTransfer->cObjHandles);
797 pTransfer->cObjHandles--;
798
799 ShClTransferObjHandleInfoDestroy(pInfo);
800
801 RTMemFree(pInfo);
802 pInfo = NULL;
803 }
804 else
805 rc = VERR_NOT_FOUND;
806
807 LogFlowFuncLeaveRC(rc);
808 return rc;
809}
810
811static DECLCALLBACK(int) vbclTransferIfaceLocalObjRead(PSHCLTXPROVIDERCTX pCtx,
812 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
813 uint32_t fFlags, uint32_t *pcbRead)
814{
815 RT_NOREF(fFlags);
816
817 LogFlowFuncEnter();
818
819 int rc;
820
821 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
822 AssertPtr(pTransfer);
823
824 PSHCLOBJHANDLEINFO pInfo = ShClTransferObjGet(pTransfer, hObj);
825 if (pInfo)
826 {
827 switch (pInfo->enmType)
828 {
829 case SHCLOBJTYPE_FILE:
830 {
831 size_t cbRead;
832 rc = RTFileRead(pInfo->u.Local.hFile, pvData, cbData, &cbRead);
833 if (RT_SUCCESS(rc))
834 {
835 if (pcbRead)
836 *pcbRead = (uint32_t)cbRead;
837 }
838 break;
839 }
840
841 default:
842 rc = VERR_NOT_SUPPORTED;
843 break;
844 }
845 }
846 else
847 rc = VERR_NOT_FOUND;
848
849 LogFlowFuncLeaveRC(rc);
850 return rc;
851}
852
853static DECLCALLBACK(int) vbclTransferIfaceLocalObjWrite(PSHCLTXPROVIDERCTX pCtx,
854 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData, uint32_t fFlags,
855 uint32_t *pcbWritten)
856{
857 RT_NOREF(fFlags);
858
859 LogFlowFuncEnter();
860
861 int rc;
862
863 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
864 AssertPtr(pTransfer);
865
866 PSHCLOBJHANDLEINFO pInfo = ShClTransferObjGet(pTransfer, hObj);
867 if (pInfo)
868 {
869 switch (pInfo->enmType)
870 {
871 case SHCLOBJTYPE_FILE:
872 {
873 rc = RTFileWrite(pInfo->u.Local.hFile, pvData, cbData, (size_t *)pcbWritten);
874 break;
875 }
876
877 default:
878 rc = VERR_NOT_SUPPORTED;
879 break;
880 }
881 }
882 else
883 rc = VERR_NOT_FOUND;
884
885 LogFlowFuncLeaveRC(rc);
886 return rc;
887}
888
889/**
890 * Queries (assigns) the local provider to an interface.
891 *
892 * The local provider is being used for accessing files on local file systems.
893 *
894 * @returns Interface pointer the provider get assigned to.
895 * @param pIface Interface to assign provider to.
896 */
897PSHCLTXPROVIDERIFACE VBClTransferQueryIfaceLocal(PSHCLTXPROVIDERIFACE pIface)
898{
899 pIface->pfnRootsGet = vbclTransferIfaceLocalRootsGet;
900 pIface->pfnListOpen = vbclTransferIfaceLocalListOpen;
901 pIface->pfnListClose = vbclTransferIfaceLocalListClose;
902 pIface->pfnListHdrRead = vbclTransferIfaceLocalListHdrRead;
903 pIface->pfnListEntryRead = vbclTransferIfaceLocalListEntryRead;
904 pIface->pfnObjOpen = vbclTransferIfaceLocalObjOpen;
905 pIface->pfnObjClose = vbclTransferIfaceLocalObjClose;
906 pIface->pfnObjRead = vbclTransferIfaceLocalObjRead;
907 pIface->pfnObjWrite = vbclTransferIfaceLocalObjWrite;
908
909 return pIface;
910}
911
Note: See TracBrowser for help on using the repository browser.

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