VirtualBox

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

Last change on this file since 100204 was 100204, checked in by vboxsync, 18 months ago

Shared Clipboard: Unified root list entry code to also use the generic list entry code, a lot of updates for the cross OS transfer handling code, more updates for HTTP server transfer handling.

This also changed the handling of how that transfers are being initiated, as we needed to have this for X11: Before, transfers were initiated as soon as on side announced the URI list format -- now we postpone initiating the transfer until the receiving side requests the data as URI list.

bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.7 KB
Line 
1/* $Id: clipboard-transfers-provider-local.cpp 100204 2023-06-19 09:11:37Z 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 Relative 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 rc = VERR_PATH_NOT_FOUND; /* Play safe by default. */
148
149 /* Make sure the given path is part of the set of root entries. */
150 PSHCLLISTENTRY pEntry;
151 RTListForEach(&pTransfer->lstRoots.lstEntries, pEntry, SHCLLISTENTRY, Node)
152 {
153 LogFlowFunc(("\tpEntry->pszName=%s\n", pEntry->pszName));
154
155 if (!RTStrCmp(pszPath, pEntry->pszName)) /* Case-sensitive! */
156 {
157 rc = VINF_SUCCESS;
158 break;
159 }
160 }
161
162 if (RT_SUCCESS(rc))
163 {
164 char *pszPathAbs = RTPathJoinA(pTransfer->pszPathRootAbs, pszPath);
165 if (pszPathAbs)
166 {
167 char szResolved[RTPATH_MAX];
168 size_t cbResolved = sizeof(szResolved);
169 rc = RTPathAbsEx(pTransfer->pszPathRootAbs, pszPathAbs, RTPATH_STR_F_STYLE_HOST, szResolved, &cbResolved);
170
171 RTStrFree(pszPathAbs);
172 pszPathAbs = NULL;
173
174 if (RT_SUCCESS(rc))
175 {
176 LogFlowFunc(("pszResolved=%s\n", szResolved));
177
178 if (RT_SUCCESS(rc))
179 *ppszResolved = RTStrDup(szResolved);
180 }
181 }
182 else
183 rc = VERR_NO_MEMORY;
184 }
185 }
186
187 if (RT_FAILURE(rc))
188 LogRel(("Shared Clipboard: Resolving absolute path for '%s' failed, rc=%Rrc\n", pszPath, rc));
189
190 LogFlowFuncLeaveRC(rc);
191 return rc;
192}
193
194/**
195 * Adds a file to a transfer list header.
196 *
197 * @returns VBox status code.
198 * @param pHdr List header to add file to.
199 * @param pszPath Path of file to add.
200 */
201static int shclTransferListHdrAddFile(PSHCLLISTHDR pHdr, const char *pszPath)
202{
203 AssertPtrReturn(pHdr, VERR_INVALID_POINTER);
204 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
205
206 uint64_t cbSize = 0;
207 int rc = RTFileQuerySizeByPath(pszPath, &cbSize);
208 if (RT_SUCCESS(rc))
209 {
210 pHdr->cbTotalSize += cbSize;
211 pHdr->cEntries++;
212 }
213
214 LogFlowFuncLeaveRC(rc);
215 return rc;
216}
217
218/**
219 * Builds a transfer list header, internal version.
220 *
221 * @returns VBox status code.
222 * @param pHdr Where to store the build list header.
223 * @param pcszPathAbs Absolute path to use for building the transfer list.
224 */
225static int shclTransferListHdrFromDir(PSHCLLISTHDR pHdr, const char *pcszPathAbs)
226{
227 AssertPtrReturn(pcszPathAbs, VERR_INVALID_POINTER);
228
229 LogFlowFunc(("pcszPathAbs=%s\n", pcszPathAbs));
230
231 RTFSOBJINFO objInfo;
232 int rc = RTPathQueryInfo(pcszPathAbs, &objInfo, RTFSOBJATTRADD_NOTHING);
233 if (RT_SUCCESS(rc))
234 {
235 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
236 {
237 RTDIR hDir;
238 rc = RTDirOpen(&hDir, pcszPathAbs);
239 if (RT_SUCCESS(rc))
240 {
241 size_t cbDirEntry = 0;
242 PRTDIRENTRYEX pDirEntry = NULL;
243 do
244 {
245 /* Retrieve the next directory entry. */
246 rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
247 if (RT_FAILURE(rc))
248 {
249 if (rc == VERR_NO_MORE_FILES)
250 rc = VINF_SUCCESS;
251 break;
252 }
253
254 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
255 {
256 case RTFS_TYPE_DIRECTORY:
257 {
258 /* Skip "." and ".." entries. */
259 if (RTDirEntryExIsStdDotLink(pDirEntry))
260 break;
261
262 pHdr->cEntries++;
263 break;
264 }
265 case RTFS_TYPE_FILE:
266 {
267 char *pszSrc = RTPathJoinA(pcszPathAbs, pDirEntry->szName);
268 if (pszSrc)
269 {
270 rc = shclTransferListHdrAddFile(pHdr, pszSrc);
271 RTStrFree(pszSrc);
272 }
273 else
274 rc = VERR_NO_MEMORY;
275 break;
276 }
277 case RTFS_TYPE_SYMLINK:
278 {
279 /** @todo Not implemented yet. */
280 }
281
282 default:
283 break;
284 }
285
286 } while (RT_SUCCESS(rc));
287
288 RTDirReadExAFree(&pDirEntry, &cbDirEntry);
289 RTDirClose(hDir);
290 }
291 }
292 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
293 {
294 rc = shclTransferListHdrAddFile(pHdr, pcszPathAbs);
295 }
296 else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))
297 {
298 /** @todo Not implemented yet. */
299 }
300 else
301 rc = VERR_NOT_SUPPORTED;
302 }
303
304 LogFlowFuncLeaveRC(rc);
305 return rc;
306}
307
308/**
309 * Creates a new list handle (local only).
310 *
311 * @returns New List handle on success, or NIL_SHCLLISTHANDLE on error.
312 * @param pTransfer Clipboard transfer to create new list handle for.
313 */
314DECLINLINE(SHCLLISTHANDLE) shClTransferListHandleNew(PSHCLTRANSFER pTransfer)
315{
316 return pTransfer->uListHandleNext++; /** @todo Good enough for now. Improve this later. */
317}
318
319static int shClTransferListEntryQueryFsInfo(PSHCLLISTENTRY pListEntry, PSHCLFSOBJINFO pFsObjInfo)
320{
321 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
322
323 const char *pcszSrcPathAbs = pListEntry->pszName;
324 AssertPtrReturn(pcszSrcPathAbs, VERR_INVALID_POINTER);
325
326 int rc;
327
328 /* Make sure that we only advertise relative source paths, not absolute ones. */
329 char *pszFileName = RTPathFilename(pcszSrcPathAbs);
330 if (pszFileName)
331 {
332 Assert(pszFileName >= pcszSrcPathAbs);
333 size_t cchDstBase = pszFileName - pcszSrcPathAbs;
334 const char *pszDstPath = &pcszSrcPathAbs[cchDstBase];
335
336 LogFlowFunc(("pcszSrcPathAbs=%s, pszDstPath=%s\n", pcszSrcPathAbs, pszDstPath));
337
338 RTFSOBJINFO fsObjInfo;
339 rc = RTPathQueryInfo(pcszSrcPathAbs, &fsObjInfo, RTFSOBJATTRADD_NOTHING);
340 if (RT_SUCCESS(rc))
341 rc = ShClFsObjInfoFromIPRT(pFsObjInfo, &fsObjInfo);
342 }
343 else
344 rc = VERR_INVALID_POINTER;
345
346 return rc;
347}
348
349/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
350static DECLCALLBACK(int) shclTransferIfaceLocalRootListRead(PSHCLTXPROVIDERCTX pCtx)
351{
352 LogFlowFuncEnter();
353
354 int rc = VINF_SUCCESS;
355
356 PSHCLLISTENTRY pEntry;
357 RTListForEach(&pCtx->pTransfer->lstRoots.lstEntries, pEntry, SHCLLISTENTRY, Node)
358 {
359 AssertBreakStmt(pEntry->cbInfo == sizeof(SHCLFSOBJINFO), rc = VERR_WRONG_ORDER);
360 rc = shClTransferListEntryQueryFsInfo(pEntry, (PSHCLFSOBJINFO)pEntry->pvInfo);
361 if (RT_FAILURE(rc)) /* Currently this is an all-or-nothing op. */
362 break;
363 }
364
365 LogFlowFuncLeaveRC(rc);
366 return rc;
367}
368
369/** @copydoc SHCLTXPROVIDERIFACE::pfnListOpen */
370static DECLCALLBACK(int) shclTransferIfaceLocalListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
371 PSHCLLISTHANDLE phList)
372{
373 LogFlowFunc(("pszPath=%s\n", pOpenParms->pszPath));
374
375 int rc;
376
377 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
378 AssertPtr(pTransfer);
379
380 PSHCLLISTHANDLEINFO pInfo
381 = (PSHCLLISTHANDLEINFO)RTMemAllocZ(sizeof(SHCLLISTHANDLEINFO));
382 if (pInfo)
383 {
384 rc = ShClTransferListHandleInfoInit(pInfo);
385 if (RT_SUCCESS(rc))
386 {
387 rc = shClTransferResolvePathAbs(pTransfer, pOpenParms->pszPath, 0 /* fFlags */, &pInfo->pszPathLocalAbs);
388 if (RT_SUCCESS(rc))
389 {
390 RTFSOBJINFO objInfo;
391 rc = RTPathQueryInfo(pInfo->pszPathLocalAbs, &objInfo, RTFSOBJATTRADD_NOTHING);
392 if (RT_SUCCESS(rc))
393 {
394 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
395 {
396 rc = RTDirOpen(&pInfo->u.Local.hDir, pInfo->pszPathLocalAbs);
397 if (RT_SUCCESS(rc))
398 {
399 pInfo->enmType = SHCLOBJTYPE_DIRECTORY;
400
401 LogRel2(("Shared Clipboard: Opening directory '%s'\n", pInfo->pszPathLocalAbs));
402 }
403 else
404 LogRel(("Shared Clipboard: Opening directory '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));
405
406 }
407 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
408 {
409 rc = RTFileOpen(&pInfo->u.Local.hFile, pInfo->pszPathLocalAbs,
410 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
411 if (RT_SUCCESS(rc))
412 {
413 pInfo->enmType = SHCLOBJTYPE_FILE;
414
415 LogRel2(("Shared Clipboard: Opening file '%s'\n", pInfo->pszPathLocalAbs));
416 }
417 else
418 LogRel(("Shared Clipboard: Opening file '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));
419 }
420 else
421 rc = VERR_NOT_SUPPORTED;
422
423 if (RT_SUCCESS(rc))
424 {
425 pInfo->hList = shClTransferListHandleNew(pTransfer);
426
427 RTListAppend(&pTransfer->lstHandles, &pInfo->Node);
428 pTransfer->cListHandles++;
429
430 if (phList)
431 *phList = pInfo->hList;
432
433 LogFlowFunc(("pszPathLocalAbs=%s, hList=%RU64, cListHandles=%RU32\n",
434 pInfo->pszPathLocalAbs, pInfo->hList, pTransfer->cListHandles));
435 }
436 else
437 {
438 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
439 {
440 if (RTDirIsValid(pInfo->u.Local.hDir))
441 RTDirClose(pInfo->u.Local.hDir);
442 }
443 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
444 {
445 if (RTFileIsValid(pInfo->u.Local.hFile))
446 RTFileClose(pInfo->u.Local.hFile);
447 }
448 }
449 }
450 }
451 }
452
453 if (RT_FAILURE(rc))
454 {
455 ShClTransferListHandleInfoDestroy(pInfo);
456
457 RTMemFree(pInfo);
458 pInfo = NULL;
459 }
460 }
461 else
462 rc = VERR_NO_MEMORY;
463
464 LogFlowFuncLeaveRC(rc);
465 return rc;
466}
467
468/** @copydoc SHCLTXPROVIDERIFACE::pfnListClose */
469static DECLCALLBACK(int) shclTransferIfaceLocalListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
470{
471 LogFlowFuncEnter();
472
473 int rc = VINF_SUCCESS;
474
475 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
476 AssertPtr(pTransfer);
477
478 PSHCLLISTHANDLEINFO pInfo = ShClTransferListGetByHandle(pTransfer, hList);
479 if (pInfo)
480 {
481 switch (pInfo->enmType)
482 {
483 case SHCLOBJTYPE_DIRECTORY:
484 {
485 if (RTDirIsValid(pInfo->u.Local.hDir))
486 {
487 RTDirClose(pInfo->u.Local.hDir);
488 pInfo->u.Local.hDir = NIL_RTDIR;
489 }
490 break;
491 }
492
493 default:
494 rc = VERR_NOT_SUPPORTED;
495 break;
496 }
497
498 RTListNodeRemove(&pInfo->Node);
499
500 Assert(pTransfer->cListHandles);
501 pTransfer->cListHandles--;
502
503 RTMemFree(pInfo);
504 }
505 else
506 rc = VERR_NOT_FOUND;
507
508 LogFlowFuncLeaveRC(rc);
509 return rc;
510}
511
512/** @copydoc SHCLTXPROVIDERIFACE::pfnListHdrRead */
513static DECLCALLBACK(int) shclTransferIfaceLocalListHdrRead(PSHCLTXPROVIDERCTX pCtx,
514 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
515{
516 LogFlowFuncEnter();
517
518 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
519 AssertPtr(pTransfer);
520
521 int rc;
522
523 PSHCLLISTHANDLEINFO pInfo = ShClTransferListGetByHandle(pTransfer, hList);
524 if (pInfo)
525 {
526 rc = ShClTransferListHdrInit(pListHdr);
527 if (RT_SUCCESS(rc))
528 {
529 switch (pInfo->enmType)
530 {
531 case SHCLOBJTYPE_DIRECTORY:
532 {
533 LogFlowFunc(("DirAbs: %s\n", pInfo->pszPathLocalAbs));
534
535 rc = shclTransferListHdrFromDir(pListHdr, pInfo->pszPathLocalAbs);
536 break;
537 }
538
539 case SHCLOBJTYPE_FILE:
540 {
541 LogFlowFunc(("FileAbs: %s\n", pInfo->pszPathLocalAbs));
542
543 pListHdr->cEntries = 1;
544
545 RTFSOBJINFO objInfo;
546 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);
547 if (RT_SUCCESS(rc))
548 {
549 pListHdr->cbTotalSize = objInfo.cbObject;
550 }
551 break;
552 }
553
554 /* We don't support symlinks (yet). */
555
556 default:
557 rc = VERR_NOT_SUPPORTED;
558 break;
559 }
560 }
561
562 LogFlowFunc(("cTotalObj=%RU64, cbTotalSize=%RU64\n", pListHdr->cEntries, pListHdr->cbTotalSize));
563 }
564 else
565 rc = VERR_NOT_FOUND;
566
567 LogFlowFuncLeaveRC(rc);
568 return rc;
569}
570
571/** @copydoc SHCLTXPROVIDERIFACE::pfnListEntryRead */
572static DECLCALLBACK(int) shclTransferIfaceLocalListEntryRead(PSHCLTXPROVIDERCTX pCtx,
573 SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)
574{
575 LogFlowFuncEnter();
576
577 int rc;
578
579 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
580 AssertPtr(pTransfer);
581
582 PSHCLLISTHANDLEINFO pInfo = ShClTransferListGetByHandle(pTransfer, hList);
583 if (pInfo)
584 {
585 switch (pInfo->enmType)
586 {
587 case SHCLOBJTYPE_DIRECTORY:
588 {
589 LogFlowFunc(("\tDirectory: %s\n", pInfo->pszPathLocalAbs));
590
591 for (;;)
592 {
593 bool fSkipEntry = false; /* Whether to skip an entry in the enumeration. */
594
595 size_t cbDirEntry = 0;
596 PRTDIRENTRYEX pDirEntry = NULL;
597 rc = RTDirReadExA(pInfo->u.Local.hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
598 if (RT_SUCCESS(rc))
599 {
600 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
601 {
602 case RTFS_TYPE_DIRECTORY:
603 {
604 /* Skip "." and ".." entries. */
605 if (RTDirEntryExIsStdDotLink(pDirEntry))
606 {
607 fSkipEntry = true;
608 break;
609 }
610
611 LogFlowFunc(("Directory: %s\n", pDirEntry->szName));
612 break;
613 }
614
615 case RTFS_TYPE_FILE:
616 {
617 LogFlowFunc(("File: %s\n", pDirEntry->szName));
618 break;
619 }
620
621 case RTFS_TYPE_SYMLINK:
622 {
623 rc = VERR_NOT_IMPLEMENTED; /** @todo Not implemented yet. */
624 break;
625 }
626
627 default:
628 break;
629 }
630
631 if ( RT_SUCCESS(rc)
632 && !fSkipEntry)
633 {
634 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pDirEntry->szName);
635 if (RT_SUCCESS(rc))
636 {
637 pEntry->cbName = (uint32_t)strlen(pEntry->pszName) + 1; /* Include termination. */
638
639 AssertPtr(pEntry->pvInfo);
640 Assert (pEntry->cbInfo == sizeof(SHCLFSOBJINFO));
641
642 ShClFsObjInfoFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &pDirEntry->Info);
643
644 LogFlowFunc(("Entry pszName=%s, pvInfo=%p, cbInfo=%RU32\n",
645 pEntry->pszName, pEntry->pvInfo, pEntry->cbInfo));
646 }
647 }
648
649 RTDirReadExAFree(&pDirEntry, &cbDirEntry);
650 }
651
652 if ( !fSkipEntry /* Do we have a valid entry? Bail out. */
653 || RT_FAILURE(rc))
654 {
655 break;
656 }
657 }
658
659 break;
660 }
661
662 case SHCLOBJTYPE_FILE:
663 {
664 LogFlowFunc(("\tSingle file: %s\n", pInfo->pszPathLocalAbs));
665
666 RTFSOBJINFO objInfo;
667 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);
668 if (RT_SUCCESS(rc))
669 {
670 pEntry->pvInfo = (PSHCLFSOBJINFO)RTMemAlloc(sizeof(SHCLFSOBJINFO));
671 if (pEntry->pvInfo)
672 {
673 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pInfo->pszPathLocalAbs);
674 if (RT_SUCCESS(rc))
675 {
676 ShClFsObjInfoFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &objInfo);
677
678 pEntry->cbInfo = sizeof(SHCLFSOBJINFO);
679 pEntry->fInfo = VBOX_SHCL_INFO_F_FSOBJINFO;
680 }
681 }
682 else
683 rc = VERR_NO_MEMORY;
684 }
685
686 break;
687 }
688
689 default:
690 rc = VERR_NOT_SUPPORTED;
691 break;
692 }
693 }
694 else
695 rc = VERR_NOT_FOUND;
696
697 LogFlowFuncLeaveRC(rc);
698 return rc;
699}
700
701/** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */
702static DECLCALLBACK(int) shclTransferIfaceLocalObjOpen(PSHCLTXPROVIDERCTX pCtx,
703 PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
704{
705 LogFlowFuncEnter();
706
707 int rc;
708
709 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
710 AssertPtr(pTransfer);
711
712 PSHCLOBJHANDLEINFO pInfo = (PSHCLOBJHANDLEINFO)RTMemAllocZ(sizeof(SHCLOBJHANDLEINFO));
713 if (pInfo)
714 {
715 rc = ShClTransferObjHandleInfoInit(pInfo);
716 if (RT_SUCCESS(rc))
717 {
718 uint64_t fOpen;
719 rc = shClConvertFileCreateFlags(pCreateParms->fCreate, &fOpen);
720 if (RT_SUCCESS(rc))
721 {
722 rc = shClTransferResolvePathAbs(pTransfer, pCreateParms->pszPath, 0 /* fFlags */,
723 &pInfo->pszPathLocalAbs);
724 if (RT_SUCCESS(rc))
725 {
726 rc = RTFileOpen(&pInfo->u.Local.hFile, pInfo->pszPathLocalAbs, fOpen);
727 if (RT_SUCCESS(rc))
728 LogRel2(("Shared Clipboard: Opened file '%s'\n", pInfo->pszPathLocalAbs));
729 else
730 LogRel(("Shared Clipboard: Error opening file '%s': rc=%Rrc\n", pInfo->pszPathLocalAbs, rc));
731 }
732 }
733 }
734
735 if (RT_SUCCESS(rc))
736 {
737 pInfo->hObj = pTransfer->uObjHandleNext++;
738 pInfo->enmType = SHCLOBJTYPE_FILE;
739
740 RTListAppend(&pTransfer->lstObj, &pInfo->Node);
741 pTransfer->cObjHandles++;
742
743 LogFlowFunc(("cObjHandles=%RU32\n", pTransfer->cObjHandles));
744
745 *phObj = pInfo->hObj;
746 }
747 else
748 {
749 ShClTransferObjHandleInfoDestroy(pInfo);
750 RTMemFree(pInfo);
751 }
752 }
753 else
754 rc = VERR_NO_MEMORY;
755
756 LogFlowFuncLeaveRC(rc);
757 return rc;
758}
759
760/** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */
761static DECLCALLBACK(int) shclTransferIfaceLocalObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
762{
763 LogFlowFuncEnter();
764
765 int rc;
766
767 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
768 AssertPtr(pTransfer);
769
770 PSHCLOBJHANDLEINFO pInfo = ShClTransferObjGet(pTransfer, hObj);
771 if (pInfo)
772 {
773 switch (pInfo->enmType)
774 {
775 case SHCLOBJTYPE_DIRECTORY:
776 {
777 rc = RTDirClose(pInfo->u.Local.hDir);
778 if (RT_SUCCESS(rc))
779 {
780 pInfo->u.Local.hDir = NIL_RTDIR;
781
782 LogRel2(("Shared Clipboard: Closed directory '%s'\n", pInfo->pszPathLocalAbs));
783 }
784 else
785 LogRel(("Shared Clipboard: Closing directory '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));
786 break;
787 }
788
789 case SHCLOBJTYPE_FILE:
790 {
791 rc = RTFileClose(pInfo->u.Local.hFile);
792 if (RT_SUCCESS(rc))
793 {
794 pInfo->u.Local.hFile = NIL_RTFILE;
795
796 LogRel2(("Shared Clipboard: Closed file '%s'\n", pInfo->pszPathLocalAbs));
797 }
798 else
799 LogRel(("Shared Clipboard: Closing file '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));
800 break;
801 }
802
803 default:
804 rc = VERR_NOT_IMPLEMENTED;
805 break;
806 }
807
808 RTListNodeRemove(&pInfo->Node);
809
810 Assert(pTransfer->cObjHandles);
811 pTransfer->cObjHandles--;
812
813 ShClTransferObjHandleInfoDestroy(pInfo);
814
815 RTMemFree(pInfo);
816 pInfo = NULL;
817 }
818 else
819 rc = VERR_NOT_FOUND;
820
821 LogFlowFuncLeaveRC(rc);
822 return rc;
823}
824
825/** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */
826static DECLCALLBACK(int) shclTransferIfaceLocalObjRead(PSHCLTXPROVIDERCTX pCtx,
827 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
828 uint32_t fFlags, uint32_t *pcbRead)
829{
830 RT_NOREF(fFlags);
831
832 LogFlowFuncEnter();
833
834 int rc;
835
836 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
837 AssertPtr(pTransfer);
838
839 PSHCLOBJHANDLEINFO pInfo = ShClTransferObjGet(pTransfer, hObj);
840 if (pInfo)
841 {
842 switch (pInfo->enmType)
843 {
844 case SHCLOBJTYPE_FILE:
845 {
846 size_t cbRead;
847 rc = RTFileRead(pInfo->u.Local.hFile, pvData, cbData, &cbRead);
848 if (RT_SUCCESS(rc))
849 {
850 if (pcbRead)
851 *pcbRead = (uint32_t)cbRead;
852 }
853 break;
854 }
855
856 default:
857 rc = VERR_NOT_SUPPORTED;
858 break;
859 }
860 }
861 else
862 rc = VERR_NOT_FOUND;
863
864 LogFlowFuncLeaveRC(rc);
865 return rc;
866}
867
868static DECLCALLBACK(int) shclTransferIfaceLocalObjWrite(PSHCLTXPROVIDERCTX pCtx,
869 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData, uint32_t fFlags,
870 uint32_t *pcbWritten)
871{
872 RT_NOREF(fFlags);
873
874 LogFlowFuncEnter();
875
876 int rc;
877
878 PSHCLTRANSFER const pTransfer = pCtx->pTransfer;
879 AssertPtr(pTransfer);
880
881 PSHCLOBJHANDLEINFO pInfo = ShClTransferObjGet(pTransfer, hObj);
882 if (pInfo)
883 {
884 switch (pInfo->enmType)
885 {
886 case SHCLOBJTYPE_FILE:
887 {
888 rc = RTFileWrite(pInfo->u.Local.hFile, pvData, cbData, (size_t *)pcbWritten);
889 break;
890 }
891
892 default:
893 rc = VERR_NOT_SUPPORTED;
894 break;
895 }
896 }
897 else
898 rc = VERR_NOT_FOUND;
899
900 LogFlowFuncLeaveRC(rc);
901 return rc;
902}
903
904/**
905 * Queries (assigns) the local provider to an interface.
906 *
907 * The local provider is being used for accessing files on local file systems.
908 *
909 * @returns Interface pointer assigned to the provider.
910 * @param pProvider Provider to assign interface to.
911 */
912PSHCLTXPROVIDERIFACE VBClTransferProviderLocalQueryInterface(PSHCLTXPROVIDER pProvider)
913{
914 pProvider->Interface.pfnRootListRead = shclTransferIfaceLocalRootListRead;
915 pProvider->Interface.pfnListOpen = shclTransferIfaceLocalListOpen;
916 pProvider->Interface.pfnListClose = shclTransferIfaceLocalListClose;
917 pProvider->Interface.pfnListHdrRead = shclTransferIfaceLocalListHdrRead;
918 pProvider->Interface.pfnListEntryRead = shclTransferIfaceLocalListEntryRead;
919 pProvider->Interface.pfnObjOpen = shclTransferIfaceLocalObjOpen;
920 pProvider->Interface.pfnObjClose = shclTransferIfaceLocalObjClose;
921 pProvider->Interface.pfnObjRead = shclTransferIfaceLocalObjRead;
922 pProvider->Interface.pfnObjWrite = shclTransferIfaceLocalObjWrite;
923
924 return &pProvider->Interface;
925}
926
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